Merge remote-tracking branch 'upstream/develop' into 3973_DisableDataSourceSearch
@ -64,13 +64,14 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
||||
*
|
||||
* @param oldArtifactTag tag to be replaced
|
||||
* @param newTagName name of the tag to replace with
|
||||
* @param comment the comment for the tag use an empty string for no comment
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"# {0} - old tag name",
|
||||
"# {1} - artifactID",
|
||||
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
||||
@Override
|
||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName) {
|
||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String comment) {
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
@ -90,7 +91,7 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
||||
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldArtifactTag.getName().getDisplayName(), newTagName.getDisplayName(), oldArtifactTag.getContent().getName()}); //NON-NLS
|
||||
|
||||
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName);
|
||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, comment);
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||
|
@ -64,7 +64,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
||||
"# {1} - content obj id",
|
||||
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
||||
@Override
|
||||
protected void replaceTag(ContentTag oldTag, TagName newTagName) {
|
||||
protected void replaceTag(ContentTag oldTag, TagName newTagName, String comment) {
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
@ -84,7 +84,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
||||
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
|
||||
|
||||
tagsManager.deleteContentTag(oldTag);
|
||||
tagsManager.addContentTag(oldTag.getContent(), newTagName);
|
||||
tagsManager.addContentTag(oldTag.getContent(), newTagName, comment);
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||
|
@ -77,10 +77,11 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
/**
|
||||
* Method to actually replace the selected tag with the given new tag
|
||||
*
|
||||
* @param oldTag
|
||||
* @param newTagName
|
||||
* @param oldTag - the TagName which is being removed from the item
|
||||
* @param newTagName - the TagName which is being added to the itme
|
||||
* @param comment the comment associated with the tag, empty string for no comment
|
||||
*/
|
||||
abstract protected void replaceTag(T oldTag, TagName newTagName);
|
||||
abstract protected void replaceTag(T oldTag, TagName newTagName, String comment);
|
||||
|
||||
/**
|
||||
* Returns elected tags which are to be replaced
|
||||
@ -140,7 +141,7 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
// Add action to replace the tag
|
||||
tagNameItem.addActionListener((ActionEvent event) -> {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, entry.getValue());
|
||||
replaceTag(oldtag, entry.getValue(), "");
|
||||
});
|
||||
});
|
||||
|
||||
@ -177,12 +178,24 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
TagName newTagName = GetTagNameDialog.doDialog();
|
||||
if (null != newTagName) {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, newTagName);
|
||||
replaceTag(oldtag, newTagName, "");
|
||||
});
|
||||
}
|
||||
});
|
||||
add(newTagMenuItem);
|
||||
|
||||
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
|
||||
// a dialog that can be used to create or select a tag name with an
|
||||
// optional comment and adds a tag with the resulting name.
|
||||
JMenuItem tagAndCommentItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment"));
|
||||
tagAndCommentItem.addActionListener((ActionEvent event) -> {
|
||||
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
|
||||
if (null != tagNameAndComment) {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, tagNameAndComment.getTagName(), tagNameAndComment.getComment());
|
||||
});
|
||||
}
|
||||
});
|
||||
add(tagAndCommentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import javax.swing.Box.Filler;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
@ -172,6 +173,9 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
||||
constraints.weighty = 1;
|
||||
gridBagLayout.setConstraints(vertGlue, constraints);
|
||||
jPanel1.setLayout(gridBagLayout);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
jScrollPane1.getVerticalScrollBar().setValue(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,7 @@ import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -1004,8 +1004,8 @@ abstract class AbstractSqlEamDb implements EamDb {
|
||||
bulkArtifacts.get(type.getDbTableName()).clear();
|
||||
}
|
||||
|
||||
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
|
||||
// Reset state
|
||||
bulkArtifactsCount = 0;
|
||||
|
@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
|
||||
/**
|
||||
@ -135,9 +135,9 @@ final class IngestModule implements FileIngestModule {
|
||||
*/
|
||||
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
|
||||
try {
|
||||
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
|
||||
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
if (!caseDisplayNamesList.isEmpty()) {
|
||||
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ CommonFilesPanel.selectedFileCategoriesButton.text=Match on the following file c
|
||||
CommonFilesPanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
|
||||
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
|
||||
CommonFilesPanel.documentsCheckbox.text=Documents
|
||||
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find duplicate files in the current case.</html>
|
||||
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
|
||||
CommonFilesPanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
|
||||
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
|
||||
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
||||
|
@ -104,12 +104,15 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
||||
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
|
||||
|
||||
boolean multipleDataSources = this.caseHasMultipleSources();
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(multipleDataSources);
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(multipleDataSources);
|
||||
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(true);
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(true);
|
||||
|
||||
if (!multipleDataSources) {
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(true);
|
||||
withinDataSourceSelected(true);
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setEnabled(false);
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(false);
|
||||
withinDataSourceSelected(false);
|
||||
CommonFilesPanel.this.selectDataSourceComboBox.setEnabled(false);
|
||||
}
|
||||
|
||||
CommonFilesPanel.this.searchButton.setEnabled(true);
|
||||
@ -120,7 +123,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
private boolean caseHasMultipleSources() {
|
||||
return CommonFilesPanel.this.dataSourceMap.size() >= 2;
|
||||
return CommonFilesPanel.this.dataSourceMap.size() >= 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,11 +19,14 @@
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.Installer;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Encapsulates a menu action which triggers the common files search dialog.
|
||||
@ -32,6 +35,7 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
||||
|
||||
private static CommonFilesSearchAction instance = null;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(CommonFilesSearchAction.class.getName());
|
||||
|
||||
CommonFilesSearchAction() {
|
||||
super();
|
||||
@ -40,7 +44,13 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(){
|
||||
return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited();
|
||||
boolean shouldBeEnabled = false;
|
||||
try {
|
||||
shouldBeEnabled = Case.isCaseOpen() && Case.getCurrentCase().getDataSources().size() > 1;
|
||||
} catch(TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
|
||||
}
|
||||
return super.isEnabled() && shouldBeEnabled;
|
||||
}
|
||||
|
||||
public static synchronized CommonFilesSearchAction getDefault() {
|
||||
|
@ -38,24 +38,27 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
||||
|
||||
private static final Map<String, Integer> COLUMN_WIDTHS;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
static {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_matchColLbl(), 235);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 150);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), 300);
|
||||
|
||||
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CommonFilesSearchResultsViewerTable.matchColLbl=Match",
|
||||
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
||||
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
|
||||
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
||||
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
||||
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source",
|
||||
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source(s)",
|
||||
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
||||
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
||||
})
|
||||
@ -68,7 +71,7 @@ public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
||||
|
||||
TableColumn column = columnsEnumerator.nextElement();
|
||||
|
||||
final Object headerValue = column.getHeaderValue();
|
||||
final String headerValue = column.getHeaderValue().toString();
|
||||
final Integer get = COLUMN_WIDTHS.get(headerValue);
|
||||
|
||||
column.setPreferredWidth(get);
|
||||
|
@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
@ -30,7 +28,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
* Used by the Common Files search feature to encapsulate instances of a given
|
||||
* MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||
*/
|
||||
public class FileInstanceNode extends FileNode {
|
||||
|
||||
@ -46,6 +44,8 @@ public class FileInstanceNode extends FileNode {
|
||||
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
||||
super(fsContent);
|
||||
this.dataSource = dataSource;
|
||||
|
||||
this.setDisplayName(fsContent.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,64 +73,16 @@ public class FileInstanceNode extends FileNode {
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
fillPropertyMap(map, this);
|
||||
|
||||
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
|
||||
for (CommonFilePropertyType propType : CommonFilePropertyType.values()) {
|
||||
final String propString = propType.toString();
|
||||
final Object property = map.get(propString);
|
||||
final NodeProperty<Object> nodeProperty = new NodeProperty<>(propString, propString, NO_DESCR, property);
|
||||
sheetSet.put(nodeProperty);
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent())));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
|
||||
|
||||
this.addTagProperty(sheetSet);
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill map with AbstractFile properties
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values are
|
||||
* put
|
||||
* @param node The item to get properties for.
|
||||
*/
|
||||
static private void fillPropertyMap(Map<String, Object> map, FileInstanceNode node) {
|
||||
|
||||
map.put(CommonFilePropertyType.ParentPath.toString(), node.getContent().getParentPath());
|
||||
map.put(CommonFilePropertyType.HashsetHits.toString(), getHashSetHitsForFile(node.getContent()));
|
||||
map.put(CommonFilePropertyType.DataSource.toString(), node.getDataSource());
|
||||
map.put(CommonFilePropertyType.MimeType.toString(), StringUtils.defaultString(node.getContent().getMIMEType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the columns to be displayed for reach row represented by an
|
||||
* instance of this object.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"CommonFilePropertyType.pathColLbl=Parent Path",
|
||||
"CommonFilePropertyType.hashsetHitsColLbl=Hash Set Hits",
|
||||
"CommonFilePropertyType.dataSourceColLbl=Data Source",
|
||||
"CommonFilePropertyType.caseColLbl=Case",
|
||||
"CommonFilePropertyType.mimeTypeColLbl=MIME Type"
|
||||
})
|
||||
public enum CommonFilePropertyType {
|
||||
|
||||
ParentPath(Bundle.CommonFilePropertyType_pathColLbl()),
|
||||
HashsetHits(Bundle.CommonFilePropertyType_hashsetHitsColLbl()),
|
||||
DataSource(Bundle.CommonFilePropertyType_dataSourceColLbl()),
|
||||
MimeType(Bundle.CommonFilePropertyType_mimeTypeColLbl());
|
||||
|
||||
final private String displayString;
|
||||
|
||||
private CommonFilePropertyType(String displayString) {
|
||||
this.displayString = displayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ package org.sleuthkit.autopsy.commonfilesearch;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
@ -50,7 +49,7 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
||||
* @param md5Metadata
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"InstanceCountNode.displayName=Matches with %s instances"
|
||||
"InstanceCountNode.displayName=Files with %s instances (%s)"
|
||||
})
|
||||
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
|
||||
super(Children.create(new Md5NodeFactory(md5Metadata), true));
|
||||
@ -58,7 +57,8 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
||||
this.instanceCount = instanceCount;
|
||||
this.metadataList = md5Metadata;
|
||||
|
||||
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount)));
|
||||
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,50 +102,12 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
fillPropertyMap(map, this);
|
||||
|
||||
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
|
||||
for (InstanceCountNode.InstanceCountNodePropertyType propType : InstanceCountNode.InstanceCountNodePropertyType.values()) {
|
||||
final String propString = propType.toString();
|
||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill map with AbstractFile properties
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values are
|
||||
* put
|
||||
* @param node The item to get properties for.
|
||||
*/
|
||||
static private void fillPropertyMap(Map<String, Object> map, InstanceCountNode node) {
|
||||
map.put(InstanceCountNodePropertyType.Match.toString(), node.getInstanceCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields which will appear in the tree table.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"InstanceCountNodePropertyType.matchCountColLbl1=Match"
|
||||
})
|
||||
public enum InstanceCountNodePropertyType{
|
||||
|
||||
Match(Bundle.InstanceCountNodePropertyType_matchCountColLbl1());
|
||||
|
||||
final private String displayString;
|
||||
|
||||
private InstanceCountNodePropertyType(String displayName){
|
||||
this.displayString = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.displayString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ChildFactory which builds CommonFileParentNodes from the
|
||||
|
@ -19,9 +19,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
@ -52,6 +50,9 @@ public class Md5Node extends DisplayableItemNode {
|
||||
private final int commonFileCount;
|
||||
private final String dataSources;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"Md5Node.Md5Node.format=MD5: %s"
|
||||
})
|
||||
/**
|
||||
* Create a Match node whose children will all have this object in common.
|
||||
* @param data the common feature, and the children
|
||||
@ -64,7 +65,8 @@ public class Md5Node extends DisplayableItemNode {
|
||||
this.dataSources = String.join(", ", data.getDataSources());
|
||||
this.md5Hash = data.getMd5();
|
||||
|
||||
this.setDisplayName(this.md5Hash);
|
||||
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.md5Hash));
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,29 +103,15 @@ public class Md5Node extends DisplayableItemNode {
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
fillPropertyMap(map, this);
|
||||
|
||||
final String NO_DESCR = Bundle.Md5Node_createSheet_noDescription();
|
||||
for (Md5Node.CommonFileParentPropertyType propType : Md5Node.CommonFileParentPropertyType.values()) {
|
||||
final String propString = propType.toString();
|
||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
||||
}
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSources()));
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill map with AbstractFile properties
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values are
|
||||
* put
|
||||
* @param node The item to get properties for.
|
||||
*/
|
||||
static private void fillPropertyMap(Map<String, Object> map, Md5Node node) {
|
||||
//map.put(CommonFileParentPropertyType.Case.toString(), "");
|
||||
map.put(CommonFileParentPropertyType.DataSource.toString(), node.getDataSources());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
@ -172,24 +160,4 @@ public class Md5Node extends DisplayableItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CommonFileParentPropertyType.fileColLbl=File",
|
||||
"CommonFileParentPropertyType.instanceColLbl=Instance Count",
|
||||
"CommonFileParentPropertyType.caseColLbl=Case",
|
||||
"CommonFileParentPropertyType.dataSourceColLbl=Data Source"})
|
||||
public enum CommonFileParentPropertyType {
|
||||
|
||||
DataSource(Bundle.CommonFileParentPropertyType_dataSourceColLbl());
|
||||
|
||||
final private String displayString;
|
||||
|
||||
private CommonFileParentPropertyType(String displayString) {
|
||||
this.displayString = displayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.displayString;
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
* but the initial method was needed only be viewers in
|
||||
* corecomponents and therefore can stay out of public API.
|
||||
*/
|
||||
class DataContentViewerUtility {
|
||||
public class DataContentViewerUtility {
|
||||
/**
|
||||
* Returns the first non-Blackboard Artifact from a Node.
|
||||
* Needed for (at least) Hex and Strings that want to view
|
||||
@ -39,7 +39,7 @@ class DataContentViewerUtility {
|
||||
* @param node Node passed into content viewer
|
||||
* @return highest priority content or null if there is no content
|
||||
*/
|
||||
static Content getDefaultContent(Node node) {
|
||||
public static Content getDefaultContent(Node node) {
|
||||
Content bbContentSeen = null;
|
||||
for (Content content : (node).getLookup().lookupAll(Content.class)) {
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
|
@ -54,7 +54,6 @@ DataModelActionsFactory.srcFileInDir.text=View Source File in Directory
|
||||
DataModelActionsFactory.fileInDir.text=View File in Directory
|
||||
DataModelActionsFactory.viewNewWin.text=View in New Window
|
||||
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
|
||||
DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash
|
||||
DataSourcesNode.name=Data Sources
|
||||
DataSourcesNode.group_by_datasource.name=Data Source Files
|
||||
DataSourcesNode.createSheet.name.name=Name
|
||||
|
@ -55,7 +55,6 @@ DataModelActionsFactory.srcFileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u
|
||||
DataModelActionsFactory.fileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u5185\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8868\u793a
|
||||
DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6\u306b\u8868\u793a
|
||||
DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a
|
||||
DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22
|
||||
DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
||||
DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||
DataSourcesNode.createSheet.name.name=\u540d\u524d
|
||||
|
@ -38,7 +38,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -76,8 +75,6 @@ public class DataModelActionsFactory {
|
||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.viewNewWin.text");
|
||||
public static final String OPEN_IN_EXTERNAL_VIEWER = NbBundle
|
||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.openExtViewer.text");
|
||||
public static final String SEARCH_FOR_FILES_SAME_MD5 = NbBundle
|
||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
|
||||
|
||||
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
@ -88,7 +85,6 @@ public class DataModelActionsFactory {
|
||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
@ -367,7 +363,6 @@ public class DataModelActionsFactory {
|
||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
@ -404,7 +399,6 @@ public class DataModelActionsFactory {
|
||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
|
@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||
@ -166,7 +165,6 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
actionsList.add(null); // Creates an item separator
|
||||
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
|
||||
actionsList.add(null); // Creates an item separator
|
||||
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||
@ -107,8 +106,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
actionsList.add(null); // creates a menu separator
|
||||
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction(
|
||||
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
|
||||
|
@ -401,10 +401,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
}
|
||||
Content c = ban.getLookup().lookup(File.class);
|
||||
Node n = null;
|
||||
boolean md5Action = false;
|
||||
if (c != null) {
|
||||
n = new FileNode((AbstractFile) c);
|
||||
md5Action = true;
|
||||
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
|
||||
n = new DirectoryNode((Directory) c);
|
||||
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
||||
@ -438,10 +436,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
if (md5Action) {
|
||||
actionsList.add(new HashSearchAction(
|
||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
|
||||
}
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
|
@ -18,11 +18,10 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="backButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="65" max="32767" attributes="0"/>
|
||||
<Component id="forwardButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="51" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
@ -43,14 +42,14 @@
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="forwardButton" max="32767" attributes="1"/>
|
||||
<Component id="backButton" min="-2" max="-2" attributes="1"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="treeView" pref="838" max="32767" attributes="0"/>
|
||||
<Component id="treeView" pref="843" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -72,7 +71,7 @@
|
||||
<Component class="javax.swing.JButton" name="backButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.backButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -80,7 +79,7 @@
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"/>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 0, 2, 0]"/>
|
||||
@ -92,10 +91,10 @@
|
||||
<Dimension value="[5, 5]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
<Dimension value="[32, 32]"/>
|
||||
</Property>
|
||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -105,7 +104,7 @@
|
||||
<Component class="javax.swing.JButton" name="forwardButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.forwardButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -113,7 +112,7 @@
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"/>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 0, 2, 0]"/>
|
||||
@ -125,10 +124,10 @@
|
||||
<Dimension value="[5, 5]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
<Dimension value="[32, 32]"/>
|
||||
</Property>
|
||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
|
@ -184,32 +184,32 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
treeView.setBorder(null);
|
||||
|
||||
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
|
||||
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
|
||||
backButton.setBorderPainted(false);
|
||||
backButton.setContentAreaFilled(false);
|
||||
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
|
||||
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"))); // NOI18N
|
||||
backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||
backButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||
backButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||
backButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
||||
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N
|
||||
backButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"))); // NOI18N
|
||||
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
backButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
|
||||
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
|
||||
forwardButton.setBorderPainted(false);
|
||||
forwardButton.setContentAreaFilled(false);
|
||||
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
|
||||
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"))); // NOI18N
|
||||
forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||
forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||
forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||
forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
||||
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N
|
||||
forwardButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"))); // NOI18N
|
||||
forwardButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
forwardButtonActionPerformed(evt);
|
||||
@ -231,11 +231,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(treeView)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 51, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(showRejectedCheckBox)
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
@ -252,11 +251,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 843, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@ -800,10 +799,23 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the directory tree
|
||||
* Rebuilds the autopsy tree.
|
||||
*
|
||||
* Does nothing if there is no open case.
|
||||
*/
|
||||
private void rebuildTree() {
|
||||
|
||||
// if no open case or has no data then there is no tree to rebuild
|
||||
Case currentCase;
|
||||
try {
|
||||
currentCase = Case.getCurrentCaseThrows();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
return;
|
||||
}
|
||||
if (null == currentCase || currentCase.hasData() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// refresh all children of the root.
|
||||
autopsyTreeChildrenFactory.refreshChildren();
|
||||
|
||||
|
@ -1,52 +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.directorytree;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbSearchAction;
|
||||
|
||||
/**
|
||||
* Action to lookup the interface and call the real action in HashDatabase. The
|
||||
* real action, HashDbSearchAction, implements HashSearchProvider, and should be
|
||||
* the only instance of it.
|
||||
*
|
||||
* //TODO: HashDBSearchAction needs a public constructor and a service
|
||||
* registration annotation for the lookup technique to work
|
||||
*/
|
||||
@Immutable
|
||||
public class HashSearchAction extends AbstractAction {
|
||||
|
||||
private final Node contentNode;
|
||||
|
||||
public HashSearchAction(String title, Node contentNode) {
|
||||
super(title);
|
||||
this.contentNode = contentNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//HashSearchProvider searcher = Lookup.getDefault().lookup(HashSearchProvider.class);
|
||||
//TODO: HashDBSearchAction needs a public constructor and a service registration annotation for the above technique to work
|
||||
HashDbSearchAction searcher = HashDbSearchAction.getDefault();
|
||||
searcher.search(contentNode);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -53,34 +53,32 @@ import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
|
||||
/**
|
||||
* Class for recording data on the health of the system.
|
||||
*
|
||||
* For timing data:
|
||||
* Modules will call getTimingMetric() before the code to be timed to get a TimingMetric object
|
||||
* Modules will call submitTimingMetric() with the obtained TimingMetric object to log it
|
||||
* For timing data: Modules will call getTimingMetric() before the code to be
|
||||
* timed to get a TimingMetric object Modules will call submitTimingMetric()
|
||||
* with the obtained TimingMetric object to log it
|
||||
*/
|
||||
public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
public final class HealthMonitor implements PropertyChangeListener {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(EnterpriseHealthMonitor.class.getName());
|
||||
private final static String DATABASE_NAME = "EnterpriseHealthMonitor";
|
||||
private final static Logger logger = Logger.getLogger(HealthMonitor.class.getName());
|
||||
private final static String DATABASE_NAME = "HealthMonitor";
|
||||
private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes
|
||||
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
|
||||
= new CaseDbSchemaVersionNumber(1, 1);
|
||||
private final static CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 1);
|
||||
|
||||
private static final AtomicBoolean isEnabled = new AtomicBoolean(false);
|
||||
private static EnterpriseHealthMonitor instance;
|
||||
private final static AtomicBoolean isEnabled = new AtomicBoolean(false);
|
||||
private static HealthMonitor instance;
|
||||
|
||||
private ScheduledThreadPoolExecutor healthMonitorOutputTimer;
|
||||
private final Map<String, TimingInfo> timingInfoMap;
|
||||
private final List<UserData> userInfoList;
|
||||
private static final int CONN_POOL_SIZE = 10;
|
||||
private final static int CONN_POOL_SIZE = 10;
|
||||
private BasicDataSource connectionPool = null;
|
||||
private CaseDbConnectionInfo connectionSettingsInUse = null;
|
||||
private String hostName;
|
||||
|
||||
private EnterpriseHealthMonitor() throws HealthMonitorException {
|
||||
private HealthMonitor() throws HealthMonitorException {
|
||||
|
||||
// Create the map to collect timing metrics. The map will exist regardless
|
||||
// of whether the monitor is enabled.
|
||||
@ -107,22 +105,25 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance of the EnterpriseHealthMonitor
|
||||
* Get the instance of the HealthMonitor
|
||||
*
|
||||
* @return the instance
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
synchronized static EnterpriseHealthMonitor getInstance() throws HealthMonitorException {
|
||||
synchronized static HealthMonitor getInstance() throws HealthMonitorException {
|
||||
if (instance == null) {
|
||||
instance = new EnterpriseHealthMonitor();
|
||||
instance = new HealthMonitor();
|
||||
Case.addPropertyChangeListener(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the health monitor.
|
||||
* Creates/initialized the database (if needed), clears any existing metrics
|
||||
* out of the maps, and sets up the timer for writing to the database.
|
||||
* Activate the health monitor. Creates/initialized the database (if
|
||||
* needed), clears any existing metrics out of the maps, and sets up the
|
||||
* timer for writing to the database.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private synchronized void activateMonitorLocally() throws HealthMonitorException {
|
||||
@ -187,14 +188,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
|
||||
|
||||
// Add the user_data table
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
|
||||
"id SERIAL PRIMARY KEY," +
|
||||
"host text NOT NULL," +
|
||||
"timestamp bigint NOT NULL," +
|
||||
"event_type int NOT NULL," +
|
||||
"is_examiner boolean NOT NULL," +
|
||||
"case_name text NOT NULL" +
|
||||
")");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("
|
||||
+ "id SERIAL PRIMARY KEY,"
|
||||
+ "host text NOT NULL,"
|
||||
+ "timestamp bigint NOT NULL,"
|
||||
+ "event_type int NOT NULL,"
|
||||
+ "is_examiner boolean NOT NULL,"
|
||||
+ "case_name text NOT NULL"
|
||||
+ ")");
|
||||
}
|
||||
|
||||
// Update the schema version
|
||||
@ -220,10 +221,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate the health monitor.
|
||||
* This should only be used when disabling the monitor, not when Autopsy is closing.
|
||||
* Clears out any metrics that haven't been written, stops the database write timer,
|
||||
* and shuts down the connection pool.
|
||||
* Deactivate the health monitor. This should only be used when disabling
|
||||
* the monitor, not when Autopsy is closing. Clears out any metrics that
|
||||
* haven't been written, stops the database write timer, and shuts down the
|
||||
* connection pool.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private synchronized void deactivateMonitorLocally() throws HealthMonitorException {
|
||||
@ -238,7 +240,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ScheduledThreadPoolExecutor that will handle the database writes.
|
||||
* Start the ScheduledThreadPoolExecutor that will handle the database
|
||||
* writes.
|
||||
*/
|
||||
private synchronized void startTimer() {
|
||||
// Make sure the previous executor (if it exists) has been stopped
|
||||
@ -258,7 +261,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the installer to set up the Health Monitor instance at startup.
|
||||
* Called from the installer to set up the Health Monitor instance at
|
||||
* startup.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
static synchronized void startUpIfEnabled() throws HealthMonitorException {
|
||||
@ -266,8 +271,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the application is closing.
|
||||
* Create a log off event and write all existing metrics to the database
|
||||
* Called when the application is closing. Create a log off event and write
|
||||
* all existing metrics to the database
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
static synchronized void shutdown() throws HealthMonitorException {
|
||||
@ -277,7 +283,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Enabled/disable the health monitor.
|
||||
*
|
||||
* @param enabled true to enable the monitor, false to disable it
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
static synchronized void setEnabled(boolean enabled) throws HealthMonitorException {
|
||||
@ -304,12 +312,13 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get a metric that will measure the time to execute a section of code.
|
||||
* Call this before the section of code to be timed and then
|
||||
* submit it afterward using submitTimingMetric().
|
||||
* This method is safe to call regardless of whether the Enterprise Health
|
||||
* Monitor is enabled.
|
||||
* Call this before the section of code to be timed and then submit it
|
||||
* afterward using submitTimingMetric(). This method is safe to call
|
||||
* regardless of whether the health monitor is enabled.
|
||||
*
|
||||
* @param name A short but descriptive name describing the code being timed.
|
||||
* This name will appear in the UI.
|
||||
*
|
||||
* @return The TimingMetric object
|
||||
*/
|
||||
public static TimingMetric getTimingMetric(String name) {
|
||||
@ -321,9 +330,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Submit the metric that was previously obtained through getTimingMetric().
|
||||
* Call this immediately after the section of code being timed.
|
||||
* This method is safe to call regardless of whether the Enterprise Health
|
||||
* Monitor is enabled.
|
||||
* Call this immediately after the section of code being timed. This method
|
||||
* is safe to call regardless of whether the health monitor is enabled.
|
||||
*
|
||||
* @param metric The TimingMetric object obtained from getTimingMetric()
|
||||
*/
|
||||
public static void submitTimingMetric(TimingMetric metric) {
|
||||
@ -340,12 +349,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Submit the metric that was previously obtained through getTimingMetric(),
|
||||
* incorporating a count that the time should be divided by.
|
||||
* Call this immediately after the section of code being timed.
|
||||
* This method is safe to call regardless of whether the Enterprise Health
|
||||
* Monitor is enabled.
|
||||
* @param metric The TimingMetric object obtained from getTimingMetric()
|
||||
* @param normalization The number to divide the time by (a zero here will be treated as a one)
|
||||
* incorporating a count that the time should be divided by. Call this
|
||||
* immediately after the section of code being timed. This method is safe to
|
||||
* call regardless of whether the health monitor is enabled.
|
||||
*
|
||||
* @param metric The TimingMetric object obtained from
|
||||
* getTimingMetric()
|
||||
* @param normalization The number to divide the time by (a zero here will
|
||||
* be treated as a one)
|
||||
*/
|
||||
public static void submitNormalizedTimingMetric(TimingMetric metric, long normalization) {
|
||||
if (isEnabled.get() && (metric != null)) {
|
||||
@ -362,7 +373,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Add the timing metric data to the map.
|
||||
* @param metric The metric to add. stopTiming() should already have been called.
|
||||
*
|
||||
* @param metric The metric to add. stopTiming() should already have been
|
||||
* called.
|
||||
*/
|
||||
private void addTimingMetric(TimingMetric metric) throws HealthMonitorException {
|
||||
|
||||
@ -385,6 +398,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Add a user event to the list.
|
||||
*
|
||||
* @param eventType
|
||||
*/
|
||||
private void addUserEvent(UserEvent eventType) {
|
||||
@ -395,18 +409,18 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Time a database query.
|
||||
* Database queries are hard to test in normal processing because the time
|
||||
* is so dependent on the size of the tables being queried. We use getImages here
|
||||
* because every table it queries is the same size (one entry for each image) so
|
||||
* we a) know the size of the tables and b) can use that table size to do
|
||||
* normalization.
|
||||
* Time a database query. Database queries are hard to test in normal
|
||||
* processing because the time is so dependent on the size of the tables
|
||||
* being queried. We use getImages here because every table it queries is
|
||||
* the same size (one entry for each image) so we a) know the size of the
|
||||
* tables and b) can use that table size to do normalization.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void performDatabaseQuery() throws HealthMonitorException {
|
||||
try {
|
||||
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Database: getImages query");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Database: getImages query");
|
||||
List<Image> images = skCase.getImages();
|
||||
|
||||
// Through testing we found that this normalization gives us fairly
|
||||
@ -422,7 +436,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
normalization += 7;
|
||||
}
|
||||
|
||||
EnterpriseHealthMonitor.submitNormalizedTimingMetric(metric, normalization);
|
||||
HealthMonitor.submitNormalizedTimingMetric(metric, normalization);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
// If there's no case open, we just can't do the metrics.
|
||||
} catch (TskCoreException ex) {
|
||||
@ -432,6 +446,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Collect metrics at a scheduled time.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void gatherTimerBasedMetrics() throws HealthMonitorException {
|
||||
@ -440,6 +455,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Write the collected metrics to the database.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void writeCurrentStateToDatabase() throws HealthMonitorException {
|
||||
@ -525,9 +541,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the health monitor database exists.
|
||||
* Does not check the schema.
|
||||
* Check whether the health monitor database exists. Does not check the
|
||||
* schema.
|
||||
*
|
||||
* @return true if the database exists, false otherwise
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private boolean databaseExists() throws HealthMonitorException {
|
||||
@ -556,6 +574,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Create a new health monitor database.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void createDatabase() throws HealthMonitorException {
|
||||
@ -576,6 +595,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Setup a connection pool for db connections.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void setupConnectionPool() throws HealthMonitorException {
|
||||
@ -609,6 +629,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Shut down the connection pool
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void shutdownConnections() throws HealthMonitorException {
|
||||
@ -625,9 +646,10 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a database connection.
|
||||
* Sets up the connection pool if needed.
|
||||
* Get a database connection. Sets up the connection pool if needed.
|
||||
*
|
||||
* @return The Connection object
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private Connection connect() throws HealthMonitorException {
|
||||
@ -645,9 +667,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the database schema has been initialized.
|
||||
* We do this by looking for the version number.
|
||||
* Test whether the database schema has been initialized. We do this by
|
||||
* looking for the version number.
|
||||
*
|
||||
* @return True if it has been initialized, false otherwise.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private boolean databaseIsInitialized() throws HealthMonitorException {
|
||||
@ -680,8 +704,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the health monitor is locally enabled.
|
||||
* This does not query the database.
|
||||
* Return whether the health monitor is locally enabled. This does not query
|
||||
* the database.
|
||||
*
|
||||
* @return true if it is enabled, false otherwise
|
||||
*/
|
||||
static boolean monitorIsEnabled() {
|
||||
@ -689,8 +714,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether monitoring should be enabled from the monitor database
|
||||
* and enable/disable as needed.
|
||||
* Check whether monitoring should be enabled from the monitor database and
|
||||
* enable/disable as needed.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
synchronized void updateFromGlobalEnabledStatus() throws HealthMonitorException {
|
||||
@ -747,9 +773,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the enabled status from the database.
|
||||
* Check that the health monitor database exists before calling this.
|
||||
* Read the enabled status from the database. Check that the health monitor
|
||||
* database exists before calling this.
|
||||
*
|
||||
* @return true if the database is enabled, false otherwise
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private boolean getGlobalEnabledStatusFromDB() throws HealthMonitorException {
|
||||
@ -769,6 +797,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Set the global enabled status in the database.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void setGlobalEnabledStatusInDB(boolean status) throws HealthMonitorException {
|
||||
@ -783,7 +812,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the current schema version
|
||||
*
|
||||
* @return the current schema version
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private CaseDbSchemaVersionNumber getVersion() throws HealthMonitorException {
|
||||
@ -837,6 +868,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Initialize the database.
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private void initializeDatabaseSchema() throws HealthMonitorException {
|
||||
@ -848,32 +880,31 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
try (Statement statement = conn.createStatement()) {
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS timing_data (" +
|
||||
"id SERIAL PRIMARY KEY," +
|
||||
"name text NOT NULL," +
|
||||
"host text NOT NULL," +
|
||||
"timestamp bigint NOT NULL," +
|
||||
"count bigint NOT NULL," +
|
||||
"average double precision NOT NULL," +
|
||||
"max double precision NOT NULL," +
|
||||
"min double precision NOT NULL" +
|
||||
")");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS timing_data ("
|
||||
+ "id SERIAL PRIMARY KEY,"
|
||||
+ "name text NOT NULL,"
|
||||
+ "host text NOT NULL,"
|
||||
+ "timestamp bigint NOT NULL,"
|
||||
+ "count bigint NOT NULL,"
|
||||
+ "average double precision NOT NULL,"
|
||||
+ "max double precision NOT NULL,"
|
||||
+ "min double precision NOT NULL"
|
||||
+ ")");
|
||||
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS db_info (" +
|
||||
"id SERIAL PRIMARY KEY NOT NULL," +
|
||||
"name text NOT NULL," +
|
||||
"value text NOT NULL" +
|
||||
")");
|
||||
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
|
||||
"id SERIAL PRIMARY KEY," +
|
||||
"host text NOT NULL," +
|
||||
"timestamp bigint NOT NULL," +
|
||||
"event_type int NOT NULL," +
|
||||
"is_examiner BOOLEAN NOT NULL," +
|
||||
"case_name text NOT NULL" +
|
||||
")");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS db_info ("
|
||||
+ "id SERIAL PRIMARY KEY NOT NULL,"
|
||||
+ "name text NOT NULL,"
|
||||
+ "value text NOT NULL"
|
||||
+ ")");
|
||||
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("
|
||||
+ "id SERIAL PRIMARY KEY,"
|
||||
+ "host text NOT NULL,"
|
||||
+ "timestamp bigint NOT NULL,"
|
||||
+ "event_type int NOT NULL,"
|
||||
+ "is_examiner BOOLEAN NOT NULL,"
|
||||
+ "case_name text NOT NULL"
|
||||
+ ")");
|
||||
|
||||
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')");
|
||||
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')");
|
||||
@ -897,8 +928,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* The task called by the ScheduledThreadPoolExecutor to handle
|
||||
* the periodic database update
|
||||
* The task called by the ScheduledThreadPoolExecutor to handle the periodic
|
||||
* database update
|
||||
*/
|
||||
static final class PeriodicHealthMonitorTask implements Runnable {
|
||||
|
||||
@ -909,11 +940,10 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform all periodic tasks:
|
||||
* - Check if monitoring has been enabled / disabled in the database
|
||||
* - Gather any additional metrics
|
||||
* - Write current metric data to the database
|
||||
* Do not run this from a new thread if the case/application is closing.
|
||||
* Perform all periodic tasks: - Check if monitoring has been enabled /
|
||||
* disabled in the database - Gather any additional metrics - Write current
|
||||
* metric data to the database Do not run this from a new thread if the
|
||||
* case/application is closing.
|
||||
*/
|
||||
private static void recordMetrics() {
|
||||
try {
|
||||
@ -946,9 +976,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging method to generate sample data for the database.
|
||||
* It will delete all current timing data and replace it with randomly generated values.
|
||||
* If there is more than one node, the second node's times will trend upwards.
|
||||
* Debugging method to generate sample data for the database. It will delete
|
||||
* all current timing data and replace it with randomly generated values. If
|
||||
* there is more than one node, the second node's times will trend upwards.
|
||||
*/
|
||||
void populateDatabaseWithSampleData(int nDays, int nNodes, boolean createVerificationData) throws HealthMonitorException {
|
||||
|
||||
@ -986,8 +1016,6 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Add timing metrics to the database
|
||||
String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
|
||||
@ -1062,7 +1090,6 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
aveTime = day * 1000000;
|
||||
}
|
||||
|
||||
|
||||
statement.setString(1, metricName);
|
||||
statement.setString(2, host);
|
||||
statement.setLong(3, timestamp);
|
||||
@ -1096,8 +1123,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get timing metrics currently stored in the database.
|
||||
*
|
||||
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
||||
*
|
||||
* @return A map with metric name mapped to a list of data
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
Map<String, List<DatabaseTimingResult>> getTimingMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
||||
@ -1156,8 +1186,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get user metrics currently stored in the database.
|
||||
*
|
||||
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
||||
*
|
||||
* @return A list of user metrics
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
List<UserData> getUserMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
||||
@ -1196,9 +1229,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exclusive lock for the health monitor database.
|
||||
* Acquire this before creating, initializing, or updating the database schema.
|
||||
* Get an exclusive lock for the health monitor database. Acquire this
|
||||
* before creating, initializing, or updating the database schema.
|
||||
*
|
||||
* @return The lock
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException {
|
||||
@ -1215,9 +1250,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an shared lock for the health monitor database.
|
||||
* Acquire this before database reads or writes.
|
||||
* Get an shared lock for the health monitor database. Acquire this before
|
||||
* database reads or writes.
|
||||
*
|
||||
* @return The lock
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
private CoordinationService.Lock getSharedDbLock() throws HealthMonitorException {
|
||||
@ -1251,6 +1288,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the integer value of the event to store in the database.
|
||||
*
|
||||
* @return value corresponding to the event
|
||||
*/
|
||||
int getEventValue() {
|
||||
@ -1259,8 +1297,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the UserEvent from the value stored in the database
|
||||
*
|
||||
* @param value
|
||||
*
|
||||
* @return the corresponding UserEvent object
|
||||
*
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
static UserEvent valueOf(int value) throws HealthMonitorException {
|
||||
@ -1273,8 +1314,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a case is considered to be open given this event
|
||||
* as the last recorded event.
|
||||
* Return whether a case is considered to be open given this event as
|
||||
* the last recorded event.
|
||||
*
|
||||
* @return true if a case is open, false otherwise
|
||||
*/
|
||||
boolean caseIsOpen() {
|
||||
@ -1284,6 +1326,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
/**
|
||||
* Return whether a user is considered to be logged in given this event
|
||||
* as the last recorded event.
|
||||
*
|
||||
* @return true if a the user is logged in, false otherwise
|
||||
*/
|
||||
boolean userIsLoggedIn() {
|
||||
@ -1294,11 +1337,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Class holding user metric data.
|
||||
* Can be used for storing new events or retrieving
|
||||
* events out of the database.
|
||||
* Class holding user metric data. Can be used for storing new events or
|
||||
* retrieving events out of the database.
|
||||
*/
|
||||
static class UserData {
|
||||
|
||||
private final UserEvent eventType;
|
||||
private long timestamp;
|
||||
private final boolean isExaminer;
|
||||
@ -1306,8 +1349,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
private String caseName;
|
||||
|
||||
/**
|
||||
* Create a new UserData object using the given event type
|
||||
* and the current settings.
|
||||
* Create a new UserData object using the given event type and the
|
||||
* current settings.
|
||||
*
|
||||
* @param eventType The type of event being recorded
|
||||
*/
|
||||
private UserData(UserEvent eventType) {
|
||||
@ -1327,7 +1371,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Create a UserData object from a database result set.
|
||||
*
|
||||
* @param resultSet The result set containing the data
|
||||
*
|
||||
* @throws SQLException
|
||||
* @throws HealthMonitorException
|
||||
*/
|
||||
@ -1342,7 +1388,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
/**
|
||||
* This should only be used to make a dummy object to use for timestamp
|
||||
* comparisons.
|
||||
*
|
||||
* @param timestamp
|
||||
*
|
||||
* @return A UserData object with the given timestamp
|
||||
*/
|
||||
static UserData createDummyUserData(long timestamp) {
|
||||
@ -1353,6 +1401,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the timestamp for the event
|
||||
*
|
||||
* @return Timestamp in milliseconds
|
||||
*/
|
||||
long getTimestamp() {
|
||||
@ -1361,6 +1410,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the host that created the metric
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
String getHostname() {
|
||||
@ -1369,6 +1419,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the type of event
|
||||
*
|
||||
* @return the event type
|
||||
*/
|
||||
UserEvent getEventType() {
|
||||
@ -1377,6 +1428,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Check whether this node is an examiner node or an auto ingest node
|
||||
*
|
||||
* @return true if it is an examiner node
|
||||
*/
|
||||
boolean isExaminerNode() {
|
||||
@ -1385,6 +1437,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the name of the case for this metric
|
||||
*
|
||||
* @return the case name. Will be the empty string if no case was open.
|
||||
*/
|
||||
String getCaseName() {
|
||||
@ -1393,14 +1446,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class for collecting timing metrics.
|
||||
* Instead of storing each TimingMetric, we only store the min and max
|
||||
* seen and the number of metrics and total duration to compute the average
|
||||
* later.
|
||||
* One TimingInfo instance should be created per metric name, and
|
||||
* additional timing metrics will be added to it.
|
||||
* Internal class for collecting timing metrics. Instead of storing each
|
||||
* TimingMetric, we only store the min and max seen and the number of
|
||||
* metrics and total duration to compute the average later. One TimingInfo
|
||||
* instance should be created per metric name, and additional timing metrics
|
||||
* will be added to it.
|
||||
*/
|
||||
private class TimingInfo {
|
||||
|
||||
private long count; // Number of metrics collected
|
||||
private double sum; // Sum of the durations collected (nanoseconds)
|
||||
private double max; // Maximum value found (nanoseconds)
|
||||
@ -1414,11 +1467,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new TimingMetric to an existing TimingInfo object.
|
||||
* This is called in a synchronized block for almost all new
|
||||
* TimingMetric objects, so do as little processing here as possible.
|
||||
* Add a new TimingMetric to an existing TimingInfo object. This is
|
||||
* called in a synchronized block for almost all new TimingMetric
|
||||
* objects, so do as little processing here as possible.
|
||||
*
|
||||
* @param metric The new metric
|
||||
* @throws HealthMonitorException Will be thrown if the metric hasn't been stopped
|
||||
*
|
||||
* @throws HealthMonitorException Will be thrown if the metric hasn't
|
||||
* been stopped
|
||||
*/
|
||||
void addMetric(TimingMetric metric) throws HealthMonitorException {
|
||||
|
||||
@ -1439,6 +1495,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the average duration
|
||||
*
|
||||
* @return average duration (milliseconds)
|
||||
*/
|
||||
double getAverage() {
|
||||
@ -1447,6 +1504,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the maximum duration
|
||||
*
|
||||
* @return maximum duration (milliseconds)
|
||||
*/
|
||||
double getMax() {
|
||||
@ -1455,6 +1513,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the minimum duration
|
||||
*
|
||||
* @return minimum duration (milliseconds)
|
||||
*/
|
||||
double getMin() {
|
||||
@ -1463,6 +1522,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the total number of metrics collected
|
||||
*
|
||||
* @return number of metrics collected
|
||||
*/
|
||||
long getCount() {
|
||||
@ -1471,10 +1531,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for retrieving timing metrics from the database to display to the user.
|
||||
* All times will be in milliseconds.
|
||||
* Class for retrieving timing metrics from the database to display to the
|
||||
* user. All times will be in milliseconds.
|
||||
*/
|
||||
static class DatabaseTimingResult {
|
||||
|
||||
private final long timestamp; // Time the metric was recorded
|
||||
private final String hostname; // Host that recorded the metric
|
||||
private final long count; // Number of metrics collected
|
||||
@ -1493,6 +1554,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the timestamp for when the metric was recorded
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
long getTimestamp() {
|
||||
@ -1501,6 +1563,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the average duration
|
||||
*
|
||||
* @return average duration (milliseconds)
|
||||
*/
|
||||
double getAverage() {
|
||||
@ -1509,6 +1572,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the maximum duration
|
||||
*
|
||||
* @return maximum duration (milliseconds)
|
||||
*/
|
||||
double getMax() {
|
||||
@ -1517,6 +1581,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the minimum duration
|
||||
*
|
||||
* @return minimum duration (milliseconds)
|
||||
*/
|
||||
double getMin() {
|
||||
@ -1525,6 +1590,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the total number of metrics collected
|
||||
*
|
||||
* @return number of metrics collected
|
||||
*/
|
||||
long getCount() {
|
||||
@ -1533,6 +1599,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Get the name of the host that recorded this metric
|
||||
*
|
||||
* @return the host
|
||||
*/
|
||||
String getHostName() {
|
@ -61,8 +61,8 @@ public class HealthMonitorDashboard {
|
||||
private final static String ADMIN_ACCESS_FILE_NAME = "adminAccess"; // NON-NLS
|
||||
private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString();
|
||||
|
||||
Map<String, List<EnterpriseHealthMonitor.DatabaseTimingResult>> timingData;
|
||||
List<EnterpriseHealthMonitor.UserData> userData;
|
||||
Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
|
||||
List<HealthMonitor.UserData> userData;
|
||||
|
||||
private JComboBox<String> timingDateComboBox = null;
|
||||
private JComboBox<String> timingHostComboBox = null;
|
||||
@ -90,7 +90,7 @@ public class HealthMonitorDashboard {
|
||||
* Display the dashboard.
|
||||
*/
|
||||
@NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor dashboard",
|
||||
"HealthMonitorDashboard.display.dashboardTitle=Enterprise Health Monitor"})
|
||||
"HealthMonitorDashboard.display.dashboardTitle=Health Monitor"})
|
||||
public void display() {
|
||||
|
||||
// Update the enabled status and get the timing data, then create all
|
||||
@ -153,14 +153,14 @@ public class HealthMonitorDashboard {
|
||||
private void updateData() throws HealthMonitorException {
|
||||
|
||||
// Update the monitor status
|
||||
EnterpriseHealthMonitor.getInstance().updateFromGlobalEnabledStatus();
|
||||
HealthMonitor.getInstance().updateFromGlobalEnabledStatus();
|
||||
|
||||
if(EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(HealthMonitor.monitorIsEnabled()) {
|
||||
// Get a copy of the timing data from the database
|
||||
timingData = EnterpriseHealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
timingData = HealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
|
||||
// Get a copy of the user data from the database
|
||||
userData = EnterpriseHealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
userData = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ public class HealthMonitorDashboard {
|
||||
private JPanel createTimingPanel() throws HealthMonitorException {
|
||||
|
||||
// If the monitor isn't enabled, just add a message
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
//timingMetricPanel.setPreferredSize(new Dimension(400,100));
|
||||
JPanel emptyTimingMetricPanel = new JPanel();
|
||||
emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
|
||||
@ -223,7 +223,7 @@ public class HealthMonitorDashboard {
|
||||
JPanel timingControlPanel = new JPanel();
|
||||
|
||||
// If the monitor is not enabled, don't add any components
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
return timingControlPanel;
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ public class HealthMonitorDashboard {
|
||||
// Create an array of host names
|
||||
Set<String> hostNameSet = new HashSet<>();
|
||||
for(String metricType:timingData.keySet()) {
|
||||
for(EnterpriseHealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
||||
for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
||||
hostNameSet.add(result.getHostName());
|
||||
}
|
||||
}
|
||||
@ -364,7 +364,7 @@ public class HealthMonitorDashboard {
|
||||
for(String metricName:timingData.keySet()) {
|
||||
|
||||
// If necessary, trim down the list of results to fit the selected time range
|
||||
List<EnterpriseHealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
|
||||
List<HealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
|
||||
if(timingDateComboBox.getSelectedItem() != null) {
|
||||
DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
|
||||
long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
|
||||
@ -403,7 +403,7 @@ public class HealthMonitorDashboard {
|
||||
"HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
|
||||
private JPanel createUserPanel() throws HealthMonitorException {
|
||||
// If the monitor isn't enabled, just add a message
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
JPanel emptyUserMetricPanel = new JPanel();
|
||||
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
|
||||
emptyUserMetricPanel.add(new JLabel(" "));
|
||||
@ -448,7 +448,7 @@ public class HealthMonitorDashboard {
|
||||
JPanel userControlPanel = new JPanel();
|
||||
|
||||
// If the monitor is not enabled, don't add any components
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
return userControlPanel;
|
||||
}
|
||||
|
||||
@ -535,7 +535,7 @@ public class HealthMonitorDashboard {
|
||||
JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
|
||||
JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
|
||||
|
||||
boolean isEnabled = EnterpriseHealthMonitor.monitorIsEnabled();
|
||||
boolean isEnabled = HealthMonitor.monitorIsEnabled();
|
||||
enableButton.setEnabled(! isEnabled);
|
||||
disableButton.setEnabled(isEnabled);
|
||||
|
||||
@ -545,7 +545,7 @@ public class HealthMonitorDashboard {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
try {
|
||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EnterpriseHealthMonitor.setEnabled(true);
|
||||
HealthMonitor.setEnabled(true);
|
||||
redisplay();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error enabling monitoring", ex);
|
||||
@ -561,7 +561,7 @@ public class HealthMonitorDashboard {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
try {
|
||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EnterpriseHealthMonitor.setEnabled(false);
|
||||
HealthMonitor.setEnabled(false);
|
||||
redisplay();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error disabling monitoring", ex);
|
||||
|
@ -45,7 +45,7 @@ public class Installer extends ModuleInstall {
|
||||
public void restored() {
|
||||
|
||||
try {
|
||||
EnterpriseHealthMonitor.startUpIfEnabled();
|
||||
HealthMonitor.startUpIfEnabled();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error starting health services monitor", ex);
|
||||
}
|
||||
@ -54,7 +54,7 @@ public class Installer extends ModuleInstall {
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
EnterpriseHealthMonitor.shutdown();
|
||||
HealthMonitor.shutdown();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error stopping health services monitor", ex);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ import java.util.logging.Level;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor.DatabaseTimingResult;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor.DatabaseTimingResult;
|
||||
|
||||
/**
|
||||
* Creates a graph of the given timing metric data
|
||||
|
@ -38,7 +38,7 @@ import javax.swing.JPanel;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor.UserData;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor.UserData;
|
||||
|
||||
/**
|
||||
* Creates graphs using the given user metric data
|
||||
|
@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
@ -184,7 +184,7 @@ public class HashDbIngestModule implements FileIngestModule {
|
||||
String md5Hash = file.getMd5Hash();
|
||||
if (md5Hash == null || md5Hash.isEmpty()) {
|
||||
try {
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
||||
long calcstart = System.currentTimeMillis();
|
||||
md5Hash = HashUtility.calculateMd5Hash(file);
|
||||
if (file.getSize() > 0) {
|
||||
@ -192,10 +192,10 @@ public class HashDbIngestModule implements FileIngestModule {
|
||||
// strongly with file size until the files get large.
|
||||
// Only normalize if the file size is greater than ~1MB.
|
||||
if (file.getSize() < 1000000) {
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
} else {
|
||||
// In testing, this normalization gave reasonable resuls
|
||||
EnterpriseHealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
||||
HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
||||
}
|
||||
}
|
||||
file.setMd5Hash(md5Hash);
|
||||
|
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCond
|
||||
*/
|
||||
public final class FilesSetsManager extends Observable {
|
||||
|
||||
@NbBundle.Messages({"FilesSetsManager.allFilesAndDirectories=All Files and Directories",
|
||||
@NbBundle.Messages({"FilesSetsManager.allFilesAndDirectories=All Files and Directories (Not Unallocated Space)",
|
||||
"FilesSetsManager.allFilesDirectoriesAndUnallocated=All Files, Directories, and Unallocated Space"})
|
||||
private static final List<String> ILLEGAL_FILE_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">")));
|
||||
private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", ":", "*", "?", "\"", "<", ">")));
|
||||
|
@ -380,6 +380,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
throw new AutoIngestMonitorException("Error removing priority for job " + job.toString(), ex);
|
||||
}
|
||||
job.setPriority(DEFAULT_PRIORITY);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(job);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -428,6 +433,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
throw new AutoIngestMonitorException("Error bumping priority for job " + job.toString(), ex);
|
||||
}
|
||||
job.setPriority(highestPriority);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(job);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -466,7 +476,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
|
||||
/*
|
||||
* If the job was still in the pending jobs queue, bump its
|
||||
* If the job was still in the pending jobs queue, reset its
|
||||
* priority.
|
||||
*/
|
||||
if (null != jobToDeprioritize) {
|
||||
@ -480,6 +490,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
jobToDeprioritize.setPriority(DEFAULT_PRIORITY);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(jobToDeprioritize);
|
||||
|
||||
/*
|
||||
* Publish a deprioritization event.
|
||||
*/
|
||||
@ -538,6 +553,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
jobToPrioritize.setPriority(highestPriority);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(jobToPrioritize);
|
||||
|
||||
/*
|
||||
* Publish a prioritization event.
|
||||
*/
|
||||
|
@ -102,6 +102,7 @@ public class SharedConfiguration {
|
||||
private boolean hideKnownFilesInViews;
|
||||
private boolean hideSlackFilesInDataSource;
|
||||
private boolean hideSlackFilesInViews;
|
||||
private boolean groupDatasources;
|
||||
private boolean keepPreferredViewer;
|
||||
|
||||
/**
|
||||
@ -206,6 +207,8 @@ public class SharedConfiguration {
|
||||
uploadHashDbSettings(remoteFolder);
|
||||
uploadFileExporterSettings(remoteFolder);
|
||||
uploadCentralRepositorySettings(remoteFolder);
|
||||
uploadObjectDetectionClassifiers(remoteFolder);
|
||||
uploadPythonModules(remoteFolder);
|
||||
|
||||
try {
|
||||
Files.deleteIfExists(uploadInProgress.toPath());
|
||||
@ -271,6 +274,8 @@ public class SharedConfiguration {
|
||||
downloadAndroidTriageSettings(remoteFolder);
|
||||
downloadFileExporterSettings(remoteFolder);
|
||||
downloadCentralRepositorySettings(remoteFolder);
|
||||
downloadObjectDetectionClassifiers(remoteFolder);
|
||||
downloadPythonModules(remoteFolder);
|
||||
|
||||
// Download general settings, then restore the current
|
||||
// values for the unshared fields
|
||||
@ -348,6 +353,7 @@ public class SharedConfiguration {
|
||||
fileIngestThreads = UserPreferences.numberOfFileIngestThreads();
|
||||
hideSlackFilesInDataSource = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||
hideSlackFilesInViews = UserPreferences.hideSlackFilesInViewsTree();
|
||||
groupDatasources = UserPreferences.groupItemsInTreeByDatasource();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,6 +370,7 @@ public class SharedConfiguration {
|
||||
UserPreferences.setNumberOfFileIngestThreads(fileIngestThreads);
|
||||
UserPreferences.setHideSlackFilesInDataSourcesTree(hideSlackFilesInDataSource);
|
||||
UserPreferences.setHideSlackFilesInViewsTree(hideSlackFilesInViews);
|
||||
UserPreferences.setGroupItemsInTreeByDatasource(groupDatasources);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -512,6 +519,71 @@ public class SharedConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an entire local settings folder to the remote folder, deleting any existing files.
|
||||
*
|
||||
* @param localFolder The local folder to copy
|
||||
* @param remoteBaseFolder The remote folder that will hold a copy of the original folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void copyLocalFolderToRemoteFolder(File localFolder, File remoteBaseFolder) throws SharedConfigurationException {
|
||||
logger.log(Level.INFO, "Uploading {0} to {1}", new Object[]{localFolder.getAbsolutePath(), remoteBaseFolder.getAbsolutePath()});
|
||||
|
||||
File newRemoteFolder = new File(remoteBaseFolder, localFolder.getName());
|
||||
|
||||
if(newRemoteFolder.exists()) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(newRemoteFolder);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to delete remote folder {0}", newRemoteFolder.getAbsolutePath());
|
||||
throw new SharedConfigurationException(String.format("Failed to delete remote folder {0}", newRemoteFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtils.copyDirectoryToDirectory(localFolder, remoteBaseFolder);
|
||||
} catch (IOException ex) {
|
||||
throw new SharedConfigurationException(String.format("Failed to copy %s to %s", localFolder, remoteBaseFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an entire remote settings folder to the local folder, deleting any existing files.
|
||||
* No error if the remote folder does not exist.
|
||||
*
|
||||
* @param localFolder The local folder that will be overwritten.
|
||||
* @param remoteBaseFolder The remote folder holding the folder that will be copied
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void copyRemoteFolderToLocalFolder(File localFolder, File remoteBaseFolder) throws SharedConfigurationException {
|
||||
logger.log(Level.INFO, "Downloading {0} from {1}", new Object[]{localFolder.getAbsolutePath(), remoteBaseFolder.getAbsolutePath()});
|
||||
|
||||
// Clean out the local folder regardless of whether the remote version exists. leave the
|
||||
// folder in place since Autopsy expects it to exist.
|
||||
if(localFolder.exists()) {
|
||||
try {
|
||||
FileUtils.cleanDirectory(localFolder);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to delete files from local folder {0}", localFolder.getAbsolutePath());
|
||||
throw new SharedConfigurationException(String.format("Failed to delete files from local folder {0}", localFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
File remoteSubFolder = new File(remoteBaseFolder, localFolder.getName());
|
||||
if(! remoteSubFolder.exists()) {
|
||||
logger.log(Level.INFO, "{0} does not exist", remoteSubFolder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtils.copyDirectory(remoteSubFolder, localFolder);
|
||||
} catch (IOException ex) {
|
||||
throw new SharedConfigurationException(String.format("Failed to copy %s from %s", localFolder, remoteBaseFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the basic set of auto-ingest settings to the shared folder.
|
||||
*
|
||||
@ -828,6 +900,58 @@ public class SharedConfiguration {
|
||||
copyToLocalFolder(AUTO_INGEST_PROPERTIES, moduleDirPath, remoteFolder, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the object detection classifiers.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void uploadObjectDetectionClassifiers(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Uploading object detection classfiers");
|
||||
File classifiersFolder = new File(PlatformUtil.getObjectDetectionClassifierPath());
|
||||
copyLocalFolderToRemoteFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the object detection classifiers.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void downloadObjectDetectionClassifiers(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Downloading object detection classfiers");
|
||||
File classifiersFolder = new File(PlatformUtil.getObjectDetectionClassifierPath());
|
||||
copyRemoteFolderToLocalFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the Python modules.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void uploadPythonModules(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Uploading python modules");
|
||||
File classifiersFolder = new File(PlatformUtil.getUserPythonModulesPath());
|
||||
copyLocalFolderToRemoteFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the Python modules.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void downloadPythonModules(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Downloading python modules");
|
||||
File classifiersFolder = new File(PlatformUtil.getUserPythonModulesPath());
|
||||
copyRemoteFolderToLocalFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload settings and hash databases to the shared folder. The general
|
||||
* algorithm is: - Copy the general settings in hashsets.xml - For each hash
|
||||
|
@ -1179,6 +1179,12 @@ public final class DrawableDB {
|
||||
* @return the number of files with Cat-0
|
||||
*/
|
||||
public long getUncategorizedCount(Collection<Long> fileIDs) {
|
||||
|
||||
// if the fileset is empty, return count as 0
|
||||
if (fileIDs.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DrawableTagsManager tagsManager = controller.getTagsManager();
|
||||
|
||||
// get a comma seperated list of TagName ids for non zero categories
|
||||
|
@ -82,6 +82,7 @@ import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData.DbType;
|
||||
|
||||
/**
|
||||
* Provides an abstraction layer on top of {@link DrawableDB} ( and to some
|
||||
@ -351,11 +352,22 @@ public class GroupManager {
|
||||
case MIME_TYPE:
|
||||
if (nonNull(db)) {
|
||||
HashSet<String> types = new HashSet<>();
|
||||
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery("select group_concat(obj_id), mime_type from tsk_files group by mime_type "); //NON-NLS
|
||||
|
||||
// Use the group_concat function to get a list of files for each mime type.
|
||||
// This has different syntax on Postgres vs SQLite
|
||||
String groupConcatClause;
|
||||
if (DbType.POSTGRESQL == controller.getSleuthKitCase().getDatabaseType()) {
|
||||
groupConcatClause = " array_to_string(array_agg(obj_id), ',') as object_ids";
|
||||
}
|
||||
else {
|
||||
groupConcatClause = "select group_concat(obj_id) as object_ids";
|
||||
}
|
||||
String query = "select " + groupConcatClause + " , mime_type from tsk_files group by mime_type ";
|
||||
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(query); //NON-NLS
|
||||
ResultSet resultSet = executeQuery.getResultSet();) {
|
||||
while (resultSet.next()) {
|
||||
final String mimeType = resultSet.getString("mime_type"); //NON-NLS
|
||||
String objIds = resultSet.getString("group_concat(obj_id)"); //NON-NLS
|
||||
String objIds = resultSet.getString("object_ids"); //NON-NLS
|
||||
|
||||
Pattern.compile(",").splitAsStream(objIds)
|
||||
.map(Long::valueOf)
|
||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -48,7 +47,6 @@ import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.Report;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
@ -126,50 +124,45 @@ class AdHocSearchFilterNode extends FilterNode {
|
||||
|
||||
@Override
|
||||
public List<Action> visit(File f) {
|
||||
return getFileActions(true);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(DerivedFile f) {
|
||||
return getFileActions(true);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(Directory d) {
|
||||
return getFileActions(false);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(LayoutFile lf) {
|
||||
//we want hashsearch enabled on carved files but not unallocated blocks
|
||||
boolean enableHashSearch = (lf.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.CARVED);
|
||||
return getFileActions(enableHashSearch);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(LocalFile lf) {
|
||||
return getFileActions(true);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(SlackFile f) {
|
||||
return getFileActions(false);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> visit(VirtualDirectory dir) {
|
||||
return getFileActions(false);
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
private List<Action> getFileActions(boolean enableHashSearch) {
|
||||
private List<Action> getFileActions() {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), AdHocSearchFilterNode.this));
|
||||
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
||||
actionsList.add(null);
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
Action hashSearchAction = new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal());
|
||||
hashSearchAction.setEnabled(enableHashSearch);
|
||||
actionsList.add(hashSearchAction);
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
|
||||
@ -185,7 +178,7 @@ class AdHocSearchFilterNode extends FilterNode {
|
||||
|
||||
@Override
|
||||
protected List<Action> defaultVisit(Content c) {
|
||||
return getFileActions(false);
|
||||
return getFileActions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import org.apache.solr.common.SolrInputDocument;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk;
|
||||
@ -237,9 +237,9 @@ class Ingester {
|
||||
|
||||
try {
|
||||
//TODO: consider timeout thread, or vary socket timeout based on size of indexed content
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
solrServer.addDocument(updateDoc);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
uncommitedIngests = true;
|
||||
|
||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||
|
@ -70,7 +70,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -710,9 +710,9 @@ public class Server {
|
||||
if (null == currentCore) {
|
||||
throw new NoOpenCoreException();
|
||||
}
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
currentCore.addDocument(doc);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
} finally {
|
||||
currentCoreLock.readLock().unlock();
|
||||
}
|
||||
@ -781,9 +781,9 @@ public class Server {
|
||||
IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory());
|
||||
currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS
|
||||
}
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
connectToSolrServer(currentSolrServer);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
|
||||
} catch (SolrServerException | IOException ex) {
|
||||
throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
|
||||
@ -1325,13 +1325,13 @@ public class Server {
|
||||
* @throws IOException
|
||||
*/
|
||||
void connectToSolrServer(HttpSolrServer solrServer) throws SolrServerException, IOException {
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
CoreAdminRequest statusRequest = new CoreAdminRequest();
|
||||
statusRequest.setCoreName( null );
|
||||
statusRequest.setAction( CoreAdminParams.CoreAdminAction.STATUS );
|
||||
statusRequest.setIndexInfoNeeded(false);
|
||||
statusRequest.process(solrServer);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
\section common_files_overview Overview
|
||||
|
||||
The common files feature allows you to search for multiple copies of the same file within a case.
|
||||
The common files feature allows you to search for multiple copies of the same file in different data sources within a case.
|
||||
|
||||
\section common_files_usage Usage
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 52 KiB |