diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index c5cc14d262..9cc7f9e7cf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.casemodule; - -import org.sleuthkit.autopsy.ingest.IngestJobConfigurator; import org.openide.util.NbBundle; import java.awt.Color; import java.awt.Component; @@ -37,6 +35,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; +import org.sleuthkit.autopsy.ingest.IngestManager; /** * second panel of add image wizard, allows user to configure ingest modules. * @@ -46,7 +47,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { private static final Logger logger = Logger.getLogger(AddImageWizardIngestConfigPanel.class.getName()); - private IngestJobConfigurator ingestConfig; + private IngestJobSettings ingestJobSettings; + /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). @@ -60,10 +62,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel messages = ingestConfig.getIngestJobConfigWarnings(); + this.ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName()); + List messages = this.ingestJobSettings.getWarnings(); if (messages.isEmpty() == false) { StringBuilder warning = new StringBuilder(); for (String message : messages) { @@ -95,7 +97,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel messages = this.ingestJobSettings.getWarnings(); + if (messages.isEmpty() == false) { + StringBuilder warning = new StringBuilder(); + for (String message : messages) { + warning.append(message).append("\n"); + } + JOptionPane.showMessageDialog(null, warning.toString()); + } + // Start ingest if it hasn't already been started readyToIngest = true; startIngest(); @@ -202,9 +212,11 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel 0) { + timeoutSec = userSpecifiedTimeoutSec; + } else { + logger.log(Level.WARNING, "Process time out value must be greater than zero. Using default time out instead."); // NON-NLS + timeoutSec = DEFAULT_TIMEOUT_SEC; + } + } + + /** + * @return true if process should be terminated, false otherwise + */ + @Override + public boolean shouldTerminateProcess() { + + // check if maximum execution time elapsed + long currentTimeSec = (new Date().getTime()) / 1000; + if (currentTimeSec - creationTimeSec > timeoutSec) { + return true; + } + + return false; + } + } + + /** * EVERYTHING FOLLOWING THIS LINE IS DEPRECATED AND SLATED FOR REMOVAL */ diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 1459a4604e..11b5773f20 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -21,8 +21,6 @@ IngestJob.progress.dataSourceIngest.displayName={0} for {1} IngestJob.progress.fileIngest.displayName=Analyzing files from {0} IngestJob.progress.cancelling={0} (Cancelling...) IngestJob.cancellationDialog.title=Cancel Ingest -IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText=Processes unallocated space, such as deleted files. Produces more complete results, but it may take longer to process on large images. -IngestJobConfigurationPanel.processUnallocCheckbox.text=Process Unallocated Space IngestDialog.title.text=Ingest Modules IngestDialog.startButton.title=Start IngestDialog.closeButton.title=Close @@ -50,8 +48,6 @@ IngestMessageTopComponent.displayReport.option.GenRpt=Generate Report IngestMessageTopComponent.msgDlg.ingestRpt.text=Ingest Report IngestMonitor.mgrErrMsg.lowDiskSpace.title=Ingest stopped - low disk space on {0} IngestMonitor.mgrErrMsg.lowDiskSpace.msg=Stopping ingest due to low disk space on disk {0}. \nEnsure the Case drive has at least 1GB free space and restart ingest. -IngestJobConfigurationPanel.advancedButton.text=Advanced -IngestJobConfigurationPanel.advancedButton.actionCommand=Advanced IngestManager.StartIngestJobsTask.run.displayName=Starting ingest IngestManager.StartIngestJobsTask.run.cancelling={0} (Cancelling...) IngestMessagePanel.sortByComboBox.model.time=Time @@ -62,11 +58,11 @@ IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg=Unable to start up one o IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution=Please disable the failed modules or fix the errors and then restart ingest \nby right clicking on the data source and selecting Run Ingest Modules. IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList=\nErrors\: \n{0} IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle=Ingest Failure -IngestJobConfigurator.createModuleSettingsFolderForContext.exception.msg=Failed to create ingest module settings folder, cannot save settings. -IngestJobConfigurator.createModuleSettingsFolderForContext.exception.title=Ingest Job Initialization Failure -IngestJobConfigurator.saveJobSettings.usermsg=Failed to save ingest job settings for {0} module. -IngestJobConfigurator.saveJobSettings.usermsg.title=Ingest Job Settings -IngestJobConfigurationPanel.descriptionLabel.text= +IngestJobSettings.createModuleSettingsFolder.warning=Failed to create ingest module settings folder, cannot save settings. +IngestJobSettings.missingModule.warning=Previously loaded {0} module could not be found. +IngestJobSettings.save.warning=Failed to save ingest job settings for {0} module. +IngestJobSettings.moduleSettingsLoad.warning=Error loading ingest job settings for {0} module for {1} context, using defaults. +IngestJobSettings.moduleSettingsSave.warning=Error saving ingest job settings for {0} module for {1} context. IngestProgressSnapshotDialog.title.text=Ingest Progress Snapshot IngestProgressSnapshotPanel.refreshButton.text=Refresh IngestProgressSnapshotPanel.closeButton.text=Close @@ -85,3 +81,8 @@ DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=Cancel cur FileIngestCancellationPanel.cancelIngestJobRadioButton.text=Cancel data source ingest and file ingest FileIngestCancellationPanel.cancelFileIngestRadioButton.text=Cancel file ingest only DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=Cancel all ingest modules +IngestJobSettingsPanel.advancedButton.actionCommand=Advanced +IngestJobSettingsPanel.advancedButton.text=Advanced +IngestJobSettingsPanel.processUnallocCheckbox.toolTipText=Processes unallocated space, such as deleted files. Produces more complete results, but it may take longer to process on large images. +IngestJobSettingsPanel.processUnallocCheckbox.text=Process Unallocated Space +IngestJobSettingsPanel.descriptionLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index ba943a0b71..85ca5bfe16 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -6,10 +6,6 @@ IngestDialog.title.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u IngestJob.progress.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 IngestJob.progress.dataSourceIngest.displayName={1}\u306e{0} IngestJob.progress.fileIngest.displayName={0}\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d -IngestJobConfigurationPanel.advancedButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 -IngestJobConfigurationPanel.advancedButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 -IngestJobConfigurationPanel.processUnallocCheckbox.text=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u306e\u51e6\u7406 -IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u7b49\u306e\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u3092\u51e6\u7406\u3002\u3088\u308a\u5b8c\u5168\u306a\u7d50\u679c\u304c\u51fa\u307e\u3059\u304c\u3001\u5927\u304d\u3044\u30a4\u30e1\u30fc\u30b8\u3067\u306f\u51e6\u7406\u6642\u9593\u304c\u9577\u304f\u306a\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 IngestManager.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc IngestManager.moduleErr.errListenToUpdates.msg=Ingest Manager\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 IngestManager.StartIngestJobsTask.run.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 @@ -57,10 +53,8 @@ IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList=\n\u30a8\u30e9\u30 IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg=\uff11\u3064\u307e\u305f\u306f\u8907\u6570\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30b9\u30bf\u30fc\u30c8\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u306f\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f\u3002 IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution=\u5931\u6557\u3057\u305f\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u7121\u52b9\u5316\u3059\u308b\u304b\u30a8\u30e9\u30fc\u3092\u89e3\u6c7a\u3057\u3001\u305d\u306e\u5f8c\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3001\n\u300c\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u5b9f\u884c\u300d\u3092\u9078\u629e\u3057\u3066\u3001\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u30ea\u30b9\u30bf\u30fc\u30c8\u3057\u3066\u4e0b\u3055\u3044\u3002 IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u5931\u6557 -IngestJobConfigurator.createModuleSettingsFolderForContext.exception.msg=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u8a2d\u5b9a\u30d5\u30a9\u30eb\u30c0\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3067\u304d\u307e\u305b\u3093\u3002 -IngestJobConfigurator.createModuleSettingsFolderForContext.exception.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u521d\u671f\u5316\u306e\u5931\u6557 -IngestJobConfigurator.saveJobSettings.usermsg={0}\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -IngestJobConfigurator.saveJobSettings.usermsg.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a +IngestJobSettings.createModuleSettingsFolder.warning=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u8a2d\u5b9a\u30d5\u30a9\u30eb\u30c0\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3067\u304d\u307e\u305b\u3093\u3002 +IngestJobSettings.save.error={0}\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 IngestJob.progress.dataSourceIngest.initialDisplayName={0}\u3092\u89e3\u6790\u4e2d IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.dataSource=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.elapsedTime=\u7d4c\u904e\u6642\u9593\uff08\u6642\uff1a\u5206\uff1a\u79d2\uff09 @@ -75,3 +69,7 @@ IngestProgressSnapshotDialog.title.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30 IngestProgressSnapshotPanel.closeButton.text=\u9589\u3058\u308b IngestProgressSnapshotPanel.refreshButton.text=\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5 IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity=\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3 +IngestJobSettingsPanel.advancedButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestJobSettingsPanel.advancedButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestJobSettingsPanel.processUnallocCheckbox.toolTipText=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u7b49\u306e\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u3092\u51e6\u7406\u3002\u3088\u308a\u5b8c\u5168\u306a\u7d50\u679c\u304c\u51fa\u307e\u3059\u304c\u3001\u5927\u304d\u3044\u30a4\u30e1\u30fc\u30b8\u3067\u306f\u51e6\u7406\u6642\u9593\u304c\u9577\u304f\u306a\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +IngestJobSettingsPanel.processUnallocCheckbox.text=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u306e\u51e6\u7406 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java index 03ebc02636..51bcae1e9c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java @@ -21,28 +21,45 @@ package org.sleuthkit.autopsy.ingest; import org.sleuthkit.autopsy.coreutils.ExecUtil; /** - * An ExecUtil process terminator for data source ingest modules that checks for - * ingest job cancellation. + * A timed process terminator for data source ingest modules. Checks for + * ingest job cancellation as well. */ -public final class DataSourceIngestModuleProcessTerminator implements ExecUtil.ProcessTerminator { - - private final IngestJobContext context; +public final class DataSourceIngestModuleProcessTerminator extends ExecUtil.TimedProcessTerminator { + public final IngestJobContext context; + /** * Constructs a process terminator for a data source ingest module. + * Uses default process execution timeout value. * * @param context The ingest job context for the ingest module. */ public DataSourceIngestModuleProcessTerminator(IngestJobContext context) { + super(); this.context = context; } /** - * @inheritDoc + * Constructs a process terminator for a data source ingest module. + * + * @param context The ingest job context for the ingest module. + * @param timeoutSec Process execution timeout value (seconds) + */ + public DataSourceIngestModuleProcessTerminator(IngestJobContext context, long timeoutSec) { + super(timeoutSec); + this.context = context; + } + + /** + * @return true if process should be terminated, false otherwise */ @Override public boolean shouldTerminateProcess() { - return this.context.dataSourceIngestIsCancelled(); + + if (this.context.dataSourceIngestIsCancelled()) + return true; + + return super.shouldTerminateProcess(); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java index d364afa423..765ad15917 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java @@ -21,28 +21,45 @@ package org.sleuthkit.autopsy.ingest; import org.sleuthkit.autopsy.coreutils.ExecUtil; /** - * An ExecUtil process terminator for data source ingest modules that checks for - * ingest job cancellation. + * A timed process terminator for data source ingest modules. Checks for + * ingest job cancellation as well. */ -public final class FileIngestModuleProcessTerminator implements ExecUtil.ProcessTerminator { - - private final IngestJobContext context; +public final class FileIngestModuleProcessTerminator extends ExecUtil.TimedProcessTerminator { + public final IngestJobContext context; + /** * Constructs a process terminator for a file ingest module. + * Uses default process execution timeout value. * * @param context The ingest job context for the ingest module. */ public FileIngestModuleProcessTerminator(IngestJobContext context) { + super(); this.context = context; } + + /** + * Constructs a process terminator for a file ingest module. + * + * @param context The ingest job context for the ingest module. + * @param timeoutSec Process execution timeout value (seconds) + */ + public FileIngestModuleProcessTerminator(IngestJobContext context, long timeoutSec) { + super(timeoutSec); + this.context = context; + } /** - * @inheritDoc + * @return true if process should be terminated, false otherwise */ @Override public boolean shouldTerminateProcess() { - return this.context.fileIngestIsCancelled(); + + if (this.context.fileIngestIsCancelled()) + return true; + + return super.shouldTerminateProcess(); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java index 8569bab9b7..720c43af46 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java @@ -141,19 +141,16 @@ final class IngestJob { * Starts an ingest job for a data source. * * @param dataSource The data source to ingest. - * @param ingestModuleTemplates The ingest module templates to use to create - * the ingest pipelines for the job. - * @param processUnallocatedSpace Whether or not the job should include - * processing of unallocated space. + * @param settings The settings for the job. * @return A collection of ingest module start up errors, empty on success. */ - static List startJob(Content dataSource, List ingestModuleTemplates, boolean processUnallocatedSpace) { + static List startJob(Content dataSource, IngestJobSettings settings) { List errors = new ArrayList<>(); if (IngestJob.jobCreationIsEnabled) { long jobId = nextJobId.incrementAndGet(); - IngestJob job = new IngestJob(jobId, dataSource, processUnallocatedSpace); + IngestJob job = new IngestJob(jobId, dataSource, settings.getProcessUnallocatedSpace()); IngestJob.jobsById.put(jobId, job); - errors = job.start(ingestModuleTemplates); + errors = job.start(settings.getEnabledIngestModuleTemplates()); if (errors.isEmpty() && job.hasIngestPipeline()) { IngestManager.getInstance().fireIngestJobStarted(jobId); IngestJob.logger.log(Level.INFO, "Ingest job {0} started", jobId); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurator.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurator.java index f9aaf17aef..ee1d65c115 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurator.java @@ -18,298 +18,78 @@ */ package org.sleuthkit.autopsy.ingest; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.logging.Level; -import javax.swing.JOptionPane; import javax.swing.JPanel; - -import org.openide.util.NbBundle; -import org.openide.util.io.NbObjectInputStream; -import org.openide.util.io.NbObjectOutputStream; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.datamodel.Content; /** * Provides a mechanism for creating and persisting an ingest job configuration * for a particular context and for launching ingest jobs that process one or * more data sources using the ingest job configuration. + * + * @deprecated Use the IngestModuleSettings and IngestJobConfigurationPanel + * classes and IngestManager.startIngestJob() instead. */ +@Deprecated public final class IngestJobConfigurator { - private static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS - private static final String DISABLED_INGEST_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS - private static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space"; //NON-NLS - private static final String MODULE_SETTINGS_FOLDER_PATH = new StringBuilder(PlatformUtil.getUserConfigDirectory()).append(File.separator).append("IngestModuleSettings").toString(); //NON-NLS - private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS - private static final Logger logger = Logger.getLogger(IngestJobConfigurator.class.getName()); - private final String launcherContext; - private String moduleSettingsFolderForContext = null; - private final List warnings = new ArrayList<>(); - private IngestJobConfigurationPanel ingestConfigPanel = null; + private final IngestJobSettings settings; + private final IngestJobSettingsPanel settingsPanel; /** - * Constructs an ingest job launcher that creates and persists an ingest job - * configuration for a particular context and launches ingest jobs that - * process one or more data sources using the ingest job configuration. + * Constructs an ingest job launcher that creates and persists ingest job + * settings for a particular context and launches ingest jobs that + * process one or more data sources using the settings. * - * @param launcherContext The context identifier. + * @param context The context identifier. */ - public IngestJobConfigurator(String launcherContext) { - this.launcherContext = launcherContext; - - createModuleSettingsFolderForContext(); - - // Get the ingest module factories discovered by the ingest module - // loader. - List moduleFactories = IngestModuleFactoryLoader.getIngestModuleFactories(); - HashSet loadedModuleNames = new HashSet<>(); - for (IngestModuleFactory moduleFactory : moduleFactories) { - loadedModuleNames.add(moduleFactory.getModuleDisplayName()); - } - - // Get the enabled and disabled ingest modules settings for the current - // context. Observe that the default settings make all loaded ingest - // modules enabled. - HashSet enabledModuleNames = getModulesNamesFromSetting(ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(loadedModuleNames)); - HashSet disabledModuleNames = getModulesNamesFromSetting(DISABLED_INGEST_MODULES_KEY, ""); - - // Check for missing modules. - List missingModuleNames = new ArrayList<>(); - for (String moduleName : enabledModuleNames) { - if (!loadedModuleNames.contains(moduleName)) { - missingModuleNames.add(moduleName); - } - } - for (String moduleName : disabledModuleNames) { - if (!loadedModuleNames.contains(moduleName)) { - missingModuleNames.add(moduleName); - } - } - for (String moduleName : missingModuleNames) { - enabledModuleNames.remove(moduleName); - disabledModuleNames.remove(moduleName); - warnings.add(String.format("Previously loaded %s module could not be found", moduleName)); //NON-NLS - } - - // Create ingest module templates. - List moduleTemplates = new ArrayList<>(); - for (IngestModuleFactory moduleFactory : moduleFactories) { - IngestModuleTemplate moduleTemplate = new IngestModuleTemplate(moduleFactory, loadJobSettings(moduleFactory)); - String moduleName = moduleTemplate.getModuleName(); - if (enabledModuleNames.contains(moduleName)) { - moduleTemplate.setEnabled(true); - } else if (disabledModuleNames.contains(moduleName)) { - moduleTemplate.setEnabled(false); - } else { - // The module factory was loaded, but the module name does not - // appear in the enabled/disabled module settings. Treat the - // module as a new module and enable it by default. - moduleTemplate.setEnabled(true); - enabledModuleNames.add(moduleName); - } - moduleTemplates.add(moduleTemplate); - } - - // Update the enabled/disabled ingest module settings to reflect any - // missing modules or newly discovered modules. - ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames)); - ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames)); - - // Get the process unallocated space flag setting. If the setting does - // not exist yet, default it to true. - if (ModuleSettings.settingExists(launcherContext, PARSE_UNALLOC_SPACE_KEY) == false) { - ModuleSettings.setConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY, "true"); //NON-NLS - } - boolean processUnallocatedSpace = Boolean.parseBoolean(ModuleSettings.getConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY)); - - // Make the configuration panel for the context. - ingestConfigPanel = new IngestJobConfigurationPanel(moduleTemplates, processUnallocatedSpace); - } - - private void createModuleSettingsFolderForContext() { - try { - StringBuilder folderPath = new StringBuilder(MODULE_SETTINGS_FOLDER_PATH); - folderPath.append(File.separator); - folderPath.append(launcherContext); - folderPath.append(File.separator); - File folder = new File(folderPath.toString()); - if (!folder.exists()) { - Files.createDirectories(folder.toPath()); - } - moduleSettingsFolderForContext = folder.getAbsolutePath(); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Failed to create ingest module settings directory", ex); //NON-NLS - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "IngestJobConfigurator.createModuleSettingsFolderForContext.exception.msg"), - NbBundle.getMessage(this.getClass(), - "IngestJobConfigurator.createModuleSettingsFolderForContext.exception.title"), - JOptionPane.ERROR_MESSAGE); - } - } - - private HashSet getModulesNamesFromSetting(String key, String defaultSetting) { - // Get the ingest modules setting from the user's config file. - // If there is no such setting yet, create the default setting. - if (ModuleSettings.settingExists(launcherContext, key) == false) { - ModuleSettings.setConfigSetting(launcherContext, key, defaultSetting); - } - HashSet moduleNames = new HashSet<>(); - String modulesSetting = ModuleSettings.getConfigSetting(launcherContext, key); - if (!modulesSetting.isEmpty()) { - String[] settingNames = modulesSetting.split(", "); - for (String name : settingNames) { - // Map some old core module names to the current core module names. - switch (name) { - case "Thunderbird Parser": //NON-NLS - case "MBox Parser": //NON-NLS - moduleNames.add("Email Parser"); //NON-NLS - break; - case "File Extension Mismatch Detection": //NON-NLS - moduleNames.add("Extension Mismatch Detector"); //NON-NLS - break; - case "EWF Verify": //NON-NLS - case "E01 Verify": //NON-NLS - moduleNames.add("E01 Verifier"); //NON-NLS - break; - default: - moduleNames.add(name); - } - } - } - return moduleNames; - } - - private IngestModuleIngestJobSettings loadJobSettings(IngestModuleFactory factory) { - IngestModuleIngestJobSettings settings = null; - File settingsFile = new File(getModuleSettingsFilePath(factory)); - if (settingsFile.exists()) { - try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) { - settings = (IngestModuleIngestJobSettings) in.readObject(); - } catch (IOException | ClassNotFoundException ex) { - String logMessage = String.format("Error loading ingest job settings for %s module for %s context, using defaults", factory.getModuleDisplayName(), launcherContext); //NON-NLS - logger.log(Level.WARNING, logMessage, ex); - } - } - if (settings == null) { - settings = factory.getDefaultIngestJobSettings(); - } - return settings; - } - - private void saveJobSettings(IngestModuleFactory factory, IngestModuleIngestJobSettings settings) { - try { - try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(getModuleSettingsFilePath(factory)))) { - out.writeObject(settings); - } - } catch (IOException ex) { - String logMessage = String.format("Error saving ingest job settings for %s module for %s context", factory.getModuleDisplayName(), launcherContext); //NON-NLS - logger.log(Level.SEVERE, logMessage, ex); - String userMessage = NbBundle.getMessage(this.getClass(), "IngestJobConfigurator.saveJobSettings.usermsg", factory.getModuleDisplayName()); - JOptionPane.showMessageDialog(null, userMessage, - NbBundle.getMessage(this.getClass(), - "IngestJobConfigurator.saveJobSettings.usermsg.title"), - JOptionPane.WARNING_MESSAGE); - } - } - - private String getModuleSettingsFilePath(IngestModuleFactory factory) { - StringBuilder filePath = new StringBuilder(this.moduleSettingsFolderForContext); - filePath.append(File.separator); - filePath.append(factory.getClass().getCanonicalName()); - filePath.append(MODULE_SETTINGS_FILE_EXT); - return filePath.toString(); + @Deprecated + public IngestJobConfigurator(String context) { + this.settings = new IngestJobSettings(context); + this.settingsPanel = new IngestJobSettingsPanel(settings); } /** - * Gets any warnings generated when the persisted ingest job configuration - * for the specified context is retrieved and loaded. + * Gets any warnings generated when the persisted ingest job settings + * for the specified context are loaded or saved. * - * @return A collection of warning messages. + * @return A collection of warning messages, possibly empty. */ + @Deprecated public List getIngestJobConfigWarnings() { - return warnings; + return this.settings.getWarnings(); } /** * Gets the user interface panel the launcher uses to obtain the user's - * ingest job configuration for the specified context. + * ingest job settings for the specified context. * - * @return A JPanel with components that can be used to create an ingest job - * configuration. + * @return The panel. */ + @Deprecated public JPanel getIngestJobConfigPanel() { - return ingestConfigPanel; + return settingsPanel; } /** - * Persists the ingest job configuration for the specified context. + * Persists the ingest job settings for the specified context. */ + @Deprecated public void saveIngestJobConfig() { - List moduleTemplates = ingestConfigPanel.getIngestModuleTemplates(); - - // Save the enabled/disabled ingest module settings for the current context. - HashSet enabledModuleNames = new HashSet<>(); - HashSet disabledModuleNames = new HashSet<>(); - for (IngestModuleTemplate moduleTemplate : moduleTemplates) { - saveJobSettings(moduleTemplate.getModuleFactory(), moduleTemplate.getModuleSettings()); - String moduleName = moduleTemplate.getModuleName(); - if (moduleTemplate.isEnabled()) { - enabledModuleNames.add(moduleName); - } else { - disabledModuleNames.add(moduleName); - } - } - ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames)); - ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames)); - - // Save the process unallocated space setting for the current context. - String processUnalloc = Boolean.toString(ingestConfigPanel.getProcessUnallocSpace()); - ModuleSettings.setConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY, processUnalloc); - } - - private static String makeCommaSeparatedList(HashSet input) { - if (input == null || input.isEmpty()) { - return ""; - } - - ArrayList list = new ArrayList<>(); - list.addAll(input); - StringBuilder csvList = new StringBuilder(); - for (int i = 0; i < list.size() - 1; ++i) { - csvList.append(list.get(i)).append(", "); - } - csvList.append(list.get(list.size() - 1)); - return csvList.toString(); + this.settings.save(); } /** * Launches ingest jobs for one or more data sources using the ingest job - * configuration for the selected context. + * settings for the specified context. * * @param dataSources The data sources to ingest. */ + @Deprecated public void startIngestJobs(List dataSources) { - // Filter out the disabled ingest module templates. - List enabledModuleTemplates = new ArrayList<>(); - List moduleTemplates = ingestConfigPanel.getIngestModuleTemplates(); - for (IngestModuleTemplate moduleTemplate : moduleTemplates) { - if (moduleTemplate.isEnabled()) { - enabledModuleTemplates.add(moduleTemplate); - } - } - - if ((!enabledModuleTemplates.isEmpty()) && (dataSources != null) && (!dataSources.isEmpty())) { - IngestManager.getInstance().startIngestJobs(dataSources, enabledModuleTemplates, ingestConfigPanel.getProcessUnallocSpace()); + IngestManager ingestManager = IngestManager.getInstance(); + for (Content dataSource : dataSources) { + ingestManager.startIngestJob(dataSource, this.settings, true); } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java new file mode 100644 index 0000000000..b53cc69e95 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -0,0 +1,385 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.openide.util.io.NbObjectInputStream; +import org.openide.util.io.NbObjectOutputStream; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Encapsulates the ingest job settings for a particular context such as the Add + * Data Source wizard or the Run Ingest Modules dialog. + */ +public class IngestJobSettings { + + private static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS + private static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS + private static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space"; //NON-NLS + private static final String PROCESS_UNALLOC_SPACE_DEFAULT = "true"; //NON-NLS + private static final String MODULE_SETTINGS_FOLDER = "IngestModuleSettings"; //NON-NLS + private static final String MODULE_SETTINGS_FOLDER_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), IngestJobSettings.MODULE_SETTINGS_FOLDER).toAbsolutePath().toString(); + private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS + private static final Logger logger = Logger.getLogger(IngestJobSettings.class.getName()); + private final String context; + private String moduleSettingsFolderPath; + private final List moduleTemplates; + private boolean processUnallocatedSpace; + private final List warnings; + + /** + * Constructs an ingest job settings object for a given context. + * + * @param context The context identifier string. + */ + public IngestJobSettings(String context) { + this.context = context; + this.moduleTemplates = new ArrayList<>(); + this.processUnallocatedSpace = Boolean.parseBoolean(IngestJobSettings.PROCESS_UNALLOC_SPACE_DEFAULT); + this.warnings = new ArrayList<>(); + this.createSavedModuleSettingsFolder(); + this.load(); + } + + /** + * Saves these ingest job settings. + */ + public void save() { + this.store(); + } + + /** + * Gets and clears any accumulated warnings associated with these ingest job + * settings. + * + * @return A list of warning messages, possibly empty. + */ + public List getWarnings() { + List warningMessages = new ArrayList<>(this.warnings); + this.warnings.clear(); + return warningMessages; + } + + /** + * Gets the ingest module templates part of these ingest job settings. + * + * @return The list of ingest module templates. + */ + List getIngestModuleTemplates() { + return Collections.unmodifiableList(this.moduleTemplates); + } + + /** + * Gets the enabled ingest module templates part of these ingest job + * settings. + * + * @return The list of enabled ingest module templates. + */ + List getEnabledIngestModuleTemplates() { + List enabledModuleTemplates = new ArrayList<>(); + for (IngestModuleTemplate moduleTemplate : this.moduleTemplates) { + if (moduleTemplate.isEnabled()) { + enabledModuleTemplates.add(moduleTemplate); + } + } + return enabledModuleTemplates; + } + + /** + * Sets the ingest module templates part of these ingest job settings. + * + * @param moduleTemplates The ingest module templates. + */ + void setIngestModuleTemplates(List moduleTemplates) { + this.moduleTemplates.clear(); + this.moduleTemplates.addAll(moduleTemplates); + } + + /** + * Gets the process unallocated space flag part of these ingest job + * settings. + * + * @return True or false. + */ + boolean getProcessUnallocatedSpace() { + return this.processUnallocatedSpace; + } + + /** + * Sets the process unallocated space flag for these ingest job settings. + * + * @param processUnallocatedSpace True or false. + */ + void setProcessUnallocatedSpace(boolean processUnallocatedSpace) { + this.processUnallocatedSpace = processUnallocatedSpace; + } + + /** + * Creates the folder for saving the individual ingest module settings part + * of these ingest job settings. + */ + private void createSavedModuleSettingsFolder() { + try { + Path folder = Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, context); + Files.createDirectories(folder); + this.moduleSettingsFolderPath = folder.toAbsolutePath().toString(); + } catch (IOException | SecurityException ex) { + logger.log(Level.SEVERE, "Failed to create ingest module settings directory " + this.moduleSettingsFolderPath, ex); //NON-NLS + this.warnings.add(NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.createModuleSettingsFolder.warning")); //NON-NLS + } + } + + /** + * Loads the saved or default ingest job settings context into memory. + */ + private void load() { + /** + * Get the ingest module factories discovered by the ingest module + * loader. + */ + List moduleFactories = IngestModuleFactoryLoader.getIngestModuleFactories(); + HashSet loadedModuleNames = new HashSet<>(); + for (IngestModuleFactory moduleFactory : moduleFactories) { + loadedModuleNames.add(moduleFactory.getModuleDisplayName()); + } + + /** + * Get the enabled/disabled ingest modules settings for this context. By + * default, all loaded modules are enabled. + */ + HashSet enabledModuleNames = getModulesNamesFromSetting(IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(loadedModuleNames)); + HashSet disabledModuleNames = getModulesNamesFromSetting(IngestJobSettings.DISABLED_MODULES_KEY, ""); //NON-NLS + + /** + * Check for missing modules and create warnings if any are found. + */ + List missingModuleNames = new ArrayList<>(); + for (String moduleName : enabledModuleNames) { + if (!loadedModuleNames.contains(moduleName)) { + missingModuleNames.add(moduleName); + } + } + for (String moduleName : disabledModuleNames) { + if (!loadedModuleNames.contains(moduleName)) { + missingModuleNames.add(moduleName); + } + } + for (String moduleName : missingModuleNames) { + enabledModuleNames.remove(moduleName); + disabledModuleNames.remove(moduleName); + String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.missingModule.warning", moduleName); //NON-NLS + logger.log(Level.WARNING, warning); + this.warnings.add(warning); + } + + /** + * Create ingest module templates. Each template encapsulates a module + * factory, the module settings for this context, and an enabled flag. + */ + for (IngestModuleFactory moduleFactory : moduleFactories) { + IngestModuleTemplate moduleTemplate = new IngestModuleTemplate(moduleFactory, loadModuleSettings(moduleFactory)); + String moduleName = moduleTemplate.getModuleName(); + if (enabledModuleNames.contains(moduleName)) { + moduleTemplate.setEnabled(true); + } else if (disabledModuleNames.contains(moduleName)) { + moduleTemplate.setEnabled(false); + } else { + // The module factory was loaded, but the module name does not + // appear in the enabled/disabled module settings. Treat the + // module as a new module and enable it by default. + moduleTemplate.setEnabled(true); + enabledModuleNames.add(moduleName); + } + this.moduleTemplates.add(moduleTemplate); + } + + /** + * Update the enabled/disabled ingest module settings for this context + * to reflect any missing modules or newly discovered modules. + */ + ModuleSettings.setConfigSetting(this.context, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); + ModuleSettings.setConfigSetting(this.context, IngestJobSettings.DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); + + // Get the process unallocated space flag setting. If the setting does + // not exist yet, default it to true. + if (ModuleSettings.settingExists(this.context, IngestJobSettings.PARSE_UNALLOC_SPACE_KEY) == false) { + ModuleSettings.setConfigSetting(this.context, IngestJobSettings.PARSE_UNALLOC_SPACE_KEY, IngestJobSettings.PROCESS_UNALLOC_SPACE_DEFAULT); + } + this.processUnallocatedSpace = Boolean.parseBoolean(ModuleSettings.getConfigSetting(this.context, IngestJobSettings.PARSE_UNALLOC_SPACE_KEY)); + } + + /** + * Gets the module names for a given key within these ingest job settings. + * + * @param key The key string. + * @param defaultSetting The default list of module names. + * @return The list of module names associated with the key. + */ + private HashSet getModulesNamesFromSetting(String key, String defaultSetting) { + if (ModuleSettings.settingExists(this.context, key) == false) { + ModuleSettings.setConfigSetting(this.context, key, defaultSetting); + } + HashSet moduleNames = new HashSet<>(); + String modulesSetting = ModuleSettings.getConfigSetting(this.context, key); + if (!modulesSetting.isEmpty()) { + String[] settingNames = modulesSetting.split(", "); + for (String name : settingNames) { + // Map some old core module names to the current core module names. + switch (name) { + case "Thunderbird Parser": //NON-NLS + case "MBox Parser": //NON-NLS + moduleNames.add("Email Parser"); //NON-NLS + break; + case "File Extension Mismatch Detection": //NON-NLS + moduleNames.add("Extension Mismatch Detector"); //NON-NLS + break; + case "EWF Verify": //NON-NLS + case "E01 Verify": //NON-NLS + moduleNames.add("E01 Verifier"); //NON-NLS + break; + default: + moduleNames.add(name); + } + } + } + return moduleNames; + } + + /** + * Gets the saved or default ingest job settings for a given ingest module + * for these ingest job settings. + * + * @param factory The ingest module factory for an ingest module. + * @return The ingest module settings. + */ + private IngestModuleIngestJobSettings loadModuleSettings(IngestModuleFactory factory) { + IngestModuleIngestJobSettings settings = null; + File settingsFile = new File(getModuleSettingsFilePath(factory)); + if (settingsFile.exists()) { + try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) { + settings = (IngestModuleIngestJobSettings) in.readObject(); + } catch (IOException | ClassNotFoundException ex) { + String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.context); //NON-NLS + logger.log(Level.WARNING, warning, ex); + this.warnings.add(warning); + } + } + if (settings == null) { + settings = factory.getDefaultIngestJobSettings(); + } + return settings; + } + + /** + * Returns the absolute path for the ingest job settings file for a given + * ingest module for these ingest job settings. + * + * @param factory The ingest module factory for an ingest module. + * @return The file path. + */ + private String getModuleSettingsFilePath(IngestModuleFactory factory) { + String fileName = factory.getClass().getCanonicalName() + IngestJobSettings.MODULE_SETTINGS_FILE_EXT; + Path path = Paths.get(this.moduleSettingsFolderPath, fileName); + return path.toAbsolutePath().toString(); + } + + /** + * Saves the ingest job settings for this context. + */ + private void store() { + /** + * Save the enabled/disabled ingest module settings. + */ + HashSet enabledModuleNames = new HashSet<>(); + HashSet disabledModuleNames = new HashSet<>(); + for (IngestModuleTemplate moduleTemplate : moduleTemplates) { + saveModuleSettings(moduleTemplate.getModuleFactory(), moduleTemplate.getModuleSettings()); + String moduleName = moduleTemplate.getModuleName(); + if (moduleTemplate.isEnabled()) { + enabledModuleNames.add(moduleName); + } else { + disabledModuleNames.add(moduleName); + } + } + ModuleSettings.setConfigSetting(this.context, ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); + ModuleSettings.setConfigSetting(this.context, DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); + + /** + * Save the process unallocated space setting. + */ + String processUnalloc = Boolean.toString(this.processUnallocatedSpace); + ModuleSettings.setConfigSetting(this.context, PARSE_UNALLOC_SPACE_KEY, processUnalloc); + } + + /** + * Serializes the ingest job settings for this context for a given ingest + * module. + * + * @param factory The ingest module factory for the module. + * @param settings The ingest job settings for the ingest module + */ + private void saveModuleSettings(IngestModuleFactory factory, IngestModuleIngestJobSettings settings) { + try { + try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(getModuleSettingsFilePath(factory)))) { + out.writeObject(settings); + } + } catch (IOException ex) { + String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsSave.warning", factory.getModuleDisplayName(), this.context); //NON-NLS + logger.log(Level.SEVERE, warning, ex); + this.warnings.add(warning); + } + } + + /** + * Makes a comma-separated values list from a hash set of strings. + * + * @param input A hash set of strings. + * @return The contents of the hash set as a single string of + * comma-separated values. + */ + private static String makeCommaSeparatedValuesList(HashSet input) { + if (input == null || input.isEmpty()) { + return ""; + } + + ArrayList list = new ArrayList<>(); + list.addAll(input); + StringBuilder csvList = new StringBuilder(); + for (int i = 0; i < list.size() - 1; ++i) { + csvList.append(list.get(i)).append(", "); + } + csvList.append(list.get(list.size() - 1)); + return csvList.toString(); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form similarity index 92% rename from Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.form rename to Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index 4119772238..08b078aba9 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -144,10 +144,10 @@ - + - + @@ -160,7 +160,7 @@ - + @@ -221,10 +221,10 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.java rename to Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 732f27522c..738313cf31 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobConfigurationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -35,39 +35,47 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; /** - * User interface component to allow a user to set ingest module options and - * enable/disable the modules. + * User interface component to allow a user to make ingest job settings. */ -class IngestJobConfigurationPanel extends javax.swing.JPanel { +public final class IngestJobSettingsPanel extends javax.swing.JPanel { - private List modules = new ArrayList<>(); - private boolean processUnallocatedSpace = false; - private IngestModuleModel selectedModule = null; + private final IngestJobSettings settings; + private final List modules; + private IngestModuleModel selectedModule; - IngestJobConfigurationPanel(List moduleTemplates, boolean processUnallocatedSpace) { - for (IngestModuleTemplate moduleTemplate : moduleTemplates) { - modules.add(new IngestModuleModel(moduleTemplate)); + /** + * Construct a user interface component to allow a user to make ingest job + * settings. + * + * @param settings The initial settings for the ingest job. + */ + public IngestJobSettingsPanel(IngestJobSettings settings) { + this.settings = settings; + this.modules = new ArrayList<>(); + for (IngestModuleTemplate moduleTemplate : settings.getIngestModuleTemplates()) { + this.modules.add(new IngestModuleModel(moduleTemplate)); } - this.processUnallocatedSpace = processUnallocatedSpace; initComponents(); customizeComponents(); } - List getIngestModuleTemplates() { + /** + * Gets the ingest settings made using this panel. + * + * @return The settings. + */ + IngestJobSettings getSettings() { List moduleTemplates = new ArrayList<>(); for (IngestModuleModel module : modules) { IngestModuleTemplate moduleTemplate = module.getIngestModuleTemplate(); if (module.hasModuleSettingsPanel()) { - IngestModuleIngestJobSettings settings = module.getModuleSettingsPanel().getSettings(); - moduleTemplate.setModuleSettings(settings); + IngestModuleIngestJobSettings moduleSettings = module.getModuleSettingsPanel().getSettings(); + moduleTemplate.setModuleSettings(moduleSettings); } moduleTemplates.add(moduleTemplate); } - return moduleTemplates; - } - - boolean getProcessUnallocSpace() { - return processUnallocCheckbox.isSelected(); + this.settings.setIngestModuleTemplates(moduleTemplates); + return this.settings; } private void customizeComponents() { @@ -113,7 +121,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel { } }); - processUnallocCheckbox.setSelected(processUnallocatedSpace); + processUnallocCheckbox.setSelected(this.settings.getProcessUnallocatedSpace()); } /** @@ -160,8 +168,8 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel { jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); jPanel1.setPreferredSize(new java.awt.Dimension(338, 257)); - advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.advancedButton.text")); // NOI18N - advancedButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.advancedButton.actionCommand")); // NOI18N + advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.text")); // NOI18N + advancedButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.actionCommand")); // NOI18N advancedButton.setEnabled(false); advancedButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -169,7 +177,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel { } }); - descriptionLabel.setText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.descriptionLabel.text")); // NOI18N + descriptionLabel.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.descriptionLabel.text")); // NOI18N jScrollPane1.setBorder(null); jScrollPane1.setPreferredSize(new java.awt.Dimension(250, 180)); @@ -208,8 +216,8 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel { processUnallocPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); - processUnallocCheckbox.setText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.processUnallocCheckbox.text")); // NOI18N - processUnallocCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText")); // NOI18N + processUnallocCheckbox.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.processUnallocCheckbox.text")); // NOI18N + processUnallocCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.processUnallocCheckbox.toolTipText")); // NOI18N processUnallocCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { processUnallocCheckboxActionPerformed(evt); @@ -261,7 +269,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void processUnallocCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processUnallocCheckboxActionPerformed - processUnallocatedSpace = processUnallocCheckbox.isSelected(); + this.settings.setProcessUnallocatedSpace(processUnallocCheckbox.isSelected()); }//GEN-LAST:event_processUnallocCheckboxActionPerformed private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index ccee8b482e..3a9a58a959 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -46,7 +46,8 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; /** - * Manages the execution of ingest jobs. + * Manages the creation and execution of ingest jobs, i.e., processing of data + * sources by ingest modules. */ public class IngestManager { @@ -64,7 +65,7 @@ public class IngestManager { private final ExecutorService fileIngestThreadPool; private final ExecutorService fireIngestEventsThreadPool = Executors.newSingleThreadExecutor(); private final AtomicLong nextThreadId = new AtomicLong(0L); - private final ConcurrentHashMap> startIngestJobsTasks = new ConcurrentHashMap<>(); // Maps thread ids to cancellation handles. + private final ConcurrentHashMap> startIngestJobsCallables = new ConcurrentHashMap<>(); // Maps thread ids to cancellation handles. private final AtomicLong ingestErrorMessagePosts = new AtomicLong(0L); private final ConcurrentHashMap ingestThreadActivitySnapshots = new ConcurrentHashMap<>(); // Maps ingest thread ids to progress ingestThreadActivitySnapshots. private final ConcurrentHashMap ingestModuleRunTimes = new ConcurrentHashMap<>(); @@ -73,6 +74,60 @@ public class IngestManager { private volatile IngestMessageTopComponent ingestMessageBox; private int numberOfFileIngestThreads = DEFAULT_NUMBER_OF_FILE_INGEST_THREADS; + /** + * Ingest job events. + */ + public enum IngestJobEvent { + + /** + * Property change event fired when an ingest job is started. The old + * value of the PropertyChangeEvent object is set to the ingest job id, + * and the new value is set to null. + */ + STARTED, + /** + * Property change event fired when an ingest job is completed. The old + * value of the PropertyChangeEvent object is set to the ingest job id, + * and the new value is set to null. + */ + COMPLETED, + /** + * Property change event fired when an ingest job is canceled. The old + * value of the PropertyChangeEvent object is set to the ingest job id, + * and the new value is set to null. + */ + CANCELLED, + }; + + /** + * Ingest module events. + */ + public enum IngestModuleEvent { + + /** + * Property change event fired when an ingest module adds new data to a + * case, usually by posting to the blackboard. The old value of the + * PropertyChangeEvent is a ModuleDataEvent object, and the new value is + * set to null. + */ + DATA_ADDED, + /** + * Property change event fired when an ingest module adds new content to + * a case or changes a recorded attribute of existing content. For + * example, if a module adds an extracted or carved file to a case, the + * module should fire this event. The old value of the + * PropertyChangeEvent is a ModuleContentEvent object, and the new value + * is set to null. + */ + CONTENT_CHANGED, + /** + * Property change event fired when the ingest of a file is completed. + * The old value of the PropertyChangeEvent is the Autopsy object ID of + * the file. The new value is the AbstractFile for that ID. + */ + FILE_DONE, + }; + /** * Gets the ingest manager. * @@ -90,6 +145,123 @@ public class IngestManager { return instance; } + /** + * Gets the number of file ingest threads the ingest manager will use to do + * ingest jobs. + * + * @return The number of file ingest threads. + */ + public int getNumberOfFileIngestThreads() { + return numberOfFileIngestThreads; + } + + /** + * Starts an ingest job, i.e., processing by ingest modules, for a data + * source. + * + * @param dataSource The data source to be processed. + * @param settings The ingest job settings. + * @param doStartupErrorsMsgBox Whether or not to display ingest module + * startup errors in a message box. + */ + public synchronized void startIngestJob(Content dataSource, IngestJobSettings settings, boolean doStartupErrorsMsgBox) { + if (!isIngestRunning()) { + clearIngestMessageBox(); + } + + if (!ingestMonitor.isRunning()) { + ingestMonitor.start(); + } + + long taskId = nextThreadId.incrementAndGet(); + Future task = startIngestJobsThreadPool.submit(new StartIngestJobsCallable(taskId, dataSource, settings, doStartupErrorsMsgBox)); + startIngestJobsCallables.put(taskId, task); + } + + /** + * Queries whether any ingest jobs are in progress. + * + * @return True or false. + */ + public boolean isIngestRunning() { + return IngestJob.ingestJobsAreRunning(); + } + + /** + * Cancels all ingest jobs in progress. + */ + public void cancelAllIngestJobs() { + // Stop creating new ingest jobs. + for (Future handle : startIngestJobsCallables.values()) { + handle.cancel(true); + } + + // Cancel all the jobs already created. + IngestJob.cancelAllJobs(); + } + + /** + * Adds an ingest job event property change listener. + * + * @param listener The PropertyChangeListener to register. + */ + public void addIngestJobEventListener(final PropertyChangeListener listener) { + ingestJobEventPublisher.addPropertyChangeListener(listener); + } + + /** + * Removes an ingest job event property change listener. + * + * @param listener The PropertyChangeListener to unregister. + */ + public void removeIngestJobEventListener(final PropertyChangeListener listener) { + ingestJobEventPublisher.removePropertyChangeListener(listener); + } + + /** + * Adds an ingest module event property change listener. + * + * @param listener The PropertyChangeListener to register. + */ + public void addIngestModuleEventListener(final PropertyChangeListener listener) { + ingestModuleEventPublisher.addPropertyChangeListener(listener); + } + + /** + * Removes an ingest module event property change listener. + * + * @param listener The PropertyChangeListener to unregister. + */ + public void removeIngestModuleEventListener(final PropertyChangeListener listener) { + ingestModuleEventPublisher.removePropertyChangeListener(listener); + } + + /** + * Adds an ingest job and ingest module event property change listener. + * + * @param listener The PropertyChangeListener to register. + * @deprecated Use addIngestJobEventListener() and/or + * addIngestModuleEventListener(). + */ + @Deprecated + public static void addPropertyChangeListener(final PropertyChangeListener listener) { + instance.ingestJobEventPublisher.addPropertyChangeListener(listener); + instance.ingestModuleEventPublisher.addPropertyChangeListener(listener); + } + + /** + * Remove an ingest job and ingest module event property change listener. + * + * @param listener The PropertyChangeListener to unregister. + * @deprecated Use removeIngestJobEventListener() and/or + * removeIngestModuleEventListener(). + */ + @Deprecated + public static void removePropertyChangeListener(final PropertyChangeListener listener) { + instance.ingestJobEventPublisher.removePropertyChangeListener(listener); + instance.ingestModuleEventPublisher.removePropertyChangeListener(listener); + } + /** * Starts the ingest monitor and submits task execution tasks (Callable * objects) to the data source ingest and file ingest thread pools. The task @@ -97,7 +269,7 @@ public class IngestManager { * the application runs */ private IngestManager() { - startDataSourceIngestTask(); + startDataSourceIngestThread(); numberOfFileIngestThreads = UserPreferences.numberOfFileIngestThreads(); if ((numberOfFileIngestThreads < MIN_NUMBER_OF_FILE_INGEST_THREADS) || (numberOfFileIngestThreads > MAX_NUMBER_OF_FILE_INGEST_THREADS)) { @@ -106,7 +278,7 @@ public class IngestManager { } fileIngestThreadPool = Executors.newFixedThreadPool(numberOfFileIngestThreads); for (int i = 0; i < numberOfFileIngestThreads; ++i) { - startFileIngestTask(); + startFileIngestThread(); } } @@ -119,20 +291,11 @@ public class IngestManager { ingestMessageBox = IngestMessageTopComponent.findInstance(); } - /** - * Gets the number of file ingest threads the ingest manager will use. - * - * @return The number of file ingest threads. - */ - public int getNumberOfFileIngestThreads() { - return numberOfFileIngestThreads; - } - /** * Submits a ExecuteIngestTasksTask Callable to the data source ingest task * thread pool. */ - private void startDataSourceIngestTask() { + private void startDataSourceIngestThread() { long threadId = nextThreadId.incrementAndGet(); dataSourceIngestThreadPool.submit(new ExecuteIngestTasksRunnable(threadId, IngestTasksScheduler.getInstance().getDataSourceIngestTaskQueue())); ingestThreadActivitySnapshots.put(threadId, new IngestThreadActivitySnapshot(threadId)); @@ -142,22 +305,12 @@ public class IngestManager { * Submits a ExecuteIngestTasksTask Callable to the data source ingest * thread pool. */ - private void startFileIngestTask() { + private void startFileIngestThread() { long threadId = nextThreadId.incrementAndGet(); fileIngestThreadPool.submit(new ExecuteIngestTasksRunnable(threadId, IngestTasksScheduler.getInstance().getFileIngestTaskQueue())); ingestThreadActivitySnapshots.put(threadId, new IngestThreadActivitySnapshot(threadId)); } - synchronized void startIngestJobs(final List dataSources, final List moduleTemplates, boolean processUnallocatedSpace) { - if (!isIngestRunning()) { - clearIngestMessageBox(); - } - - long taskId = nextThreadId.incrementAndGet(); - Future task = startIngestJobsThreadPool.submit(new StartIngestJobsCallable(taskId, dataSources, moduleTemplates, processUnallocatedSpace)); - startIngestJobsTasks.put(taskId, task); - } - private void subscribeToCaseEvents() { Case.addPropertyChangeListener(new PropertyChangeListener() { @Override @@ -191,15 +344,6 @@ public class IngestManager { ingestErrorMessagePosts.set(0); } - /** - * Test if any ingest jobs are in progress. - * - * @return True if any ingest jobs are in progress, false otherwise. - */ - public boolean isIngestRunning() { - return IngestJob.ingestJobsAreRunning(); - } - /** * Called each time a module in a data source pipeline starts * @@ -292,132 +436,6 @@ public class IngestManager { return new ArrayList<>(ingestThreadActivitySnapshots.values()); } - public void cancelAllIngestJobs() { - // Stop creating new ingest jobs. - for (Future handle : startIngestJobsTasks.values()) { - handle.cancel(true); - } - - // Cancel all the jobs already created. - IngestJob.cancelAllJobs(); - } - - /** - * Ingest job events. - */ - public enum IngestJobEvent { - - /** - * Property change event fired when an ingest job is started. The old - * value of the PropertyChangeEvent object is set to the ingest job id, - * and the new value is set to null. - */ - STARTED, - /** - * Property change event fired when an ingest job is completed. The old - * value of the PropertyChangeEvent object is set to the ingest job id, - * and the new value is set to null. - */ - COMPLETED, - /** - * Property change event fired when an ingest job is canceled. The old - * value of the PropertyChangeEvent object is set to the ingest job id, - * and the new value is set to null. - */ - CANCELLED, - }; - - /** - * Ingest module events. - */ - public enum IngestModuleEvent { - - /** - * Property change event fired when an ingest module adds new data to a - * case, usually by posting to the blackboard. The old value of the - * PropertyChangeEvent is a ModuleDataEvent object, and the new value is - * set to null. - */ - DATA_ADDED, - /** - * Property change event fired when an ingest module adds new content to - * a case or changes a recorded attribute of existing content. For - * example, if a module adds an extracted or carved file to a case, the - * module should fire this event. The old value of the - * PropertyChangeEvent is a ModuleContentEvent object, and the new value - * is set to null. - */ - CONTENT_CHANGED, - /** - * Property change event fired when the ingest of a file is completed. - * The old value of the PropertyChangeEvent is the Autopsy object ID of - * the file. The new value is the AbstractFile for that ID. - */ - FILE_DONE, - }; - - /** - * Add an ingest job event property change listener. - * - * @param listener The PropertyChangeListener to register. - */ - public void addIngestJobEventListener(final PropertyChangeListener listener) { - ingestJobEventPublisher.addPropertyChangeListener(listener); - } - - /** - * Remove an ingest job event property change listener. - * - * @param listener The PropertyChangeListener to unregister. - */ - public void removeIngestJobEventListener(final PropertyChangeListener listener) { - ingestJobEventPublisher.removePropertyChangeListener(listener); - } - - /** - * Add an ingest module event property change listener. - * - * @param listener The PropertyChangeListener to register. - */ - public void addIngestModuleEventListener(final PropertyChangeListener listener) { - ingestModuleEventPublisher.addPropertyChangeListener(listener); - } - - /** - * Remove an ingest module event property change listener. - * - * @param listener The PropertyChangeListener to unregister. - */ - public void removeIngestModuleEventListener(final PropertyChangeListener listener) { - ingestModuleEventPublisher.removePropertyChangeListener(listener); - } - - /** - * Add an ingest job and ingest module event property change listener. - * - * @deprecated Use addIngestJobEventListener() and/or - * addIngestModuleEventListener(). - * @param listener The PropertyChangeListener to register. - */ - @Deprecated - public static void addPropertyChangeListener(final PropertyChangeListener listener) { - instance.ingestJobEventPublisher.addPropertyChangeListener(listener); - instance.ingestModuleEventPublisher.addPropertyChangeListener(listener); - } - - /** - * Remove an ingest job and ingest module event property change listener. - * - * @deprecated Use removeIngestJobEventListener() and/or - * removeIngestModuleEventListener(). - * @param listener The PropertyChangeListener to unregister. - */ - @Deprecated - public static void removePropertyChangeListener(final PropertyChangeListener listener) { - instance.ingestJobEventPublisher.removePropertyChangeListener(listener); - instance.ingestModuleEventPublisher.removePropertyChangeListener(listener); - } - /** * Fire an ingest event signifying an ingest job started. * @@ -513,26 +531,34 @@ public class IngestManager { } /** - * Creates ingest jobs. + * Creates and starts an ingest job, i.e., processing by ingest modules, for + * a data source. */ private final class StartIngestJobsCallable implements Callable { private final long threadId; - private final List dataSources; - private final List moduleTemplates; - private final boolean processUnallocatedSpace; + private final Content dataSource; + private final IngestJobSettings settings; + private final boolean doStartupErrorsMsgBox; private ProgressHandle progress; - StartIngestJobsCallable(long threadId, List dataSources, List moduleTemplates, boolean processUnallocatedSpace) { + StartIngestJobsCallable(long threadId, Content dataSource, IngestJobSettings settings, boolean doStartupErrorsMsgBox) { this.threadId = threadId; - this.dataSources = dataSources; - this.moduleTemplates = moduleTemplates; - this.processUnallocatedSpace = processUnallocatedSpace; + this.dataSource = dataSource; + this.settings = settings; + this.doStartupErrorsMsgBox = doStartupErrorsMsgBox; } @Override public Void call() { try { + if (Thread.currentThread().isInterrupted()) { + return null; + } + + /** + * Set up a progress bar. + */ final String displayName = NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.displayName"); progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() { @@ -543,62 +569,50 @@ public class IngestManager { "IngestManager.StartIngestJobsTask.run.cancelling", displayName)); } - Future handle = startIngestJobsTasks.remove(threadId); + Future handle = startIngestJobsCallables.remove(threadId); handle.cancel(true); return true; } }); - progress.start(dataSources.size()); + progress.switchToIndeterminate(); + progress.start(); - if (!ingestMonitor.isRunning()) { - ingestMonitor.start(); - } - - int dataSourceProcessed = 0; - for (Content dataSource : dataSources) { - if (Thread.currentThread().isInterrupted()) { - break; - } - - // Start an ingest job for the data source. - List errors = IngestJob.startJob(dataSource, moduleTemplates, processUnallocatedSpace); - if (!errors.isEmpty()) { - // Report the errors to the user. They have already been logged. - StringBuilder moduleStartUpErrors = new StringBuilder(); - for (IngestModuleError error : errors) { - String moduleName = error.getModuleDisplayName(); - moduleStartUpErrors.append(moduleName); - moduleStartUpErrors.append(": "); - moduleStartUpErrors.append(error.getModuleError().getLocalizedMessage()); - moduleStartUpErrors.append("\n"); - } - StringBuilder notifyMessage = new StringBuilder(); - notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg")); - notifyMessage.append("\n"); - notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution")); - notifyMessage.append("\n"); - notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList", - moduleStartUpErrors.toString())); - notifyMessage.append("\n\n"); - JOptionPane.showMessageDialog(null, notifyMessage.toString(), - NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle"), JOptionPane.ERROR_MESSAGE); - } - progress.progress(++dataSourceProcessed); - - if (!Thread.currentThread().isInterrupted()) { - break; + /** + * Create and start an ingest job for the data source. + */ + List errors = IngestJob.startJob(dataSource, this.settings); + if (!errors.isEmpty() && this.doStartupErrorsMsgBox) { + // Report the errors to the user. They have already been logged. + StringBuilder moduleStartUpErrors = new StringBuilder(); + for (IngestModuleError error : errors) { + String moduleName = error.getModuleDisplayName(); + moduleStartUpErrors.append(moduleName); + moduleStartUpErrors.append(": "); + moduleStartUpErrors.append(error.getModuleError().getLocalizedMessage()); + moduleStartUpErrors.append("\n"); } + StringBuilder notifyMessage = new StringBuilder(); + notifyMessage.append(NbBundle.getMessage(this.getClass(), + "IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg")); + notifyMessage.append("\n"); + notifyMessage.append(NbBundle.getMessage(this.getClass(), + "IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution")); + notifyMessage.append("\n"); + notifyMessage.append(NbBundle.getMessage(this.getClass(), + "IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList", + moduleStartUpErrors.toString())); + notifyMessage.append("\n\n"); + JOptionPane.showMessageDialog(null, notifyMessage.toString(), + NbBundle.getMessage(this.getClass(), + "IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle"), JOptionPane.ERROR_MESSAGE); } } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to create ingest job", ex); //NON-NLS } finally { progress.finish(); - startIngestJobsTasks.remove(threadId); + startIngestJobsCallables.remove(threadId); } + return null; } } @@ -758,4 +772,5 @@ public class IngestManager { return processedFilesCount; } } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 9f722789d2..99fe0438ea 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -44,13 +44,13 @@ public final class RunIngestModulesDialog extends JDialog { private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private static Dimension DIMENSIONS = new Dimension(500, 300); - private List dataSources = new ArrayList<>(); - private IngestJobConfigurator ingestJobLauncher; + private final List dataSources = new ArrayList<>(); + private IngestJobSettings ingestJobSettings; public RunIngestModulesDialog(JFrame frame, String title, boolean modal) { super(frame, title, modal); - ingestJobLauncher = new IngestJobConfigurator(RunIngestModulesDialog.class.getCanonicalName()); - List messages = ingestJobLauncher.getIngestJobConfigWarnings(); + ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName()); + List messages = ingestJobSettings.getWarnings(); if (messages.isEmpty() == false) { StringBuilder warning = new StringBuilder(); for (String message : messages) { @@ -79,28 +79,31 @@ public final class RunIngestModulesDialog extends JDialog { // set the location of the popUp Window on the center of the screen setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - add(ingestJobLauncher.getIngestJobConfigPanel(), BorderLayout.PAGE_START); + add(new IngestJobSettingsPanel(ingestJobSettings), BorderLayout.PAGE_START); JButton startButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.startButton.title")); JButton closeButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.closeButton.title")); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ingestJobLauncher.saveIngestJobConfig(); - ingestJobLauncher.startIngestJobs(dataSources); + ingestJobSettings.save(); + IngestManager ingestManager = IngestManager.getInstance(); + for (Content dataSource : dataSources) { + ingestManager.startIngestJob(dataSource, ingestJobSettings, true); + } close(); } }); closeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ingestJobLauncher.saveIngestJobConfig(); + ingestJobSettings.save(); close(); } }); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - ingestJobLauncher.saveIngestJobConfig(); + ingestJobSettings.save(); close(); } }); diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Back.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Back.java index 7a273aca31..ab00eddd7f 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Back.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Back.java @@ -23,14 +23,14 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; -import org.controlsfx.control.action.AbstractAction; +import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerController; /** - * + * */ //TODO: This and the corresponding timeline action are identical except for the type of the controller... abstract something! -jm -public class Back extends AbstractAction { +public class Back extends Action { private static final Image BACK_IMAGE = new Image("/org/sleuthkit/autopsy/imageanalyzer/images/arrow-180.png", 16, 16, true, true, true); @@ -42,10 +42,9 @@ public class Back extends AbstractAction { setAccelerator(new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN)); this.controller = controller; disabledProperty().bind(controller.getCanRetreat().not()); + setEventHandler((ActionEvent ae) -> { + controller.retreat(); + }); } - @Override - public void handle(ActionEvent ae) { - controller.retreat(); - } } diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Forward.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Forward.java index e6282f397e..2a2532fa23 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Forward.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/Forward.java @@ -23,14 +23,14 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; -import org.controlsfx.control.action.AbstractAction; +import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerController; /** * */ //TODO: This and the corresponding timeline action are identical except for the type of the controller... abstract something! -jm -public class Forward extends AbstractAction { +public class Forward extends Action { private static final Image BACK_IMAGE = new Image("/org/sleuthkit/autopsy/imageanalyzer/images/arrow.png", 16, 16, true, true, true); @@ -42,10 +42,9 @@ public class Forward extends AbstractAction { setAccelerator(new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN)); this.controller = controller; disabledProperty().bind(controller.getCanAdvance().not()); - } - @Override - public void handle(ActionEvent ae) { - controller.advance(); + setEventHandler((ActionEvent t) -> { + controller.advance(); + }); } } diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/NextUnseenGroup.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/NextUnseenGroup.java index eb96cf1e3d..21780cba97 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/NextUnseenGroup.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/NextUnseenGroup.java @@ -21,14 +21,14 @@ package org.sleuthkit.autopsy.imageanalyzer.actions; import javafx.beans.Observable; import javafx.event.ActionEvent; import javafx.scene.image.ImageView; -import org.controlsfx.control.action.AbstractAction; +import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerController; import org.sleuthkit.autopsy.imageanalyzer.grouping.GroupViewState; /** * */ -public class NextUnseenGroup extends AbstractAction { +public class NextUnseenGroup extends Action { private final ImageAnalyzerController controller; @@ -40,15 +40,14 @@ public class NextUnseenGroup extends AbstractAction { controller.getGroupManager().getUnSeenGroups().addListener((Observable observable) -> { disabledProperty().set(controller.getGroupManager().getUnSeenGroups().size() <= 1); }); - } - @Override - public void handle(ActionEvent event) { - if (controller.viewState() != null && controller.viewState().get() != null && controller.viewState().get().getGroup() != null) { - controller.getGroupManager().markGroupSeen(controller.viewState().get().getGroup()); - } - if (controller.getGroupManager().getUnSeenGroups().size() > 0) { - controller.advance(GroupViewState.tile(controller.getGroupManager().getUnSeenGroups().get(0))); - } + setEventHandler((ActionEvent t) -> { + if (controller.viewState() != null && controller.viewState().get() != null && controller.viewState().get().getGroup() != null) { + controller.getGroupManager().markGroupSeen(controller.viewState().get().getGroup()); + } + if (controller.getGroupManager().getUnSeenGroups().size() > 0) { + controller.advance(GroupViewState.tile(controller.getGroupManager().getUnSeenGroups().get(0))); + } + }); } }