Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataSourceIngestJob.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2014-2019 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 java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.CopyOnWriteArrayList;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.concurrent.atomic.AtomicLong;
31 import java.util.logging.Level;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 import java.util.stream.Stream;
35 import javax.swing.JOptionPane;
36 import org.netbeans.api.progress.ProgressHandle;
37 import org.openide.util.Cancellable;
38 import org.openide.util.NbBundle;
39 import org.openide.windows.WindowManager;
47 import org.sleuthkit.datamodel.AbstractFile;
48 import org.sleuthkit.datamodel.Content;
49 import org.sleuthkit.datamodel.IngestJobInfo;
50 import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType;
51 import org.sleuthkit.datamodel.IngestModuleInfo;
52 import org.sleuthkit.datamodel.IngestModuleInfo.IngestModuleType;
53 import org.sleuthkit.datamodel.SleuthkitCase;
54 import org.sleuthkit.datamodel.TskCoreException;
57 
62 public final class DataSourceIngestJob {
63 
64  private static String AUTOPSY_MODULE_PREFIX = "org.sleuthkit.autopsy";
65 
66  private static final Logger logger = Logger.getLogger(DataSourceIngestJob.class.getName());
67 
68  // to match something like: "org.python.proxies.GPX_Parser_Module$GPXParserFileIngestModuleFactory$14"
69  private static final Pattern JYTHON_REGEX = Pattern.compile("org\\.python\\.proxies\\.(.+?)\\$(.+?)(\\$[0-9]*)?$");
70 
77  private final IngestJob parentJob;
78  private static final AtomicLong nextJobId = new AtomicLong(0L);
79  private final long id;
80  private final IngestJobSettings settings;
81  private final Content dataSource;
82  private final List<AbstractFile> files = new ArrayList<>();
83 
87  private static enum Stages {
88 
106  FINALIZATION
107  };
109  private final Object stageCompletionCheckLock = new Object();
110 
119  private final Object dataSourceIngestPipelineLock = new Object();
120  private DataSourceIngestPipeline firstStageDataSourceIngestPipeline;
121  private DataSourceIngestPipeline secondStageDataSourceIngestPipeline;
122  private DataSourceIngestPipeline currentDataSourceIngestPipeline;
123 
131  private final LinkedBlockingQueue<FileIngestPipeline> fileIngestPipelinesQueue = new LinkedBlockingQueue<>();
132  private final List<FileIngestPipeline> fileIngestPipelines = new ArrayList<>();
133 
145  private volatile boolean currentDataSourceIngestModuleCancelled;
146  private final List<String> cancelledDataSourceIngestModules = new CopyOnWriteArrayList<>();
147  private volatile boolean cancelled;
149 
154  private static final IngestTasksScheduler taskScheduler = IngestTasksScheduler.getInstance();
155 
160  private final boolean doUI;
161 
166  private final Object dataSourceIngestProgressLock = new Object();
167  private ProgressHandle dataSourceIngestProgress;
168 
173  private final Object fileIngestProgressLock = new Object();
174  private final List<String> filesInProgress = new ArrayList<>();
176  private long processedFiles;
177  private ProgressHandle fileIngestProgress;
178  private String currentFileIngestModule = "";
179  private String currentFileIngestTask = "";
180  private final List<IngestModuleInfo> ingestModules = new ArrayList<>();
181  private volatile IngestJobInfo ingestJob;
182 
186  private final long createTime;
187 
199  DataSourceIngestJob(IngestJob parentJob, Content dataSource, IngestJobSettings settings, boolean runInteractively) {
200  this(parentJob, dataSource, Collections.emptyList(), settings, runInteractively);
201  }
202 
216  DataSourceIngestJob(IngestJob parentJob, Content dataSource, List<AbstractFile> files, IngestJobSettings settings, boolean runInteractively) {
217  this.parentJob = parentJob;
218  this.id = DataSourceIngestJob.nextJobId.getAndIncrement();
219  this.dataSource = dataSource;
220  this.files.addAll(files);
221  this.settings = settings;
222  this.doUI = runInteractively;
223  this.createTime = new Date().getTime();
224  this.createIngestPipelines();
225  }
226 
237  private static void addOrdered(final List<IngestModuleTemplate> dest,
238  final Map<String, IngestModuleTemplate> src, final Map<String, IngestModuleTemplate> jythonSrc) {
239 
240  final List<IngestModuleTemplate> autopsyModules = new ArrayList<>();
241  final List<IngestModuleTemplate> thirdPartyModules = new ArrayList<>();
242 
243  Stream.concat(src.entrySet().stream(), jythonSrc.entrySet().stream()).forEach((templateEntry) -> {
244  if (templateEntry.getKey().startsWith(AUTOPSY_MODULE_PREFIX)) {
245  autopsyModules.add(templateEntry.getValue());
246  } else {
247  thirdPartyModules.add(templateEntry.getValue());
248  }
249  });
250 
251  dest.addAll(autopsyModules);
252  dest.addAll(thirdPartyModules);
253  }
254 
265  private static String getJythonName(String canonicalName) {
266  Matcher m = JYTHON_REGEX.matcher(canonicalName);
267  if (m.find()) {
268  return String.format("%s.%s", m.group(1), m.group(2));
269  } else {
270  return null;
271  }
272  }
273 
283  private static void addModule(Map<String, IngestModuleTemplate> mapping,
284  Map<String, IngestModuleTemplate> jythonMapping, IngestModuleTemplate template) {
285 
286  String className = template.getModuleFactory().getClass().getCanonicalName();
287  String jythonName = getJythonName(className);
288  if (jythonName != null) {
289  jythonMapping.put(jythonName, template);
290  } else {
291  mapping.put(className, template);
292  }
293  }
294 
298  private void createIngestPipelines() {
299  List<IngestModuleTemplate> ingestModuleTemplates = this.settings.getEnabledIngestModuleTemplates();
300 
304  Map<String, IngestModuleTemplate> dataSourceModuleTemplates = new LinkedHashMap<>();
305  Map<String, IngestModuleTemplate> fileModuleTemplates = new LinkedHashMap<>();
306 
307  // mappings for jython modules. These mappings are only used to determine modules in the pipelineconfig.xml.
308 
309  Map<String, IngestModuleTemplate> jythonDataSourceModuleTemplates = new LinkedHashMap<>();
310  Map<String, IngestModuleTemplate> jythonFileModuleTemplates = new LinkedHashMap<>();
311 
312  for (IngestModuleTemplate template : ingestModuleTemplates) {
313  if (template.isDataSourceIngestModuleTemplate()) {
314  addModule(dataSourceModuleTemplates, jythonDataSourceModuleTemplates, template);
315  }
316  if (template.isFileIngestModuleTemplate()) {
317  addModule(fileModuleTemplates, jythonFileModuleTemplates, template);
318  }
319  }
320 
325  IngestPipelinesConfiguration pipelineConfigs = IngestPipelinesConfiguration.getInstance();
326  List<IngestModuleTemplate> firstStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(
327  dataSourceModuleTemplates, jythonDataSourceModuleTemplates, pipelineConfigs.getStageOneDataSourceIngestPipelineConfig());
328 
329  List<IngestModuleTemplate> fileIngestModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(
330  fileModuleTemplates, jythonFileModuleTemplates, pipelineConfigs.getFileIngestPipelineConfig());
331 
332  List<IngestModuleTemplate> secondStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(
333  dataSourceModuleTemplates, null, pipelineConfigs.getStageTwoDataSourceIngestPipelineConfig());
334 
340  addOrdered(firstStageDataSourceModuleTemplates, dataSourceModuleTemplates, jythonDataSourceModuleTemplates);
341  addOrdered(fileIngestModuleTemplates, fileModuleTemplates, jythonFileModuleTemplates);
342 
346  this.firstStageDataSourceIngestPipeline = new DataSourceIngestPipeline(this, firstStageDataSourceModuleTemplates);
347  this.secondStageDataSourceIngestPipeline = new DataSourceIngestPipeline(this, secondStageDataSourceModuleTemplates);
348 
352  try {
353  int numberOfFileIngestThreads = IngestManager.getInstance().getNumberOfFileIngestThreads();
354  for (int i = 0; i < numberOfFileIngestThreads; ++i) {
355  FileIngestPipeline pipeline = new FileIngestPipeline(this, fileIngestModuleTemplates);
356  this.fileIngestPipelinesQueue.put(pipeline);
357  this.fileIngestPipelines.add(pipeline);
358  }
359  } catch (InterruptedException ex) {
365  Thread.currentThread().interrupt();
366  }
367  try {
368  SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
369  this.addIngestModules(firstStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
370  this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase);
371  this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
372  } catch (TskCoreException | NoCurrentCaseException ex) {
373  logErrorMessage(Level.WARNING, "Failed to add ingest modules listing to case database", ex);
374  }
375  }
376 
377  private void addIngestModules(List<IngestModuleTemplate> templates, IngestModuleType type, SleuthkitCase skCase) throws TskCoreException {
378  for (IngestModuleTemplate module : templates) {
379  ingestModules.add(skCase.addIngestModule(module.getModuleName(), FactoryClassNameNormalizer.normalize(module.getModuleFactory().getClass().getCanonicalName()), type, module.getModuleFactory().getModuleVersionNumber()));
380  }
381  }
382 
403  private static List<IngestModuleTemplate> getConfiguredIngestModuleTemplates(
404  Map<String, IngestModuleTemplate> ingestModuleTemplates, Map<String, IngestModuleTemplate> jythonIngestModuleTemplates, List<String> pipelineConfig) {
405  List<IngestModuleTemplate> templates = new ArrayList<>();
406  for (String moduleClassName : pipelineConfig) {
407  if (ingestModuleTemplates != null && ingestModuleTemplates.containsKey(moduleClassName)) {
408  templates.add(ingestModuleTemplates.remove(moduleClassName));
409  } else if (jythonIngestModuleTemplates != null && jythonIngestModuleTemplates.containsKey(moduleClassName)) {
410  templates.add(jythonIngestModuleTemplates.remove(moduleClassName));
411  }
412  }
413  return templates;
414  }
415 
421  long getId() {
422  return this.id;
423  }
424 
430  String getExecutionContext() {
431  return this.settings.getExecutionContext();
432  }
433 
439  Content getDataSource() {
440  return this.dataSource;
441  }
442 
449  boolean shouldProcessUnallocatedSpace() {
450  return this.settings.getProcessUnallocatedSpace();
451  }
452 
458  FilesSet getFileIngestFilter() {
459  return this.settings.getFileFilter();
460  }
461 
467  boolean hasIngestPipeline() {
469  || this.hasFileIngestPipeline()
471  }
472 
480  return (this.firstStageDataSourceIngestPipeline.isEmpty() == false);
481  }
482 
490  return (this.secondStageDataSourceIngestPipeline.isEmpty() == false);
491  }
492 
498  private boolean hasFileIngestPipeline() {
499  if (!this.fileIngestPipelines.isEmpty()) {
500  return !this.fileIngestPipelines.get(0).isEmpty();
501  }
502  return false;
503  }
504 
510  List<IngestModuleError> start() {
511  List<IngestModuleError> errors = startUpIngestPipelines();
512  if (errors.isEmpty()) {
513  try {
514  this.ingestJob = Case.getCurrentCaseThrows().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, "");
515  } catch (TskCoreException | NoCurrentCaseException ex) {
516  logErrorMessage(Level.WARNING, "Failed to add ingest job info to case database", ex); //NON-NLS
517  }
519  logInfoMessage("Starting first stage analysis"); //NON-NLS
520  this.startFirstStage();
521  } else if (this.hasSecondStageDataSourceIngestPipeline()) {
522  logInfoMessage("Starting second stage analysis"); //NON-NLS
523  this.startSecondStage();
524  }
525  }
526  return errors;
527  }
528 
535  private List<IngestModuleError> startUpIngestPipelines() {
536  List<IngestModuleError> errors = new ArrayList<>();
537 
538  /*
539  * Start the data-source-level ingest module pipelines.
540  */
541  errors.addAll(this.firstStageDataSourceIngestPipeline.startUp());
542  errors.addAll(this.secondStageDataSourceIngestPipeline.startUp());
543 
544  /*
545  * If the data-source-level ingest pipelines were successfully started,
546  * start the Start the file-level ingest pipelines (one per file ingest
547  * thread).
548  */
549  if (errors.isEmpty()) {
550  for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) {
551  errors.addAll(pipeline.startUp());
552  if (!errors.isEmpty()) {
553  /*
554  * If there are start up errors, the ingest job will not
555  * proceed, so shut down any file ingest pipelines that did
556  * start up.
557  */
558  while (!this.fileIngestPipelinesQueue.isEmpty()) {
559  FileIngestPipeline startedPipeline = this.fileIngestPipelinesQueue.poll();
560  if (startedPipeline.isRunning()) {
561  List<IngestModuleError> shutDownErrors = startedPipeline.shutDown();
562  if (!shutDownErrors.isEmpty()) {
563  /*
564  * The start up errors will ultimately be
565  * reported to the user for possible remedy, but
566  * the shut down errors are logged here.
567  */
568  logIngestModuleErrors(shutDownErrors);
569  }
570  }
571  }
572  break;
573  }
574  }
575  }
576 
577  return errors;
578  }
579 
583  private void startFirstStage() {
584  this.stage = DataSourceIngestJob.Stages.FIRST;
585 
586  if (this.hasFileIngestPipeline()) {
587  synchronized (this.fileIngestProgressLock) {
588  this.estimatedFilesToProcess = this.dataSource.accept(new GetFilesCountVisitor());
589  }
590  }
591 
592  if (this.doUI) {
598  }
599  if (this.hasFileIngestPipeline()) {
601  }
602  }
603 
608  synchronized (this.dataSourceIngestPipelineLock) {
609  this.currentDataSourceIngestPipeline = this.firstStageDataSourceIngestPipeline;
610  }
611 
616  logInfoMessage("Scheduling first stage data source and file level analysis tasks"); //NON-NLS
617  DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this);
618  } else if (this.hasFirstStageDataSourceIngestPipeline()) {
619  logInfoMessage("Scheduling first stage data source level analysis tasks"); //NON-NLS
620  DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
621  } else {
622  logInfoMessage("Scheduling file level analysis tasks, no first stage data source level analysis configured"); //NON-NLS
623  DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this, this.files);
624 
633  this.checkForStageCompleted();
634  }
635  }
636 
640  private void startSecondStage() {
641  logInfoMessage("Starting second stage analysis"); //NON-NLS
642  this.stage = DataSourceIngestJob.Stages.SECOND;
643  if (this.doUI) {
645  }
646  synchronized (this.dataSourceIngestPipelineLock) {
647  this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline;
648  }
649  logInfoMessage("Scheduling second stage data source level analysis tasks"); //NON-NLS
650  DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
651  }
652 
657  if (this.doUI) {
658  synchronized (this.dataSourceIngestProgressLock) {
659  String displayName = NbBundle.getMessage(this.getClass(),
660  "IngestJob.progress.dataSourceIngest.initialDisplayName",
661  this.dataSource.getName());
662  this.dataSourceIngestProgress = ProgressHandle.createHandle(displayName, new Cancellable() {
663  @Override
664  public boolean cancel() {
665  // If this method is called, the user has already pressed
666  // the cancel button on the progress bar and the OK button
667  // of a cancelation confirmation dialog supplied by
668  // NetBeans. What remains to be done is to find out whether
669  // the user wants to cancel only the currently executing
670  // data source ingest module or the entire ingest job.
671  DataSourceIngestCancellationPanel panel = new DataSourceIngestCancellationPanel();
672  String dialogTitle = NbBundle.getMessage(DataSourceIngestJob.this.getClass(), "IngestJob.cancellationDialog.title");
673  JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), panel, dialogTitle, JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE);
674  if (panel.cancelAllDataSourceIngestModules()) {
676  } else {
677  DataSourceIngestJob.this.cancelCurrentDataSourceIngestModule();
678  }
679  return true;
680  }
681  });
682  this.dataSourceIngestProgress.start();
683  this.dataSourceIngestProgress.switchToIndeterminate();
684  }
685  }
686  }
687 
691  private void startFileIngestProgressBar() {
692  if (this.doUI) {
693  synchronized (this.fileIngestProgressLock) {
694  String displayName = NbBundle.getMessage(this.getClass(),
695  "IngestJob.progress.fileIngest.displayName",
696  this.dataSource.getName());
697  this.fileIngestProgress = ProgressHandle.createHandle(displayName, new Cancellable() {
698  @Override
699  public boolean cancel() {
700  // If this method is called, the user has already pressed
701  // the cancel button on the progress bar and the OK button
702  // of a cancelation confirmation dialog supplied by
703  // NetBeans.
705  return true;
706  }
707  });
708  this.fileIngestProgress.start();
709  this.fileIngestProgress.switchToDeterminate((int) this.estimatedFilesToProcess);
710  }
711  }
712  }
713 
718  private void checkForStageCompleted() {
719  synchronized (this.stageCompletionCheckLock) {
720  if (DataSourceIngestJob.taskScheduler.tasksForJobAreCompleted(this)) {
721  switch (this.stage) {
722  case FIRST:
723  this.finishFirstStage();
724  break;
725  case SECOND:
726  this.finish();
727  break;
728  }
729  }
730  }
731  }
732 
737  private void finishFirstStage() {
738  logInfoMessage("Finished first stage analysis"); //NON-NLS
739 
740  // Shut down the file ingest pipelines. Note that no shut down is
741  // required for the data source ingest pipeline because data source
742  // ingest modules do not have a shutdown() method.
743  List<IngestModuleError> errors = new ArrayList<>();
744  while (!this.fileIngestPipelinesQueue.isEmpty()) {
745  FileIngestPipeline pipeline = fileIngestPipelinesQueue.poll();
746  if (pipeline.isRunning()) {
747  errors.addAll(pipeline.shutDown());
748  }
749  }
750  if (!errors.isEmpty()) {
751  logIngestModuleErrors(errors);
752  }
753 
754  if (this.doUI) {
755  // Finish the first stage data source ingest progress bar, if it hasn't
756  // already been finished.
757  synchronized (this.dataSourceIngestProgressLock) {
758  if (this.dataSourceIngestProgress != null) {
759  this.dataSourceIngestProgress.finish();
760  this.dataSourceIngestProgress = null;
761  }
762  }
763 
764  // Finish the file ingest progress bar, if it hasn't already
765  // been finished.
766  synchronized (this.fileIngestProgressLock) {
767  if (this.fileIngestProgress != null) {
768  this.fileIngestProgress.finish();
769  this.fileIngestProgress = null;
770  }
771  }
772  }
773 
777  if (!this.cancelled && this.hasSecondStageDataSourceIngestPipeline()) {
778  this.startSecondStage();
779  } else {
780  this.finish();
781  }
782  }
783 
787  private void finish() {
788  logInfoMessage("Finished analysis"); //NON-NLS
790 
791  if (this.doUI) {
792  // Finish the second stage data source ingest progress bar, if it hasn't
793  // already been finished.
794  synchronized (this.dataSourceIngestProgressLock) {
795  if (this.dataSourceIngestProgress != null) {
796  this.dataSourceIngestProgress.finish();
797  this.dataSourceIngestProgress = null;
798  }
799  }
800  }
801  if (ingestJob != null) {
802  if (this.cancelled) {
803  try {
804  ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
805  } catch (TskCoreException ex) {
806  logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex);
807  }
808  } else {
809  try {
810  ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
811  } catch (TskCoreException ex) {
812  logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex);
813  }
814  }
815  try {
816  this.ingestJob.setEndDateTime(new Date());
817  } catch (TskCoreException ex) {
818  logErrorMessage(Level.WARNING, "Failed to set job end date in case database", ex);
819  }
820  }
821  this.parentJob.dataSourceJobFinished(this);
822  }
823 
830  void process(DataSourceIngestTask task) {
831  try {
832  synchronized (this.dataSourceIngestPipelineLock) {
833  if (!this.isCancelled() && !this.currentDataSourceIngestPipeline.isEmpty()) {
834  List<IngestModuleError> errors = new ArrayList<>();
835  errors.addAll(this.currentDataSourceIngestPipeline.process(task));
836  if (!errors.isEmpty()) {
837  logIngestModuleErrors(errors);
838  }
839  }
840  }
841 
842  if (this.doUI) {
847  synchronized (this.dataSourceIngestProgressLock) {
848  if (null != this.dataSourceIngestProgress) {
849  this.dataSourceIngestProgress.finish();
850  this.dataSourceIngestProgress = null;
851  }
852  }
853  }
854 
855  } finally {
856  DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
857  this.checkForStageCompleted();
858  }
859  }
860 
872  void process(FileIngestTask task) throws InterruptedException {
873  try {
874  if (!this.isCancelled()) {
875  FileIngestPipeline pipeline = this.fileIngestPipelinesQueue.take();
876  if (!pipeline.isEmpty()) {
877  AbstractFile file = task.getFile();
878 
879  synchronized (this.fileIngestProgressLock) {
880  ++this.processedFiles;
881  if (this.doUI) {
885  if (this.processedFiles <= this.estimatedFilesToProcess) {
886  this.fileIngestProgress.progress(file.getName(), (int) this.processedFiles);
887  } else {
888  this.fileIngestProgress.progress(file.getName(), (int) this.estimatedFilesToProcess);
889  }
890  this.filesInProgress.add(file.getName());
891  }
892  }
893 
897  List<IngestModuleError> errors = new ArrayList<>();
898  errors.addAll(pipeline.process(task));
899  if (!errors.isEmpty()) {
900  logIngestModuleErrors(errors);
901  }
902 
903  if (this.doUI && !this.cancelled) {
904  synchronized (this.fileIngestProgressLock) {
909  this.filesInProgress.remove(file.getName());
910  if (this.filesInProgress.size() > 0) {
911  this.fileIngestProgress.progress(this.filesInProgress.get(0));
912  } else {
913  this.fileIngestProgress.progress("");
914  }
915  }
916  }
917  }
918  this.fileIngestPipelinesQueue.put(pipeline);
919  }
920  } finally {
921  DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
922  this.checkForStageCompleted();
923  }
924  }
925 
933  void addFiles(List<AbstractFile> files) {
934  if (DataSourceIngestJob.Stages.FIRST == this.stage) {
935  DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files);
936  } else {
937  logErrorMessage(Level.SEVERE, "Adding files to job during second stage analysis not supported");
938  }
939 
946  this.checkForStageCompleted();
947  }
948 
955  void updateDataSourceIngestProgressBarDisplayName(String displayName) {
956  if (this.doUI && !this.cancelled) {
957  synchronized (this.dataSourceIngestProgressLock) {
958  this.dataSourceIngestProgress.setDisplayName(displayName);
959  }
960  }
961  }
962 
971  void switchDataSourceIngestProgressBarToDeterminate(int workUnits) {
972  if (this.doUI && !this.cancelled) {
973  synchronized (this.dataSourceIngestProgressLock) {
974  if (null != this.dataSourceIngestProgress) {
975  this.dataSourceIngestProgress.switchToDeterminate(workUnits);
976  }
977  }
978  }
979  }
980 
986  void switchDataSourceIngestProgressBarToIndeterminate() {
987  if (this.doUI && !this.cancelled) {
988  synchronized (this.dataSourceIngestProgressLock) {
989  if (null != this.dataSourceIngestProgress) {
990  this.dataSourceIngestProgress.switchToIndeterminate();
991  }
992  }
993  }
994  }
995 
1002  void advanceDataSourceIngestProgressBar(int workUnits) {
1003  if (this.doUI && !this.cancelled) {
1004  synchronized (this.dataSourceIngestProgressLock) {
1005  if (null != this.dataSourceIngestProgress) {
1006  this.dataSourceIngestProgress.progress("", workUnits);
1007  }
1008  }
1009  }
1010  }
1011 
1018  void advanceDataSourceIngestProgressBar(String currentTask) {
1019  if (this.doUI && !this.cancelled) {
1020  synchronized (this.dataSourceIngestProgressLock) {
1021  if (null != this.dataSourceIngestProgress) {
1022  this.dataSourceIngestProgress.progress(currentTask);
1023  }
1024  }
1025  }
1026  }
1027 
1036  void advanceDataSourceIngestProgressBar(String currentTask, int workUnits) {
1037  if (this.doUI && !this.cancelled) {
1038  synchronized (this.fileIngestProgressLock) {
1039  this.dataSourceIngestProgress.progress(currentTask, workUnits);
1040  }
1041  }
1042  }
1043 
1051  boolean currentDataSourceIngestModuleIsCancelled() {
1053  }
1054 
1061  void currentDataSourceIngestModuleCancellationCompleted(String moduleDisplayName) {
1062  this.currentDataSourceIngestModuleCancelled = false;
1063  this.cancelledDataSourceIngestModules.add(moduleDisplayName);
1064 
1065  if (this.doUI) {
1073  synchronized (this.dataSourceIngestProgressLock) {
1074  this.dataSourceIngestProgress.finish();
1075  this.dataSourceIngestProgress = null;
1077  }
1078  }
1079  }
1080 
1086  DataSourceIngestPipeline.PipelineModule getCurrentDataSourceIngestModule() {
1087  if (null != this.currentDataSourceIngestPipeline) {
1088  return this.currentDataSourceIngestPipeline.getCurrentlyRunningModule();
1089  } else {
1090  return null;
1091  }
1092  }
1093 
1098  void cancelCurrentDataSourceIngestModule() {
1099  this.currentDataSourceIngestModuleCancelled = true;
1100  }
1101 
1108  void cancel(IngestJob.CancellationReason reason) {
1109  this.cancelled = true;
1110  this.cancellationReason = reason;
1111  DataSourceIngestJob.taskScheduler.cancelPendingTasksForIngestJob(this);
1112 
1113  if (this.doUI) {
1114  synchronized (this.dataSourceIngestProgressLock) {
1115  if (null != dataSourceIngestProgress) {
1116  dataSourceIngestProgress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestJob.progress.dataSourceIngest.initialDisplayName", dataSource.getName()));
1117  dataSourceIngestProgress.progress(NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling"));
1118  }
1119  }
1120 
1121  synchronized (this.fileIngestProgressLock) {
1122  if (null != this.fileIngestProgress) {
1123  this.fileIngestProgress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestJob.progress.fileIngest.displayName", this.dataSource.getName()));
1124  this.fileIngestProgress.progress(NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling"));
1125  }
1126  }
1127  }
1128  }
1129 
1137  void setCurrentFileIngestModule(String moduleName, String taskName) {
1138  this.currentFileIngestModule = moduleName;
1139  this.currentFileIngestTask = taskName;
1140  }
1141 
1148  boolean isCancelled() {
1149  return this.cancelled;
1150  }
1151 
1157  IngestJob.CancellationReason getCancellationReason() {
1158  return this.cancellationReason;
1159  }
1160 
1167  private void logInfoMessage(String message) {
1168  logger.log(Level.INFO, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS
1169  }
1170 
1179  private void logErrorMessage(Level level, String message, Throwable throwable) {
1180  logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id), throwable); //NON-NLS
1181  }
1182 
1190  private void logErrorMessage(Level level, String message) {
1191  logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS
1192  }
1193 
1199  private void logIngestModuleErrors(List<IngestModuleError> errors) {
1200  for (IngestModuleError error : errors) {
1201  logErrorMessage(Level.SEVERE, String.format("%s experienced an error during analysis", error.getModuleDisplayName()), error.getThrowable()); //NON-NLS
1202  }
1203  }
1204 
1210  Snapshot getSnapshot(boolean getIngestTasksSnapshot) {
1216  boolean fileIngestRunning = false;
1217  Date fileIngestStartTime = null;
1218 
1219  for (FileIngestPipeline pipeline : this.fileIngestPipelines) {
1220  if (pipeline.isRunning()) {
1221  fileIngestRunning = true;
1222  }
1223  Date pipelineStartTime = pipeline.getStartTime();
1224  if (null != pipelineStartTime && (null == fileIngestStartTime || pipelineStartTime.before(fileIngestStartTime))) {
1225  fileIngestStartTime = pipelineStartTime;
1226  }
1227  }
1228 
1229  long processedFilesCount = 0;
1230  long estimatedFilesToProcessCount = 0;
1231  long snapShotTime = new Date().getTime();
1232  IngestJobTasksSnapshot tasksSnapshot = null;
1233 
1234  if (getIngestTasksSnapshot) {
1235  synchronized (fileIngestProgressLock) {
1236  processedFilesCount = this.processedFiles;
1237  estimatedFilesToProcessCount = this.estimatedFilesToProcess;
1238  snapShotTime = new Date().getTime();
1239  }
1240  tasksSnapshot = DataSourceIngestJob.taskScheduler.getTasksSnapshotForJob(id);
1241 
1242  }
1243 
1244  return new Snapshot(this.dataSource.getName(), id, createTime,
1245  getCurrentDataSourceIngestModule(), fileIngestRunning, fileIngestStartTime,
1247  processedFilesCount, estimatedFilesToProcessCount, snapShotTime, tasksSnapshot);
1248  }
1249 
1253  public static final class Snapshot implements Serializable {
1254 
1255  private static final long serialVersionUID = 1L;
1256 
1257  private final String dataSource;
1258  private final long jobId;
1259  private final long jobStartTime;
1260  private final long snapShotTime;
1261  transient private final PipelineModule dataSourceLevelIngestModule;
1262  private final boolean fileIngestRunning;
1263  private final Date fileIngestStartTime;
1264  private final long processedFiles;
1265  private final long estimatedFilesToProcess;
1266  private final IngestJobTasksSnapshot tasksSnapshot;
1267  transient private final boolean jobCancelled;
1269  transient private final List<String> cancelledDataSourceModules;
1270 
1275  Snapshot(String dataSourceName, long jobId, long jobStartTime, PipelineModule dataSourceIngestModule,
1276  boolean fileIngestRunning, Date fileIngestStartTime,
1277  boolean jobCancelled, CancellationReason cancellationReason, List<String> cancelledModules,
1278  long processedFiles, long estimatedFilesToProcess,
1279  long snapshotTime, IngestJobTasksSnapshot tasksSnapshot) {
1280  this.dataSource = dataSourceName;
1281  this.jobId = jobId;
1282  this.jobStartTime = jobStartTime;
1283  this.dataSourceLevelIngestModule = dataSourceIngestModule;
1284 
1285  this.fileIngestRunning = fileIngestRunning;
1286  this.fileIngestStartTime = fileIngestStartTime;
1287  this.jobCancelled = jobCancelled;
1288  this.jobCancellationReason = cancellationReason;
1289  this.cancelledDataSourceModules = cancelledModules;
1290 
1291  this.processedFiles = processedFiles;
1292  this.estimatedFilesToProcess = estimatedFilesToProcess;
1293  this.snapShotTime = snapshotTime;
1294  this.tasksSnapshot = tasksSnapshot;
1295  }
1296 
1303  long getSnapshotTime() {
1304  return snapShotTime;
1305  }
1306 
1313  String getDataSource() {
1314  return dataSource;
1315  }
1316 
1323  long getJobId() {
1324  return this.jobId;
1325  }
1326 
1333  long getJobStartTime() {
1334  return jobStartTime;
1335  }
1336 
1337  DataSourceIngestPipeline.PipelineModule getDataSourceLevelIngestModule() {
1338  return this.dataSourceLevelIngestModule;
1339  }
1340 
1341  boolean getFileIngestIsRunning() {
1342  return this.fileIngestRunning;
1343  }
1344 
1345  Date getFileIngestStartTime() {
1346  return this.fileIngestStartTime;
1347  }
1348 
1355  double getSpeed() {
1356  return (double) processedFiles / ((snapShotTime - jobStartTime) / 1000);
1357  }
1358 
1364  long getFilesProcessed() {
1365  return processedFiles;
1366  }
1367 
1374  long getFilesEstimated() {
1375  return estimatedFilesToProcess;
1376  }
1377 
1378  long getRootQueueSize() {
1379  if (null == this.tasksSnapshot) {
1380  return 0;
1381  }
1382  return this.tasksSnapshot.getRootQueueSize();
1383  }
1384 
1385  long getDirQueueSize() {
1386  if (null == this.tasksSnapshot) {
1387  return 0;
1388  }
1389  return this.tasksSnapshot.getDirectoryTasksQueueSize();
1390  }
1391 
1392  long getFileQueueSize() {
1393  if (null == this.tasksSnapshot) {
1394  return 0;
1395  }
1396  return this.tasksSnapshot.getFileQueueSize();
1397  }
1398 
1399  long getDsQueueSize() {
1400  if (null == this.tasksSnapshot) {
1401  return 0;
1402  }
1403  return this.tasksSnapshot.getDsQueueSize();
1404  }
1405 
1406  long getRunningListSize() {
1407  if (null == this.tasksSnapshot) {
1408  return 0;
1409  }
1410  return this.tasksSnapshot.getRunningListSize();
1411  }
1412 
1413  boolean isCancelled() {
1414  return this.jobCancelled;
1415  }
1416 
1422  IngestJob.CancellationReason getCancellationReason() {
1423  return this.jobCancellationReason;
1424  }
1425 
1433  List<String> getCancelledDataSourceIngestModules() {
1434  return Collections.unmodifiableList(this.cancelledDataSourceModules);
1435  }
1436 
1437  }
1438 
1439 }
static synchronized IngestManager getInstance()
static void addOrdered(final List< IngestModuleTemplate > dest, final Map< String, IngestModuleTemplate > src, final Map< String, IngestModuleTemplate > jythonSrc)
void logErrorMessage(Level level, String message, Throwable throwable)
static List< IngestModuleTemplate > getConfiguredIngestModuleTemplates(Map< String, IngestModuleTemplate > ingestModuleTemplates, Map< String, IngestModuleTemplate > jythonIngestModuleTemplates, List< String > pipelineConfig)
static String getJythonName(String canonicalName)
void logIngestModuleErrors(List< IngestModuleError > errors)
List< IngestModuleTemplate > getEnabledIngestModuleTemplates()
static void addModule(Map< String, IngestModuleTemplate > mapping, Map< String, IngestModuleTemplate > jythonMapping, IngestModuleTemplate template)
void addIngestModules(List< IngestModuleTemplate > templates, IngestModuleType type, SleuthkitCase skCase)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
final LinkedBlockingQueue< FileIngestPipeline > fileIngestPipelinesQueue
final List< FileIngestPipeline > fileIngestPipelines
volatile IngestJob.CancellationReason cancellationReason

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