Autopsy  4.1
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 2011-2016 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.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.concurrent.CopyOnWriteArrayList;
28 import java.util.concurrent.LinkedBlockingQueue;
29 import java.util.concurrent.atomic.AtomicLong;
30 import java.util.logging.Level;
31 import javax.swing.JOptionPane;
32 import org.netbeans.api.progress.ProgressHandle;
33 import org.openide.util.Cancellable;
34 import org.openide.util.NbBundle;
38 import org.sleuthkit.datamodel.AbstractFile;
39 import org.sleuthkit.datamodel.Content;
40 import org.sleuthkit.datamodel.IngestJobInfo;
41 import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType;
42 import org.sleuthkit.datamodel.IngestModuleInfo;
43 import org.sleuthkit.datamodel.IngestModuleInfo.IngestModuleType;
44 import org.sleuthkit.datamodel.SleuthkitCase;
45 import org.sleuthkit.datamodel.TskCoreException;
46 
51 final class DataSourceIngestJob {
52 
53  private static final Logger logger = Logger.getLogger(DataSourceIngestJob.class.getName());
54 
59  private final IngestJob parentJob;
60  private static final AtomicLong nextJobId = new AtomicLong(0L);
61  private final long id;
62  private final IngestJobSettings settings;
63  private final Content dataSource;
64 
68  private static enum Stages {
69 
87  FINALIZATION
88  };
89  private volatile Stages stage = DataSourceIngestJob.Stages.INITIALIZATION;
90  private final Object stageCompletionCheckLock = new Object();
91 
100  private final Object dataSourceIngestPipelineLock = new Object();
101  private DataSourceIngestPipeline firstStageDataSourceIngestPipeline;
102  private DataSourceIngestPipeline secondStageDataSourceIngestPipeline;
103  private DataSourceIngestPipeline currentDataSourceIngestPipeline;
104 
112  private final LinkedBlockingQueue<FileIngestPipeline> fileIngestPipelinesQueue = new LinkedBlockingQueue<>();
113  private final List<FileIngestPipeline> fileIngestPipelines = new ArrayList<>();
114 
126  private volatile boolean currentDataSourceIngestModuleCancelled;
127  private volatile boolean cancelled;
128  private volatile IngestJob.CancellationReason cancellationReason = IngestJob.CancellationReason.NOT_CANCELLED;
129  private final Object cancellationStateMonitor = new Object();
130  private final List<String> cancelledDataSourceIngestModules = new CopyOnWriteArrayList<>();
131 
136  private static final IngestTasksScheduler taskScheduler = IngestTasksScheduler.getInstance();
137 
142  private final boolean doUI;
143 
148  private final Object dataSourceIngestProgressLock = new Object();
149  private ProgressHandle dataSourceIngestProgress;
150 
155  private final Object fileIngestProgressLock = new Object();
156  private final List<String> filesInProgress = new ArrayList<>();
157  private long estimatedFilesToProcess;
158  private long processedFiles;
159  private ProgressHandle fileIngestProgress;
160  private String currentFileIngestModule = "";
161  private String currentFileIngestTask = "";
162  private List<IngestModuleInfo> ingestModules = new ArrayList<>();
163  private IngestJobInfo ingestJob;
164 
168  private final long createTime;
169 
181  DataSourceIngestJob(IngestJob parentJob, Content dataSource, IngestJobSettings settings, boolean runInteractively) {
182  this.parentJob = parentJob;
183  this.id = DataSourceIngestJob.nextJobId.getAndIncrement();
184  this.dataSource = dataSource;
185  this.settings = settings;
186  this.doUI = runInteractively;
187  this.createTime = new Date().getTime();
188  this.createIngestPipelines();
189  }
190 
194  private void createIngestPipelines() {
195  List<IngestModuleTemplate> ingestModuleTemplates = this.settings.getEnabledIngestModuleTemplates();
196 
200  Map<String, IngestModuleTemplate> dataSourceModuleTemplates = new HashMap<>();
201  Map<String, IngestModuleTemplate> fileModuleTemplates = new HashMap<>();
202  for (IngestModuleTemplate template : ingestModuleTemplates) {
203  if (template.isDataSourceIngestModuleTemplate()) {
204  dataSourceModuleTemplates.put(template.getModuleFactory().getClass().getCanonicalName(), template);
205  }
206  if (template.isFileIngestModuleTemplate()) {
207  fileModuleTemplates.put(template.getModuleFactory().getClass().getCanonicalName(), template);
208  }
209  }
210 
215  IngestPipelinesConfiguration pipelineConfigs = IngestPipelinesConfiguration.getInstance();
216  List<IngestModuleTemplate> firstStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(dataSourceModuleTemplates, pipelineConfigs.getStageOneDataSourceIngestPipelineConfig());
217  List<IngestModuleTemplate> fileIngestModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(fileModuleTemplates, pipelineConfigs.getFileIngestPipelineConfig());
218  List<IngestModuleTemplate> secondStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(dataSourceModuleTemplates, pipelineConfigs.getStageTwoDataSourceIngestPipelineConfig());
219 
225  for (IngestModuleTemplate template : dataSourceModuleTemplates.values()) {
226  firstStageDataSourceModuleTemplates.add(template);
227  }
228  for (IngestModuleTemplate template : fileModuleTemplates.values()) {
229  fileIngestModuleTemplates.add(template);
230  }
231 
235  this.firstStageDataSourceIngestPipeline = new DataSourceIngestPipeline(this, firstStageDataSourceModuleTemplates);
236  this.secondStageDataSourceIngestPipeline = new DataSourceIngestPipeline(this, secondStageDataSourceModuleTemplates);
237 
241  try {
242  int numberOfFileIngestThreads = IngestManager.getInstance().getNumberOfFileIngestThreads();
243  for (int i = 0; i < numberOfFileIngestThreads; ++i) {
244  FileIngestPipeline pipeline = new FileIngestPipeline(this, fileIngestModuleTemplates);
245  this.fileIngestPipelinesQueue.put(pipeline);
246  this.fileIngestPipelines.add(pipeline);
247  }
248  } catch (InterruptedException ex) {
254  Thread.currentThread().interrupt();
255  }
256  SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
257  try {
258  this.addIngestModules(firstStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
259  this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase);
260  this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
261  } catch (TskCoreException ex) {
262  logger.log(Level.SEVERE, "Failed to add ingest modules to database.", ex);
263  }
264  }
265 
266  private void addIngestModules(List<IngestModuleTemplate> templates, IngestModuleType type, SleuthkitCase skCase) throws TskCoreException {
267  for (IngestModuleTemplate module : templates) {
268  ingestModules.add(skCase.addIngestModule(module.getModuleName(), FactoryClassNameNormalizer.normalize(module.getModuleFactory().getClass().getCanonicalName()), type, module.getModuleFactory().getModuleVersionNumber()));
269  }
270  }
271 
287  private static List<IngestModuleTemplate> getConfiguredIngestModuleTemplates(Map<String, IngestModuleTemplate> ingestModuleTemplates, List<String> pipelineConfig) {
288  List<IngestModuleTemplate> templates = new ArrayList<>();
289  for (String moduleClassName : pipelineConfig) {
290  if (ingestModuleTemplates.containsKey(moduleClassName)) {
291  templates.add(ingestModuleTemplates.remove(moduleClassName));
292  }
293  }
294  return templates;
295  }
296 
302  long getId() {
303  return this.id;
304  }
305 
311  String getExecutionContext() {
312  return this.settings.getExecutionContext();
313  }
314 
320  Content getDataSource() {
321  return this.dataSource;
322  }
323 
330  boolean shouldProcessUnallocatedSpace() {
331  return this.settings.getProcessUnallocatedSpace();
332  }
333 
339  boolean hasIngestPipeline() {
340  return this.hasFirstStageDataSourceIngestPipeline()
341  || this.hasFileIngestPipeline()
342  || this.hasSecondStageDataSourceIngestPipeline();
343  }
344 
351  private boolean hasFirstStageDataSourceIngestPipeline() {
352  return (this.firstStageDataSourceIngestPipeline.isEmpty() == false);
353  }
354 
361  private boolean hasSecondStageDataSourceIngestPipeline() {
362  return (this.secondStageDataSourceIngestPipeline.isEmpty() == false);
363  }
364 
370  private boolean hasFileIngestPipeline() {
371  if (!this.fileIngestPipelines.isEmpty()) {
372  return !this.fileIngestPipelines.get(0).isEmpty();
373  }
374  return false;
375  }
376 
382  List<IngestModuleError> start() {
383  List<IngestModuleError> errors = startUpIngestPipelines();
384  if (errors.isEmpty()) {
385  if (this.hasFirstStageDataSourceIngestPipeline() || this.hasFileIngestPipeline()) {
386  logger.log(Level.INFO, "Starting first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
387  this.startFirstStage();
388  } else if (this.hasSecondStageDataSourceIngestPipeline()) {
389  logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1}), no first stage configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
390  this.startSecondStage();
391  }
392  try {
393  this.ingestJob = Case.getCurrentCase().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, "");
394  } catch (TskCoreException ex) {
395  logger.log(Level.SEVERE, "Failed to add ingest job to database.", ex);
396  }
397  }
398  return errors;
399  }
400 
407  private List<IngestModuleError> startUpIngestPipelines() {
408  List<IngestModuleError> errors = new ArrayList<>();
409 
410  /*
411  * Start the data-source-level ingest module pipelines.
412  */
413  errors.addAll(this.firstStageDataSourceIngestPipeline.startUp());
414  errors.addAll(this.secondStageDataSourceIngestPipeline.startUp());
415 
416  /*
417  * If the data-source-level ingest pipelines were successfully started,
418  * start the Start the file-level ingest pipelines (one per file ingest
419  * thread).
420  */
421  if (errors.isEmpty()) {
422  for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) {
423  errors.addAll(pipeline.startUp());
424  if (!errors.isEmpty()) {
425  /*
426  * If there are start up errors, the ingest job will not
427  * proceed, so shut down any file ingest pipelines that did
428  * start up.
429  */
430  while (!this.fileIngestPipelinesQueue.isEmpty()) {
431  FileIngestPipeline startedPipeline = this.fileIngestPipelinesQueue.poll();
432  if (startedPipeline.isRunning()) {
433  List<IngestModuleError> shutDownErrors = startedPipeline.shutDown();
434  if (!shutDownErrors.isEmpty()) {
435  /*
436  * The start up errors will ultimately be
437  * reported to the user for possible remedy, but
438  * the shut down errors are logged here.
439  */
440  logIngestModuleErrors(shutDownErrors);
441  }
442  }
443  }
444  break;
445  }
446  }
447  }
448 
449  return errors;
450  }
451 
455  private void startFirstStage() {
456  this.stage = DataSourceIngestJob.Stages.FIRST;
457 
458  if (this.hasFileIngestPipeline()) {
459  synchronized (this.fileIngestProgressLock) {
460  this.estimatedFilesToProcess = this.dataSource.accept(new GetFilesCountVisitor());
461  }
462  }
463 
464  if (this.doUI) {
468  if (this.hasFirstStageDataSourceIngestPipeline()) {
469  this.startDataSourceIngestProgressBar();
470  }
471  if (this.hasFileIngestPipeline()) {
472  this.startFileIngestProgressBar();
473  }
474  }
475 
480  synchronized (this.dataSourceIngestPipelineLock) {
481  this.currentDataSourceIngestPipeline = this.firstStageDataSourceIngestPipeline;
482  }
483 
487  if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) {
488  logger.log(Level.INFO, "Scheduling first stage data source and file level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
489  DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this);
490  } else if (this.hasFirstStageDataSourceIngestPipeline()) {
491  logger.log(Level.INFO, "Scheduling first stage data source level analysis tasks for {0} (jobId={1}), no file level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
492  DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
493  } else {
494  logger.log(Level.INFO, "Scheduling file level analysis tasks for {0} (jobId={1}), no first stage data source level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
495  DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this);
496 
505  this.checkForStageCompleted();
506  }
507  }
508 
512  private void startSecondStage() {
513  logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
514  this.stage = DataSourceIngestJob.Stages.SECOND;
515  if (this.doUI) {
516  this.startDataSourceIngestProgressBar();
517  }
518  synchronized (this.dataSourceIngestPipelineLock) {
519  this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline;
520  }
521  logger.log(Level.INFO, "Scheduling second stage data source level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
522  DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
523  }
524 
528  private void startDataSourceIngestProgressBar() {
529  if (this.doUI) {
530  synchronized (this.dataSourceIngestProgressLock) {
531  String displayName = NbBundle.getMessage(this.getClass(),
532  "IngestJob.progress.dataSourceIngest.initialDisplayName",
533  this.dataSource.getName());
534  this.dataSourceIngestProgress = ProgressHandle.createHandle(displayName, new Cancellable() {
535  @Override
536  public boolean cancel() {
537  // If this method is called, the user has already pressed
538  // the cancel button on the progress bar and the OK button
539  // of a cancelation confirmation dialog supplied by
540  // NetBeans. What remains to be done is to find out whether
541  // the user wants to cancel only the currently executing
542  // data source ingest module or the entire ingest job.
543  DataSourceIngestCancellationPanel panel = new DataSourceIngestCancellationPanel();
544  String dialogTitle = NbBundle.getMessage(DataSourceIngestJob.this.getClass(), "IngestJob.cancellationDialog.title");
545  JOptionPane.showConfirmDialog(null, panel, dialogTitle, JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE);
546  if (panel.cancelAllDataSourceIngestModules()) {
547  DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
548  } else {
549  DataSourceIngestJob.this.cancelCurrentDataSourceIngestModule();
550  }
551  return true;
552  }
553  });
554  this.dataSourceIngestProgress.start();
555  this.dataSourceIngestProgress.switchToIndeterminate();
556  }
557  }
558  }
559 
563  private void startFileIngestProgressBar() {
564  if (this.doUI) {
565  synchronized (this.fileIngestProgressLock) {
566  String displayName = NbBundle.getMessage(this.getClass(),
567  "IngestJob.progress.fileIngest.displayName",
568  this.dataSource.getName());
569  this.fileIngestProgress = ProgressHandle.createHandle(displayName, new Cancellable() {
570  @Override
571  public boolean cancel() {
572  // If this method is called, the user has already pressed
573  // the cancel button on the progress bar and the OK button
574  // of a cancelation confirmation dialog supplied by
575  // NetBeans.
576  DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
577  return true;
578  }
579  });
580  this.fileIngestProgress.start();
581  this.fileIngestProgress.switchToDeterminate((int) this.estimatedFilesToProcess);
582  }
583  }
584  }
585 
590  private void checkForStageCompleted() {
591  synchronized (this.stageCompletionCheckLock) {
592  if (DataSourceIngestJob.taskScheduler.tasksForJobAreCompleted(this)) {
593  switch (this.stage) {
594  case FIRST:
595  this.finishFirstStage();
596  break;
597  case SECOND:
598  this.finish();
599  break;
600  }
601  }
602  }
603  }
604 
609  private void finishFirstStage() {
610  logger.log(Level.INFO, "Finished first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
611 
612  // Shut down the file ingest pipelines. Note that no shut down is
613  // required for the data source ingest pipeline because data source
614  // ingest modules do not have a shutdown() method.
615  List<IngestModuleError> errors = new ArrayList<>();
616  while (!this.fileIngestPipelinesQueue.isEmpty()) {
617  FileIngestPipeline pipeline = fileIngestPipelinesQueue.poll();
618  if (pipeline.isRunning()) {
619  errors.addAll(pipeline.shutDown());
620  }
621  }
622  if (!errors.isEmpty()) {
623  logIngestModuleErrors(errors);
624  }
625 
626  if (this.doUI) {
627  // Finish the first stage data source ingest progress bar, if it hasn't
628  // already been finished.
629  synchronized (this.dataSourceIngestProgressLock) {
630  if (this.dataSourceIngestProgress != null) {
631  this.dataSourceIngestProgress.finish();
632  this.dataSourceIngestProgress = null;
633  }
634  }
635 
636  // Finish the file ingest progress bar, if it hasn't already
637  // been finished.
638  synchronized (this.fileIngestProgressLock) {
639  if (this.fileIngestProgress != null) {
640  this.fileIngestProgress.finish();
641  this.fileIngestProgress = null;
642  }
643  }
644  }
645 
649  if (!this.cancelled && this.hasSecondStageDataSourceIngestPipeline()) {
650  this.startSecondStage();
651  } else {
652  this.finish();
653  }
654  }
655 
659  private void finish() {
660  logger.log(Level.INFO, "Finished analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
661  this.stage = DataSourceIngestJob.Stages.FINALIZATION;
662 
663  if (this.doUI) {
664  // Finish the second stage data source ingest progress bar, if it hasn't
665  // already been finished.
666  synchronized (this.dataSourceIngestProgressLock) {
667  if (this.dataSourceIngestProgress != null) {
668  this.dataSourceIngestProgress.finish();
669  this.dataSourceIngestProgress = null;
670  }
671  }
672  }
673  if (this.cancelled) {
674  try {
675  ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
676  } catch (TskCoreException ex) {
677  logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex);
678  }
679  } else {
680  try {
681  ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
682  } catch (TskCoreException ex) {
683  logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex);
684  }
685  }
686  try {
687  this.ingestJob.setEndDateTime(new Date());
688  } catch (TskCoreException ex) {
689  logger.log(Level.SEVERE, "Failed to set end date for ingest job in database.", ex);
690  }
691  this.parentJob.dataSourceJobFinished(this);
692 
693  }
694 
701  void process(DataSourceIngestTask task) {
702  try {
703  synchronized (this.dataSourceIngestPipelineLock) {
704  if (!this.isCancelled() && !this.currentDataSourceIngestPipeline.isEmpty()) {
705  List<IngestModuleError> errors = new ArrayList<>();
706  errors.addAll(this.currentDataSourceIngestPipeline.process(task));
707  if (!errors.isEmpty()) {
708  logIngestModuleErrors(errors);
709  }
710  }
711  }
712 
713  if (this.doUI) {
718  synchronized (this.dataSourceIngestProgressLock) {
719  if (null != this.dataSourceIngestProgress) {
720  this.dataSourceIngestProgress.finish();
721  this.dataSourceIngestProgress = null;
722  }
723  }
724  }
725 
726  } finally {
727  DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
728  this.checkForStageCompleted();
729  }
730  }
731 
743  void process(FileIngestTask task) throws InterruptedException {
744  try {
745  if (!this.isCancelled()) {
746  FileIngestPipeline pipeline = this.fileIngestPipelinesQueue.take();
747  if (!pipeline.isEmpty()) {
748  AbstractFile file = task.getFile();
749 
750  synchronized (this.fileIngestProgressLock) {
751  ++this.processedFiles;
752  if (this.doUI) {
756  if (this.processedFiles <= this.estimatedFilesToProcess) {
757  this.fileIngestProgress.progress(file.getName(), (int) this.processedFiles);
758  } else {
759  this.fileIngestProgress.progress(file.getName(), (int) this.estimatedFilesToProcess);
760  }
761  this.filesInProgress.add(file.getName());
762  }
763  }
764 
768  List<IngestModuleError> errors = new ArrayList<>();
769  errors.addAll(pipeline.process(task));
770  if (!errors.isEmpty()) {
771  logIngestModuleErrors(errors);
772  }
773 
774  if (this.doUI && !this.cancelled) {
775  synchronized (this.fileIngestProgressLock) {
780  this.filesInProgress.remove(file.getName());
781  if (this.filesInProgress.size() > 0) {
782  this.fileIngestProgress.progress(this.filesInProgress.get(0));
783  } else {
784  this.fileIngestProgress.progress("");
785  }
786  }
787  }
788  }
789  this.fileIngestPipelinesQueue.put(pipeline);
790  }
791  } finally {
792  DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
793  this.checkForStageCompleted();
794  }
795  }
796 
804  void addFiles(List<AbstractFile> files) {
805  if (DataSourceIngestJob.Stages.FIRST == this.stage) {
806  for (AbstractFile file : files) {
807  DataSourceIngestJob.taskScheduler.scheduleFileIngestTask(this, file);
808  }
809  } else {
810  DataSourceIngestJob.logger.log(Level.SEVERE, "Adding files during second stage not supported"); //NON-NLS
811  }
812 
819  this.checkForStageCompleted();
820  }
821 
828  void updateDataSourceIngestProgressBarDisplayName(String displayName) {
829  if (this.doUI && !this.cancelled) {
830  synchronized (this.dataSourceIngestProgressLock) {
831  this.dataSourceIngestProgress.setDisplayName(displayName);
832  }
833  }
834  }
835 
844  void switchDataSourceIngestProgressBarToDeterminate(int workUnits) {
845  if (this.doUI && !this.cancelled) {
846  synchronized (this.dataSourceIngestProgressLock) {
847  if (null != this.dataSourceIngestProgress) {
848  this.dataSourceIngestProgress.switchToDeterminate(workUnits);
849  }
850  }
851  }
852  }
853 
859  void switchDataSourceIngestProgressBarToIndeterminate() {
860  if (this.doUI && !this.cancelled) {
861  synchronized (this.dataSourceIngestProgressLock) {
862  if (null != this.dataSourceIngestProgress) {
863  this.dataSourceIngestProgress.switchToIndeterminate();
864  }
865  }
866  }
867  }
868 
875  void advanceDataSourceIngestProgressBar(int workUnits) {
876  if (this.doUI && !this.cancelled) {
877  synchronized (this.dataSourceIngestProgressLock) {
878  if (null != this.dataSourceIngestProgress) {
879  this.dataSourceIngestProgress.progress("", workUnits);
880  }
881  }
882  }
883  }
884 
891  void advanceDataSourceIngestProgressBar(String currentTask) {
892  if (this.doUI && !this.cancelled) {
893  synchronized (this.dataSourceIngestProgressLock) {
894  if (null != this.dataSourceIngestProgress) {
895  this.dataSourceIngestProgress.progress(currentTask);
896  }
897  }
898  }
899  }
900 
909  void advanceDataSourceIngestProgressBar(String currentTask, int workUnits) {
910  if (this.doUI && !this.cancelled) {
911  synchronized (this.fileIngestProgressLock) {
912  this.dataSourceIngestProgress.progress(currentTask, workUnits);
913  }
914  }
915  }
916 
924  boolean currentDataSourceIngestModuleIsCancelled() {
925  return this.currentDataSourceIngestModuleCancelled;
926  }
927 
934  void currentDataSourceIngestModuleCancellationCompleted(String moduleDisplayName) {
935  this.currentDataSourceIngestModuleCancelled = false;
936  this.cancelledDataSourceIngestModules.add(moduleDisplayName);
937 
938  if (this.doUI) {
946  synchronized (this.dataSourceIngestProgressLock) {
947  this.dataSourceIngestProgress.finish();
948  this.dataSourceIngestProgress = null;
949  this.startDataSourceIngestProgressBar();
950  }
951  }
952  }
953 
959  DataSourceIngestPipeline.PipelineModule getCurrentDataSourceIngestModule() {
960  if (null != this.currentDataSourceIngestPipeline) {
961  return this.currentDataSourceIngestPipeline.getCurrentlyRunningModule();
962  } else {
963  return null;
964  }
965  }
966 
971  void cancelCurrentDataSourceIngestModule() {
972  this.currentDataSourceIngestModuleCancelled = true;
973  }
974 
981  void cancel(IngestJob.CancellationReason reason) {
982  if (this.doUI) {
987  synchronized (this.dataSourceIngestProgressLock) {
988  if (dataSourceIngestProgress != null) {
989  final String displayName = NbBundle.getMessage(this.getClass(),
990  "IngestJob.progress.dataSourceIngest.initialDisplayName",
991  dataSource.getName());
992  dataSourceIngestProgress.setDisplayName(
993  NbBundle.getMessage(this.getClass(),
994  "IngestJob.progress.cancelling",
995  displayName));
996  }
997  }
998 
1003  synchronized (this.fileIngestProgressLock) {
1004  if (this.fileIngestProgress != null) {
1005  final String displayName = NbBundle.getMessage(this.getClass(),
1006  "IngestJob.progress.fileIngest.displayName",
1007  this.dataSource.getName());
1008  this.fileIngestProgress.setDisplayName(
1009  NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling",
1010  displayName));
1011  if (!this.currentFileIngestModule.isEmpty() && !this.currentFileIngestTask.isEmpty()) {
1012  this.fileIngestProgress.progress(NbBundle.getMessage(this.getClass(),
1013  "IngestJob.progress.fileIngest.cancelMessage",
1014  this.currentFileIngestModule, this.currentFileIngestTask));
1015  }
1016 
1017  }
1018  }
1019  }
1020 
1021  /*
1022  * If the work is not already done, show this job as cancelled for the
1023  * given reason.
1024  */
1025  if (Stages.FINALIZATION != stage) {
1026  synchronized (cancellationStateMonitor) {
1027  /*
1028  * These fields are volatile for reading, synchronized on the
1029  * monitor here for writing.
1030  */
1031  this.cancelled = true;
1032  this.cancellationReason = reason;
1033  }
1034  }
1035 
1040  DataSourceIngestJob.taskScheduler.cancelPendingTasksForIngestJob(this);
1041  this.checkForStageCompleted();
1042  }
1043 
1051  void setCurrentFileIngestModule(String moduleName, String taskName) {
1052  this.currentFileIngestModule = moduleName;
1053  this.currentFileIngestTask = taskName;
1054  }
1055 
1062  boolean isCancelled() {
1063  return this.cancelled;
1064  }
1065 
1071  IngestJob.CancellationReason getCancellationReason() {
1072  return this.cancellationReason;
1073  }
1074 
1080  private void logIngestModuleErrors(List<IngestModuleError> errors) {
1081  for (IngestModuleError error : errors) {
1082  DataSourceIngestJob.logger.log(Level.SEVERE, String.format("%s experienced an error analyzing %s (jobId=%d)", error.getModuleDisplayName(), dataSource.getName(), this.id), error.getThrowable()); //NON-NLS
1083  }
1084  }
1085 
1091  Snapshot getSnapshot(boolean getIngestTasksSnapshot) {
1092  return new Snapshot(getIngestTasksSnapshot);
1093  }
1094 
1098  final class Snapshot {
1099 
1100  private final String dataSource;
1101  private final long jobId;
1102  private final long jobStartTime;
1103  private final long snapShotTime;
1104  private final DataSourceIngestPipeline.PipelineModule dataSourceLevelIngestModule;
1105  private boolean fileIngestRunning;
1106  private Date fileIngestStartTime;
1107  private final long processedFiles;
1108  private final long estimatedFilesToProcess;
1109  private final IngestTasksScheduler.IngestJobTasksSnapshot tasksSnapshot;
1110  private final boolean jobCancelled;
1111  private final IngestJob.CancellationReason jobCancellationReason;
1112  private final List<String> cancelledDataSourceModules;
1113 
1118  Snapshot(boolean getIngestTasksSnapshot) {
1119  this.dataSource = DataSourceIngestJob.this.dataSource.getName();
1120  this.jobId = DataSourceIngestJob.this.id;
1121  this.jobStartTime = DataSourceIngestJob.this.createTime;
1122  this.dataSourceLevelIngestModule = DataSourceIngestJob.this.getCurrentDataSourceIngestModule();
1123 
1129  for (FileIngestPipeline pipeline : DataSourceIngestJob.this.fileIngestPipelines) {
1130  if (pipeline.isRunning()) {
1131  this.fileIngestRunning = true;
1132  }
1133  Date pipelineStartTime = pipeline.getStartTime();
1134  if (null != pipelineStartTime && (null == this.fileIngestStartTime || pipelineStartTime.before(this.fileIngestStartTime))) {
1135  this.fileIngestStartTime = pipelineStartTime;
1136  }
1137  }
1138 
1139  this.jobCancelled = cancelled;
1140  this.jobCancellationReason = cancellationReason;
1141  this.cancelledDataSourceModules = new ArrayList<>(DataSourceIngestJob.this.cancelledDataSourceIngestModules);
1142 
1143  if (getIngestTasksSnapshot) {
1144  synchronized (DataSourceIngestJob.this.fileIngestProgressLock) {
1145  this.processedFiles = DataSourceIngestJob.this.processedFiles;
1146  this.estimatedFilesToProcess = DataSourceIngestJob.this.estimatedFilesToProcess;
1147  this.snapShotTime = new Date().getTime();
1148  }
1149  this.tasksSnapshot = DataSourceIngestJob.taskScheduler.getTasksSnapshotForJob(this.jobId);
1150 
1151  } else {
1152  this.processedFiles = 0;
1153  this.estimatedFilesToProcess = 0;
1154  this.snapShotTime = new Date().getTime();
1155  this.tasksSnapshot = null;
1156  }
1157  }
1158 
1165  long getSnapshotTime() {
1166  return snapShotTime;
1167  }
1168 
1175  String getDataSource() {
1176  return dataSource;
1177  }
1178 
1185  long getJobId() {
1186  return this.jobId;
1187  }
1188 
1195  long getJobStartTime() {
1196  return jobStartTime;
1197  }
1198 
1199  DataSourceIngestPipeline.PipelineModule getDataSourceLevelIngestModule() {
1200  return this.dataSourceLevelIngestModule;
1201  }
1202 
1203  boolean fileIngestIsRunning() {
1204  return this.fileIngestRunning;
1205  }
1206 
1207  Date fileIngestStartTime() {
1208  return this.fileIngestStartTime;
1209  }
1210 
1217  double getSpeed() {
1218  return (double) processedFiles / ((snapShotTime - jobStartTime) / 1000);
1219  }
1220 
1226  long getFilesProcessed() {
1227  return processedFiles;
1228  }
1229 
1236  long getFilesEstimated() {
1237  return estimatedFilesToProcess;
1238  }
1239 
1240  long getRootQueueSize() {
1241  if (null == this.tasksSnapshot) {
1242  return 0;
1243  }
1244  return this.tasksSnapshot.getRootQueueSize();
1245  }
1246 
1247  long getDirQueueSize() {
1248  if (null == this.tasksSnapshot) {
1249  return 0;
1250  }
1251  return this.tasksSnapshot.getDirectoryTasksQueueSize();
1252  }
1253 
1254  long getFileQueueSize() {
1255  if (null == this.tasksSnapshot) {
1256  return 0;
1257  }
1258  return this.tasksSnapshot.getFileQueueSize();
1259  }
1260 
1261  long getDsQueueSize() {
1262  if (null == this.tasksSnapshot) {
1263  return 0;
1264  }
1265  return this.tasksSnapshot.getDsQueueSize();
1266  }
1267 
1268  long getRunningListSize() {
1269  if (null == this.tasksSnapshot) {
1270  return 0;
1271  }
1272  return this.tasksSnapshot.getRunningListSize();
1273  }
1274 
1275  boolean isCancelled() {
1276  return this.jobCancelled;
1277  }
1278 
1284  IngestJob.CancellationReason getCancellationReason() {
1285  return this.jobCancellationReason;
1286  }
1287 
1295  List<String> getCancelledDataSourceIngestModules() {
1296  return Collections.unmodifiableList(this.cancelledDataSourceModules);
1297  }
1298 
1299  }
1300 
1301 }

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