Package com.github.hakko.musiccabinet.service.library

Source Code of com.github.hakko.musiccabinet.service.library.LibraryScannerService

package com.github.hakko.musiccabinet.service.library;

import static com.github.hakko.musiccabinet.service.library.LibraryUtil.FINISHED_MESSAGE;
import static com.github.hakko.musiccabinet.service.library.LibraryUtil.msg;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.core.PollableChannel;

import com.github.hakko.musiccabinet.domain.model.aggr.SearchIndexUpdateProgress;
import com.github.hakko.musiccabinet.domain.model.library.File;
import com.github.hakko.musiccabinet.exception.ApplicationException;
import com.github.hakko.musiccabinet.io.LibraryScanner;
import com.github.hakko.musiccabinet.log.Logger;

/*
* The library scanning is modeled according to the "Pipes and Filters"
* Enterprise Integration Pattern (EIP), and realized by Spring Integration.
*
* This class acts as a starting point that initiates all filters (running
* them as separate threads), and sends out a finishing message when the
* scanning is done.
*/
public class LibraryScannerService {

  private PollableChannel libraryPresenceChannel; // producer of
 
  private TaskExecutor taskExecutor;
  private CountDownLatch workerThreads = new CountDownLatch(0);
 
  private LibraryPresenceService libraryPresenceService;
  private LibraryMetadataService libraryMetadataService;
  private LibraryAdditionService libraryAdditionService;
  private LibraryDeletionService libraryDeletionService;
 
  protected String fileSeparator = java.io.File.separator;

  private boolean isLibraryBeingScanned = false;
 
  private static final Logger LOG = Logger.getLogger(LibraryScannerService.class);

  public void add(Set<String> paths) throws ApplicationException {
    update(paths, true);
  }

  public void update(Set<String> paths, boolean isRootPaths) throws ApplicationException {
    isLibraryBeingScanned = true;
    try {
      clearImport();
      startReceivingServices();
      Set<String> rootPaths = getRootPaths(paths);
      for (String path : rootPaths) {
        Files.walkFileTree(Paths.get(path), new LibraryScanner(libraryPresenceChannel));
      }
      if (isRootPaths) {
        libraryPresenceChannel.send(msg(null, rootPaths, new HashSet<File>()));
      }
      libraryPresenceChannel.send(FINISHED_MESSAGE);
      workerThreads.await();
      updateLibrary();
    } catch (IOException | InterruptedException e) {
      throw new ApplicationException("Scanning aborted due to error!", e);
    }
    isLibraryBeingScanned = false;
  }
 
  public void delete(Set<String> paths) throws ApplicationException {
    isLibraryBeingScanned = true;
    libraryDeletionService.delete(paths);
    isLibraryBeingScanned = false;
  }

  /*
   * If a user attempts to scan both /a and /a/b, silently ignore /a/b
   * and just scan /a.
   */
  protected Set<String> getRootPaths(Set<String> paths) {
    List<String> list = new ArrayList<>(paths);
    Collections.sort(list);
    Iterator<String> it = list.iterator();
    for (String prev = null; it.hasNext(); ) {
      String path = it.next();
      if (prev != null && path.startsWith(prev)) {
        it.remove();
      } else {
        prev = path.endsWith(fileSeparator) ? path : (path + fileSeparator);
      }
    }
    return new HashSet<>(list);
  }
 
  public boolean isLibraryBeingScanned() {
    return isLibraryBeingScanned;
  }
 
  public List<SearchIndexUpdateProgress> getUpdateProgress() {
    List<SearchIndexUpdateProgress> updateProgress = new ArrayList<>();
    updateProgress.add(libraryPresenceService.getUpdateProgress());
    updateProgress.add(libraryMetadataService.getUpdateProgress());
    return updateProgress;
  }
 
  private void clearImport() {
    libraryAdditionService.clearImport();
    libraryDeletionService.clearImport();
  }
 
  private void updateLibrary() {
    libraryDeletionService.updateLibrary();
    libraryAdditionService.updateLibrary();
  }
 
  private void startReceivingServices() {
    List<LibraryReceiverService> libraryReceiverServices = new ArrayList<>();
    libraryReceiverServices.add(libraryPresenceService);
    libraryReceiverServices.add(libraryMetadataService);
    libraryReceiverServices.add(libraryAdditionService);
    libraryReceiverServices.add(libraryDeletionService);
    workerThreads = new CountDownLatch(libraryReceiverServices.size());
    for (final LibraryReceiverService libraryReceiverService : libraryReceiverServices) {
      taskExecutor.execute(new Runnable() {
        @Override
        public void run() {
          try {
            libraryReceiverService.receive();
          } catch (Throwable t) {
            LOG.error("Unexpected error caught during scanning!", t);
            t.printStackTrace();
          } finally {
            workerThreads.countDown();
          }
        }
      });
    }
  }

  public void setLibraryPresenceChannel(PollableChannel libraryPresenceChannel) {
    this.libraryPresenceChannel = libraryPresenceChannel;
  }

  public void setTaskExecutor(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void setLibraryPresenceService(LibraryPresenceService libraryPresenceService) {
    this.libraryPresenceService = libraryPresenceService;
  }

  public void setLibraryMetadataService(LibraryMetadataService libraryMetadataService) {
    this.libraryMetadataService = libraryMetadataService;
  }

  public void setLibraryAdditionService(LibraryAdditionService libraryAdditionService) {
    this.libraryAdditionService = libraryAdditionService;
  }

  public void setLibraryDeletionService(LibraryDeletionService libraryDeletionService) {
    this.libraryDeletionService = libraryDeletionService;
  }

  protected void setFileSeparator(String fileSeparator) {
    this.fileSeparator = fileSeparator;
  }
 
}
TOP

Related Classes of com.github.hakko.musiccabinet.service.library.LibraryScannerService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.