diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 0e8ae6bc76..7f52ec6b25 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -188,6 +188,7 @@
org.sleuthkit.autopsy.casemodule.services
org.sleuthkit.autopsy.contentviewers
org.sleuthkit.autopsy.core
+ org.sleuthkit.autopsy.core.events
org.sleuthkit.autopsy.corecomponentinterfaces
org.sleuthkit.autopsy.corecomponents
org.sleuthkit.autopsy.coreutils
diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
index 2568ba2936..91dc25193c 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.actions;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
@@ -61,21 +62,26 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
@Override
protected void addTag(TagName tagName, String comment) {
- Collection extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
- for (BlackboardArtifact artifact : selectedArtifacts) {
- try {
- Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
- }
- catch (TskCoreException ex) {
- Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddBlackboardArtifactTagAction.unableToTag.msg",
- artifact.getDisplayName()),
- NbBundle.getMessage(this.getClass(),
- "AddBlackboardArtifactTagAction.taggingErr"),
- JOptionPane.ERROR_MESSAGE);
- }
- }
+ final Collection extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
+
+ new Thread(() -> {
+ for (BlackboardArtifact artifact : selectedArtifacts) {
+ try {
+ Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddBlackboardArtifactTagAction.unableToTag.msg",
+ artifact.getDisplayName()),
+ NbBundle.getMessage(this.getClass(),
+ "AddBlackboardArtifactTagAction.taggingErr"),
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }
+ }).start();
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
index cff35af7c1..6f1b493ecf 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
@@ -64,81 +65,98 @@ public class AddContentTagAction extends AddTagAction {
@Override
protected void addTag(TagName tagName, String comment) {
- Collection extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
- for (AbstractFile file : selectedFiles) {
- try {
- // Handle the special cases of current (".") and parent ("..") directory entries.
- if (file.getName().equals(".")) {
- Content parentFile = file.getParent();
- if (parentFile instanceof AbstractFile) {
- file = (AbstractFile)parentFile;
- }
- else {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.unableToTag.msg",
- parentFile.getName()),
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.cannotApplyTagErr"),
- JOptionPane.WARNING_MESSAGE);
- continue;
- }
- }
- else if (file.getName().equals("..")) {
- Content parentFile = file.getParent();
- if (parentFile instanceof AbstractFile) {
- parentFile = (AbstractFile)((AbstractFile)parentFile).getParent();
+ final Collection extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
+
+ new Thread(() -> {
+ for (AbstractFile file : selectedFiles) {
+ try {
+ // Handle the special cases of current (".") and parent ("..") directory entries.
+ if (file.getName().equals(".")) {
+ Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile)parentFile;
}
else {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.unableToTag.msg",
- parentFile.getName()),
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.cannotApplyTagErr"),
- JOptionPane.WARNING_MESSAGE);
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.unableToTag.msg",
+ parentFile.getName()),
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.cannotApplyTagErr"),
+ JOptionPane.WARNING_MESSAGE);
+ });
continue;
}
}
- else {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.unableToTag.msg",
- parentFile.getName()),
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.cannotApplyTagErr"),
- JOptionPane.WARNING_MESSAGE);
- continue;
- }
- }
- // check if the same tag is being added for the same abstract file.
- TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
- List contentTagList = tagsManager.getContentTagsByContent(file);
- for (ContentTag contentTag : contentTagList) {
- if (contentTag.getName().getDisplayName().equals(tagName.getDisplayName())) {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.tagExists",
- file.getName(), tagName.getDisplayName()),
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.cannotApplyTagErr"),
- JOptionPane.WARNING_MESSAGE);
- return;
+ else if (file.getName().equals("..")) {
+ Content parentFile = file.getParent();
+ if (parentFile instanceof AbstractFile) {
+ parentFile = (AbstractFile)((AbstractFile)parentFile).getParent();
+ if (parentFile instanceof AbstractFile) {
+ file = (AbstractFile)parentFile;
+ }
+ else {
+ final Content parentFileCopy = parentFile;
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.unableToTag.msg",
+ parentFileCopy.getName()),
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.cannotApplyTagErr"),
+ JOptionPane.WARNING_MESSAGE);
+ });
+ continue;
+ }
+ }
+ else {
+ final Content parentFileCopy = parentFile;
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.unableToTag.msg",
+ parentFileCopy.getName()),
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.cannotApplyTagErr"),
+ JOptionPane.WARNING_MESSAGE);
+ });
+ continue;
+ }
}
+ // check if the same tag is being added for the same abstract file.
+ TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
+ List contentTagList = tagsManager.getContentTagsByContent(file);
+ for (ContentTag contentTag : contentTagList) {
+ if (contentTag.getName().getDisplayName().equals(tagName.getDisplayName())) {
+ AbstractFile fileCopy = file;
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.tagExists",
+ fileCopy.getName(), tagName.getDisplayName()),
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.cannotApplyTagErr"),
+ JOptionPane.WARNING_MESSAGE);
+ });
+ return;
+ }
+ }
+ tagsManager.addContentTag(file, tagName, comment);
}
- tagsManager.addContentTag(file, tagName, comment);
- }
- catch (TskCoreException ex) {
- Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "AddContentTagAction.unableToTag.msg2",
- file.getName()),
- NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
+ catch (TskCoreException ex) {
+ Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
+ AbstractFile fileCopy = file;
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AddContentTagAction.unableToTag.msg2",
+ fileCopy.getName()),
+ NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }
+ }).start();
+ }
}
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java
index ac9e29fe59..51482c0928 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@@ -55,22 +56,26 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent event) {
- Collection extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
- for (BlackboardArtifactTag tag : selectedTags) {
- try {
- Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
- }
- catch (TskCoreException ex) {
- Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "DeleteBlackboardArtifactTagAction.unableToDelTag.msg",
- tag.getName()),
- NbBundle.getMessage(this.getClass(),
- "DeleteBlackboardArtifactTagAction.tagDelErr"),
- JOptionPane.ERROR_MESSAGE);
- }
- }
+ final Collection extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
+ new Thread(() -> {
+ for (BlackboardArtifactTag tag : selectedTags) {
+ try {
+ Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "DeleteBlackboardArtifactTagAction.unableToDelTag.msg",
+ tag.getName()),
+ NbBundle.getMessage(this.getClass(),
+ "DeleteBlackboardArtifactTagAction.tagDelErr"),
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }
+ }).start();
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
index c716311eea..f215df8a40 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@@ -55,20 +56,24 @@ public class DeleteContentTagAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
- Collection extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
- for (ContentTag tag : selectedTags) {
- try {
- Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
- }
- catch (TskCoreException ex) {
- Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "DeleteContentTagAction.unableToDelTag.msg",
- tag.getName()),
- NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
- JOptionPane.ERROR_MESSAGE);
- }
- }
+ final Collection extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
+ new Thread(() -> {
+ for (ContentTag tag : selectedTags) {
+ try {
+ Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "DeleteContentTagAction.unableToDelTag.msg",
+ tag.getName()),
+ NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }
+ }).start();
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java
index d9479c5a6d..2633d0f74e 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java
@@ -238,7 +238,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel {
+ Case.getCurrentCase().notifyAddingNewDataSource(dataSourceId);
+ }).start();
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback () {
@Override
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) {
@@ -258,8 +260,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel {
+ Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
+ }).start();
+ dsProcessor.cancel();
}
/*
@@ -307,11 +311,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel {
+ if (!newContents.isEmpty()) {
+ Case.getCurrentCase().notifyNewDataSource(newContents.get(0), dataSourceId);
+ } else {
+ Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
+ }
+ }).start();
// Start ingest if we can
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
index 784d7c4d8a..9c16f20263 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
@@ -242,14 +242,6 @@ LocalFilesPanel.errorLabel.text=Error Label
NewCaseVisualPanel1.errorLabel.text=Error Label
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
-CollaborationMonitor.failedService.notify.title=Collaboration Service Failed
-CollaborationMonitor.failedDbService.notify.msg=Lost connection to database server
-CollaborationMonitor.failedSolrService.notify.msg=Lost connection to keyword search server
-CollaborationMonitor.failedMessageService.notify.msg=Lost connection to messaging server
-CollaborationMonitor.restoredService.notify.title=Collaboration Service Restored
-CollaborationMonitor.restoredDbService.notify.msg=Connection to database server restored
-CollaborationMonitor.restoredSolrService.notify.msg=Connection to keyword search server restored
-CollaborationMonitor.restoredMessageService.notify.msg=Connection to messaging server restored
MissingImageDialog.lbWarning.text=
MissingImageDialog.lbWarning.toolTipText=
CaseConverter.AlreadyMultiUser=Case is already multi-user!
@@ -264,4 +256,4 @@ CaseConverter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique.
CaseConverter.ConvertedToMultiUser=This case was converted to a Multi-user collaborative case on
CaseConverter.UnableToCopySourceImages=Unable to copy source images
CaseConverter.ConversionSuccessful=. Conversion successful:
-CaseConverter.DeletingCase=Deleting original case folder
\ No newline at end of file
+CaseConverter.DeletingCase=Deleting original case folder
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index b67c7d0436..af785d02e2 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -44,6 +44,7 @@ import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.SystemAction;
@@ -329,7 +330,9 @@ public class Case {
currentCase = newCase;
Logger.setLogDirectory(currentCase.getLogDirectoryPath());
doCaseChange(currentCase);
- RecentCases.getInstance().addRecentCase(currentCase.name, currentCase.configFilePath); // update the recent cases
+ SwingUtilities.invokeLater(() -> {
+ RecentCases.getInstance().addRecentCase(currentCase.name, currentCase.configFilePath); // update the recent cases
+ });
if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) {
try {
/**
@@ -524,20 +527,24 @@ public class Case {
String dbPath = caseDir + File.separator + "autopsy.db"; //NON-NLS
db = SleuthkitCase.openCase(dbPath);
if (null != db.getBackupDatabasePath()) {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg",
- db.getBackupDatabasePath()),
- NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
- JOptionPane.INFORMATION_MESSAGE);
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg",
+ db.getBackupDatabasePath()),
+ NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
+ JOptionPane.INFORMATION_MESSAGE);
+ });
}
} else {
db = SleuthkitCase.openCase(xmlcm.getDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir);
if (null != db.getBackupDatabasePath()) {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg",
- db.getBackupDatabasePath()),
- NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
- JOptionPane.INFORMATION_MESSAGE);
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg",
+ db.getBackupDatabasePath()),
+ NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
+ JOptionPane.INFORMATION_MESSAGE);
+ });
}
}
@@ -646,6 +653,8 @@ public class Case {
/**
* Notifies case event subscribers (property change listeners) that a data
* source is being added to the case database.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param dataSourceId A unique identifier for the data source. This UUID
* should be used to call notifyNewDataSource() after the
@@ -658,6 +667,8 @@ public class Case {
/**
* Notifies case event subscribers (property change listeners) that a data
* source failed to be added to the case database.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param dataSourceId A unique identifier for the data source.
*/
@@ -668,6 +679,8 @@ public class Case {
/**
* Notifies case event subscribers (property change listeners) that a data
* source is being added to the case database.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param newDataSource New data source added.
* @param dataSourceId A unique identifier for the data source. Should be
@@ -680,6 +693,8 @@ public class Case {
/**
* Notifies the UI that a new ContentTag has been added.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param newTag new ContentTag added
*/
@@ -689,6 +704,8 @@ public class Case {
/**
* Notifies the UI that a ContentTag has been deleted.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param deletedTag ContentTag deleted
*/
@@ -698,6 +715,8 @@ public class Case {
/**
* Notifies the UI that a new BlackboardArtifactTag has been added.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param newTag new BlackboardArtifactTag added
*/
@@ -706,7 +725,9 @@ public class Case {
}
/**
- * Notifies the UI that a BlackboardArtifactTag has been.
+ * Notifies the UI that a BlackboardArtifactTag has been deleted.
+ *
+ * This should not be called from the event dispatch thread (EDT)
*
* @param deletedTag BlackboardArtifactTag deleted
*/
@@ -775,6 +796,8 @@ public class Case {
/**
* Updates the case name.
+ *
+ * This should not be called from the EDT.
*
* @param oldCaseName the old case name that wants to be updated
* @param oldPath the old path that wants to be updated
@@ -785,9 +808,15 @@ public class Case {
try {
xmlcm.setCaseName(newCaseName); // set the case
name = newCaseName; // change the local value
- RecentCases.getInstance().updateRecentCase(oldCaseName, oldPath, newCaseName, newPath); // update the recent case
eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName));
- updateMainWindowTitle(newCaseName);
+ SwingUtilities.invokeLater(() -> {
+ try{
+ RecentCases.getInstance().updateRecentCase(oldCaseName, oldPath, newCaseName, newPath); // update the recent case
+ updateMainWindowTitle(newCaseName);
+ } catch (Exception e) {
+ Logger.getLogger(CasePropertiesForm.class.getName()).log(Level.WARNING, "Error: problem updating case name.", e); //NON-NLS
+ }
+ });
} catch (Exception e) {
throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateCaseName.exception.msg"), e);
}
@@ -795,6 +824,8 @@ public class Case {
/**
* Updates the case examiner
+ *
+ * This should not be called from the EDT.
*
* @param oldExaminer the old examiner
* @param newExaminer the new examiner
@@ -811,6 +842,8 @@ public class Case {
/**
* Updates the case number
+ *
+ * This should not be called from the EDT.
*
* @param oldCaseNumber the old case number
* @param newCaseNumber the new case number
@@ -1468,44 +1501,61 @@ public class Case {
if (IngestManager.getInstance().isRunningInteractively()) {
// enable these menus
- CallableSystemAction.get(AddImageAction.class).setEnabled(true);
- CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
- CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
- CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu
+ SwingUtilities.invokeLater(() -> {
+ CallableSystemAction.get(AddImageAction.class).setEnabled(true);
+ CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
+ CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
+ CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu
+ });
if (toChangeTo.hasData()) {
// open all top components
- CoreComponentControl.openCoreWindows();
+ SwingUtilities.invokeLater(() -> {
+ CoreComponentControl.openCoreWindows();
+ });
} else {
// close all top components
- CoreComponentControl.closeCoreWindows();
+ SwingUtilities.invokeLater(() -> {
+ CoreComponentControl.closeCoreWindows();
+ });
}
}
if (IngestManager.getInstance().isRunningInteractively()) {
- updateMainWindowTitle(currentCase.name);
+ SwingUtilities.invokeLater(() -> {
+ updateMainWindowTitle(currentCase.name);
+ });
} else {
- Frame f = WindowManager.getDefault().getMainWindow();
- f.setTitle(Case.getAppName()); // set the window name to just application name
+ SwingUtilities.invokeLater(() -> {
+ Frame f = WindowManager.getDefault().getMainWindow();
+ f.setTitle(Case.getAppName()); // set the window name to just application name
+ });
}
} else { // case is closed
if (IngestManager.getInstance().isRunningInteractively()) {
- // close all top components first
- CoreComponentControl.closeCoreWindows();
-
- // disable these menus
- CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu
- CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu
- CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu
- CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu
+
+ SwingUtilities.invokeLater(() -> {
+ // close all top components first
+ CoreComponentControl.closeCoreWindows();
+
+ // disable these menus
+ CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu
+ CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu
+ CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu
+ CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu
+ });
}
//clear pending notifications
- MessageNotifyUtil.Notify.clear();
+ SwingUtilities.invokeLater(() -> {
+ MessageNotifyUtil.Notify.clear();
+ });
- Frame f = WindowManager.getDefault().getMainWindow();
- f.setTitle(Case.getAppName()); // set the window name to just application name
+ SwingUtilities.invokeLater(() -> {
+ Frame f = WindowManager.getDefault().getMainWindow();
+ f.setTitle(Case.getAppName()); // set the window name to just application name
+ });
//try to force gc to happen
System.gc();
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
index ad0b4cc952..702162b987 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
@@ -27,6 +27,7 @@ import java.util.logging.Level;import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
+import javax.swing.SwingWorker;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
@@ -70,19 +71,24 @@ import org.openide.util.actions.Presenter;
return;
}
- Case result = Case.getCurrentCase();
- try {
- result.closeCase();
- } catch (Exception ex) {
- Logger.getLogger(CaseCloseAction.class.getName()).log(Level.SEVERE, "Error closing case.", ex); //NON-NLS
- }
-
- EventQueue.invokeLater(new Runnable() {
+ new SwingWorker() {
+
@Override
- public void run() {
+ protected Void doInBackground() throws Exception {
+ try{
+ Case result = Case.getCurrentCase();
+ result.closeCase();
+ } catch (CaseActionException | IllegalStateException ex){
+ Logger.getLogger(CaseCloseAction.class.getName()).log(Level.SEVERE, "Error closing case.", ex); //NON-NLS
+ }
+ return null;
+ }
+
+ @Override
+ protected void done() {
StartupWindowProvider.getInstance().open();
}
- });
+ }.execute();
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java
index f767efcf09..5bae094395 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java
@@ -23,9 +23,12 @@ import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
+import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.openide.util.NbBundle;
@@ -76,7 +79,7 @@ public final class CaseOpenAction implements ActionListener {
int retval = fc.showOpenDialog(WindowManager.getDefault().getMainWindow());
if (retval == JFileChooser.APPROVE_OPTION) {
- String path = fc.getSelectedFile().getPath();
+ final String path = fc.getSelectedFile().getPath();
String dirPath = fc.getSelectedFile().getParent();
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE, dirPath.substring(0, dirPath.lastIndexOf(File.separator)));
// check if the file exists
@@ -96,20 +99,27 @@ public final class CaseOpenAction implements ActionListener {
// no need to show the error message to the user.
logger.log(Level.WARNING, "Error closing startup window.", ex); //NON-NLS
}
- try {
- Case.open(path); // open the case
- } catch (CaseActionException ex) {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(),
- "CaseOpenAction.msgDlg.cantOpenCase.msg", path,
- ex.getMessage()),
- NbBundle.getMessage(this.getClass(),
- "CaseOpenAction.msgDlg.cantOpenCase.title"),
- JOptionPane.ERROR_MESSAGE);
- logger.log(Level.WARNING, "Error opening case in folder " + path, ex); //NON-NLS
+
+ new Thread(() -> {
+ // Create case.
+ try{
+ Case.open(path);
+ } catch (CaseActionException ex) {
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "CaseOpenAction.msgDlg.cantOpenCase.msg", path,
+ ex.getMessage()),
+ NbBundle.getMessage(this.getClass(),
+ "CaseOpenAction.msgDlg.cantOpenCase.title"),
+ JOptionPane.ERROR_MESSAGE);
- StartupWindowProvider.getInstance().open();
- }
+
+ StartupWindowProvider.getInstance().open();
+ });
+ logger.log(Level.WARNING, "Error opening case in folder " + path, ex); //NON-NLS
+ }
+ }).start();
}
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java
index 16dfde423d..b75213bcc8 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java
@@ -22,8 +22,6 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
@@ -36,46 +34,36 @@ import java.util.UUID;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
-import javax.jms.Connection;
-import javax.jms.JMSException;
-import org.apache.activemq.ActiveMQConnectionFactory;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
-import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.events.AutopsyEventException;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
-import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent;
-import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
-import org.sleuthkit.datamodel.CaseDbConnectionInfo;
/**
* A collaboration monitor listens to local events and translates them into
- * collaboration tasks that are broadcast to collaborating nodes, informs the
- * user of collaboration tasks on other nodes using progress bars, and monitors
- * the health of key collaboration services.
+ * collaboration tasks that are broadcast to collaborating nodes and informs the
+ * user of collaboration tasks on other nodes using progress bars.
*/
final class CollaborationMonitor {
private static final String EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events";
private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT";
private static final Set CASE_EVENTS_OF_INTEREST = new HashSet<>(Arrays.asList(new String[]{Case.Events.ADDING_DATA_SOURCE.toString(), Case.Events.DATA_SOURCE_ADDED.toString(), Case.Events.ADDING_DATA_SOURCE_FAILED.toString()}));
- private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 3;
+ private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 2;
private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d";
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
private static final long MAX_MISSED_HEARTBEATS = 5;
private static final long STALE_TASKS_DETECTION_INTERVAL_MINUTES = 2;
- private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2;
private static final long EXECUTOR_TERMINATION_WAIT_SECS = 30;
private static final Logger logger = Logger.getLogger(CollaborationMonitor.class.getName());
private final String hostName;
@@ -130,12 +118,10 @@ final class CollaborationMonitor {
*
* 1. Send heartbeats to collaboration monitors on other nodes.
* 2. Check for stale remote tasks.
- * 3. Check the availability of key collaboration services.
*/
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES);
periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECTION_INTERVAL_MINUTES, STALE_TASKS_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
- periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
}
/**
@@ -497,80 +483,6 @@ final class CollaborationMonitor {
}
}
- /**
- * A Runnable task that periodically checks the availability of
- * collaboration resources (PostgreSQL server, Solr server, Active MQ
- * message broker) and reports status to the user in case of a gap in
- * service.
- */
- private final static class CrashDetectionTask implements Runnable {
-
- private static boolean dbServerIsRunning = true;
- private static boolean solrServerIsRunning = true;
- private static boolean messageServerIsRunning = true;
- private static final Object lock = new Object();
-
- /**
- * Monitor the availability of collaboration resources
- */
- @Override
- public void run() {
- synchronized (lock) {
- CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo();
- if (dbInfo.canConnect()) {
- if (!dbServerIsRunning) {
- dbServerIsRunning = true;
- logger.log(Level.INFO, "Connection to PostgreSQL server restored"); //NON-NLS
- MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredDbService.notify.msg"));
- }
- } else {
- if (dbServerIsRunning) {
- dbServerIsRunning = false;
- logger.log(Level.SEVERE, "Failed to connect to PostgreSQL server"); //NON-NLS
- MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedDbService.notify.msg"));
- }
- }
-
- KeywordSearchService kwsService = Case.getCurrentCase().getServices().getKeywordSearchService();
-
- if (kwsService.canConnectToRemoteSolrServer()) {
- if (!solrServerIsRunning) {
- solrServerIsRunning = true;
- logger.log(Level.INFO, "Connection to Solr server restored"); //NON-NLS
- MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredSolrService.notify.msg"));
- }
- }
- else {
- if (solrServerIsRunning) {
- solrServerIsRunning = false;
- logger.log(Level.SEVERE, "Failed to connect to Solr server"); //NON-NLS
- MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedSolrService.notify.msg"));
- }
- }
-
- MessageServiceConnectionInfo msgInfo = UserPreferences.getMessageServiceConnectionInfo();
- try {
- ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(msgInfo.getUserName(), msgInfo.getPassword(), msgInfo.getURI());
- Connection connection = connectionFactory.createConnection();
- connection.start();
- connection.close();
- if (!messageServerIsRunning) {
- messageServerIsRunning = true;
- logger.log(Level.INFO, "Connection to ActiveMQ server restored"); //NON-NLS
- MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredMessageService.notify.msg"));
- }
- } catch (URISyntaxException | JMSException ex) {
- if (messageServerIsRunning) {
- messageServerIsRunning = false;
- logger.log(Level.SEVERE, "Failed to connect to ActiveMQ server", ex); //NON-NLS
- MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedMessageService.notify.msg"));
- }
- }
- }
- }
-
- }
-
/**
* An Autopsy event to be sent in event messages to the collaboration
* monitors on other Autopsy nodes.
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
index bc9cdea275..aad75a51c0 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
@@ -24,7 +24,10 @@ import java.awt.Dialog;
import java.io.File;
import java.text.MessageFormat;
import java.util.logging.Level;
+import java.util.concurrent.ExecutionException;
import javax.swing.JComponent;
+import javax.swing.SwingWorker;
+import javax.swing.SwingUtilities;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -81,7 +84,7 @@ import org.sleuthkit.datamodel.TskData.DbType;
* The method to perform new case creation
*/
private void newCaseAction() {
- WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
+ final WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.newCase.windowTitle.text"));
@@ -89,44 +92,71 @@ import org.sleuthkit.datamodel.TskData.DbType;
dialog.setVisible(true);
dialog.toFront();
+ if(wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION){
+ new SwingWorker() {
- boolean finished = wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION; // check if it finishes (it's not cancelled)
- boolean isCancelled = wizardDescriptor.getValue() == WizardDescriptor.CANCEL_OPTION; // check if the "Cancel" button is pressed
+ @Override
+ protected Void doInBackground() throws Exception {
+ // Create case.
+
+ String caseNumber = (String) wizardDescriptor.getProperty("caseNumber"); //NON-NLS
+ String examiner = (String) wizardDescriptor.getProperty("caseExaminer"); //NON-NLS
+ final String caseName = (String) wizardDescriptor.getProperty("caseName"); //NON-NLS
+ String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
+ CaseType caseType = CaseType.values()[(int)wizardDescriptor.getProperty("caseType")]; //NON-NLS
- // if the finish button is pressed (not cancelled)
- if (finished) {
- // now start the 'Add Image' wizard
- //TODO fix for local
- CaseType currentCaseType = CaseType.fromString(ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, ModuleSettings.CURRENT_CASE_TYPE));
- CaseDbConnectionInfo info = UserPreferences.getDatabaseConnectionInfo();
- if ((currentCaseType==CaseType.SINGLE_USER_CASE) || ((info.getDbType() != DbType.SQLITE) && info.canConnect())) {
- AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
- addImageAction.actionPerformed(null);
- } else {
- JOptionPane.showMessageDialog(null,
- NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem1.text"),
- NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem2.text"),
- JOptionPane.ERROR_MESSAGE);
- isCancelled = true;
- }
+ Case.create(createdDirectory, caseName, caseNumber, examiner, caseType);
+ return null;
+ }
+
+ @Override
+ protected void done() {
+ try {
+ get();
+ CaseType currentCaseType = CaseType.values()[(int)wizardDescriptor.getProperty("caseType")]; //NON-NLS
+ CaseDbConnectionInfo info = UserPreferences.getDatabaseConnectionInfo();
+ if ((currentCaseType==CaseType.SINGLE_USER_CASE) || ((info.getDbType() != DbType.SQLITE) && info.canConnect())) {
+ AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
+ addImageAction.actionPerformed(null);
+ } else {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem1.text"),
+ NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem2.text"),
+ JOptionPane.ERROR_MESSAGE);
+ doFailedCaseCleanup(wizardDescriptor);
+ }
+
+
+ } catch (Exception ex) {
+ final String caseName = (String) wizardDescriptor.getProperty("caseName"); //NON-NLS
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(),
+ "CaseCreateAction.msgDlg.cantCreateCase.msg")+" "+caseName,
+ NbBundle.getMessage(this.getClass(),
+ "CaseOpenAction.msgDlg.cantOpenCase.title"),
+ JOptionPane.ERROR_MESSAGE);
+ });
+ doFailedCaseCleanup(wizardDescriptor);
+ }
+ }
+ }.execute();
+
+
+ } else {
+ new Thread(() -> {
+ doFailedCaseCleanup(wizardDescriptor);
+ }).start();
}
-
- // if Cancel button is pressed
- if (isCancelled) {
- String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
- // if there's case opened, close the case
- if (Case.existsCurrentCase()) {
- // close the previous case if there's any
- CaseCloseAction closeCase = SystemAction.get(CaseCloseAction.class);
- closeCase.actionPerformed(null);
- }
- if (createdDirectory != null) {
- logger.log(Level.INFO, "Deleting a created case directory due to isCancelled set, dir: " + createdDirectory); //NON-NLS
- Case.deleteCaseDirectory(new File(createdDirectory));
- }
- }
- panels = null; // reset the panel
}
+
+ private void doFailedCaseCleanup(WizardDescriptor wizardDescriptor){
+ String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
+
+ if (createdDirectory != null) {
+ logger.log(Level.INFO, "Deleting a created case directory due to an error, dir: " + createdDirectory); //NON-NLS
+ Case.deleteCaseDirectory(new File(createdDirectory));
+ }
+ }
/**
* Initialize panels representing individual wizard's steps and sets
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java
index 98a972a5af..f3edbe0370 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java
@@ -171,33 +171,12 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel {
+ // Create case.
+ try{
+ Case.open(casePath);
+ } catch (CaseActionException ex) {
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.cantOpenCase.msg", caseName,
ex.getMessage()),
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
- logger.log(Level.WARNING, "Error: couldn't open case: " + caseName, ex); //NON-NLS
+ });
+ logger.log(Level.WARNING, "Error: couldn't open case: " + caseName, ex); //NON-NLS
+ }
+ }).start();
}
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java b/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java
index 43de7bbb7f..763dfe59d2 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java
@@ -23,9 +23,12 @@ import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
+import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -35,8 +38,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
*/
class RecentItems implements ActionListener {
- String caseName;
- String casePath;
+ final String caseName;
+ final String casePath;
private JPanel caller; // for error handling
/** the constructor */
@@ -76,15 +79,20 @@ class RecentItems implements ActionListener {
}
}
else {
- try {
- Case.open(casePath); // open the case
- } catch (CaseActionException ex) {
- JOptionPane.showMessageDialog(null,
+ new Thread(() -> {
+ // Create case.
+ try{
+ Case.open(casePath);
+ } catch (CaseActionException ex) {
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.msg", casePath,
ex.getMessage()), NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
- Logger.getLogger(RecentItems.class.getName()).log(Level.WARNING, "Error: Couldn't open recent case at " + casePath, ex); //NON-NLS
- }
+ });
+ Logger.getLogger(RecentItems.class.getName()).log(Level.WARNING, "Error: Couldn't open recent case at " + casePath, ex); //NON-NLS
+ }
+ }).start();
}
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties
index ff08a90d89..8d0d3087ce 100644
--- a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties
@@ -12,3 +12,12 @@ org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xm
Services/AutoupdateType/org_sleuthkit_autopsy_core_update_center.settings=Autopsy Update Center
Installer.errorInitJavafx.msg=Error initializing JavaFX.
Installer.errorInitJavafx.details=\ Some features will not be available. Check that you have the right JRE installed (Oracle JRE > 1.7.10).
+ServicesMonitor.failedService.notify.title=Service Failed
+ServicesMonitor.failedService.notify.msg=Lost connection to {0}
+ServicesMonitor.restoredService.notify.title=Service Restored
+ServicesMonitor.restoredService.notify.msg=Connection to {0} restored
+ServicesMonitor.statusChange.notify.title=Service Status Update
+ServicesMonitor.statusChange.notify.msg=Status for {0} is {1}
+ServicesMonitor.nullServiceName.excepton.txt=Requested service name is null
+ServicesMonitor.nullStatusOrDetails.excepton.txt=Status or details string is null
+ServicesMonitor.unknownServiceName.excepton.txt=Requested service name {0} is unknown
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java
new file mode 100644
index 0000000000..9fb7389fb5
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java
@@ -0,0 +1,383 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2013-2015 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.core;
+
+import org.sleuthkit.autopsy.core.events.ServiceEvent;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.beans.PropertyChangeListener;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
+import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
+import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
+
+/**
+ * This class periodically checks availability of collaboration resources -
+ * remote database, remote keyword search server, messaging service - and
+ * reports status updates to the user in case of a gap in service.
+ */
+public class ServicesMonitor {
+
+ private AutopsyEventPublisher eventPublisher;
+ private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName());
+ private final ScheduledThreadPoolExecutor periodicTasksExecutor;
+
+ private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d";
+ private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
+ private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2;
+
+ private static final Set servicesList = Stream.of(ServicesMonitor.Service.values())
+ .map(Service::toString)
+ .collect(Collectors.toSet());
+
+ /**
+ * The service monitor maintains a mapping of each service to it's last
+ * status update.
+ */
+ private final ConcurrentHashMap statusByService;
+
+ /**
+ * Call constructor on start-up so that the first check of services is done
+ * as soon as possible.
+ */
+ private static ServicesMonitor instance = new ServicesMonitor();
+
+ /**
+ * List of services that are being monitored. The service names should be
+ * representative of the service functionality and readable as they get
+ * logged when service outage occurs.
+ */
+ public enum Service {
+
+ /**
+ * Property change event fired when remote case database service status
+ * changes. New value is set to updated ServiceStatus, old value is
+ * null.
+ */
+ REMOTE_CASE_DATABASE("Multi-user case database service"),
+ /**
+ * Property change event fired when remote keyword search service status
+ * changes. New value is set to updated ServiceStatus, old value is
+ * null.
+ */
+ REMOTE_KEYWORD_SEARCH("Multi-user keyword search service"),
+ /**
+ * Property change event fired when messaging service status changes.
+ * New value is set to updated ServiceStatus, old value is null.
+ */
+ MESSAGING("Messaging service");
+
+ private final String displayName;
+
+ private Service(String name) {
+ this.displayName = name;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+ };
+
+ /**
+ * List of possible service statuses.
+ */
+ public enum ServiceStatus {
+
+ /**
+ * Service is currently up.
+ */
+ UP,
+ /**
+ * Service is currently down.
+ */
+ DOWN
+ };
+
+ public synchronized static ServicesMonitor getInstance() {
+ if (instance == null) {
+ instance = new ServicesMonitor();
+ }
+ return instance;
+ }
+
+ private ServicesMonitor() {
+
+ this.eventPublisher = new AutopsyEventPublisher();
+ this.statusByService = new ConcurrentHashMap<>();
+
+ // First check is triggered immediately on current thread.
+ checkAllServices();
+
+ /**
+ * Start periodic task that check the availability of key collaboration
+ * services.
+ */
+ periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
+ periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
+ }
+
+ /**
+ * Updates service status and publishes the service status update if it is
+ * different from previous status. Event is published locally. Logs status
+ * changes.
+ *
+ * @param service Name of the service.
+ * @param status Updated status for the service.
+ * @param details Details of the event.
+ * @throws
+ * org.sleuthkit.autopsy.core.ServicesMonitor.ServicesMonitorException
+ * Thrown if either of input parameters is null.
+ */
+ public void setServiceStatus(String service, String status, String details) throws ServicesMonitorException {
+
+ if (service == null) {
+ logger.log(Level.SEVERE, "Call to setServiceStatus() with null service name"); //NON-NLS
+ throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullServiceName.excepton.txt"));
+ }
+
+ if (status == null || details == null) {
+ logger.log(Level.SEVERE, "Call to setServiceStatus() with null status or details"); //NON-NLS
+ throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullStatusOrDetails.excepton.txt"));
+ }
+
+ // if the status update is for an existing service who's status hasn't changed - do nothing.
+ if (statusByService.containsKey(service) && status.equals(statusByService.get(service))) {
+ return;
+ }
+
+ // new service or status has changed - identify service's display name
+ String serviceDisplayName;
+ try {
+ serviceDisplayName = ServicesMonitor.Service.valueOf(service).getDisplayName();
+ } catch (IllegalArgumentException ignore) {
+ // custom service that is not listed in ServicesMonitor.Service enum. Use service name as display name.
+ serviceDisplayName = service;
+ }
+
+ if (status.equals(ServiceStatus.UP.toString())) {
+ logger.log(Level.INFO, "Connection to {0} restored", serviceDisplayName); //NON-NLS
+ MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.title"),
+ NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.msg", serviceDisplayName));
+ } else if (status.equals(ServiceStatus.DOWN.toString())) {
+ logger.log(Level.SEVERE, "Failed to connect to {0}", serviceDisplayName); //NON-NLS
+ MessageNotifyUtil.Notify.error(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.title"),
+ NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.msg", serviceDisplayName));
+ } else {
+ logger.log(Level.INFO, "Status for {0} is {1}", new Object[]{serviceDisplayName, status}); //NON-NLS
+ MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.title"),
+ NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.msg", new Object[]{serviceDisplayName, status}));
+ }
+
+ // update and publish new status
+ statusByService.put(service, status);
+ eventPublisher.publishLocally(new ServiceEvent(service, status, details));
+ }
+
+ /**
+ * Get last status update for a service.
+ *
+ * @param service Name of the service.
+ * @return ServiceStatus Status for the service.
+ * @throws
+ * org.sleuthkit.autopsy.core.ServicesMonitor.ServicesMonitorException
+ * Thrown if service name is null or service doesn't exist.
+ */
+ public String getServiceStatus(String service) throws ServicesMonitorException {
+
+ if (service == null) {
+ throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullServiceName.excepton.txt"));
+ }
+
+ String status = statusByService.get(service);
+ if (status == null) {
+ // no such service
+ throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.unknownServiceName.excepton.txt", service));
+ }
+ return status;
+ }
+
+ /**
+ * Performs service availability status check.
+ *
+ * @param service Name of the service.
+ */
+ private void checkServiceStatus(String service) {
+ if (service.equals(Service.REMOTE_CASE_DATABASE.toString())) {
+ checkDatabaseConnectionStatus();
+ } else if (service.equals(Service.REMOTE_KEYWORD_SEARCH.toString())) {
+ checkKeywordSearchServerConnectionStatus();
+ } else if (service.equals(Service.MESSAGING.toString())) {
+ checkMessagingServerConnectionStatus();
+ }
+ }
+
+ /**
+ * Performs case database service availability status check.
+ */
+ private void checkDatabaseConnectionStatus() {
+ try {
+ if (UserPreferences.getDatabaseConnectionInfo().canConnect()) {
+ setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.UP.toString(), "");
+ } else {
+ setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.DOWN.toString(), "");
+ }
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Exception while checking database connection status", ex); //NON-NLS
+ }
+ }
+
+ /**
+ * Performs keyword search service availability status check.
+ */
+ private void checkKeywordSearchServerConnectionStatus() {
+ try {
+ KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
+ if (kwsService != null && kwsService.canConnectToRemoteSolrServer()) {
+ setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.UP.toString(), "");
+ } else {
+ setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(), "");
+ }
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Exception while checking keyword search server connection status", ex); //NON-NLS
+ }
+ }
+
+ /**
+ * Performs messaging service availability status check.
+ */
+ private void checkMessagingServerConnectionStatus() {
+ try {
+ if (UserPreferences.getMessageServiceConnectionInfo().canConnect()) {
+ setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.UP.toString(), "");
+ } else {
+ setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.DOWN.toString(), "");
+ }
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Exception while checking messaging server connection status", ex); //NON-NLS
+ }
+ }
+
+ /**
+ * Adds an event subscriber to this publisher. Subscriber will be subscribed
+ * to all events from this publisher.
+ *
+ * @param subscriber The subscriber to add.
+ */
+ public void addSubscriber(PropertyChangeListener subscriber) {
+ eventPublisher.addSubscriber(servicesList, subscriber);
+ }
+
+ /**
+ * Adds an event subscriber to this publisher.
+ *
+ * @param eventNames The events the subscriber is interested in.
+ * @param subscriber The subscriber to add.
+ */
+ public void addSubscriber(Set eventNames, PropertyChangeListener subscriber) {
+ eventPublisher.addSubscriber(eventNames, subscriber);
+ }
+
+ /**
+ * Adds an event subscriber to this publisher.
+ *
+ * @param eventName The event the subscriber is interested in.
+ * @param subscriber The subscriber to add.
+ */
+ public void addSubscriber(String eventName, PropertyChangeListener subscriber) {
+ eventPublisher.addSubscriber(eventName, subscriber);
+ }
+
+ /**
+ * Removes an event subscriber from this publisher.
+ *
+ * @param eventNames The events the subscriber is no longer interested in.
+ * @param subscriber The subscriber to remove.
+ */
+ public void removeSubscriber(Set eventNames, PropertyChangeListener subscriber) {
+ eventPublisher.removeSubscriber(eventNames, subscriber);
+ }
+
+ /**
+ * Removes an event subscriber from this publisher.
+ *
+ * @param eventName The event the subscriber is no longer interested in.
+ * @param subscriber The subscriber to remove.
+ */
+ public void removeSubscriber(String eventName, PropertyChangeListener subscriber) {
+ eventPublisher.removeSubscriber(eventName, subscriber);
+ }
+
+ /**
+ * Removes an event subscriber to this publisher. Subscriber will be removed
+ * from all event notifications from this publisher.
+ *
+ * @param subscriber The subscriber to remove.
+ */
+ public void removeSubscriber(PropertyChangeListener subscriber) {
+ eventPublisher.removeSubscriber(servicesList, subscriber);
+ }
+
+ /**
+ * Verifies connectivity to all services.
+ */
+ private void checkAllServices() {
+ for (String service : servicesList) {
+ checkServiceStatus(service);
+ }
+ }
+
+ /**
+ * A Runnable task that periodically checks the availability of
+ * collaboration resources (remote database, remote keyword search service,
+ * message broker) and reports status to the user in case of a gap in
+ * service.
+ */
+ private final class CrashDetectionTask implements Runnable {
+
+ /**
+ * Monitor the availability of collaboration resources
+ */
+ @Override
+ public void run() {
+ checkAllServices();
+ }
+ }
+
+ /**
+ * Exception thrown when service status query results in an error.
+ */
+ public class ServicesMonitorException extends Exception {
+
+ public ServicesMonitorException(String message) {
+ super(message);
+ }
+
+ public ServicesMonitorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/core/events/ServiceEvent.java b/Core/src/org/sleuthkit/autopsy/core/events/ServiceEvent.java
new file mode 100644
index 0000000000..057d9cd563
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/core/events/ServiceEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2013-2015 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.core.events;
+
+import java.io.Serializable;
+import org.sleuthkit.autopsy.events.AutopsyEvent;
+
+/**
+ * A class for events to be published to registered subscribers of Service
+ * Monitor on this Autopsy node. The class extends PropertyChangeEvent (via
+ * AutopsyEvent) to integrate with legacy use of JavaBeans PropertyChangeEvents
+ * and PropertyChangeListeners as an application event system, and implements
+ * Serializable to allow it to be published over a network in serialized form.
+ */
+public final class ServiceEvent extends AutopsyEvent implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final String details;
+
+ public ServiceEvent(String serviceName, String status, String details) {
+ super(serviceName, null, status);
+ this.details = details;
+ }
+
+ /**
+ * Gets details string passed as input to ServiceEvent constructor.
+ *
+ * @return String Details of the event.
+ */
+ public String getDetails() {
+ return details;
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java
index d38e58525e..14da528efc 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java
@@ -24,10 +24,12 @@ import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
+import java.util.concurrent.ExecutionException;
import javax.swing.BorderFactory;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.SwingWorker;
import org.netbeans.spi.sendopts.OptionProcessor;
import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI;
import org.openide.modules.ModuleInstall;
@@ -74,13 +76,18 @@ public class Installer extends ModuleInstall {
for (OptionProcessor processor : processors) {
if (processor instanceof OpenFromArguments) {
OpenFromArguments argsProcessor = (OpenFromArguments) processor;
- String caseFile = argsProcessor.getDefaultArg();
+ final String caseFile = argsProcessor.getDefaultArg();
if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(".aut") && new File(caseFile).exists()) { //NON-NLS
- try {
- Case.open(caseFile);
- return;
- } catch (Exception e) {
- }
+
+ new Thread(() -> {
+ // Create case.
+ try{
+ Case.open(caseFile);
+ } catch(Exception ex){
+ logger.log(Level.WARNING, "Error opening case. ", ex); //NON-NLS
+ }
+ }).start();
+ return;
}
}
}
@@ -99,13 +106,15 @@ public class Installer extends ModuleInstall {
@Override
public void close() {
- try {
- if (Case.isCaseOpen())
- Case.getCurrentCase().closeCase();
- }
- catch (CaseActionException ex) {
- logger.log(Level.WARNING, "Error closing case. ", ex); //NON-NLS
- }
+ new Thread(() -> {
+ try {
+ if (Case.isCaseOpen())
+ Case.getCurrentCase().closeCase();
+ }
+ catch (CaseActionException | IllegalStateException ex) {
+ logger.log(Level.WARNING, "Error closing case. ", ex); //NON-NLS
+ }
+ }).start();
}
private void setupLAF() {
diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
index 791272d57b..d93f3d1ba8 100644
--- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
+++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
@@ -567,8 +567,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
*/
try {
Case.getCurrentCase();
- CoreComponentControl.openCoreWindows();
- SwingUtilities.invokeLater(this::componentOpened);
+ SwingUtilities.invokeLater(() -> {
+ CoreComponentControl.openCoreWindows();
+ componentOpened();
+ });
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java
index fb011a1484..d099fa2a65 100644
--- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java
+++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java
@@ -62,7 +62,7 @@ public class AutopsyEvent extends PropertyChangeEvent implements Serializable {
/**
* Gets the source type (local or remote).
*
- * @param sourceType The source type of the event, local or remote.
+ * @return SourceType The source type of the event, local or remote.
*/
public SourceType getSourceType() {
return sourceType;
diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java
index df2b21674a..eca2f8dfb6 100644
--- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java
+++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java
@@ -120,7 +120,7 @@ public final class AutopsyEventPublisher {
/**
* Removes an event subscriber from this publisher.
*
- * @param eventNames The event the subscriber is no longer interested in.
+ * @param eventName The event the subscriber is no longer interested in.
* @param subscriber The subscriber to remove.
*/
public void removeSubscriber(String eventName, PropertyChangeListener subscriber) {
diff --git a/Core/src/org/sleuthkit/autopsy/events/MessageServiceConnectionInfo.java b/Core/src/org/sleuthkit/autopsy/events/MessageServiceConnectionInfo.java
index 8bebf16f0d..2e26d3a04c 100644
--- a/Core/src/org/sleuthkit/autopsy/events/MessageServiceConnectionInfo.java
+++ b/Core/src/org/sleuthkit/autopsy/events/MessageServiceConnectionInfo.java
@@ -21,6 +21,10 @@ package org.sleuthkit.autopsy.events;
import java.net.URI;
import java.net.URISyntaxException;
import javax.annotation.concurrent.Immutable;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.sleuthkit.autopsy.core.UserPreferences;
/**
* Connection info for a Java Message Service (JMS) provider. Thread-safe.
@@ -99,4 +103,20 @@ public final class MessageServiceConnectionInfo {
return new URI(String.format(MESSAGE_SERVICE_URI, host, port));
}
+ /**
+ * Verifies connection to messaging service.
+ *
+ * @return True if connection can be established, false otherwise.
+ */
+ public boolean canConnect() {
+ try {
+ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(getUserName(), getPassword(), getURI());
+ Connection connection = connectionFactory.createConnection();
+ connection.start();
+ connection.close();
+ return true;
+ } catch (URISyntaxException | JMSException ex) {
+ return false;
+ }
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java
index dde382e397..01e47342ae 100644
--- a/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java
+++ b/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java
@@ -169,7 +169,9 @@ final class RemoteEventPublisher {
if (object instanceof AutopsyEvent) {
AutopsyEvent event = (AutopsyEvent) object;
event.setSourceType(AutopsyEvent.SourceType.REMOTE);
- localPublisher.publish(event);
+ new Thread(() -> {
+ localPublisher.publish(event);
+ }).start();
}
}
} catch (Exception ex) {
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
index cfea3bd790..9cf8cdc91c 100755
--- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
@@ -103,3 +103,5 @@ IngestJobSettingsPanel.jButtonSelectAll.text=Select All
IngestJobSettingsPanel.jButtonDeselectAll.text=Deselect All
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
+IngestManager.cancellingIngest.msgDlg.text=Cancelling all currently running ingest jobs
+IngestManager.serviceIsDown.msgDlg.text={0} is down
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java
index 3ee3267d8a..68d8863b17 100644
--- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java
+++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -44,6 +45,7 @@ import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.core.ServicesMonitor;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -150,6 +152,12 @@ public class IngestManager {
* is the default.
*/
private volatile boolean runInteractively;
+
+ /**
+ * Ingest manager subscribes to service outage notifications. If key services are down,
+ * ingest manager cancels all ingest jobs in progress.
+ */
+ private final ServicesMonitor servicesMonitor;
/**
* Ingest job events.
@@ -264,6 +272,9 @@ public class IngestManager {
this.nextThreadId = new AtomicLong(0L);
this.jobsById = new ConcurrentHashMap<>();
this.ingestJobStarters = new ConcurrentHashMap<>();
+
+ this.servicesMonitor = ServicesMonitor.getInstance();
+ subscribeToServiceMonitorEvents();
this.startDataSourceIngestThread();
@@ -313,6 +324,56 @@ public class IngestManager {
}
});
}
+
+ /**
+ * Subscribe ingest manager to service monitor events. Cancels ingest
+ * if one of services it's subscribed to goes down.
+ */
+ private void subscribeToServiceMonitorEvents() {
+ PropertyChangeListener propChangeListener = new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getNewValue().equals(ServicesMonitor.ServiceStatus.DOWN.toString())) {
+
+ // check whether a milti-user case is currently being processed
+ try {
+ if (!Case.isCaseOpen() || Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) {
+ return;
+ }
+ } catch (IllegalStateException ignore) {
+ // thorown by Case.getCurrentCase() when no case is open
+ return;
+ }
+
+ // one of the services we subscribed to went down
+ String serviceDisplayName = ServicesMonitor.Service.valueOf(evt.getPropertyName()).getDisplayName();
+ logger.log(Level.SEVERE, "Service {0} is down! Cancelling all running ingest jobs", serviceDisplayName); //NON-NLS
+
+ // display notification if running interactively
+ if (isIngestRunning() && isRunningInteractively()) {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(), "IngestManager.cancellingIngest.msgDlg.text"),
+ NbBundle.getMessage(this.getClass(), "IngestManager.serviceIsDown.msgDlg.text", serviceDisplayName),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ }
+
+ // cancel ingest if running
+ cancelAllIngestJobs();
+ }
+ }
+ };
+
+ // subscribe to services of interest
+ Set servicesList = new HashSet<>();
+ servicesList.add(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString());
+ servicesList.add(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString());
+ this.servicesMonitor.addSubscriber(servicesList, propChangeListener);
+ }
synchronized void handleCaseOpened() {
this.jobCreationIsEnabled = true;
@@ -361,6 +422,7 @@ public class IngestManager {
* The ingest manager can be directed to forgo use of message boxes, the
* ingest message box, NetBeans progress handles, etc. Running interactively
* is the default.
+ * @return true if running interactively, false otherwise.
*/
public boolean isRunningInteractively() {
return this.runInteractively;
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
index c047e67009..2f492f46a2 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
@@ -53,9 +53,13 @@ public class SolrSearchService implements KeywordSearchService {
if (artifactId > 0)
return;
- Case currentCase = Case.getCurrentCase();
- if (currentCase == null)
+ Case currentCase;
+ try {
+ currentCase = Case.getCurrentCase();
+ } catch (IllegalStateException ignore) {
+ // thorown by Case.getCurrentCase() if currentCase is null
return;
+ }
SleuthkitCase sleuthkitCase = currentCase.getSleuthkitCase();
if (sleuthkitCase == null)
@@ -153,6 +157,9 @@ public class SolrSearchService implements KeywordSearchService {
try {
String host = UserPreferences.getIndexingServerHost();
String port = UserPreferences.getIndexingServerPort();
+ if (host.isEmpty() || port.isEmpty()){
+ return false;
+ }
HttpSolrServer solrServer = new HttpSolrServer("http://" + host + ":" + port + "/solr"); //NON-NLS;
KeywordSearch.getServer().connectToSolrServer(solrServer);
}
diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties
index 54a8353a13..84e42eab37 100644
--- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties
+++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties
@@ -1,5 +1,5 @@
#Updated by build script
-#Thu, 25 Jun 2015 13:09:21 -0400
+#Thu, 23 Jul 2015 09:29:40 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538
@@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
SplashRunningTextColor=0x0
SplashRunningTextFontSize=19
-currentVersion=Autopsy 3.1.2
+currentVersion=Autopsy 3.1.3
diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties
index 3b8f688ddc..122b976d9e 100644
--- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties
+++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties
@@ -1,5 +1,5 @@
#Updated by build script
-#Thu, 25 Jun 2015 13:09:21 -0400
+#Thu, 23 Jul 2015 09:29:40 -0400
-CTL_MainWindow_Title=Autopsy 3.1.2
-CTL_MainWindow_Title_No_Project=Autopsy 3.1.2
+CTL_MainWindow_Title=Autopsy 3.1.3
+CTL_MainWindow_Title_No_Project=Autopsy 3.1.3