19 package org.sleuthkit.autopsy.ingest;
 
   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;
 
   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;
 
   35 import org.openide.windows.WindowManager;
 
   43 import org.
sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType;
 
   45 import org.
sleuthkit.datamodel.IngestModuleInfo.IngestModuleType;
 
   54 final class DataSourceIngestJob {
 
   56     private static final Logger logger = Logger.getLogger(DataSourceIngestJob.class.getName());
 
   64     private final IngestJob parentJob;
 
   65     private static final AtomicLong nextJobId = 
new AtomicLong(0L);
 
   66     private final long id;
 
   67     private final IngestJobSettings settings;
 
   68     private final Content dataSource;
 
   69     private final List<AbstractFile> files = 
new ArrayList<>();
 
   96     private final Object stageCompletionCheckLock = 
new Object();
 
  106     private final Object dataSourceIngestPipelineLock = 
new Object();
 
  107     private DataSourceIngestPipeline firstStageDataSourceIngestPipeline;
 
  108     private DataSourceIngestPipeline secondStageDataSourceIngestPipeline;
 
  109     private DataSourceIngestPipeline currentDataSourceIngestPipeline;
 
  118     private final LinkedBlockingQueue<FileIngestPipeline> fileIngestPipelinesQueue = 
new LinkedBlockingQueue<>();
 
  119     private final List<FileIngestPipeline> fileIngestPipelines = 
new ArrayList<>();
 
  132     private volatile boolean currentDataSourceIngestModuleCancelled;
 
  133     private final List<String> cancelledDataSourceIngestModules = 
new CopyOnWriteArrayList<>();
 
  134     private volatile boolean cancelled;
 
  141     private static final IngestTasksScheduler taskScheduler = IngestTasksScheduler.getInstance();
 
  147     private final boolean doUI;
 
  153     private final Object dataSourceIngestProgressLock = 
new Object();
 
  154     private ProgressHandle dataSourceIngestProgress;
 
  160     private final Object fileIngestProgressLock = 
new Object();
 
  161     private final List<String> filesInProgress = 
new ArrayList<>();
 
  162     private long estimatedFilesToProcess;
 
  163     private long processedFiles;
 
  164     private ProgressHandle fileIngestProgress;
 
  165     private String currentFileIngestModule = 
"";
 
  166     private String currentFileIngestTask = 
"";
 
  167     private final List<IngestModuleInfo> ingestModules = 
new ArrayList<>();
 
  168     private volatile IngestJobInfo ingestJob;
 
  173     private final long createTime;
 
  187         this(parentJob, dataSource, Collections.emptyList(), settings, runInteractively);
 
  203     DataSourceIngestJob(
IngestJob parentJob, Content dataSource, List<AbstractFile> files, 
IngestJobSettings settings, 
boolean runInteractively) {
 
  204         this.parentJob = parentJob;
 
  205         this.
id = DataSourceIngestJob.nextJobId.getAndIncrement();
 
  206         this.dataSource = dataSource;
 
  207         this.files.addAll(files);
 
  208         this.settings = settings;
 
  209         this.doUI = runInteractively;
 
  210         this.createTime = 
new Date().getTime();
 
  211         this.createIngestPipelines();
 
  217     private void createIngestPipelines() {
 
  223         Map<String, IngestModuleTemplate> dataSourceModuleTemplates = 
new HashMap<>();
 
  224         Map<String, IngestModuleTemplate> fileModuleTemplates = 
new HashMap<>();
 
  225         for (IngestModuleTemplate 
template : ingestModuleTemplates) {
 
  226             if (
template.isDataSourceIngestModuleTemplate()) {
 
  227                 dataSourceModuleTemplates.put(
template.getModuleFactory().getClass().getCanonicalName(), 
template);
 
  229             if (
template.isFileIngestModuleTemplate()) {
 
  230                 fileModuleTemplates.put(
template.getModuleFactory().getClass().getCanonicalName(), 
template);
 
  238         IngestPipelinesConfiguration pipelineConfigs = IngestPipelinesConfiguration.getInstance();
 
  239         List<IngestModuleTemplate> firstStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(dataSourceModuleTemplates, pipelineConfigs.getStageOneDataSourceIngestPipelineConfig());
 
  240         List<IngestModuleTemplate> fileIngestModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(fileModuleTemplates, pipelineConfigs.getFileIngestPipelineConfig());
 
  241         List<IngestModuleTemplate> secondStageDataSourceModuleTemplates = DataSourceIngestJob.getConfiguredIngestModuleTemplates(dataSourceModuleTemplates, pipelineConfigs.getStageTwoDataSourceIngestPipelineConfig());
 
  248         for (IngestModuleTemplate 
template : dataSourceModuleTemplates.values()) {
 
  249             firstStageDataSourceModuleTemplates.add(
template);
 
  251         for (IngestModuleTemplate 
template : fileModuleTemplates.values()) {
 
  252             fileIngestModuleTemplates.add(
template);
 
  258         this.firstStageDataSourceIngestPipeline = 
new DataSourceIngestPipeline(
this, firstStageDataSourceModuleTemplates);
 
  259         this.secondStageDataSourceIngestPipeline = 
new DataSourceIngestPipeline(
this, secondStageDataSourceModuleTemplates);
 
  265             int numberOfFileIngestThreads = IngestManager.getInstance().getNumberOfFileIngestThreads();
 
  266             for (
int i = 0; i < numberOfFileIngestThreads; ++i) {
 
  267                 FileIngestPipeline pipeline = 
new FileIngestPipeline(
this, fileIngestModuleTemplates);
 
  268                 this.fileIngestPipelinesQueue.put(pipeline);
 
  269                 this.fileIngestPipelines.add(pipeline);
 
  271         } 
catch (InterruptedException ex) {
 
  277             Thread.currentThread().interrupt();
 
  280             SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase();
 
  281             this.addIngestModules(firstStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
 
  282             this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase);
 
  283             this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
 
  284         } 
catch (TskCoreException | NoCurrentCaseException ex) {
 
  285             logger.log(Level.SEVERE, 
"Failed to add ingest modules to database.", ex);
 
  289     private void addIngestModules(List<IngestModuleTemplate> templates, IngestModuleType type, SleuthkitCase skCase) 
throws TskCoreException {
 
  290         for (IngestModuleTemplate module : templates) {
 
  291             ingestModules.add(skCase.addIngestModule(module.getModuleName(), FactoryClassNameNormalizer.normalize(module.getModuleFactory().getClass().getCanonicalName()), type, module.getModuleFactory().getModuleVersionNumber()));
 
  310     private static List<IngestModuleTemplate> getConfiguredIngestModuleTemplates(Map<String, IngestModuleTemplate> ingestModuleTemplates, List<String> pipelineConfig) {
 
  311         List<IngestModuleTemplate> templates = 
new ArrayList<>();
 
  312         for (String moduleClassName : pipelineConfig) {
 
  313             if (ingestModuleTemplates.containsKey(moduleClassName)) {
 
  314                 templates.add(ingestModuleTemplates.remove(moduleClassName));
 
  334     String getExecutionContext() {
 
  343     Content getDataSource() {
 
  344         return this.dataSource;
 
  353     boolean shouldProcessUnallocatedSpace() {
 
  362     FilesSet getFileIngestFilter() {
 
  371     boolean hasIngestPipeline() {
 
  372         return this.hasFirstStageDataSourceIngestPipeline()
 
  373                 || this.hasFileIngestPipeline()
 
  374                 || this.hasSecondStageDataSourceIngestPipeline();
 
  383     private boolean hasFirstStageDataSourceIngestPipeline() {
 
  384         return (this.firstStageDataSourceIngestPipeline.isEmpty() == 
false);
 
  393     private boolean hasSecondStageDataSourceIngestPipeline() {
 
  394         return (this.secondStageDataSourceIngestPipeline.isEmpty() == 
false);
 
  402     private boolean hasFileIngestPipeline() {
 
  403         if (!this.fileIngestPipelines.isEmpty()) {
 
  404             return !this.fileIngestPipelines.get(0).isEmpty();
 
  414     List<IngestModuleError> start() {
 
  415         List<IngestModuleError> errors = startUpIngestPipelines();
 
  416         if (errors.isEmpty()) {
 
  418                 this.ingestJob = Case.getOpenCase().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, 
new Date(this.createTime), 
new Date(0), IngestJobStatusType.STARTED, 
"");
 
  419             } 
catch (TskCoreException | NoCurrentCaseException ex) {
 
  420                 logger.log(Level.SEVERE, 
"Failed to add ingest job to database.", ex);
 
  422             if (this.hasFirstStageDataSourceIngestPipeline() || this.hasFileIngestPipeline()) {
 
  423                 logger.log(Level.INFO, 
"Starting first stage analysis for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  424                 this.startFirstStage();
 
  425             } 
else if (this.hasSecondStageDataSourceIngestPipeline()) {
 
  426                 logger.log(Level.INFO, 
"Starting second stage analysis for {0} (jobId={1}), no first stage configured", 
new Object[]{dataSource.getName(), this.id}); 
 
  427                 this.startSecondStage();
 
  439     private List<IngestModuleError> startUpIngestPipelines() {
 
  440         List<IngestModuleError> errors = 
new ArrayList<>();
 
  445         errors.addAll(this.firstStageDataSourceIngestPipeline.startUp());
 
  446         errors.addAll(this.secondStageDataSourceIngestPipeline.startUp());
 
  453         if (errors.isEmpty()) {
 
  454             for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) {
 
  455                 errors.addAll(pipeline.startUp());
 
  456                 if (!errors.isEmpty()) {
 
  462                     while (!this.fileIngestPipelinesQueue.isEmpty()) {
 
  463                         FileIngestPipeline startedPipeline = this.fileIngestPipelinesQueue.poll();
 
  464                         if (startedPipeline.isRunning()) {
 
  465                             List<IngestModuleError> shutDownErrors = startedPipeline.shutDown();
 
  466                             if (!shutDownErrors.isEmpty()) {
 
  472                                 logIngestModuleErrors(shutDownErrors);
 
  487     private void startFirstStage() {
 
  488         this.stage = DataSourceIngestJob.Stages.
FIRST;
 
  490         if (this.hasFileIngestPipeline()) {
 
  491             synchronized (this.fileIngestProgressLock) {
 
  492                 this.estimatedFilesToProcess = this.dataSource.accept(
new GetFilesCountVisitor());
 
  500             if (this.hasFirstStageDataSourceIngestPipeline()) {
 
  501                 this.startDataSourceIngestProgressBar();
 
  503             if (this.hasFileIngestPipeline()) {
 
  504                 this.startFileIngestProgressBar();
 
  512         synchronized (this.dataSourceIngestPipelineLock) {
 
  513             this.currentDataSourceIngestPipeline = this.firstStageDataSourceIngestPipeline;
 
  519         if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) {
 
  520             logger.log(Level.INFO, 
"Scheduling first stage data source and file level analysis tasks for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  521             DataSourceIngestJob.taskScheduler.scheduleIngestTasks(
this);
 
  522         } 
else if (this.hasFirstStageDataSourceIngestPipeline()) {
 
  523             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}); 
 
  524             DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(
this);
 
  526             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}); 
 
  527             DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(
this, this.files);
 
  537             this.checkForStageCompleted();
 
  544     private void startSecondStage() {
 
  545         logger.log(Level.INFO, 
"Starting second stage analysis for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  546         this.stage = DataSourceIngestJob.Stages.
SECOND;
 
  548             this.startDataSourceIngestProgressBar();
 
  550         synchronized (this.dataSourceIngestPipelineLock) {
 
  551             this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline;
 
  553         logger.log(Level.INFO, 
"Scheduling second stage data source level analysis tasks for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  554         DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(
this);
 
  560     private void startDataSourceIngestProgressBar() {
 
  562             synchronized (this.dataSourceIngestProgressLock) {
 
  563                 String displayName = NbBundle.getMessage(this.getClass(),
 
  564                         "IngestJob.progress.dataSourceIngest.initialDisplayName",
 
  565                         this.dataSource.getName());
 
  566                 this.dataSourceIngestProgress = ProgressHandle.createHandle(displayName, 
new Cancellable() {
 
  568                     public boolean cancel() {
 
  575                         DataSourceIngestCancellationPanel panel = 
new DataSourceIngestCancellationPanel();
 
  576                         String dialogTitle = NbBundle.getMessage(DataSourceIngestJob.this.getClass(), 
"IngestJob.cancellationDialog.title");
 
  577                         JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), panel, dialogTitle, JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE);
 
  578                         if (panel.cancelAllDataSourceIngestModules()) {
 
  579                             DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
 
  581                             DataSourceIngestJob.this.cancelCurrentDataSourceIngestModule();
 
  586                 this.dataSourceIngestProgress.start();
 
  587                 this.dataSourceIngestProgress.switchToIndeterminate();
 
  595     private void startFileIngestProgressBar() {
 
  597             synchronized (this.fileIngestProgressLock) {
 
  598                 String displayName = NbBundle.getMessage(this.getClass(),
 
  599                         "IngestJob.progress.fileIngest.displayName",
 
  600                         this.dataSource.getName());
 
  601                 this.fileIngestProgress = ProgressHandle.createHandle(displayName, 
new Cancellable() {
 
  603                     public boolean cancel() {
 
  608                         DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
 
  612                 this.fileIngestProgress.start();
 
  613                 this.fileIngestProgress.switchToDeterminate((
int) this.estimatedFilesToProcess);
 
  622     private void checkForStageCompleted() {
 
  623         synchronized (this.stageCompletionCheckLock) {
 
  624             if (DataSourceIngestJob.taskScheduler.tasksForJobAreCompleted(
this)) {
 
  625                 switch (this.stage) {
 
  627                         this.finishFirstStage();
 
  641     private void finishFirstStage() {
 
  642         logger.log(Level.INFO, 
"Finished first stage analysis for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  647         List<IngestModuleError> errors = 
new ArrayList<>();
 
  648         while (!this.fileIngestPipelinesQueue.isEmpty()) {
 
  649             FileIngestPipeline pipeline = fileIngestPipelinesQueue.poll();
 
  650             if (pipeline.isRunning()) {
 
  651                 errors.addAll(pipeline.shutDown());
 
  654         if (!errors.isEmpty()) {
 
  655             logIngestModuleErrors(errors);
 
  661             synchronized (this.dataSourceIngestProgressLock) {
 
  662                 if (this.dataSourceIngestProgress != null) {
 
  663                     this.dataSourceIngestProgress.finish();
 
  664                     this.dataSourceIngestProgress = null;
 
  670             synchronized (this.fileIngestProgressLock) {
 
  671                 if (this.fileIngestProgress != null) {
 
  672                     this.fileIngestProgress.finish();
 
  673                     this.fileIngestProgress = null;
 
  681         if (!this.cancelled && this.hasSecondStageDataSourceIngestPipeline()) {
 
  682             this.startSecondStage();
 
  691     private void finish() {
 
  692         logger.log(Level.INFO, 
"Finished analysis for {0} (jobId={1})", 
new Object[]{dataSource.getName(), this.id}); 
 
  698             synchronized (this.dataSourceIngestProgressLock) {
 
  699                 if (this.dataSourceIngestProgress != null) {
 
  700                     this.dataSourceIngestProgress.finish();
 
  701                     this.dataSourceIngestProgress = null;
 
  705         if (ingestJob != null) {
 
  706             if (this.cancelled) {
 
  708                     ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
 
  709                 } 
catch (TskCoreException ex) {
 
  710                     logger.log(Level.SEVERE, 
"Failed to set ingest status for ingest job in database.", ex);
 
  714                     ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
 
  715                 } 
catch (TskCoreException ex) {
 
  716                     logger.log(Level.SEVERE, 
"Failed to set ingest status for ingest job in database.", ex);
 
  720                 this.ingestJob.setEndDateTime(
new Date());
 
  721             } 
catch (TskCoreException ex) {
 
  722                 logger.log(Level.SEVERE, 
"Failed to set end date for ingest job in database.", ex);
 
  725         this.parentJob.dataSourceJobFinished(
this);
 
  734     void process(DataSourceIngestTask task) {
 
  736             synchronized (this.dataSourceIngestPipelineLock) {
 
  737                 if (!this.isCancelled() && !this.currentDataSourceIngestPipeline.isEmpty()) {
 
  738                     List<IngestModuleError> errors = 
new ArrayList<>();
 
  739                     errors.addAll(this.currentDataSourceIngestPipeline.process(task));
 
  740                     if (!errors.isEmpty()) {
 
  741                         logIngestModuleErrors(errors);
 
  751                 synchronized (this.dataSourceIngestProgressLock) {
 
  752                     if (null != this.dataSourceIngestProgress) {
 
  753                         this.dataSourceIngestProgress.finish();
 
  754                         this.dataSourceIngestProgress = null;
 
  760             DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
 
  761             this.checkForStageCompleted();
 
  776     void process(FileIngestTask task) 
throws InterruptedException {
 
  778             if (!this.isCancelled()) {
 
  779                 FileIngestPipeline pipeline = this.fileIngestPipelinesQueue.take();
 
  780                 if (!pipeline.isEmpty()) {
 
  781                     AbstractFile file = task.getFile();
 
  783                     synchronized (this.fileIngestProgressLock) {
 
  784                         ++this.processedFiles;
 
  789                             if (this.processedFiles <= this.estimatedFilesToProcess) {
 
  790                                 this.fileIngestProgress.progress(file.getName(), (int) this.processedFiles);
 
  792                                 this.fileIngestProgress.progress(file.getName(), (int) this.estimatedFilesToProcess);
 
  794                             this.filesInProgress.add(file.getName());
 
  801                     List<IngestModuleError> errors = 
new ArrayList<>();
 
  802                     errors.addAll(pipeline.process(task));
 
  803                     if (!errors.isEmpty()) {
 
  804                         logIngestModuleErrors(errors);
 
  807                     if (this.doUI && !this.cancelled) {
 
  808                         synchronized (this.fileIngestProgressLock) {
 
  813                             this.filesInProgress.remove(file.getName());
 
  814                             if (this.filesInProgress.size() > 0) {
 
  815                                 this.fileIngestProgress.progress(this.filesInProgress.get(0));
 
  817                                 this.fileIngestProgress.progress(
"");
 
  822                 this.fileIngestPipelinesQueue.put(pipeline);
 
  825             DataSourceIngestJob.taskScheduler.notifyTaskCompleted(task);
 
  826             this.checkForStageCompleted();
 
  837     void addFiles(List<AbstractFile> files) {
 
  838         if (DataSourceIngestJob.Stages.FIRST == 
this.stage) {
 
  839             DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(
this, files);
 
  841             DataSourceIngestJob.logger.log(Level.SEVERE, 
"Adding files during second stage not supported"); 
 
  850         this.checkForStageCompleted();
 
  859     void updateDataSourceIngestProgressBarDisplayName(String displayName) {
 
  860         if (this.doUI && !this.cancelled) {
 
  861             synchronized (this.dataSourceIngestProgressLock) {
 
  862                 this.dataSourceIngestProgress.setDisplayName(displayName);
 
  875     void switchDataSourceIngestProgressBarToDeterminate(
int workUnits) {
 
  876         if (this.doUI && !this.cancelled) {
 
  877             synchronized (this.dataSourceIngestProgressLock) {
 
  878                 if (null != this.dataSourceIngestProgress) {
 
  879                     this.dataSourceIngestProgress.switchToDeterminate(workUnits);
 
  890     void switchDataSourceIngestProgressBarToIndeterminate() {
 
  891         if (this.doUI && !this.cancelled) {
 
  892             synchronized (this.dataSourceIngestProgressLock) {
 
  893                 if (null != this.dataSourceIngestProgress) {
 
  894                     this.dataSourceIngestProgress.switchToIndeterminate();
 
  906     void advanceDataSourceIngestProgressBar(
int workUnits) {
 
  907         if (this.doUI && !this.cancelled) {
 
  908             synchronized (this.dataSourceIngestProgressLock) {
 
  909                 if (null != this.dataSourceIngestProgress) {
 
  910                     this.dataSourceIngestProgress.progress(
"", workUnits);
 
  922     void advanceDataSourceIngestProgressBar(String currentTask) {
 
  923         if (this.doUI && !this.cancelled) {
 
  924             synchronized (this.dataSourceIngestProgressLock) {
 
  925                 if (null != this.dataSourceIngestProgress) {
 
  926                     this.dataSourceIngestProgress.progress(currentTask);
 
  940     void advanceDataSourceIngestProgressBar(String currentTask, 
int workUnits) {
 
  941         if (this.doUI && !this.cancelled) {
 
  942             synchronized (this.fileIngestProgressLock) {
 
  943                 this.dataSourceIngestProgress.progress(currentTask, workUnits);
 
  955     boolean currentDataSourceIngestModuleIsCancelled() {
 
  956         return this.currentDataSourceIngestModuleCancelled;
 
  965     void currentDataSourceIngestModuleCancellationCompleted(String moduleDisplayName) {
 
  966         this.currentDataSourceIngestModuleCancelled = 
false;
 
  967         this.cancelledDataSourceIngestModules.add(moduleDisplayName);
 
  977             synchronized (this.dataSourceIngestProgressLock) {
 
  978                 this.dataSourceIngestProgress.finish();
 
  979                 this.dataSourceIngestProgress = null;
 
  980                 this.startDataSourceIngestProgressBar();
 
  990     DataSourceIngestPipeline.PipelineModule getCurrentDataSourceIngestModule() {
 
  991         if (null != this.currentDataSourceIngestPipeline) {
 
  992             return this.currentDataSourceIngestPipeline.getCurrentlyRunningModule();
 
 1002     void cancelCurrentDataSourceIngestModule() {
 
 1003         this.currentDataSourceIngestModuleCancelled = 
true;
 
 1012     void cancel(IngestJob.CancellationReason reason) {
 
 1013         this.cancelled = 
true;
 
 1014         this.cancellationReason = reason;
 
 1015         DataSourceIngestJob.taskScheduler.cancelPendingTasksForIngestJob(
this);
 
 1018             synchronized (this.dataSourceIngestProgressLock) {
 
 1019                 if (null != dataSourceIngestProgress) {
 
 1020                     dataSourceIngestProgress.setDisplayName(NbBundle.getMessage(
this.getClass(), 
"IngestJob.progress.dataSourceIngest.initialDisplayName", dataSource.getName()));
 
 1021                     dataSourceIngestProgress.progress(NbBundle.getMessage(
this.getClass(), 
"IngestJob.progress.cancelling"));
 
 1025             synchronized (this.fileIngestProgressLock) {
 
 1026                 if (null != this.fileIngestProgress) {
 
 1027                     this.fileIngestProgress.setDisplayName(NbBundle.getMessage(
this.getClass(), 
"IngestJob.progress.fileIngest.displayName", this.dataSource.getName()));
 
 1028                     this.fileIngestProgress.progress(NbBundle.getMessage(
this.getClass(), 
"IngestJob.progress.cancelling"));
 
 1041     void setCurrentFileIngestModule(String moduleName, String taskName) {
 
 1042         this.currentFileIngestModule = moduleName;
 
 1043         this.currentFileIngestTask = taskName;
 
 1052     boolean isCancelled() {
 
 1053         return this.cancelled;
 
 1061     IngestJob.CancellationReason getCancellationReason() {
 
 1062         return this.cancellationReason;
 
 1070     private void logIngestModuleErrors(List<IngestModuleError> errors) {
 
 1071         for (IngestModuleError error : errors) {
 
 1072             DataSourceIngestJob.logger.log(Level.SEVERE, String.format(
"%s experienced an error analyzing %s (jobId=%d)", error.getModuleDisplayName(), dataSource.getName(), this.id), error.getThrowable()); 
 
 1081     Snapshot getSnapshot(
boolean getIngestTasksSnapshot) {
 
 1082         return new Snapshot(getIngestTasksSnapshot);
 
 1088     final class Snapshot {
 
 1090         private final String dataSource;
 
 1091         private final long jobId;
 
 1092         private final long jobStartTime;
 
 1093         private final long snapShotTime;
 
 1094         private final DataSourceIngestPipeline.PipelineModule dataSourceLevelIngestModule;
 
 1095         private boolean fileIngestRunning;
 
 1096         private Date fileIngestStartTime;
 
 1097         private final long processedFiles;
 
 1098         private final long estimatedFilesToProcess;
 
 1099         private final IngestTasksScheduler.IngestJobTasksSnapshot tasksSnapshot;
 
 1100         private final boolean jobCancelled;
 
 1101         private final IngestJob.CancellationReason jobCancellationReason;
 
 1102         private final List<String> cancelledDataSourceModules;
 
 1108         Snapshot(
boolean getIngestTasksSnapshot) {
 
 1109             this.dataSource = DataSourceIngestJob.this.dataSource.getName();
 
 1110             this.jobId = DataSourceIngestJob.this.id;
 
 1111             this.jobStartTime = DataSourceIngestJob.this.createTime;
 
 1112             this.dataSourceLevelIngestModule = DataSourceIngestJob.this.getCurrentDataSourceIngestModule();
 
 1119             for (FileIngestPipeline pipeline : DataSourceIngestJob.this.fileIngestPipelines) {
 
 1120                 if (pipeline.isRunning()) {
 
 1121                     this.fileIngestRunning = 
true;
 
 1123                 Date pipelineStartTime = pipeline.getStartTime();
 
 1124                 if (null != pipelineStartTime && (null == this.fileIngestStartTime || pipelineStartTime.before(
this.fileIngestStartTime))) {
 
 1125                     this.fileIngestStartTime = pipelineStartTime;
 
 1129             this.jobCancelled = cancelled;
 
 1130             this.jobCancellationReason = cancellationReason;
 
 1131             this.cancelledDataSourceModules = 
new ArrayList<>(DataSourceIngestJob.this.cancelledDataSourceIngestModules);
 
 1133             if (getIngestTasksSnapshot) {
 
 1134                 synchronized (DataSourceIngestJob.this.fileIngestProgressLock) {
 
 1135                     this.processedFiles = DataSourceIngestJob.this.processedFiles;
 
 1136                     this.estimatedFilesToProcess = DataSourceIngestJob.this.estimatedFilesToProcess;
 
 1137                     this.snapShotTime = 
new Date().getTime();
 
 1139                 this.tasksSnapshot = DataSourceIngestJob.taskScheduler.getTasksSnapshotForJob(this.jobId);
 
 1142                 this.processedFiles = 0;
 
 1143                 this.estimatedFilesToProcess = 0;
 
 1144                 this.snapShotTime = 
new Date().getTime();
 
 1145                 this.tasksSnapshot = null;
 
 1155         long getSnapshotTime() {
 
 1156             return snapShotTime;
 
 1165         String getDataSource() {
 
 1185         long getJobStartTime() {
 
 1186             return jobStartTime;
 
 1189         DataSourceIngestPipeline.PipelineModule getDataSourceLevelIngestModule() {
 
 1190             return this.dataSourceLevelIngestModule;
 
 1193         boolean fileIngestIsRunning() {
 
 1194             return this.fileIngestRunning;
 
 1197         Date fileIngestStartTime() {
 
 1198             return this.fileIngestStartTime;
 
 1208             return (
double) processedFiles / ((snapShotTime - jobStartTime) / 1000);
 
 1216         long getFilesProcessed() {
 
 1217             return processedFiles;
 
 1226         long getFilesEstimated() {
 
 1227             return estimatedFilesToProcess;
 
 1230         long getRootQueueSize() {
 
 1231             if (null == this.tasksSnapshot) {
 
 1234             return this.tasksSnapshot.getRootQueueSize();
 
 1237         long getDirQueueSize() {
 
 1238             if (null == this.tasksSnapshot) {
 
 1241             return this.tasksSnapshot.getDirectoryTasksQueueSize();
 
 1244         long getFileQueueSize() {
 
 1245             if (null == this.tasksSnapshot) {
 
 1248             return this.tasksSnapshot.getFileQueueSize();
 
 1251         long getDsQueueSize() {
 
 1252             if (null == this.tasksSnapshot) {
 
 1255             return this.tasksSnapshot.getDsQueueSize();
 
 1258         long getRunningListSize() {
 
 1259             if (null == this.tasksSnapshot) {
 
 1262             return this.tasksSnapshot.getRunningListSize();
 
 1265         boolean isCancelled() {
 
 1266             return this.jobCancelled;
 
 1274         IngestJob.CancellationReason getCancellationReason() {
 
 1275             return this.jobCancellationReason;
 
 1285         List<String> getCancelledDataSourceIngestModules() {
 
 1286             return Collections.unmodifiableList(this.cancelledDataSourceModules);
 
List< IngestModuleTemplate > getEnabledIngestModuleTemplates()
 
String getExecutionContext()
 
boolean getProcessUnallocatedSpace()