diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 477e4b3cec..2de52ff7ed 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -198,7 +198,7 @@ NewCaseWizardAction.newCase.windowTitle.text=New Case Information NewCaseWizardAction.getName.text=New Case Wizard NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols\: \\ / \: * ? " < > | NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists. -NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory ''{0}'' doesn''t exist. \ +NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory ''{0}'' doesn't exist. \ \ Do you want to create that directory? NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java index 0776e34b42..1dcb158629 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java @@ -580,7 +580,8 @@ import org.xml.sax.SAXException; bw.close(); } catch (IOException ex) { logger.log(Level.SEVERE, "Error writing to case file"); //NON-NLS - throw new CaseActionException("Error writing to case file", ex); + throw new CaseActionException( + NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index a0d2233622..d94ee00059 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; @@ -57,27 +55,25 @@ public class IngestManager { private static final Logger logger = Logger.getLogger(IngestManager.class.getName()); private static final PropertyChangeSupport pcs = new PropertyChangeSupport(IngestManager.class); private static final Preferences userPreferences = NbPreferences.forModule(IngestManager.class); - private static IngestManager instance; + private static final IngestManager instance = new IngestManager(); private final IngestScheduler scheduler = IngestScheduler.getInstance(); private final IngestMonitor ingestMonitor = new IngestMonitor(); private final ExecutorService startIngestJobsExecutor = Executors.newSingleThreadExecutor(); private final ExecutorService dataSourceIngestTasksExecutor = Executors.newSingleThreadExecutor(); private final ExecutorService fileIngestTasksExecutor = Executors.newFixedThreadPool(MAX_NUMBER_OF_FILE_INGEST_THREADS); + private final ExecutorService fireEventTasksExecutor = Executors.newSingleThreadExecutor(); private final ConcurrentHashMap ingestJobs = new ConcurrentHashMap<>(1, 0.9f, 4); // Maps job ids to jobs. - private final HashMap> ingestTasks = new HashMap<>(); // Maps task ids to task cancellation handles. Guarded by this. - private AtomicLong ingestJobId = new AtomicLong(0L); - private AtomicLong ingestTaskId = new AtomicLong(0L); - private volatile IngestUI ingestMessageBox; + private final ConcurrentHashMap> ingestTasks = new ConcurrentHashMap<>(); // Maps task ids to task cancellation handles. Guarded by this. + private final AtomicLong ingestJobId = new AtomicLong(0L); + private final AtomicLong ingestTaskId = new AtomicLong(0L); + private volatile IngestMessageTopComponent ingestMessageBox; /** * Gets the IngestManager singleton, creating it if necessary. * * @returns The IngestManager singleton. */ - public synchronized static IngestManager getInstance() { - if (instance == null) { - instance = new IngestManager(); - } + public static IngestManager getInstance() { return instance; } @@ -85,8 +81,9 @@ public class IngestManager { } /** - * Finds the top component for the ingest messages in box. Called by the - * custom installer for this package once the window system is initialized. + * Signals to the ingest manager that it can go find the top component for + * the ingest messages in box. Called by the custom installer for this + * package once the window system is initialized. */ void initIngestMessageInbox() { if (this.ingestMessageBox == null) { @@ -258,13 +255,6 @@ public class IngestManager { } } - /** - * Module publishes message using InegestManager handle Does not block. The - * message gets enqueued in the GUI thread and displayed in a widget - * IngestModule should make an attempt not to publish the same message - * multiple times. Viewer will attempt to identify duplicate messages and - * filter them out (slower) - */ void postIngestMessage(IngestMessage message) { if (ingestMessageBox != null) { ingestMessageBox.displayMessage(message); @@ -286,53 +276,8 @@ public class IngestManager { } } - private synchronized void startIngestTasks() { - if (!ingestMonitor.isRunning()) { - ingestMonitor.start(); - } - - long taskId = ingestTaskId.incrementAndGet(); - Future task = dataSourceIngestTasksExecutor.submit(new RunDataSourceIngestModulesTask(taskId)); - ingestTasks.put(taskId, task); - - int numberOfFileTasksRequested = getNumberOfFileIngestThreads(); - for (int i = 0; i < numberOfFileTasksRequested; ++i) { - taskId = ingestTaskId.incrementAndGet(); - task = fileIngestTasksExecutor.submit(new RunFileSourceIngestModulesTask(taskId)); - ingestTasks.put(taskId, task); - } - } - - private void stopIngestTasks() { - // First mark all of the ingest jobs as cancelled. This way the - // ingest modules will know they are being shut down due to - // cancellation when the cancelled run ingest module tasks release - // their pipelines. - for (IngestJob job : ingestJobs.values()) { - job.cancel(); - } - - // Cancel the run ingest module tasks, setting the state of the threads - // running them to interrupted. - synchronized(this) { - for (Future task : ingestTasks.values()) { - task.cancel(true); - } - } - - // Jettision the remaining data source and file ingest tasks. - scheduler.getFileIngestScheduler().emptyQueues(); - scheduler.getDataSourceIngestScheduler().emptyQueues(); - } - - private synchronized void reportStartIngestJobsTaskDone(long taskId) { - ingestTasks.remove(taskId); - } - private void reportRunIngestModulesTaskDone(long taskId) { - synchronized(this) { - ingestTasks.remove(taskId); - } + ingestTasks.remove(taskId); List completedJobs = new ArrayList<>(); for (IngestJob job : ingestJobs.values()) { @@ -344,7 +289,7 @@ public class IngestManager { for (Long jobId : completedJobs) { IngestJob job = ingestJobs.remove(jobId); - fireIngestJobEvent(job.isCancelled() ? IngestEvent.INGEST_JOB_CANCELLED.toString() : IngestEvent.INGEST_JOB_COMPLETED.toString(), jobId); + fireEventTasksExecutor.submit(new FireIngestJobEventTask(jobId, job.isCancelled() ? IngestEvent.INGEST_JOB_CANCELLED : IngestEvent.INGEST_JOB_COMPLETED)); } } @@ -410,18 +355,18 @@ public class IngestManager { } StringBuilder notifyMessage = new StringBuilder(); notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg")); + "IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg")); notifyMessage.append("\n"); notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution")); + "IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution")); notifyMessage.append("\n"); notifyMessage.append(NbBundle.getMessage(this.getClass(), - "IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList", - moduleStartUpErrors.toString())); + "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); + NbBundle.getMessage(this.getClass(), + "IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle"), JOptionPane.ERROR_MESSAGE); // Jettison the ingest job and move on to the next one. ingestJob.cancel(); @@ -433,24 +378,38 @@ public class IngestManager { final String inputName = dataSource.getName(); progress.progress( NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.progress.msg1", - inputName), workUnitsCompleted); + inputName), workUnitsCompleted); scheduler.getDataSourceIngestScheduler().queueForIngest(ingestJob); progress.progress( NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.progress.msg2", - inputName), ++workUnitsCompleted); + inputName), ++workUnitsCompleted); // Queue the file ingest tasks for the ingest job. progress.progress( NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.progress.msg3", - inputName), workUnitsCompleted); + inputName), workUnitsCompleted); scheduler.getFileIngestScheduler().queueForIngest(ingestJob); progress.progress( NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.progress.msg4", - inputName), ++workUnitsCompleted); + inputName), ++workUnitsCompleted); if (!Thread.currentThread().isInterrupted()) { - startIngestTasks(); - fireIngestJobEvent(IngestEvent.INGEST_JOB_STARTED.toString(), ingestJob.getId()); + if (!ingestMonitor.isRunning()) { + ingestMonitor.start(); + } + + long taskId = ingestTaskId.incrementAndGet(); + Future task = dataSourceIngestTasksExecutor.submit(new RunDataSourceIngestModulesTask(taskId)); + ingestTasks.put(taskId, task); + + int numberOfFileTasksRequested = getNumberOfFileIngestThreads(); + for (int i = 0; i < numberOfFileTasksRequested; ++i) { + taskId = ingestTaskId.incrementAndGet(); + task = fileIngestTasksExecutor.submit(new RunFileSourceIngestModulesTask(taskId)); + ingestTasks.put(taskId, task); + } + + fireEventTasksExecutor.submit(new FireIngestJobEventTask(ingestJob.getId(), IngestEvent.INGEST_JOB_STARTED)); } } } catch (Exception ex) { @@ -460,7 +419,7 @@ public class IngestManager { NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.catchException.msg")); } finally { progress.finish(); - reportStartIngestJobsTaskDone(id); + ingestTasks.remove(id); } } } @@ -525,11 +484,42 @@ public class IngestManager { } } - class IngestCancellationWorker extends SwingWorker { + private class FireIngestJobEventTask implements Runnable { + + private final long ingestJobId; + private final IngestEvent event; + + FireIngestJobEventTask(long ingestJobId, IngestEvent event) { + this.ingestJobId = ingestJobId; + this.event = event; + } + + @Override + public void run() { + fireIngestJobEvent(event.toString(), ingestJobId); + } + } + + private class IngestCancellationWorker extends SwingWorker { @Override protected Void doInBackground() throws Exception { - stopIngestTasks(); + // First mark all of the ingest jobs as cancelled. This way the + // ingest modules will know they are being shut down due to + // cancellation when the cancelled run ingest module tasks release + // their pipelines. + for (IngestJob job : ingestJobs.values()) { + job.cancel(); + } + + for (Future task : ingestTasks.values()) { + task.cancel(true); + } + + // Jettision the remaining data source and file ingest tasks. + scheduler.getFileIngestScheduler().emptyQueues(); + scheduler.getDataSourceIngestScheduler().emptyQueues(); + return null; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java index ed291bb6eb..7b2bcd9804 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2014 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,7 +44,7 @@ import org.sleuthkit.datamodel.Content; /** * Top component which displays something. */ - final class IngestMessageTopComponent extends TopComponent implements IngestUI { + final class IngestMessageTopComponent extends TopComponent { private static IngestMessageTopComponent instance; private static final Logger logger = Logger.getLogger(IngestMessageTopComponent.class.getName()); @@ -246,7 +246,6 @@ import org.sleuthkit.datamodel.Content; /** * Display ingest summary report in some dialog */ - @Override public void displayReport(String ingestReport) { Object[] options = {NbBundle.getMessage(this.getClass(), "IngestMessageTopComponent.displayReport.option.OK"), @@ -290,7 +289,6 @@ import org.sleuthkit.datamodel.Content; /** * Display IngestMessage from module (forwarded by IngestManager) */ - @Override public void displayMessage(IngestMessage ingestMessage) { messagePanel.addMessage(ingestMessage); @@ -317,17 +315,14 @@ import org.sleuthkit.datamodel.Content; } } - @Override public int getMessagesCount() { return messagePanel.getMessagesCount(); } - @Override public void clearMessages() { messagePanel.clearMessages(); } - @Override public void displayIngestDialog(final Content ingestDataSource) { /* final IngestDialog ingestDialog = new IngestDialog(); @@ -336,12 +331,10 @@ import org.sleuthkit.datamodel.Content; */ } - @Override public void restoreMessages() { //componentShowing(); } - @Override public Action[] getActions() { //disable TC toolbar actions return new Action[0]; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestUI.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestUI.java deleted file mode 100644 index e4984bf38e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestUI.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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 org.sleuthkit.datamodel.Content; - -/** - * UI support for ingest - */ - interface IngestUI { - void displayMessage(final IngestMessage message); - int getMessagesCount(); - void clearMessages(); - void restoreMessages(); - void displayIngestDialog(final Content ingestDataSource); - void displayReport(final String report); - -} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Installer.java b/Core/src/org/sleuthkit/autopsy/ingest/Installer.java index a3599d8ff2..6738aa0ddb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/Installer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2014 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.ingest; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; @@ -43,17 +41,12 @@ public class Installer extends ModuleInstall { @Override public void restored() { - - Logger logger = Logger.getLogger(Installer.class.getName()); - logger.log(Level.INFO, "Initializing ingest manager"); //NON-NLS final IngestManager manager = IngestManager.getInstance(); WindowManager.getDefault().invokeWhenUIReady(new Runnable() { @Override public void run() { //at this point UI top component is present for sure, ensure manager has it manager.initIngestMessageInbox(); - //force ingest inbox closed, even if previous state was open - //IngestMessageTopComponent.findInstance().close(); } }); @@ -63,7 +56,6 @@ public class Installer extends ModuleInstall { public boolean closing() { //force ingest inbox closed on exit and save state as such IngestMessageTopComponent.findInstance().close(); - return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index cd48ed2764..2f0cdf79f6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -911,7 +911,7 @@ import org.sleuthkit.datamodel.TskData; } // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(rs.getLong("artifact_id")); + HashSet uniqueTagNames = getUniqueTagNames(rs.getLong("artifact_id")); //NON-NLS if(failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } @@ -1047,7 +1047,7 @@ import org.sleuthkit.datamodel.TskData; } // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(rs.getLong("artifact_id")); + HashSet uniqueTagNames = getUniqueTagNames(rs.getLong("artifact_id")); //NON-NLS if(failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalListSettingsPanel.java index b17ea121b5..0c2ddcf0ef 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalListSettingsPanel.java @@ -45,7 +45,6 @@ final class KeywordSearchGlobalListSettingsPanel extends javax.swing.JPanel impl String toDelete = editListPanel.getCurrentKeywordList().getName(); editListPanel.setCurrentKeywordList(null); editListPanel.setButtonStates(); - // RJCTODO: Move this into a deleteList method in the manager KeywordSearchListsXML deleter = KeywordSearchListsXML.getCurrent(); deleter.deleteList(toDelete); listsManagementPanel.resync(); @@ -79,7 +78,6 @@ final class KeywordSearchGlobalListSettingsPanel extends javax.swing.JPanel impl return; } - // RJCTODO: Move chunks of this into manager KeywordSearchListsXML writer = KeywordSearchListsXML.getCurrent(); if (writer.listExists(listName) && writer.getList(listName).isLocked()) { KeywordSearchUtil.displayDialog(FEATURE_NAME, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.noOwDefaultMsg"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java index 36562b776f..82cfb9a30c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java @@ -307,7 +307,6 @@ class KeywordSearchListsManagementPanel extends javax.swing.JPanel implements Op @Override public void store() { // Implemented by parent panel - // RJCTODO: The parent panel calls save on the XML doc thing, does this still work? } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsXML.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsXML.java index ca072e00f8..42e3650270 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsXML.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsXML.java @@ -62,10 +62,6 @@ final class KeywordSearchListsXML extends KeywordSearchListsAbstract { private static KeywordSearchListsXML currentInstance = null; private DateFormat dateFormatter; - /** - * RJCTODO: Move this one to the manager - * @return - */ static synchronized KeywordSearchListsXML getCurrent() { if (currentInstance == null) { currentInstance = new KeywordSearchListsXML(CUR_LISTS_FILE); diff --git a/test/script/regression.py b/test/script/regression.py index e689fdccff..3704901106 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -144,16 +144,17 @@ class TestRunner(object): time.sleep(10) Reports.write_html_foot(test_config.html_log) - # TODO: possibly worth putting this in a sub method + + if test_config.jenkins: + setupAttachments(Errors.errors_out, test_config) + if all([ test_data.overall_passed for test_data in test_data_list ]): pass else: html = open(test_config.html_log) Errors.add_errors_out(html.name) html.close() - - if test_config.jenkins: - setupAttachments(Errors.errors_out, test_config) + sys.exit(1) def _run_autopsy_ingest(test_data): """Run Autopsy ingest for the image in the given TestData.