mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 19:14:55 +00:00
Merge branch 'collaborative' of github.com:sleuthkit/autopsy into directory_tree_refresh_work
This commit is contained in:
commit
f32a70cdad
@ -188,6 +188,7 @@
|
||||
<package>org.sleuthkit.autopsy.casemodule.services</package>
|
||||
<package>org.sleuthkit.autopsy.contentviewers</package>
|
||||
<package>org.sleuthkit.autopsy.core</package>
|
||||
<package>org.sleuthkit.autopsy.core.events</package>
|
||||
<package>org.sleuthkit.autopsy.corecomponentinterfaces</package>
|
||||
<package>org.sleuthkit.autopsy.corecomponents</package>
|
||||
<package>org.sleuthkit.autopsy.coreutils</package>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<ContentTag> 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<ContentTag> 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
// get the selected DSProcessor
|
||||
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
|
||||
|
||||
Case.getCurrentCase().notifyAddingNewDataSource(dataSourceId);
|
||||
new Thread(() -> {
|
||||
Case.getCurrentCase().notifyAddingNewDataSource(dataSourceId);
|
||||
}).start();
|
||||
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback () {
|
||||
@Override
|
||||
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
|
||||
@ -258,8 +260,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
* Cancels the data source processing - in case the users presses 'Cancel'
|
||||
*/
|
||||
private void cancelDataSourceProcessing(UUID dataSourceId) {
|
||||
Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
|
||||
dsProcessor.cancel();
|
||||
new Thread(() -> {
|
||||
Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
|
||||
}).start();
|
||||
dsProcessor.cancel();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -307,11 +311,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
newContents.addAll(contents);
|
||||
|
||||
//notify the UI of the new content added to the case
|
||||
if (!newContents.isEmpty()) {
|
||||
Case.getCurrentCase().notifyNewDataSource(newContents.get(0), dataSourceId);
|
||||
} else {
|
||||
Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
|
||||
}
|
||||
new Thread(() -> {
|
||||
if (!newContents.isEmpty()) {
|
||||
Case.getCurrentCase().notifyNewDataSource(newContents.get(0), dataSourceId);
|
||||
} else {
|
||||
Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
// Start ingest if we can
|
||||
|
@ -192,7 +192,7 @@ MissingImageDialog.confDlg.noFileSel.title=Missing Image
|
||||
MissingImageDialog.ErrorSettingImage=Error setting image path. Please try again.
|
||||
NewCaseVisualPanel1.getName.text=Case Info
|
||||
NewCaseVisualPanel1.caseDirBrowse.selectButton.text=Select
|
||||
NewCaseVisualPanel1.badCredentials.text=Bad multi-user settings. See Tools, Options, Multi-user.
|
||||
NewCaseVisualPanel1.badCredentials.text=Bad multi-user settings (see Tools, Options, Multi-user) or services are down.
|
||||
NewCaseVisualPanel1.MultiUserDisabled.text=Multi-user cases not enabled. See Tools, Options, Multi-user.
|
||||
NewCaseVisualPanel2.getName.text=Additional Information
|
||||
NewCaseWizardAction.closeCurCase.confMsg.msg=Do you want to save and close this case and proceed with the new case creation?
|
||||
@ -242,13 +242,18 @@ 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!
|
||||
CaseConverter.FinishedConverting=Finished converting
|
||||
CaseConverter.To= to
|
||||
CaseConverter.BadCaseSourceFolder=Case source folder does not exist!
|
||||
CaseConverter.BadImageSourceFolder=Image source folder does not exist!
|
||||
CaseConverter.BadDatabaseFileName=Database file does not exist!
|
||||
CaseConverter.NonUniqueOutputFolder=Output folder not unique. Skipping
|
||||
CaseConverter.NonUniqueDatabaseName=Database name not unique. Skipping.
|
||||
CaseConverter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead.
|
||||
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
|
||||
|
@ -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;
|
||||
@ -60,6 +61,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEventException;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
||||
@ -328,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 {
|
||||
/**
|
||||
@ -460,7 +464,7 @@ public class Case {
|
||||
*
|
||||
* @return the sanitized case name to use for Database, Solr, and ActiveMQ
|
||||
*/
|
||||
private static String sanitizeCaseName(String caseName) {
|
||||
public static String sanitizeCaseName(String caseName) {
|
||||
|
||||
String result;
|
||||
|
||||
@ -523,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,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
|
||||
@ -657,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.
|
||||
*/
|
||||
@ -667,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
|
||||
@ -679,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
|
||||
*/
|
||||
@ -688,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
|
||||
*/
|
||||
@ -697,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
|
||||
*/
|
||||
@ -705,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
|
||||
*/
|
||||
@ -774,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
|
||||
@ -784,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);
|
||||
}
|
||||
@ -794,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
|
||||
@ -810,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
|
||||
@ -1016,7 +1050,7 @@ public class Case {
|
||||
public String getModuleOutputDirectoryRelativePath() {
|
||||
Path thePath;
|
||||
if (getCaseType() == CaseType.MULTI_USER_CASE) {
|
||||
thePath = Paths.get(getLocalHostName(), MODULE_FOLDER);
|
||||
thePath = Paths.get(NetworkUtils.getLocalHostName(), MODULE_FOLDER);
|
||||
} else {
|
||||
thePath = Paths.get(MODULE_FOLDER);
|
||||
}
|
||||
@ -1029,7 +1063,7 @@ public class Case {
|
||||
* Get the host output directory path where modules should save their
|
||||
* permanent data. If single-user case, the directory is a subdirectory of
|
||||
* the case directory. If multi-user case, the directory is a subdirectory
|
||||
* of HostName, which is a subdirectory of the case directory.
|
||||
* of the hostName, which is a subdirectory of the case directory.
|
||||
*
|
||||
* @return the path to the host output directory
|
||||
*/
|
||||
@ -1037,7 +1071,7 @@ public class Case {
|
||||
String caseDirectory = getCaseDirectory();
|
||||
Path hostPath;
|
||||
if (caseType == CaseType.MULTI_USER_CASE) {
|
||||
hostPath = Paths.get(caseDirectory, getLocalHostName());
|
||||
hostPath = Paths.get(caseDirectory, NetworkUtils.getLocalHostName());
|
||||
} else {
|
||||
hostPath = Paths.get(caseDirectory);
|
||||
}
|
||||
@ -1353,7 +1387,7 @@ public class Case {
|
||||
String hostClause = "";
|
||||
|
||||
if (caseType == CaseType.MULTI_USER_CASE) {
|
||||
hostClause = File.separator + getLocalHostName();
|
||||
hostClause = File.separator + NetworkUtils.getLocalHostName();
|
||||
}
|
||||
result = result && (new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
|
||||
&& (new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
|
||||
@ -1467,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();
|
||||
@ -1568,27 +1619,5 @@ public class Case {
|
||||
return hasData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host name variable. Sometimes the network can be finicky, so the
|
||||
* answer returned by getHostName() could throw an exception or be null.
|
||||
* Have it read the environment variable if getHostName() is unsuccessful.
|
||||
* Also note that some calls into the Case class are static via Case.*, so
|
||||
* anywhere we use HOSTNAME prior to a Case class being instantiated, we
|
||||
* must call getLocalHostName() first.
|
||||
*/
|
||||
private static String getLocalHostName() {
|
||||
if (HostName == null || HostName.isEmpty()) {
|
||||
try {
|
||||
HostName = java.net.InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException ex) {
|
||||
// getLocalHost().getHostName() can fail in some situations.
|
||||
// Use environment variable if so.
|
||||
HostName = System.getenv("COMPUTERNAME");
|
||||
}
|
||||
if (HostName == null || HostName.isEmpty()) {
|
||||
HostName = System.getenv("COMPUTERNAME");
|
||||
}
|
||||
}
|
||||
return HostName;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Void, Void>() {
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,45 +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<String> 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;
|
||||
@ -95,7 +84,7 @@ final class CollaborationMonitor {
|
||||
* Get the local host name so it can be used to identify the source of
|
||||
* collaboration tasks broadcast by this node.
|
||||
*/
|
||||
hostName = getHostName();
|
||||
hostName = NetworkUtils.getLocalHostName();
|
||||
|
||||
/**
|
||||
* Create an event publisher that will be used to communicate with
|
||||
@ -129,30 +118,10 @@ final class CollaborationMonitor {
|
||||
*
|
||||
* 1. Send heartbeats to collaboration monitors on other nodes.<br>
|
||||
* 2. Check for stale remote tasks.<br>
|
||||
* 3. Check the availability of key collaboration services.<br>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the name of the local host for use in describing local tasks.
|
||||
*
|
||||
* @return The host name of this Autopsy node.
|
||||
*/
|
||||
private static String getHostName() {
|
||||
String name;
|
||||
try {
|
||||
name = java.net.InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException notUsed) {
|
||||
name = System.getenv("COMPUTERNAME");
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
name = "Collaborator";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -514,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.
|
||||
|
@ -0,0 +1,5 @@
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
public interface ConversionDoneCallback {
|
||||
void conversionDoneCallback(boolean result);
|
||||
}
|
@ -29,13 +29,9 @@
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="caseDirTextField" alignment="0" max="32767" attributes="1"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="0" pref="58" max="32767" attributes="0"/>
|
||||
<Component id="lbBadMultiUserSettings" min="-2" pref="372" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="227" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="caseDirLabel" min="-2" max="-2" attributes="0"/>
|
||||
@ -47,6 +43,7 @@
|
||||
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
|
||||
<Component id="caseNameTextField" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="lbBadMultiUserSettings" alignment="1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="caseDirBrowseButton" min="-2" max="-2" attributes="0"/>
|
||||
|
@ -50,27 +50,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
this.wizPanel = wizPanel;
|
||||
caseNameTextField.getDocument().addDocumentListener(this);
|
||||
caseParentDirTextField.getDocument().addDocumentListener(this);
|
||||
CaseDbConnectionInfo info = UserPreferences.getDatabaseConnectionInfo();
|
||||
if (info.getDbType() == DbType.SQLITE) {
|
||||
rbSingleUserCase.setSelected(true);
|
||||
rbSingleUserCase.setEnabled(false);
|
||||
rbMultiUserCase.setEnabled(false);
|
||||
lbBadMultiUserSettings.setForeground(new java.awt.Color(153, 153, 153)); // Gray
|
||||
lbBadMultiUserSettings.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.MultiUserDisabled.text"));
|
||||
} else {
|
||||
rbSingleUserCase.setEnabled(true);
|
||||
rbMultiUserCase.setEnabled(true);
|
||||
if (true == info.canConnect()) {
|
||||
rbMultiUserCase.setSelected(true); // default to multi-user if available
|
||||
} else {
|
||||
// if we cannot connect to the shared database, don't present the option
|
||||
lbBadMultiUserSettings.setForeground(new java.awt.Color(255, 0, 0)); // Red
|
||||
lbBadMultiUserSettings.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.badCredentials.text"));
|
||||
rbSingleUserCase.setSelected(true);
|
||||
rbSingleUserCase.setEnabled(false);
|
||||
rbMultiUserCase.setEnabled(false);
|
||||
}
|
||||
}
|
||||
rbMultiUserCase.setSelected(true); // default to multi-user if available
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,12 +188,9 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 58, Short.MAX_VALUE)
|
||||
.addComponent(lbBadMultiUserSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addGap(0, 227, Short.MAX_VALUE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addComponent(caseDirLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
@ -221,7 +198,8 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(caseNameLabel)
|
||||
.addGap(26, 26, 26)
|
||||
.addComponent(caseNameTextField)))
|
||||
.addComponent(caseNameTextField))
|
||||
.addComponent(lbBadMultiUserSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(caseDirBrowseButton)))
|
||||
.addContainerGap())
|
||||
@ -324,6 +302,11 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
this.wizPanel.fireChangeEvent();
|
||||
/*
|
||||
NOTE: verifyMultiUserSettings() is called from here as opposed to updateUI()
|
||||
because updateUI() is called several times when this wizard is loaded.
|
||||
*/
|
||||
verifyMultiUserSettings();
|
||||
updateUI(e);
|
||||
}
|
||||
|
||||
@ -378,6 +361,40 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
warnIfPathIsInvalid(parentDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests multi-user settings by verifying connectivity to all required
|
||||
* multi-user services.
|
||||
*/
|
||||
private void verifyMultiUserSettings(){
|
||||
CaseDbConnectionInfo info = UserPreferences.getDatabaseConnectionInfo();
|
||||
if (info.getDbType() == DbType.SQLITE) {
|
||||
rbSingleUserCase.setSelected(true);
|
||||
rbSingleUserCase.setEnabled(false);
|
||||
rbMultiUserCase.setEnabled(false);
|
||||
lbBadMultiUserSettings.setForeground(new java.awt.Color(153, 153, 153)); // Gray
|
||||
lbBadMultiUserSettings.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.MultiUserDisabled.text"));
|
||||
} else {
|
||||
rbSingleUserCase.setEnabled(true);
|
||||
rbMultiUserCase.setEnabled(true);
|
||||
// multi-user cases must have multi-user database service running
|
||||
if (info.canConnect()) {
|
||||
/* NOTE: natural way would be to call lbBadMultiUserSettings.setVisible(false)
|
||||
but if you do that Netbeans for some reason resizes the entire panel so it
|
||||
becomes much narrower horizontally.
|
||||
*/
|
||||
lbBadMultiUserSettings.setText("");
|
||||
} else {
|
||||
// if we cannot connect to the shared database, don't present the option
|
||||
lbBadMultiUserSettings.setForeground(new java.awt.Color(255, 0, 0)); // Red
|
||||
lbBadMultiUserSettings.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.badCredentials.text"));
|
||||
lbBadMultiUserSettings.setVisible(true);
|
||||
rbSingleUserCase.setSelected(true);
|
||||
rbSingleUserCase.setEnabled(false);
|
||||
rbMultiUserCase.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates path to selected case output folder. Displays warning if path is invalid.
|
||||
*
|
||||
|
@ -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<Void, Void>() {
|
||||
|
||||
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
|
||||
|
@ -171,33 +171,12 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
|
||||
*/
|
||||
@Override
|
||||
public void storeSettings(WizardDescriptor settings) {
|
||||
NewCaseVisualPanel2 currentComponent = getComponent();
|
||||
settings.putProperty("caseNumber", currentComponent.getCaseNumber());
|
||||
settings.putProperty("caseExaminer", currentComponent.getExaminer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws WizardValidationException {
|
||||
|
||||
NewCaseVisualPanel2 currentComponent = getComponent();
|
||||
final String caseNumber = currentComponent.getCaseNumber();
|
||||
final String examiner = currentComponent.getExaminer();
|
||||
try {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Case.create(createdDirectory, caseName, caseNumber, examiner, caseType);
|
||||
} catch (Exception ex) {
|
||||
JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(),
|
||||
"CaseCreateAction.msgDlg.cantCreateCase.msg")+" "+caseName,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"CaseOpenAction.msgDlg.cantOpenCase.title"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
throw new WizardValidationException(this.getComponent(),
|
||||
NbBundle.getMessage(this.getClass(), "NewCaseWizardPanel2.validate.errCreateCase.msg"), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,12 @@ import java.awt.EventQueue;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import org.openide.util.NbBundle;
|
||||
@ -187,8 +190,8 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
|
||||
logger.log(Level.INFO, "No Case paths exist, cannot open the case"); //NON-NLS
|
||||
return;
|
||||
}
|
||||
String casePath = casePaths[imagesTable.getSelectedRow()];
|
||||
String caseName = caseNames[imagesTable.getSelectedRow()];
|
||||
final String casePath = casePaths[imagesTable.getSelectedRow()];
|
||||
final String caseName = caseNames[imagesTable.getSelectedRow()];
|
||||
if (!casePath.equals("")) {
|
||||
// Close the startup menu
|
||||
try {
|
||||
@ -198,34 +201,39 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
|
||||
logger.log(Level.WARNING, "Error: couldn't open case: " + caseName, ex); //NON-NLS
|
||||
}
|
||||
// Open the recent cases
|
||||
try {
|
||||
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg",
|
||||
caseName),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"OpenRecentCasePanel.openCase.msgDlg.err"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
|
||||
|
||||
//if case is not opened, open the start window
|
||||
if (Case.isCaseOpen() == false) {
|
||||
StartupWindowProvider.getInstance().open();
|
||||
}
|
||||
|
||||
} else {
|
||||
Case.open(casePath); // open the case
|
||||
}
|
||||
} catch (CaseActionException ex) {
|
||||
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg",
|
||||
caseName),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"OpenRecentCasePanel.openCase.msgDlg.err"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
|
||||
|
||||
//if case is not opened, open the start window
|
||||
if (Case.isCaseOpen() == false) {
|
||||
StartupWindowProvider.getInstance().open();
|
||||
}
|
||||
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,7 +45,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @author jantonius
|
||||
*/
|
||||
class XMLCaseManagement implements CaseConfigFileInterface {
|
||||
class XMLCaseManagement implements CaseConfigFileInterface {
|
||||
|
||||
final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS
|
||||
final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS
|
||||
@ -98,7 +98,7 @@ import org.xml.sax.SAXException;
|
||||
/**
|
||||
* The constructor
|
||||
*/
|
||||
XMLCaseManagement() {
|
||||
public XMLCaseManagement() {
|
||||
autopsySavedVersion = System.getProperty("netbeans.buildnumber");
|
||||
}
|
||||
|
||||
@ -153,6 +153,22 @@ import org.xml.sax.SAXException;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the created date on the XML configuration file. This method is for
|
||||
* preserving the created date when converting a case from single-user to
|
||||
* multi-user.
|
||||
*
|
||||
* @param createdDate the date the case was originally created
|
||||
* @throws org.sleuthkit.autopsy.casemodule.CaseActionException
|
||||
*/
|
||||
public void setCreatedDate(String createdDate) throws CaseActionException {
|
||||
String newDate = dateFormat.format(new Date());
|
||||
Element rootEl = getRootElement();
|
||||
rootEl.getElementsByTagName(CREATED_DATE_NAME).item(0).setTextContent(createdDate);
|
||||
rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate);
|
||||
writeFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the examiner on the XML configuration file
|
||||
*
|
||||
@ -369,7 +385,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @return createdDate the creation date of this case
|
||||
*/
|
||||
protected String getCreatedDate() {
|
||||
public String getCreatedDate() {
|
||||
if (doc != null) {
|
||||
Element crDateElement = (Element) getRootElement().getElementsByTagName(CREATED_DATE_NAME).item(0);
|
||||
return crDateElement.getTextContent();
|
||||
@ -533,7 +549,7 @@ import org.xml.sax.SAXException;
|
||||
* a Postgre db name.
|
||||
* @param textIndexName The name of the index where extracted text is stored.
|
||||
*/
|
||||
protected void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException {
|
||||
public void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException {
|
||||
clear(); // clear the previous data
|
||||
|
||||
// set the case Name and Directory and the parent directory
|
||||
|
@ -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
|
389
Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java
Normal file
389
Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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<String> 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<String, String> 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"));
|
||||
}
|
||||
|
||||
// if request is for one of our "core" services - perform an on demand check
|
||||
// to make sure we have the latest status.
|
||||
if (servicesList.contains(service)){
|
||||
checkServiceStatus(service);
|
||||
}
|
||||
|
||||
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<String> 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<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -109,7 +109,7 @@ public final class UserPreferences {
|
||||
public static CaseDbConnectionInfo getDatabaseConnectionInfo() {
|
||||
DbType dbType;
|
||||
try {
|
||||
dbType = DbType.valueOf(preferences.get(EXTERNAL_DATABASE_TYPE, "UNKOWN"));
|
||||
dbType = DbType.valueOf(preferences.get(EXTERNAL_DATABASE_TYPE, "SQLITE"));
|
||||
} catch (Exception ex) {
|
||||
dbType = DbType.SQLITE;
|
||||
}
|
||||
|
49
Core/src/org/sleuthkit/autopsy/core/events/ServiceEvent.java
Normal file
49
Core/src/org/sleuthkit/autopsy/core/events/ServiceEvent.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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;
|
||||
}
|
||||
}
|
@ -150,7 +150,6 @@ FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk
|
||||
OptionsCategory_Name_Multi_User_Settings=Multi-user
|
||||
OptionsCategory_Keywords_Multi_User_Options=Multi-user Options
|
||||
MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings
|
||||
MultiUserSettingsPanel.lbOops.text=
|
||||
MultiUserSettingsPanel.tbPassword.toolTipText=Password
|
||||
MultiUserSettingsPanel.tbPassword.text=
|
||||
MultiUserSettingsPanel.tbUsername.toolTipText=User Name
|
||||
@ -185,3 +184,4 @@ DataContentViewerHex.goToOffsetLabel.text=Jump to Offset
|
||||
DataContentViewerHex.goToOffsetTextField.text=
|
||||
DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset: {0}
|
||||
DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue=Cannot jump to the resultant offset
|
||||
MultiUserSettingsPanel.tbOops.text=
|
||||
|
@ -65,7 +65,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
private DataContent customContentViewer;
|
||||
private boolean isMain;
|
||||
private String title;
|
||||
private final DummyNodeListener dummyNodeListener = new DummyNodeListener();
|
||||
private final RootNodeListener rootNodeListener = new RootNodeListener();
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataResultPanel.class.getName() );
|
||||
private boolean listeningToTabbedPane = false;
|
||||
@ -369,7 +369,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
if (this.rootNode != null) {
|
||||
this.rootNode.removeNodeListener(dummyNodeListener);
|
||||
this.rootNode.removeNodeListener(rootNodeListener);
|
||||
}
|
||||
// Deferring becoming a listener to the tabbed pane until this point
|
||||
// eliminates handling a superfluous stateChanged event during construction.
|
||||
@ -380,8 +380,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
|
||||
this.rootNode = selectedNode;
|
||||
if (this.rootNode != null) {
|
||||
dummyNodeListener.reset();
|
||||
this.rootNode.addNodeListener(dummyNodeListener);
|
||||
rootNodeListener.reset();
|
||||
this.rootNode.addNodeListener(rootNodeListener);
|
||||
}
|
||||
|
||||
resetTabs(selectedNode);
|
||||
@ -620,28 +620,33 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyNodeListener implements NodeListener {
|
||||
private class RootNodeListener implements NodeListener {
|
||||
|
||||
private volatile boolean waitingForData = true;
|
||||
|
||||
private volatile boolean load = true;
|
||||
|
||||
public void reset() {
|
||||
load = true;
|
||||
waitingForData = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void childrenAdded(final NodeMemberEvent nme) {
|
||||
Node[] delta = nme.getDelta();
|
||||
if (load && containsReal(delta)) {
|
||||
load = false;
|
||||
updateMatches();
|
||||
|
||||
/* There is a known issue in this code whereby we will only
|
||||
call setupTabs() once even though childrenAdded could be
|
||||
called multiple times. That means that each panel may not
|
||||
have access to all of the children when they decide if they
|
||||
support the content */
|
||||
if (waitingForData && containsReal(delta)) {
|
||||
waitingForData = false;
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -36,8 +36,8 @@
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="cbEnableMultiUser" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="lbOops" min="-2" pref="314" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="tbOops" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="pnSolrSettings" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="pnDatabaseSettings" alignment="0" max="32767" attributes="0"/>
|
||||
@ -50,18 +50,17 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="cbEnableMultiUser" alignment="3" max="32767" attributes="0"/>
|
||||
<Component id="lbOops" alignment="3" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="2" attributes="0">
|
||||
<Component id="tbOops" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cbEnableMultiUser" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnDatabaseSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnSolrSettings" min="-2" pref="106" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnMessagingSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -126,9 +125,6 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbHostnameOrIp.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbHostnameOrIpActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbPortNumber">
|
||||
<Properties>
|
||||
@ -242,9 +238,6 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbIndexingServerHost.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbIndexingServerHostActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbIndexingServerPort">
|
||||
<Properties>
|
||||
@ -255,26 +248,9 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbIndexingServerPort.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbIndexingServerPortActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="lbOops">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="12" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="verticalAlignment" type="int" value="3"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="pnMessagingSettings">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
@ -396,6 +372,26 @@
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cbEnableMultiUserItemStateChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbOops">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="f0" green="f0" red="f0" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="12" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
@ -119,7 +119,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
lbSolrSettings = new javax.swing.JLabel();
|
||||
tbIndexingServerHost = new javax.swing.JTextField();
|
||||
tbIndexingServerPort = new javax.swing.JTextField();
|
||||
lbOops = new javax.swing.JLabel();
|
||||
pnMessagingSettings = new javax.swing.JPanel();
|
||||
lbMessagingSettings = new javax.swing.JLabel();
|
||||
msgHostTextField = new javax.swing.JTextField();
|
||||
@ -127,17 +126,13 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
msgPortTextField = new javax.swing.JTextField();
|
||||
msgPasswordField = new javax.swing.JPasswordField();
|
||||
cbEnableMultiUser = new javax.swing.JCheckBox();
|
||||
tbOops = new javax.swing.JTextField();
|
||||
|
||||
pnDatabaseSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
|
||||
tbHostnameOrIp.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
tbHostnameOrIp.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbHostnameOrIp.text")); // NOI18N
|
||||
tbHostnameOrIp.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbHostnameOrIp.toolTipText")); // NOI18N
|
||||
tbHostnameOrIp.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
tbHostnameOrIpActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
tbPortNumber.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
tbPortNumber.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbPortNumber.text")); // NOI18N
|
||||
@ -194,19 +189,9 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
tbIndexingServerHost.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
tbIndexingServerHost.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerHost.toolTipText")); // NOI18N
|
||||
tbIndexingServerHost.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
tbIndexingServerHostActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
tbIndexingServerPort.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
tbIndexingServerPort.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerPort.toolTipText")); // NOI18N
|
||||
tbIndexingServerPort.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
tbIndexingServerPortActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout pnSolrSettingsLayout = new javax.swing.GroupLayout(pnSolrSettings);
|
||||
pnSolrSettings.setLayout(pnSolrSettingsLayout);
|
||||
@ -234,11 +219,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
.addGap(45, 45, 45))
|
||||
);
|
||||
|
||||
lbOops.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
|
||||
lbOops.setForeground(new java.awt.Color(255, 0, 0));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbOops, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbOops.text")); // NOI18N
|
||||
lbOops.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM);
|
||||
|
||||
pnMessagingSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
|
||||
lbMessagingSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
@ -299,6 +279,13 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
tbOops.setEditable(false);
|
||||
tbOops.setBackground(new java.awt.Color(240, 240, 240));
|
||||
tbOops.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
|
||||
tbOops.setForeground(new java.awt.Color(255, 0, 0));
|
||||
tbOops.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbOops.text")); // NOI18N
|
||||
tbOops.setBorder(null);
|
||||
|
||||
javax.swing.GroupLayout pnOverallPanelLayout = new javax.swing.GroupLayout(pnOverallPanel);
|
||||
pnOverallPanel.setLayout(pnOverallPanelLayout);
|
||||
pnOverallPanelLayout.setHorizontalGroup(
|
||||
@ -308,8 +295,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
.addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addGroup(pnOverallPanelLayout.createSequentialGroup()
|
||||
.addComponent(cbEnableMultiUser)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(lbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 314, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(tbOops))
|
||||
.addComponent(pnSolrSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(pnDatabaseSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(pnMessagingSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
@ -318,17 +305,16 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
pnOverallPanelLayout.setVerticalGroup(
|
||||
pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnOverallPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cbEnableMultiUser, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(lbOops, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGap(16, 16, 16)
|
||||
.addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(cbEnableMultiUser))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnDatabaseSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnSolrSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnMessagingSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(35, 35, 35))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
@ -356,24 +342,12 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
private void cbEnableMultiUserItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cbEnableMultiUserItemStateChanged
|
||||
if (!cbEnableMultiUser.isSelected()) {
|
||||
lbOops.setText("");
|
||||
tbOops.setText("");
|
||||
}
|
||||
enableMultiUserComponents(textBoxes, cbEnableMultiUser.isSelected());
|
||||
controller.changed();
|
||||
}//GEN-LAST:event_cbEnableMultiUserItemStateChanged
|
||||
|
||||
private void tbHostnameOrIpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbHostnameOrIpActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_tbHostnameOrIpActionPerformed
|
||||
|
||||
private void tbIndexingServerHostActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbIndexingServerHostActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_tbIndexingServerHostActionPerformed
|
||||
|
||||
private void tbIndexingServerPortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbIndexingServerPortActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_tbIndexingServerPortActionPerformed
|
||||
|
||||
void load() {
|
||||
CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo();
|
||||
tbHostnameOrIp.setText(dbInfo.getHost().trim());
|
||||
@ -451,7 +425,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
* @return true if it's okay, false otherwise.
|
||||
*/
|
||||
boolean valid() {
|
||||
lbOops.setText("");
|
||||
tbOops.setText("");
|
||||
if (cbEnableMultiUser.isSelected()) {
|
||||
return settingsAreComplete() && databaseSettingsAreValid() && indexingServerSettingsAreValid() && messageServiceSettingsAreValid();
|
||||
} else {
|
||||
@ -473,7 +447,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
|| !messageServiceFieldsArePopulated()) {
|
||||
// We don't even have everything filled out
|
||||
result = false;
|
||||
lbOops.setText(INCOMPLETE_SETTINGS_MSG);
|
||||
tbOops.setText(INCOMPLETE_SETTINGS_MSG);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -487,7 +461,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
if (portNumberIsValid(tbPortNumber.getText())) {
|
||||
return true;
|
||||
} else {
|
||||
lbOops.setText(INVALID_DB_PORT_MSG);
|
||||
tbOops.setText(INVALID_DB_PORT_MSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -499,7 +473,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
boolean messageServiceSettingsAreValid() {
|
||||
if (!portNumberIsValid(msgPortTextField.getText())) {
|
||||
lbOops.setText(INVALID_MESSAGE_SERVICE_PORT_MSG);
|
||||
tbOops.setText(INVALID_MESSAGE_SERVICE_PORT_MSG);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -513,7 +487,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
boolean indexingServerSettingsAreValid() {
|
||||
if (!portNumberIsValid(tbIndexingServerPort.getText())) {
|
||||
lbOops.setText(INVALID_INDEXING_SERVER_PORT_MSG);
|
||||
tbOops.setText(INVALID_INDEXING_SERVER_PORT_MSG);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -543,7 +517,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
private javax.swing.JCheckBox cbEnableMultiUser;
|
||||
private javax.swing.JLabel lbDatabaseSettings;
|
||||
private javax.swing.JLabel lbMessagingSettings;
|
||||
private javax.swing.JLabel lbOops;
|
||||
private javax.swing.JLabel lbSolrSettings;
|
||||
private javax.swing.JTextField msgHostTextField;
|
||||
private javax.swing.JPasswordField msgPasswordField;
|
||||
@ -556,6 +529,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
private javax.swing.JTextField tbHostnameOrIp;
|
||||
private javax.swing.JTextField tbIndexingServerHost;
|
||||
private javax.swing.JTextField tbIndexingServerPort;
|
||||
private javax.swing.JTextField tbOops;
|
||||
private javax.swing.JPasswordField tbPassword;
|
||||
private javax.swing.JTextField tbPortNumber;
|
||||
private javax.swing.JTextField tbUsername;
|
||||
|
43
Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java
Normal file
43
Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.coreutils;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class NetworkUtils {
|
||||
/**
|
||||
* Set the host name variable. Sometimes the network can be finicky, so the
|
||||
* answer returned by getHostName() could throw an exception or be null.
|
||||
* Have it read the environment variable if getHostName() is unsuccessful.
|
||||
*/
|
||||
public static String getLocalHostName() {
|
||||
String hostName = "";
|
||||
try {
|
||||
hostName = java.net.InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException ex) {
|
||||
// getLocalHost().getHostName() can fail in some situations.
|
||||
// Use environment variable if so.
|
||||
hostName = System.getenv("COMPUTERNAME");
|
||||
}
|
||||
if (hostName == null || hostName.isEmpty()) {
|
||||
hostName = System.getenv("COMPUTERNAME");
|
||||
}
|
||||
return hostName;
|
||||
}
|
||||
}
|
53
Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java
Normal file
53
Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.coreutils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Class offers utility functions to identify and process time stamped folders.
|
||||
*/
|
||||
public final class TimeStampUtils {
|
||||
|
||||
// Pattern to identify whether case name contains a generated time stamp.
|
||||
// Sample case name with time stamp: Case 1_2015_02_02_12_10_31 for case "Case 1"
|
||||
private static final Pattern timeStampPattern = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$");
|
||||
private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp
|
||||
|
||||
/**
|
||||
* Checks whether a string ends with a time stamp defined by pattern.
|
||||
*
|
||||
* @param inputString Input string
|
||||
* @return true if string ends with a time stamp, false otherwise.
|
||||
*/
|
||||
public static boolean endsWithTimeStamp(String inputString) {
|
||||
Matcher m = timeStampPattern.matcher(inputString);
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns length of time stamp string.
|
||||
*
|
||||
* @return length of time stamp string.
|
||||
*/
|
||||
public static int getTimeStampLength() {
|
||||
return LENGTH_OF_DATE_TIME_STAMP;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.coreutils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
/*
|
||||
* Formatter to wrap another formatter and prepend a timestampe to each formatted string
|
||||
* Not currently used.
|
||||
*/
|
||||
class TimestampingFormatter extends Formatter {
|
||||
|
||||
Formatter original;
|
||||
DateFormat timestampFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US);
|
||||
String lineSeparator = System.getProperty("line.separator");
|
||||
|
||||
TimestampingFormatter(Formatter original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
long millis = record.getMillis();
|
||||
String timestamp = timestampFormat.format(new Date(millis));
|
||||
|
||||
return timestamp + lineSeparator + original.format(record);
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -386,9 +386,11 @@ final class DataSourceIngestJob {
|
||||
// errors are likely redundant.
|
||||
while (!this.fileIngestPipelinesQueue.isEmpty()) {
|
||||
pipeline = this.fileIngestPipelinesQueue.poll();
|
||||
List<IngestModuleError> shutDownErrors = pipeline.shutDown();
|
||||
if (!shutDownErrors.isEmpty()) {
|
||||
logIngestModuleErrors(shutDownErrors);
|
||||
if(pipeline.isRunning()){
|
||||
List<IngestModuleError> shutDownErrors = pipeline.shutDown();
|
||||
if (!shutDownErrors.isEmpty()) {
|
||||
logIngestModuleErrors(shutDownErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -565,7 +567,9 @@ final class DataSourceIngestJob {
|
||||
List<IngestModuleError> errors = new ArrayList<>();
|
||||
while (!this.fileIngestPipelinesQueue.isEmpty()) {
|
||||
FileIngestPipeline pipeline = fileIngestPipelinesQueue.poll();
|
||||
errors.addAll(pipeline.shutDown());
|
||||
if(pipeline.isRunning()){
|
||||
errors.addAll(pipeline.shutDown());
|
||||
}
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
logIngestModuleErrors(errors);
|
||||
|
@ -145,16 +145,18 @@ final class FileIngestPipeline {
|
||||
*/
|
||||
synchronized List<IngestModuleError> shutDown() {
|
||||
List<IngestModuleError> errors = new ArrayList<>();
|
||||
for (PipelineModule module : this.modules) {
|
||||
try {
|
||||
module.shutDown();
|
||||
} catch (Throwable ex) { // Catch-all exception firewall
|
||||
errors.add(new IngestModuleError(module.getDisplayName(), ex));
|
||||
String msg = ex.getMessage();
|
||||
// Jython run-time errors don't seem to have a message, but have details in toString.
|
||||
if (msg == null)
|
||||
msg = ex.toString();
|
||||
MessageNotifyUtil.Notify.error(module.getDisplayName() + " Error", msg);
|
||||
if(this.running == true){ // Don't shut down pipelines that never started
|
||||
for (PipelineModule module : this.modules) {
|
||||
try {
|
||||
module.shutDown();
|
||||
} catch (Throwable ex) { // Catch-all exception firewall
|
||||
errors.add(new IngestModuleError(module.getDisplayName(), ex));
|
||||
String msg = ex.getMessage();
|
||||
// Jython run-time errors don't seem to have a message, but have details in toString.
|
||||
if (msg == null)
|
||||
msg = ex.toString();
|
||||
MessageNotifyUtil.Notify.error(module.getDisplayName() + " Error", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.running = false;
|
||||
|
@ -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<String> 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;
|
||||
@ -468,6 +530,31 @@ public class IngestManager {
|
||||
if (runInteractively && jobsById.size() == 1) {
|
||||
clearIngestMessageBox();
|
||||
}
|
||||
|
||||
// multi-user cases must have multi-user database service running
|
||||
if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) {
|
||||
try {
|
||||
if (!servicesMonitor.getServiceStatus(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()).equals(ServicesMonitor.ServiceStatus.UP.toString())) {
|
||||
// display notification if running interactively
|
||||
if (isRunningInteractively()) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String serviceDisplayName = ServicesMonitor.Service.REMOTE_CASE_DATABASE.getDisplayName();
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(), "IngestManager.cancellingIngest.msgDlg.text"),
|
||||
NbBundle.getMessage(this.getClass(), "IngestManager.serviceIsDown.msgDlg.text", serviceDisplayName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
});
|
||||
}
|
||||
// abort ingest
|
||||
return false;
|
||||
}
|
||||
} catch (ServicesMonitor.ServicesMonitorException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ingestMonitor.isRunning()) {
|
||||
ingestMonitor.start();
|
||||
|
@ -126,11 +126,13 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
|
||||
*/
|
||||
@Override
|
||||
public void shutDown() {
|
||||
if (refCounter.decrementAndGet(this.context.getJobId()) == 0) {
|
||||
// Shutting down the last instance of this module for this ingest
|
||||
// job, so discard the interesting file sets definitions snapshot
|
||||
// for the job.
|
||||
FilesIdentifierIngestModule.interestingFileSetsByJob.remove(this.context.getJobId());
|
||||
if(context != null){
|
||||
if (refCounter.decrementAndGet(this.context.getJobId()) == 0) {
|
||||
// Shutting down the last instance of this module for this ingest
|
||||
// job, so discard the interesting file sets definitions snapshot
|
||||
// for the job.
|
||||
FilesIdentifierIngestModule.interestingFileSetsByJob.remove(this.context.getJobId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ KeywordSearchFilterNode.getFileActions.openExternViewActLbl=Open in External Vie
|
||||
KeywordSearchFilterNode.getFileActions.searchSameMd5=Search for files with the same MD5 hash
|
||||
KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl=View in New Window
|
||||
KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly initialized, cannot run keyword search ingest.
|
||||
KeywordSearchIngestModule.init.verifyConnection=Please verify credentials and connectivity to multi-user keyword search service.
|
||||
KeywordSearchIngestModule.init.tryStopSolrMsg={0}<br />Please try stopping old java Solr process (if it exists) and restart the application.
|
||||
KeywordSearchIngestModule.init.noKwInLstMsg=No keywords in keyword list.
|
||||
KeywordSearchIngestModule.init.onlyIdxKwSkipMsg=Only indexing will be done and and keyword search will be skipped (you can still add keyword lists using the Keyword Lists - Add to Ingest).
|
||||
|
@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
|
||||
@ -35,6 +36,7 @@ import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
|
||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -141,46 +143,59 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
// increment the module reference count
|
||||
// if first instance of this module for this job then check the server and existence of keywords
|
||||
if (refCounter.incrementAndGet(jobId) == 1) {
|
||||
final Server server = KeywordSearch.getServer();
|
||||
try {
|
||||
if (!server.isRunning()) {
|
||||
if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) {
|
||||
// for multi-user cases need to verify connection to remore SOLR server
|
||||
KeywordSearchService kwsService = new SolrSearchService();
|
||||
if (!kwsService.canConnectToRemoteSolrServer()) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
|
||||
logger.log(Level.SEVERE, msg);
|
||||
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.verifyConnection");
|
||||
services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), msg, details));
|
||||
throw new IngestModuleException(msg);
|
||||
}
|
||||
} else {
|
||||
// for single-user cases need to verify connection to local SOLR service
|
||||
final Server server = KeywordSearch.getServer();
|
||||
try {
|
||||
if (!server.isRunning()) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
|
||||
logger.log(Level.SEVERE, msg);
|
||||
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
|
||||
services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), msg, details));
|
||||
throw new IngestModuleException(msg);
|
||||
}
|
||||
} catch (KeywordSearchModuleException ex) {
|
||||
logger.log(Level.WARNING, "Error checking if Solr server is running while initializing ingest", ex); //NON-NLS
|
||||
//this means Solr is not properly initialized
|
||||
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
|
||||
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
|
||||
services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), msg, details));
|
||||
throw new IngestModuleException(msg);
|
||||
}
|
||||
} catch (KeywordSearchModuleException ex) {
|
||||
logger.log(Level.WARNING, "Error checking if Solr server is running while initializing ingest", ex); //NON-NLS
|
||||
//this means Solr is not properly initialized
|
||||
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
|
||||
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
|
||||
services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), msg, details));
|
||||
throw new IngestModuleException(msg);
|
||||
}
|
||||
try {
|
||||
try {
|
||||
// make an actual query to verify that server is responding
|
||||
// we had cases where getStatus was OK, but the connection resulted in a 404
|
||||
server.queryNumIndexedDocuments();
|
||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||
throw new IngestModuleException(
|
||||
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.exception.errConnToSolr.msg",
|
||||
ex.getMessage()));
|
||||
}
|
||||
// we had cases where getStatus was OK, but the connection resulted in a 404
|
||||
server.queryNumIndexedDocuments();
|
||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||
throw new IngestModuleException(
|
||||
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.exception.errConnToSolr.msg",
|
||||
ex.getMessage()));
|
||||
}
|
||||
|
||||
// check if this job has any searchable keywords
|
||||
List<KeywordList> keywordLists = XmlKeywordSearchList.getCurrent().getListsL();
|
||||
boolean hasKeywordsForSearch = false;
|
||||
for (KeywordList keywordList : keywordLists) {
|
||||
if (settings.keywordListIsEnabled(keywordList.getName()) && !keywordList.getKeywords().isEmpty()) {
|
||||
hasKeywordsForSearch = true;
|
||||
break;
|
||||
// check if this job has any searchable keywords
|
||||
List<KeywordList> keywordLists = XmlKeywordSearchList.getCurrent().getListsL();
|
||||
boolean hasKeywordsForSearch = false;
|
||||
for (KeywordList keywordList : keywordLists) {
|
||||
if (settings.keywordListIsEnabled(keywordList.getName()) && !keywordList.getKeywords().isEmpty()) {
|
||||
hasKeywordsForSearch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasKeywordsForSearch) {
|
||||
services.postMessage(IngestMessage.createWarningMessage(KeywordSearchModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.noKwInLstMsg"),
|
||||
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.onlyIdxKwSkipMsg")));
|
||||
}
|
||||
}
|
||||
if (!hasKeywordsForSearch) {
|
||||
services.postMessage(IngestMessage.createWarningMessage(KeywordSearchModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.noKwInLstMsg"),
|
||||
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.onlyIdxKwSkipMsg")));
|
||||
}
|
||||
}
|
||||
|
||||
//initialize extractors
|
||||
@ -245,7 +260,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
public void shutDown() {
|
||||
logger.log(Level.INFO, "Instance {0}", instanceNum); //NON-NLS
|
||||
|
||||
if (initialized == false) {
|
||||
if ((initialized == false) || (context == null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -314,6 +329,9 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
|
||||
synchronized(ingestStatus) {
|
||||
Map<Long, IngestStatus> ingestStatusForJob = ingestStatus.get(jobId);
|
||||
if(ingestStatusForJob == null){
|
||||
return;
|
||||
}
|
||||
for (IngestStatus s : ingestStatusForJob.values()) {
|
||||
switch (s) {
|
||||
case TEXT_INGESTED:
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user