Autopsy  3.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
IngestManager.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2014 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.ingest;
20 
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.awt.EventQueue;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.beans.PropertyChangeSupport;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Date;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.Callable;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.concurrent.ExecutorService;
35 import java.util.concurrent.Executors;
36 import java.util.concurrent.Future;
37 import java.util.concurrent.atomic.AtomicLong;
38 import java.util.logging.Level;
39 import javax.swing.JOptionPane;
40 import org.netbeans.api.progress.ProgressHandle;
41 import org.netbeans.api.progress.ProgressHandleFactory;
42 import org.openide.util.Cancellable;
43 import org.openide.util.NbBundle;
50 
55 public class IngestManager {
56 
57  private static final Logger logger = Logger.getLogger(IngestManager.class.getName());
58  private static IngestManager instance;
59 
64  private final ConcurrentHashMap<Long, IngestJob> jobsById;
65 
70  private final AtomicLong nextThreadId;
71 
78  private final ConcurrentHashMap<Long, Future<Void>> ingestJobStarters;
79  private final ExecutorService startIngestJobsThreadPool;
80 
88  private final ExecutorService dataSourceIngestThreadPool;
89  private static final int MIN_NUMBER_OF_FILE_INGEST_THREADS = 1;
90  private static final int MAX_NUMBER_OF_FILE_INGEST_THREADS = 16;
91  private static final int DEFAULT_NUMBER_OF_FILE_INGEST_THREADS = 2;
93  private final ExecutorService fileIngestThreadPool;
94 
101  private final PropertyChangeSupport ingestJobEventPublisher;
102  private final PropertyChangeSupport ingestModuleEventPublisher;
103  private final ExecutorService fireIngestEventsThreadPool;
104 
111 
117  private static final int MAX_ERROR_MESSAGE_POSTS = 200;
118  private volatile IngestMessageTopComponent ingestMessageBox;
119  private final AtomicLong ingestErrorMessagePosts;
120 
126  private final ConcurrentHashMap<Long, IngestThreadActivitySnapshot> ingestThreadActivitySnapshots;
127  private final ConcurrentHashMap<String, Long> ingestModuleRunTimes;
128 
133  private volatile boolean jobCreationIsEnabled;
134 
140  private volatile boolean runInteractively;
141 
145  public enum IngestJobEvent {
146 
165  };
166 
170  public enum IngestModuleEvent {
171 
194  };
195 
202  public synchronized static IngestManager getInstance() {
203  if (instance == null) {
209  instance = new IngestManager();
210  instance.subscribeToCaseEvents();
211  }
212  return instance;
213  }
214 
223  private IngestManager() {
224  this.runInteractively = true;
225  this.ingestModuleRunTimes = new ConcurrentHashMap<>();
226  this.ingestThreadActivitySnapshots = new ConcurrentHashMap<>();
227  this.ingestErrorMessagePosts = new AtomicLong(0L);
228  this.ingestMonitor = new IngestMonitor();
229  this.ingestModuleEventPublisher = new PropertyChangeSupport(IngestManager.class);
230  this.fireIngestEventsThreadPool = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IM-ingest-events-%d").build()); //NON-NLS
231  this.ingestJobEventPublisher = new PropertyChangeSupport(IngestManager.class);
232  this.dataSourceIngestThreadPool = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IM-data-source-ingest-%d").build()); //NON-NLS
233  this.startIngestJobsThreadPool = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IM-start-ingest-jobs-%d").build()); //NON-NLS
234  this.nextThreadId = new AtomicLong(0L);
235  this.jobsById = new ConcurrentHashMap<>();
236  this.ingestJobStarters = new ConcurrentHashMap<>();
237 
239 
240  numberOfFileIngestThreads = UserPreferences.numberOfFileIngestThreads();
241  if ((numberOfFileIngestThreads < MIN_NUMBER_OF_FILE_INGEST_THREADS) || (numberOfFileIngestThreads > MAX_NUMBER_OF_FILE_INGEST_THREADS)) {
242  numberOfFileIngestThreads = DEFAULT_NUMBER_OF_FILE_INGEST_THREADS;
243  UserPreferences.setNumberOfFileIngestThreads(numberOfFileIngestThreads);
244  }
245  fileIngestThreadPool = Executors.newFixedThreadPool(numberOfFileIngestThreads, new ThreadFactoryBuilder().setNameFormat("IM-file-ingest-%d").build()); //NON-NLS
246  for (int i = 0; i < numberOfFileIngestThreads; ++i) {
248  }
249  }
250 
256  long threadId = nextThreadId.incrementAndGet();
257  dataSourceIngestThreadPool.submit(new IngestTaskExecuter(threadId, IngestTasksScheduler.getInstance().getDataSourceIngestTaskQueue()));
258  ingestThreadActivitySnapshots.put(threadId, new IngestThreadActivitySnapshot(threadId));
259  }
260 
265  private void startFileIngestThread() {
266  long threadId = nextThreadId.incrementAndGet();
267  fileIngestThreadPool.submit(new IngestTaskExecuter(threadId, IngestTasksScheduler.getInstance().getFileIngestTaskQueue()));
268  ingestThreadActivitySnapshots.put(threadId, new IngestThreadActivitySnapshot(threadId));
269  }
270 
271  private void subscribeToCaseEvents() {
272  Case.addPropertyChangeListener(new PropertyChangeListener() {
273  @Override
274  public void propertyChange(PropertyChangeEvent event) {
275  if (event.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
276  if (event.getNewValue() != null) {
277  handleCaseOpened();
278  } else {
279  handleCaseClosed();
280  }
281  }
282  }
283  });
284  }
285 
286  synchronized void handleCaseOpened() {
287  this.jobCreationIsEnabled = true;
289  }
290 
291  synchronized void handleCaseClosed() {
292  this.jobCreationIsEnabled = false;
295  }
296 
305  public synchronized void setRunInteractively(boolean runInteractively) {
306  this.runInteractively = runInteractively;
307  }
308 
314  void initIngestMessageInbox() {
315  ingestMessageBox = IngestMessageTopComponent.findInstance();
316  }
317 
323  synchronized void postIngestMessage(IngestMessage message) {
324  if (ingestMessageBox != null && this.runInteractively) {
325  if (message.getMessageType() != IngestMessage.MessageType.ERROR && message.getMessageType() != IngestMessage.MessageType.WARNING) {
326  ingestMessageBox.displayMessage(message);
327  } else {
328  long errorPosts = ingestErrorMessagePosts.incrementAndGet();
329  if (errorPosts <= MAX_ERROR_MESSAGE_POSTS) {
330  ingestMessageBox.displayMessage(message);
331  } else if (errorPosts == MAX_ERROR_MESSAGE_POSTS + 1) {
332  IngestMessage errorMessageLimitReachedMessage = IngestMessage.createErrorMessage(
333  NbBundle.getMessage(this.getClass(), "IngestManager.IngestMessage.ErrorMessageLimitReached.title"),
334  NbBundle.getMessage(this.getClass(), "IngestManager.IngestMessage.ErrorMessageLimitReached.subject"),
335  NbBundle.getMessage(this.getClass(), "IngestManager.IngestMessage.ErrorMessageLimitReached.msg", MAX_ERROR_MESSAGE_POSTS));
336  ingestMessageBox.displayMessage(errorMessageLimitReachedMessage);
337  }
338  }
339  }
340  }
341 
342  private void clearIngestMessageBox() {
343  if (ingestMessageBox != null) {
344  ingestMessageBox.clearMessages();
345  }
346  ingestErrorMessagePosts.set(0);
347  }
348 
357  }
358 
366  public synchronized void queueIngestJob(Collection<Content> dataSources, IngestJobSettings settings) {
367  if (this.jobCreationIsEnabled) {
368  IngestJob job = new IngestJob(dataSources, settings, this.runInteractively);
369  if (job.hasIngestPipeline()) {
370  long taskId = nextThreadId.incrementAndGet();
371  Future<Void> task = startIngestJobsThreadPool.submit(new IngestJobStarter(taskId, job));
372  ingestJobStarters.put(taskId, task);
373  }
374  }
375  }
376 
384  public synchronized IngestJob startIngestJob(Collection<Content> dataSources, IngestJobSettings settings) {
385  if (this.jobCreationIsEnabled) {
386  IngestJob job = new IngestJob(dataSources, settings, this.runInteractively);
387  if (job.hasIngestPipeline()) {
388  if (this.startIngestJob(job)) {
389  return job;
390  }
391  }
392  }
393  return null;
394  }
395 
402  private boolean startIngestJob(IngestJob job) {
403  boolean success = false;
404  if (this.jobCreationIsEnabled) {
408  if (runInteractively && jobsById.size() == 1) {
410  }
411 
412  if (!ingestMonitor.isRunning()) {
413  ingestMonitor.start();
414  }
415 
422  this.jobsById.put(job.getId(), job);
423  List<IngestModuleError> errors = job.start();
424  if (errors.isEmpty()) {
425  this.fireIngestJobStarted(job.getId());
426  IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS
427  success = true;
428  } else {
429  this.jobsById.remove(job.getId());
430  for (IngestModuleError error : errors) {
431  logger.log(Level.SEVERE, String.format("Error starting %s ingest module", error.getModuleDisplayName()), error.getModuleError()); //NON-NLS
432  }
433  IngestManager.logger.log(Level.INFO, "Ingest job {0} could not be started", job.getId()); //NON-NLS
434  if (this.runInteractively) {
435  EventQueue.invokeLater(new Runnable() {
436 
437  @Override
438  public void run() {
439  StringBuilder moduleStartUpErrors = new StringBuilder();
440  for (IngestModuleError error : errors) {
441  String moduleName = error.getModuleDisplayName();
442  moduleStartUpErrors.append(moduleName);
443  moduleStartUpErrors.append(": ");
444  moduleStartUpErrors.append(error.getModuleError().getLocalizedMessage());
445  moduleStartUpErrors.append("\n");
446  }
447  StringBuilder notifyMessage = new StringBuilder();
448  notifyMessage.append(NbBundle.getMessage(this.getClass(),
449  "IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg"));
450  notifyMessage.append("\n");
451  notifyMessage.append(NbBundle.getMessage(this.getClass(),
452  "IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution"));
453  notifyMessage.append("\n");
454  notifyMessage.append(NbBundle.getMessage(this.getClass(),
455  "IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList",
456  moduleStartUpErrors.toString()));
457  notifyMessage.append("\n\n");
458  JOptionPane.showMessageDialog(null, notifyMessage.toString(),
459  NbBundle.getMessage(this.getClass(),
460  "IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle"), JOptionPane.ERROR_MESSAGE);
461  }
462  });
463  }
464  }
465  }
466  return success;
467  }
468 
469  synchronized void finishIngestJob(IngestJob job) {
470  long jobId = job.getId();
471  this.jobsById.remove(jobId);
472  if (!job.isCancelled()) {
473  IngestManager.logger.log(Level.INFO, "Ingest job {0} completed", jobId); //NON-NLS
474  this.fireIngestJobCompleted(jobId);
475  } else {
476  IngestManager.logger.log(Level.INFO, "Ingest job {0} cancelled", jobId); //NON-NLS
477  this.fireIngestJobCancelled(jobId);
478  }
479  }
480 
486  public boolean isIngestRunning() {
487  return !this.jobsById.isEmpty();
488  }
489 
493  public synchronized void cancelAllIngestJobs() {
494  // Stop creating new ingest jobs.
495  for (Future<Void> handle : ingestJobStarters.values()) {
496  handle.cancel(true);
497  }
498 
499  // Cancel all the jobs already created.
500  for (IngestJob job : this.jobsById.values()) {
501  job.cancel();
502  }
503  }
504 
510  public void addIngestJobEventListener(final PropertyChangeListener listener) {
511  ingestJobEventPublisher.addPropertyChangeListener(listener);
512  }
513 
519  public void removeIngestJobEventListener(final PropertyChangeListener listener) {
520  ingestJobEventPublisher.removePropertyChangeListener(listener);
521  }
522 
528  public void addIngestModuleEventListener(final PropertyChangeListener listener) {
529  ingestModuleEventPublisher.addPropertyChangeListener(listener);
530  }
531 
537  public void removeIngestModuleEventListener(final PropertyChangeListener listener) {
538  ingestModuleEventPublisher.removePropertyChangeListener(listener);
539  }
540 
548  @Deprecated
549  public static void addPropertyChangeListener(final PropertyChangeListener listener) {
550  instance.ingestJobEventPublisher.addPropertyChangeListener(listener);
551  instance.ingestModuleEventPublisher.addPropertyChangeListener(listener);
552  }
553 
561  @Deprecated
562  public static void removePropertyChangeListener(final PropertyChangeListener listener) {
563  instance.ingestJobEventPublisher.removePropertyChangeListener(listener);
564  instance.ingestModuleEventPublisher.removePropertyChangeListener(listener);
565  }
566 
572  void fireIngestJobStarted(long ingestJobId) {
573  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestJobEventPublisher, IngestJobEvent.STARTED, ingestJobId, null));
574  }
575 
581  void fireIngestJobCompleted(long ingestJobId) {
582  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestJobEventPublisher, IngestJobEvent.COMPLETED, ingestJobId, null));
583  }
584 
590  void fireIngestJobCancelled(long ingestJobId) {
591  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestJobEventPublisher, IngestJobEvent.CANCELLED, ingestJobId, null));
592  }
593 
599  void fireFileIngestDone(AbstractFile file) {
600  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestModuleEventPublisher, IngestModuleEvent.FILE_DONE, file.getId(), file));
601  }
602 
608  void fireIngestModuleDataEvent(ModuleDataEvent moduleDataEvent) {
609  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestModuleEventPublisher, IngestModuleEvent.DATA_ADDED, moduleDataEvent, null));
610  }
611 
619  void fireIngestModuleContentEvent(ModuleContentEvent moduleContentEvent) {
620  fireIngestEventsThreadPool.submit(new IngestEventPublisher(ingestModuleEventPublisher, IngestModuleEvent.CONTENT_CHANGED, moduleContentEvent, null));
621  }
622 
629  void setIngestTaskProgress(DataSourceIngestTask task, String ingestModuleDisplayName) {
630  ingestThreadActivitySnapshots.put(task.getThreadId(), new IngestThreadActivitySnapshot(task.getThreadId(), task.getIngestJob().getId(), ingestModuleDisplayName, task.getDataSource()));
631  }
632 
639  void setIngestTaskProgress(FileIngestTask task, String ingestModuleDisplayName) {
640  IngestThreadActivitySnapshot prevSnap = ingestThreadActivitySnapshots.get(task.getThreadId());
641  IngestThreadActivitySnapshot newSnap = new IngestThreadActivitySnapshot(task.getThreadId(), task.getIngestJob().getId(), ingestModuleDisplayName, task.getDataSource(), task.getFile());
642  ingestThreadActivitySnapshots.put(task.getThreadId(), newSnap);
643 
644  incrementModuleRunTime(prevSnap.getActivity(), newSnap.getStartTime().getTime() - prevSnap.getStartTime().getTime());
645  }
646 
652  void setIngestTaskProgressCompleted(DataSourceIngestTask task) {
653  ingestThreadActivitySnapshots.put(task.getThreadId(), new IngestThreadActivitySnapshot(task.getThreadId()));
654  }
655 
661  void setIngestTaskProgressCompleted(FileIngestTask task) {
662  IngestThreadActivitySnapshot prevSnap = ingestThreadActivitySnapshots.get(task.getThreadId());
663  IngestThreadActivitySnapshot newSnap = new IngestThreadActivitySnapshot(task.getThreadId());
664  ingestThreadActivitySnapshots.put(task.getThreadId(), newSnap);
665  incrementModuleRunTime(prevSnap.getActivity(), newSnap.getStartTime().getTime() - prevSnap.getStartTime().getTime());
666  }
667 
674  private void incrementModuleRunTime(String moduleName, Long duration) {
675  if (moduleName.equals("IDLE")) { //NON-NLS
676  return;
677  }
678 
679  synchronized (ingestModuleRunTimes) {
680  Long prevTimeL = ingestModuleRunTimes.get(moduleName);
681  long prevTime = 0;
682  if (prevTimeL != null) {
683  prevTime = prevTimeL;
684  }
685  prevTime += duration;
686  ingestModuleRunTimes.put(moduleName, prevTime);
687  }
688  }
689 
695  Map<String, Long> getModuleRunTimes() {
696  synchronized (ingestModuleRunTimes) {
697  Map<String, Long> times = new HashMap<>(ingestModuleRunTimes);
698  return times;
699  }
700  }
701 
707  List<IngestThreadActivitySnapshot> getIngestThreadActivitySnapshots() {
708  return new ArrayList<>(ingestThreadActivitySnapshots.values());
709  }
710 
716  List<DataSourceIngestJob.Snapshot> getIngestJobSnapshots() {
717  List<DataSourceIngestJob.Snapshot> snapShots = new ArrayList<>();
718  for (IngestJob job : this.jobsById.values()) {
719  snapShots.addAll(job.getDataSourceIngestJobSnapshots());
720  }
721  return snapShots;
722  }
723 
730  long getFreeDiskSpace() {
731  if (ingestMonitor != null) {
732  return ingestMonitor.getFreeSpace();
733  } else {
734  return -1;
735  }
736  }
737 
741  private final class IngestJobStarter implements Callable<Void> {
742 
743  private final long threadId;
744  private final IngestJob job;
745  private ProgressHandle progress;
746 
747  IngestJobStarter(long threadId, IngestJob job) {
748  this.threadId = threadId;
749  this.job = job;
750  }
751 
752  @Override
753  public Void call() {
754  try {
755  if (Thread.currentThread().isInterrupted()) {
756  jobsById.remove(job.getId());
757  return null;
758  }
759 
760  if (runInteractively) {
761  final String displayName = NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.displayName");
762  this.progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() {
763  @Override
764  public boolean cancel() {
765  if (progress != null) {
766  progress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.cancelling", displayName));
767  }
768  Future<?> handle = ingestJobStarters.remove(threadId);
769  handle.cancel(true);
770  return true;
771  }
772  });
773  progress.start();
774  }
775 
776  startIngestJob(job);
777  return null;
778 
779  } finally {
780  if (null != progress) {
781  progress.finish();
782  }
783  ingestJobStarters.remove(threadId);
784  }
785  }
786 
787  }
788 
792  private final class IngestTaskExecuter implements Runnable {
793 
794  private final long threadId;
795  private final IngestTaskQueue tasks;
796 
797  IngestTaskExecuter(long threadId, IngestTaskQueue tasks) {
798  this.threadId = threadId;
799  this.tasks = tasks;
800  }
801 
802  @Override
803  public void run() {
804  while (true) {
805  try {
806  IngestTask task = tasks.getNextTask(); // Blocks.
807  task.execute(threadId);
808  } catch (InterruptedException ex) {
809  break;
810  }
811  if (Thread.currentThread().isInterrupted()) {
812  break;
813  }
814  }
815  }
816  }
817 
821  private static final class IngestEventPublisher implements Runnable {
822 
823  private final PropertyChangeSupport publisher;
824  private final IngestJobEvent jobEvent;
826  private final Object oldValue;
827  private final Object newValue;
828 
829  IngestEventPublisher(PropertyChangeSupport publisher, IngestJobEvent event, Object oldValue, Object newValue) {
830  this.publisher = publisher;
831  this.jobEvent = event;
832  this.moduleEvent = null;
833  this.oldValue = oldValue;
834  this.newValue = newValue;
835  }
836 
837  IngestEventPublisher(PropertyChangeSupport publisher, IngestModuleEvent event, Object oldValue, Object newValue) {
838  this.publisher = publisher;
839  this.jobEvent = null;
840  this.moduleEvent = event;
841  this.oldValue = oldValue;
842  this.newValue = newValue;
843  }
844 
845  @Override
846  public void run() {
847  try {
848  publisher.firePropertyChange((jobEvent != null ? jobEvent.toString() : moduleEvent.toString()), oldValue, newValue);
849  } catch (Exception e) {
850  logger.log(Level.SEVERE, "Ingest manager listener threw exception", e); //NON-NLS
851  MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"),
852  NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"),
854  }
855  }
856  }
857 
858  static final class IngestThreadActivitySnapshot {
859 
860  private final long threadId;
861  private final Date startTime;
862  private final String activity;
863  private final String dataSourceName;
864  private final String fileName;
865  private final long jobId;
866 
867  // nothing is running on the thread
868  IngestThreadActivitySnapshot(long threadId) {
869  this.threadId = threadId;
870  startTime = new Date();
871  this.activity = NbBundle.getMessage(this.getClass(), "IngestManager.IngestThreadActivitySnapshot.idleThread");
872  this.dataSourceName = "";
873  this.fileName = "";
874  this.jobId = 0;
875  }
876 
877  // data souce thread
878  IngestThreadActivitySnapshot(long threadId, long jobId, String activity, Content dataSource) {
879  this.threadId = threadId;
880  this.jobId = jobId;
881  startTime = new Date();
882  this.activity = activity;
883  this.dataSourceName = dataSource.getName();
884  this.fileName = "";
885  }
886 
887  // file ingest thread
888  IngestThreadActivitySnapshot(long threadId, long jobId, String activity, Content dataSource, AbstractFile file) {
889  this.threadId = threadId;
890  this.jobId = jobId;
891  startTime = new Date();
892  this.activity = activity;
893  this.dataSourceName = dataSource.getName();
894  this.fileName = file.getName();
895  }
896 
897  long getJobId() {
898  return jobId;
899  }
900 
901  long getThreadId() {
902  return threadId;
903  }
904 
905  Date getStartTime() {
906  return startTime;
907  }
908 
909  String getActivity() {
910  return activity;
911  }
912 
913  String getDataSourceName() {
914  return dataSourceName;
915  }
916 
917  String getFileName() {
918  return fileName;
919  }
920 
921  }
922 
923 }
final ConcurrentHashMap< String, Long > ingestModuleRunTimes
final ConcurrentHashMap< Long, IngestJob > jobsById
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
final PropertyChangeSupport ingestJobEventPublisher
static void addPropertyChangeListener(final PropertyChangeListener listener)
final ConcurrentHashMap< Long, Future< Void > > ingestJobStarters
static void removePropertyChangeListener(final PropertyChangeListener listener)
volatile IngestMessageTopComponent ingestMessageBox
synchronized void queueIngestJob(Collection< Content > dataSources, IngestJobSettings settings)
void removeIngestJobEventListener(final PropertyChangeListener listener)
void incrementModuleRunTime(String moduleName, Long duration)
void addIngestJobEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:833
static void show(String title, String message, MessageType type, ActionListener actionListener)
synchronized IngestJob startIngestJob(Collection< Content > dataSources, IngestJobSettings settings)
final ConcurrentHashMap< Long, IngestThreadActivitySnapshot > ingestThreadActivitySnapshots
static Logger getLogger(String name)
Definition: Logger.java:131
synchronized void setRunInteractively(boolean runInteractively)
final PropertyChangeSupport ingestModuleEventPublisher

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.