Merge branch 'collaborative' of github.com:sleuthkit/autopsy into directory_tree_refresh_work

This commit is contained in:
esaunders 2015-07-24 13:46:09 -04:00
commit f32a70cdad
44 changed files with 2574 additions and 667 deletions

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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();
}
/**

View File

@ -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();
}
}
}

View File

@ -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.

View File

@ -0,0 +1,5 @@
package org.sleuthkit.autopsy.casemodule;
public interface ConversionDoneCallback {
void conversionDoneCallback(boolean result);
}

View File

@ -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"/>

View File

@ -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.
*

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View 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);
}
}
}

View File

@ -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;
}

View 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;
}
}

View File

@ -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=

View File

@ -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();
}
});
}

View File

@ -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() {

View File

@ -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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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>

View File

@ -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;

View 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;
}
}

View 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;
}
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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());
}
}
}
}

View File

@ -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).

View File

@ -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:

View File

@ -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);
}