Merge branch 'develop' of https://github.com/briangsweeney/autopsy into 4121_correlation_types

# Conflicts:
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/AllInterCaseCommonAttributeSearcher.java
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/Bundle.properties
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.form
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.java
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/IntraCaseCommonAttributeSearcher.java
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/SingleInterCaseCommonAttributeSearcher.java
This commit is contained in:
Brian Sweeney 2018-08-31 15:08:59 -06:00
commit 8ef34cb4d6
23 changed files with 631 additions and 380 deletions

View File

@ -104,17 +104,18 @@ public abstract class AbstractCommonAttributeSearcher {
} }
} }
static Map<Integer, List<CommonAttributeValue>> collateMatchesByNumberOfInstances(Map<String, CommonAttributeValue> commonFiles) { static Map<Integer, CommonAttributeValueList> collateMatchesByNumberOfInstances(Map<String, CommonAttributeValue> commonFiles) {
//collate matches by number of matching instances - doing this in sql doesnt seem efficient //collate matches by number of matching instances - doing this in sql doesnt seem efficient
Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = new TreeMap<>(); Map<Integer, CommonAttributeValueList> instanceCollatedCommonFiles = new TreeMap<>();
for(CommonAttributeValue md5Metadata : commonFiles.values()){ for(CommonAttributeValue md5Metadata : commonFiles.values()){
Integer size = md5Metadata.getInstanceCount(); Integer size = md5Metadata.getInstanceCount();
if(instanceCollatedCommonFiles.containsKey(size)){ if(instanceCollatedCommonFiles.containsKey(size)){
instanceCollatedCommonFiles.get(size).add(md5Metadata); instanceCollatedCommonFiles.get(size).addMetadataToList(md5Metadata);
} else { } else {
ArrayList<CommonAttributeValue> value = new ArrayList<>(); CommonAttributeValueList value = new CommonAttributeValueList();
value.add(md5Metadata); value.addMetadataToList(md5Metadata);
instanceCollatedCommonFiles.put(size, value); instanceCollatedCommonFiles.put(size, value);
} }
} }

View File

@ -49,7 +49,7 @@ public class AllInterCaseCommonAttributeSearcher extends InterCaseCommonAttribut
@Override @Override
public CommonAttributeSearchResults findMatches() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException { public CommonAttributeSearchResults findMatches() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), corAttrType); InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), corAttrType);
Map<Integer, List<CommonAttributeValue>> interCaseCommonFiles = eamDbAttrInst.findInterCaseCommonAttributeValues(Case.getCurrentCase()); Map<Integer, CommonAttributeValueList> interCaseCommonFiles = eamDbAttrInst.findInterCaseCommonAttributeValues(Case.getCurrentCase());
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold); return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold);
} }

View File

@ -9,10 +9,14 @@ IntraCasePanel.withinDataSourceRadioButton.text=At least one match must appear i
IntraCasePanel.selectDataSourceComboBox.actionCommand= IntraCasePanel.selectDataSourceComboBox.actionCommand=
InterCasePanel.specificCentralRepoCaseRadio.text=Matches must be from the following Central Repo case: InterCasePanel.specificCentralRepoCaseRadio.text=Matches must be from the following Central Repo case:
InterCasePanel.anyCentralRepoCaseRadio.text=Matches may be from any Central Repo case InterCasePanel.anyCentralRepoCaseRadio.text=Matches may be from any Central Repo case
CommonAttributePanel.commonFilesSearchLabel2.text=Scope of Search CommonAttributePanel.jCheckBox1.text=Hide files found in over
CommonAttributePanel.jLabel1.text=% of data sources in central repository.
CommonAttributePanel.percentageThresholdTextTwo.text_1=% of data sources in central repository.
CommonAttributePanel.percentageThresholdTextOne.text=20
CommonAttributePanel.percentageThresholdCheck.text_1=Hide files found in over
CommonAttributePanel.intraCaseRadio.text=Within current case CommonAttributePanel.intraCaseRadio.text=Within current case
CommonAttributePanel.commonFilesSearchLabel1.text=<html>Find common files to correlate data soures or cases.</html> CommonAttributePanel.commonFilesSearchLabel1.text=<html>Find common files to correlate data soures or cases.</html>
CommonAttributePanel.errorText.text=In order to search, you must select a file category. CommonAttributePanel.errorText.text=<html>In order to search, you must select a file category.</html>
CommonAttributePanel.categoriesLabel.text=File Types To Include: CommonAttributePanel.categoriesLabel.text=File Types To Include:
CommonAttributePanel.documentsCheckbox.text=Documents CommonAttributePanel.documentsCheckbox.text=Documents
CommonAttributePanel.pictureVideoCheckbox.text=Pictures and Videos CommonAttributePanel.pictureVideoCheckbox.text=Pictures and Videos
@ -30,3 +34,4 @@ CommonAttributePanel.jLabel1.text_1=% of data sources in central repository.
CommonAttributePanel.percentageThresholdCheck.text_1=Hide files found in over CommonAttributePanel.percentageThresholdCheck.text_1=Hide files found in over
InterCasePanel.comboBoxLabel.text=Select correlation type to search: InterCasePanel.comboBoxLabel.text=Select correlation type to search:
InterCasePanel.correlationTypeComboBox.toolTipText=Selected Correlation Type InterCasePanel.correlationTypeComboBox.toolTipText=Selected Correlation Type
CommonAttributePanel.commonFilesSearchLabel2.text=Scope of Search

View File

@ -9,10 +9,10 @@
</NonVisualComponents> </NonVisualComponents>
<Properties> <Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 440]"/> <Dimension value="[450, 440]"/>
</Property> </Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 440]"/> <Dimension value="[450, 440]"/>
</Property> </Property>
<Property name="resizable" type="boolean" value="false"/> <Property name="resizable" type="boolean" value="false"/>
</Properties> </Properties>
@ -40,14 +40,15 @@
<Container class="javax.swing.JPanel" name="jPanel1"> <Container class="javax.swing.JPanel" name="jPanel1">
<Properties> <Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 440]"/> <Dimension value="[450, 440]"/>
</Property> </Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 440]"/> <Dimension value="[450, 440]"/>
</Property> </Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 440]"/> <Dimension value="[450, 440]"/>
</Property> </Property>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties> </Properties>
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
@ -58,45 +59,57 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="commonFilesSearchLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="intraCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="interCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="commonFilesSearchLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="allFileCategoriesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="percentageThresholdCheck" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="percentageThreshold" min="-2" pref="40" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="searchButton" min="-2" max="-2" attributes="0"/> <Component id="searchButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/> <Component id="cancelButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="errorText" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="filler1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="80" max="-2" attributes="0"/>
<Component id="filler2" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="errorText" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="commonFilesSearchLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="intraCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="interCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="commonFilesSearchLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="allFileCategoriesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="percentageThresholdCheck" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="percentageThresholdTextOne" min="-2" pref="40" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="percentageThresholdTextTwo" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace pref="9" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -126,16 +139,22 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="percentageThresholdCheck" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="percentageThresholdCheck" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="percentageThreshold" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="percentageThresholdTextOne" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="percentageThresholdTextTwo" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="1" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="filler2" min="-2" max="-2" attributes="0"/>
<Component id="errorText" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="filler1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="errorText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -251,6 +270,7 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.errorText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.errorText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel1"> <Component class="javax.swing.JLabel" name="commonFilesSearchLabel1">
@ -318,10 +338,10 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="percentageThresholdCheckActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="percentageThresholdCheckActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JTextField" name="percentageThreshold"> <Component class="javax.swing.JTextField" name="percentageThresholdTextOne">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThreshold.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdTextOne.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[40, 24]"/> <Dimension value="[40, 24]"/>
@ -334,13 +354,33 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="jLabel1"> <Component class="javax.swing.JLabel" name="percentageThresholdTextTwo">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.jLabel1.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdTextTwo.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.Box$Filler" name="filler1">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 32767]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
</AuxValues>
</Component>
<Component class="javax.swing.Box$Filler" name="filler2">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 32767]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.Glue"/>
</AuxValues>
</Component>
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>

View File

@ -85,7 +85,6 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
initComponents(); initComponents();
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
this.errorText.setVisible(false);
this.setupDataSources(); this.setupDataSources();
if (CommonAttributePanel.isEamDbAvailableForIntercaseSearch()) { if (CommonAttributePanel.isEamDbAvailableForIntercaseSearch()) {
@ -102,13 +101,13 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
} }
this.errorManager = new UserInputErrorManager(); this.errorManager = new UserInputErrorManager();
this.percentageThreshold.getDocument().addDocumentListener(new DocumentListener() { this.percentageThresholdTextOne.getDocument().addDocumentListener(new DocumentListener(){
private Dimension preferredSize = CommonAttributePanel.this.percentageThreshold.getPreferredSize(); private Dimension preferredSize = CommonAttributePanel.this.percentageThresholdTextOne.getPreferredSize();
private void maintainSize() { private void maintainSize() {
CommonAttributePanel.this.percentageThreshold.setSize(preferredSize); CommonAttributePanel.this.percentageThresholdTextOne.setSize(preferredSize);
} }
@Override @Override
@ -472,11 +471,13 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
intraCasePanel = new org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel(); intraCasePanel = new org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel();
interCasePanel = new org.sleuthkit.autopsy.commonfilesearch.InterCasePanel(); interCasePanel = new org.sleuthkit.autopsy.commonfilesearch.InterCasePanel();
percentageThresholdCheck = new javax.swing.JCheckBox(); percentageThresholdCheck = new javax.swing.JCheckBox();
percentageThreshold = new javax.swing.JTextField(); percentageThresholdTextOne = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel(); percentageThresholdTextTwo = new javax.swing.JLabel();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 32767));
setMaximumSize(new java.awt.Dimension(412, 440)); setMaximumSize(new java.awt.Dimension(450, 440));
setMinimumSize(new java.awt.Dimension(412, 440)); setMinimumSize(new java.awt.Dimension(450, 440));
setResizable(false); setResizable(false);
addWindowListener(new java.awt.event.WindowAdapter() { addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosed(java.awt.event.WindowEvent evt) { public void windowClosed(java.awt.event.WindowEvent evt) {
@ -484,9 +485,10 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
} }
}); });
jPanel1.setMaximumSize(new java.awt.Dimension(412, 440)); jPanel1.setMaximumSize(new java.awt.Dimension(450, 440));
jPanel1.setMinimumSize(new java.awt.Dimension(412, 440)); jPanel1.setMinimumSize(new java.awt.Dimension(450, 440));
jPanel1.setPreferredSize(new java.awt.Dimension(412, 440)); jPanel1.setPreferredSize(new java.awt.Dimension(450, 375));
jPanel1.setRequestFocusEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel2, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel2.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel2, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel2.text")); // NOI18N
commonFilesSearchLabel2.setFocusable(false); commonFilesSearchLabel2.setFocusable(false);
@ -554,6 +556,7 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
errorText.setForeground(new java.awt.Color(255, 0, 0)); errorText.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorText, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.errorText.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(errorText, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.errorText.text")); // NOI18N
errorText.setVerticalAlignment(javax.swing.SwingConstants.TOP);
org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel1, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel1.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel1, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel1.text")); // NOI18N
commonFilesSearchLabel1.setFocusable(false); commonFilesSearchLabel1.setFocusable(false);
@ -586,12 +589,12 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
} }
}); });
percentageThreshold.setText(org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.percentageThreshold.text")); // NOI18N percentageThresholdTextOne.setText(org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.percentageThresholdTextOne.text")); // NOI18N
percentageThreshold.setMaximumSize(new java.awt.Dimension(40, 24)); percentageThresholdTextOne.setMaximumSize(new java.awt.Dimension(40, 24));
percentageThreshold.setMinimumSize(new java.awt.Dimension(40, 24)); percentageThresholdTextOne.setMinimumSize(new java.awt.Dimension(40, 24));
percentageThreshold.setPreferredSize(new java.awt.Dimension(40, 24)); percentageThresholdTextOne.setPreferredSize(new java.awt.Dimension(40, 24));
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.jLabel1.text_1")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdTextTwo, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.percentageThresholdTextTwo.text_1")); // NOI18N
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout); jPanel1.setLayout(jPanel1Layout);
@ -600,35 +603,43 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addComponent(commonFilesSearchLabel2)
.addComponent(intraCaseRadio)
.addComponent(interCaseRadio)
.addComponent(commonFilesSearchLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(categoriesLabel)
.addComponent(selectedFileCategoriesButton)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(29, 29, 29)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(documentsCheckbox)
.addComponent(pictureVideoCheckbox)))
.addComponent(allFileCategoriesRadioButton)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(layoutPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(percentageThresholdCheck)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(percentageThreshold, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(searchButton) .addComponent(searchButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton) .addComponent(cancelButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorText))) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addContainerGap()) .addGroup(jPanel1Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(80, 80, 80)
.addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(errorText)))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commonFilesSearchLabel2)
.addComponent(intraCaseRadio)
.addComponent(interCaseRadio)
.addComponent(commonFilesSearchLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(categoriesLabel)
.addComponent(selectedFileCategoriesButton)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(29, 29, 29)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(documentsCheckbox)
.addComponent(pictureVideoCheckbox)))
.addComponent(allFileCategoriesRadioButton)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(layoutPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(percentageThresholdCheck)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(percentageThresholdTextOne, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(percentageThresholdTextTwo)))
.addContainerGap(9, Short.MAX_VALUE))))
); );
jPanel1Layout.setVerticalGroup( jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -656,68 +667,72 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(percentageThresholdCheck) .addComponent(percentageThresholdCheck)
.addComponent(percentageThreshold, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(percentageThresholdTextOne, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)) .addComponent(percentageThresholdTextTwo))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(searchButton) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(cancelButton) .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(errorText)) .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(searchButton)
.addComponent(cancelButton)
.addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
); );
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER); getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
search();
SwingUtilities.windowForComponent(this).dispose();
}//GEN-LAST:event_searchButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
SwingUtilities.windowForComponent(this).dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_documentsCheckboxActionPerformed
private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intraCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).first(this.layoutPanel);
}//GEN-LAST:event_intraCaseRadioActionPerformed
private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).last(this.layoutPanel);
}//GEN-LAST:event_interCaseRadioActionPerformed
private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
SwingUtilities.windowForComponent(this).dispose(); SwingUtilities.windowForComponent(this).dispose();
}//GEN-LAST:event_formWindowClosed }//GEN-LAST:event_formWindowClosed
private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdCheckActionPerformed private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdCheckActionPerformed
if (this.percentageThresholdCheck.isSelected()) { if (this.percentageThresholdCheck.isSelected()) {
this.percentageThreshold.setEnabled(true); this.percentageThresholdTextOne.setEnabled(true);
} else { } else {
this.percentageThreshold.setEnabled(false); this.percentageThresholdTextOne.setEnabled(false);
} }
this.handleFrequencyPercentageState(); this.handleFrequencyPercentageState();
}//GEN-LAST:event_percentageThresholdCheckActionPerformed }//GEN-LAST:event_percentageThresholdCheckActionPerformed
private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).last(this.layoutPanel);
}//GEN-LAST:event_interCaseRadioActionPerformed
private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intraCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).first(this.layoutPanel);
}//GEN-LAST:event_intraCaseRadioActionPerformed
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_documentsCheckboxActionPerformed
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
SwingUtilities.windowForComponent(this).dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
search();
SwingUtilities.windowForComponent(this).dispose();
}//GEN-LAST:event_searchButtonActionPerformed
private void percentageThresholdChanged() { private void percentageThresholdChanged() {
String percentageString = this.percentageThreshold.getText(); String percentageString = this.percentageThresholdTextOne.getText();
try { try {
this.percentageThresholdValue = Integer.parseInt(percentageString); this.percentageThresholdValue = Integer.parseInt(percentageString);
@ -743,15 +758,17 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
} }
private void enablePercentageOptions() { private void enablePercentageOptions() {
this.percentageThreshold.setEnabled(true); this.percentageThresholdTextOne.setEnabled(true);
this.percentageThresholdCheck.setEnabled(true); this.percentageThresholdCheck.setEnabled(true);
this.percentageThresholdCheck.setSelected(true); this.percentageThresholdCheck.setSelected(true);
this.percentageThresholdTextTwo.setEnabled(true);
} }
private void disablePercentageOptions() { private void disablePercentageOptions() {
this.percentageThreshold.setEnabled(false); this.percentageThresholdTextOne.setEnabled(false);
this.percentageThresholdCheck.setEnabled(false); this.percentageThresholdCheck.setEnabled(false);
this.percentageThresholdCheck.setSelected(false); this.percentageThresholdCheck.setSelected(false);
this.percentageThresholdTextTwo.setEnabled(false);
} }
private void handleFileTypeCheckBoxState() { private void handleFileTypeCheckBoxState() {
@ -803,16 +820,18 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
private javax.swing.JCheckBox documentsCheckbox; private javax.swing.JCheckBox documentsCheckbox;
private javax.swing.JLabel errorText; private javax.swing.JLabel errorText;
private javax.swing.ButtonGroup fileTypeFilterButtonGroup; private javax.swing.ButtonGroup fileTypeFilterButtonGroup;
private javax.swing.Box.Filler filler1;
private javax.swing.Box.Filler filler2;
private org.sleuthkit.autopsy.commonfilesearch.InterCasePanel interCasePanel; private org.sleuthkit.autopsy.commonfilesearch.InterCasePanel interCasePanel;
private javax.swing.JRadioButton interCaseRadio; private javax.swing.JRadioButton interCaseRadio;
private javax.swing.ButtonGroup interIntraButtonGroup; private javax.swing.ButtonGroup interIntraButtonGroup;
private org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel intraCasePanel; private org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel intraCasePanel;
private javax.swing.JRadioButton intraCaseRadio; private javax.swing.JRadioButton intraCaseRadio;
private javax.swing.JLabel jLabel1;
private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel1;
private java.awt.Panel layoutPanel; private java.awt.Panel layoutPanel;
private javax.swing.JTextField percentageThreshold;
private javax.swing.JCheckBox percentageThresholdCheck; private javax.swing.JCheckBox percentageThresholdCheck;
private javax.swing.JTextField percentageThresholdTextOne;
private javax.swing.JLabel percentageThresholdTextTwo;
private javax.swing.JCheckBox pictureVideoCheckbox; private javax.swing.JCheckBox pictureVideoCheckbox;
private javax.swing.JButton searchButton; private javax.swing.JButton searchButton;
private javax.swing.JRadioButton selectedFileCategoriesButton; private javax.swing.JRadioButton selectedFileCategoriesButton;

View File

@ -93,7 +93,7 @@ final public class CommonAttributeSearchResultRootNode extends DisplayableItemNo
@Override @Override
protected Node createNodeForKey(Integer instanceCount){ protected Node createNodeForKey(Integer instanceCount){
List<CommonAttributeValue> attributeValues = this.searchResults.getAttributeValuesForInstanceCount(instanceCount); CommonAttributeValueList attributeValues = this.searchResults.getAttributeValuesForInstanceCount(instanceCount);
return new InstanceCountNode(instanceCount, attributeValues); return new InstanceCountNode(instanceCount, attributeValues);
} }
} }

View File

@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
final public class CommonAttributeSearchResults { final public class CommonAttributeSearchResults {
// maps instance count to list of attribute values. // maps instance count to list of attribute values.
private final Map<Integer, List<CommonAttributeValue>> instanceCountToAttributeValues; private final Map<Integer, CommonAttributeValueList> instanceCountToAttributeValues;
private final int percentageThreshold; private final int percentageThreshold;
@ -46,7 +46,7 @@ final public class CommonAttributeSearchResults {
* @param values list of CommonAttributeValue indexed by size of * @param values list of CommonAttributeValue indexed by size of
* CommonAttributeValue * CommonAttributeValue
*/ */
CommonAttributeSearchResults(Map<Integer, List<CommonAttributeValue>> metadata, int percentageThreshold) { CommonAttributeSearchResults(Map<Integer, CommonAttributeValueList> metadata, int percentageThreshold) {
//wrap in a new object in case any client code has used an unmodifiable collection //wrap in a new object in case any client code has used an unmodifiable collection
this.instanceCountToAttributeValues = new HashMap<>(metadata); this.instanceCountToAttributeValues = new HashMap<>(metadata);
this.percentageThreshold = percentageThreshold; this.percentageThreshold = percentageThreshold;
@ -61,7 +61,7 @@ final public class CommonAttributeSearchResults {
* @param instanceCount key * @param instanceCount key
* @return list of values which represent matches * @return list of values which represent matches
*/ */
List<CommonAttributeValue> getAttributeValuesForInstanceCount(Integer instanceCount) { CommonAttributeValueList getAttributeValuesForInstanceCount(Integer instanceCount) {
return this.instanceCountToAttributeValues.get(instanceCount); return this.instanceCountToAttributeValues.get(instanceCount);
} }
@ -72,7 +72,7 @@ final public class CommonAttributeSearchResults {
* *
* @return map of sizes of children to list of matches * @return map of sizes of children to list of matches
*/ */
public Map<Integer, List<CommonAttributeValue>> getMetadata() throws EamDbException { public Map<Integer, CommonAttributeValueList> getMetadata() throws EamDbException {
if(this.percentageThreshold == 0){ if(this.percentageThreshold == 0){
return Collections.unmodifiableMap(this.instanceCountToAttributeValues); return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
} else { } else {
@ -86,13 +86,13 @@ final public class CommonAttributeSearchResults {
* search. * search.
* *
* Remove results which are not found in the portion of available data * Remove results which are not found in the portion of available data
* sources described by minimumPercentageThreshold. sources described by maximumPercentageThreshold.
* *
* @return metadata * @return metadata
*/ */
private Map<Integer, List<CommonAttributeValue>> getMetadata(int minimumPercentageThreshold) throws EamDbException { private Map<Integer, CommonAttributeValueList> getMetadata(int maximumPercentageThreshold) throws EamDbException {
if(minimumPercentageThreshold == 0){ if(maximumPercentageThreshold == 0){
return Collections.unmodifiableMap(this.instanceCountToAttributeValues); return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
} }
@ -106,16 +106,16 @@ final public class CommonAttributeSearchResults {
Map<Integer, List<CommonAttributeValue>> itemsToRemove = new HashMap<>(); Map<Integer, List<CommonAttributeValue>> itemsToRemove = new HashMap<>();
for(Entry<Integer, List<CommonAttributeValue>> listOfValues : Collections.unmodifiableMap(this.instanceCountToAttributeValues).entrySet()){ for(Entry<Integer, CommonAttributeValueList> listOfValues : Collections.unmodifiableMap(this.instanceCountToAttributeValues).entrySet()){
final Integer key = listOfValues.getKey(); final Integer key = listOfValues.getKey();
final List<CommonAttributeValue> values = listOfValues.getValue(); final CommonAttributeValueList values = listOfValues.getValue();
for(CommonAttributeValue value : values){ for(CommonAttributeValue value : values.getDelayedMetadataList()){ // Need the real metadata
int frequencyPercentage = eamDb.getFrequencyPercentage(new CorrelationAttributeInstance(fileAttributeType, value.getValue())); int frequencyPercentage = eamDb.getFrequencyPercentage(new CorrelationAttributeInstance(fileAttributeType, value.getValue()));
if(frequencyPercentage < minimumPercentageThreshold){ if(frequencyPercentage > maximumPercentageThreshold){
if(itemsToRemove.containsKey(key)){ if(itemsToRemove.containsKey(key)){
itemsToRemove.get(key).add(value); itemsToRemove.get(key).add(value);
} else { } else {
@ -133,10 +133,10 @@ final public class CommonAttributeSearchResults {
final List<CommonAttributeValue> values = valuesToRemove.getValue(); final List<CommonAttributeValue> values = valuesToRemove.getValue();
for (CommonAttributeValue value : values){ for (CommonAttributeValue value : values){
final List<CommonAttributeValue> instanceCountValue = this.instanceCountToAttributeValues.get(key); final CommonAttributeValueList instanceCountValue = this.instanceCountToAttributeValues.get(key);
instanceCountValue.remove(value); instanceCountValue.removeMetaData(value);
if(instanceCountValue.isEmpty()){ if(instanceCountValue.getDelayedMetadataList().isEmpty()){ // Check the real metadata
this.instanceCountToAttributeValues.remove(key); this.instanceCountToAttributeValues.remove(key);
} }
} }
@ -153,8 +153,8 @@ final public class CommonAttributeSearchResults {
public int size() { public int size() {
int count = 0; int count = 0;
for (List<CommonAttributeValue> data : this.instanceCountToAttributeValues.values()) { for (CommonAttributeValueList data : this.instanceCountToAttributeValues.values()) {
for (CommonAttributeValue md5 : data) { for(CommonAttributeValue md5 : data.getMetadataList()){
count += md5.getInstanceCount(); count += md5.getInstanceCount();
} }
} }

View File

@ -39,6 +39,7 @@ final public class CommonAttributeValue {
CommonAttributeValue(String md5, List<AbstractCommonAttributeInstance> fileInstances) { CommonAttributeValue(String md5, List<AbstractCommonAttributeInstance> fileInstances) {
this.md5 = md5; this.md5 = md5;
this.fileInstances = fileInstances; this.fileInstances = fileInstances;
} }
CommonAttributeValue(String md5) { CommonAttributeValue(String md5) {
@ -85,4 +86,7 @@ final public class CommonAttributeValue {
public int getInstanceCount() { public int getInstanceCount() {
return this.fileInstances.size(); return this.fileInstances.size();
} }
} }

View File

@ -0,0 +1,111 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2018 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.commonfilesearch;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Utility and wrapper model around data required for Common Files Search
* results. Subclass this to implement different selections of files from the
* case.
*/
final public class CommonAttributeValueList {
/**
* The list of value nodes, which begins empty.
*/
private final List<CommonAttributeValue> metadataList;
/**
* The backing list of value nodes, which will be dynamically loaded
* when requested.
*/
private final List<CommonAttributeValue> delayedMetadataList;
/**
* Create a metadata object containing the list of metadata which can be
* handed off to the node factories.
*
* @param metadata list of Md5Metadata indexed by size of Md5Metadata
*/
CommonAttributeValueList(List<CommonAttributeValue> metadata) {
this.metadataList = new ArrayList<>();
this.delayedMetadataList = metadata;
}
CommonAttributeValueList() {
this.metadataList = new ArrayList<>();
this.delayedMetadataList = new ArrayList<>();
}
/**
* Get the list of value nodes. Will be empty if
* displayDelayedMetadata() has not been called for the
* parent InstanceCountNode
* @return metadataList the list of nodes
*/
public List<CommonAttributeValue> getMetadataList() {
return Collections.unmodifiableList(this.metadataList);
}
/**
* Get the delayed list of value nodes. Only use for
* determining how many CommonAttributeValues
* actually exist in the list.
* @return metadataList the list of nodes
*/
List<CommonAttributeValue> getDelayedMetadataList() {
return Collections.unmodifiableList(this.delayedMetadataList);
}
void removeMetaData(CommonAttributeValue commonVal) {
this.delayedMetadataList.remove(commonVal);
}
/**
* Return the size of the backing list, in case
* displayDelayedMetadata() has not be called yet.
* @return int the number of matches for this value
*/
int getCommonAttributeListSize() {
return this.delayedMetadataList.size();
}
/**
* Dynamically load the list CommonAttributeValue when called. Until called
* metadataList should be empty. The parent node, InstanceCountNode, will
* trigger the factory call and refresh.
*/
public void displayDelayedMetadata() {
if (metadataList.isEmpty()) {
this.metadataList.addAll(this.delayedMetadataList);
}
}
/**
* A a value node to the list, to be loaded later.
* @param metadata the node to add
*/
void addMetadataToList(CommonAttributeValue metadata) {
delayedMetadataList.add(metadata);
}
}

View File

@ -29,6 +29,7 @@ import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.DelayedLoadChildNodesOnTreeExpansion;
/** /**
* <code>DataResultViewerTable</code> which overrides the default column * <code>DataResultViewerTable</code> which overrides the default column
@ -59,7 +60,19 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa
COLUMN_WIDTHS = Collections.unmodifiableMap(map); COLUMN_WIDTHS = Collections.unmodifiableMap(map);
} }
/**
* Implements a DataResultViewerTable which constructs a tabular result viewer that
* displays the children of the given root node using an OutlineView. The explorer
* manager will be discovered at runtime.
*
* Adds a TreeExpansionsListener to the outlineView to receive tree expansion events
* which dynamically loads children nodes when requested.
*/
public CommonAttributesSearchResultsViewerTable() {
super();
outlineView.addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion());
}
@NbBundle.Messages({ @NbBundle.Messages({
"CommonFilesSearchResultsViewerTable.noDescText= ", "CommonFilesSearchResultsViewerTable.noDescText= ",
"CommonFilesSearchResultsViewerTable.filesColLbl=Files", "CommonFilesSearchResultsViewerTable.filesColLbl=Files",

View File

@ -19,7 +19,6 @@
*/ */
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -29,52 +28,68 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.datamodel.NodeProperty;
/** /**
* Node used to indicate the number of matches found with the MD5 children * Node used to indicate the number of matches found with the MD5 children of
* of this Node. * this Node.
*/ */
final public class InstanceCountNode extends DisplayableItemNode { final public class InstanceCountNode extends DisplayableItemNode {
private static final Logger logger = Logger.getLogger(InstanceCountNode.class.getName());
final private int instanceCount; final private int instanceCount;
final private List<CommonAttributeValue> attributeValues; final private CommonAttributeValueList attributeValues;
/** /**
* Create a node with the given number of instances, and the given * Create a node with the given number of instances, and the given selection
* selection of metadata. * of metadata.
*
* @param instanceCount * @param instanceCount
* @param attributeValues * @param attributeValues
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"InstanceCountNode.displayName=Files with %s instances (%s)" "InstanceCountNode.displayName=Files with %s instances (%s)"
}) })
public InstanceCountNode(int instanceCount, List<CommonAttributeValue> attributeValues) { public InstanceCountNode(int instanceCount, CommonAttributeValueList attributeValues) {
super(Children.create(new CommonAttributeValueNodeFactory(attributeValues), true)); super(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList()), true));
this.instanceCount = instanceCount; this.instanceCount = instanceCount;
this.attributeValues = attributeValues; this.attributeValues = attributeValues;
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), attributeValues.size())); this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), attributeValues.getCommonAttributeListSize()));
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
} }
/** /**
* Number of matches found for each of the MD5 children. * Number of matches found for each of the MD5 children.
*
* @return int match count * @return int match count
*/ */
int getInstanceCount() { int getInstanceCount() {
return this.instanceCount; return this.instanceCount;
} }
/**
* Refresh the node, by dynamically loading in the children when called, and
* calling the CommonAttributeValueNodeFactory to generate nodes for the
* children in attributeValues.
*/
public void refresh() {
attributeValues.displayDelayedMetadata();
setChildren(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList()), true));
}
/** /**
* Get a list of metadata for the MD5s which are children of this object. * Get a list of metadata for the MD5s which are children of this object.
*
* @return List<Md5Metadata> * @return List<Md5Metadata>
*/ */
List<CommonAttributeValue> getAttributeValues() { CommonAttributeValueList getAttributeValues() {
return Collections.unmodifiableList(this.attributeValues); return this.attributeValues;
} }
@Override @Override
@ -101,17 +116,23 @@ final public class InstanceCountNode extends DisplayableItemNode {
sheetSet = Sheet.createPropertiesSet(); sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet); sheet.put(sheetSet);
} }
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription(); final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, "")); 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())); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), NO_DESCR, ""));
return sheet; return sheet;
} }
/** /**
* ChildFactory which builds CommonFileParentNodes from the * ChildFactory which builds CommonFileParentNodes from the
* CommonFilesMetaaData models. * CommonAttributeValue metadata models.
*/ */
static class CommonAttributeValueNodeFactory extends ChildFactory<String> { static class CommonAttributeValueNodeFactory extends ChildFactory<String> {
@ -138,11 +159,11 @@ final public class InstanceCountNode extends DisplayableItemNode {
list.addAll(this.metadata.keySet()); list.addAll(this.metadata.keySet());
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String attributeValue) { protected Node createNodeForKey(String attributeValue) {
CommonAttributeValue md5Metadata = this.metadata.get(attributeValue); CommonAttributeValue md5Metadata = this.metadata.get(attributeValue);
return new CommonAttributeValueNode(md5Metadata); return new CommonAttributeValueNode(md5Metadata);
} }
} }
} }

View File

@ -20,10 +20,8 @@ package org.sleuthkit.autopsy.commonfilesearch;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
@ -140,7 +138,7 @@ final class InterCaseSearchResultsProcessor {
* *
* @param currentCase The current TSK Case. * @param currentCase The current TSK Case.
*/ */
Map<Integer, List<CommonAttributeValue>> findInterCaseCommonAttributeValues(Case currentCase) { Map<Integer, CommonAttributeValueList> findInterCaseCommonAttributeValues(Case currentCase) {
try { try {
InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback(); InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback();
EamDb DbManager = EamDb.getInstance(); EamDb DbManager = EamDb.getInstance();
@ -167,7 +165,7 @@ final class InterCaseSearchResultsProcessor {
* @param currentCase The current TSK Case. * @param currentCase The current TSK Case.
* @param singleCase The case of interest. Matches must exist in this case. * @param singleCase The case of interest. Matches must exist in this case.
*/ */
Map<Integer, List<CommonAttributeValue>> findSingleInterCaseCommonAttributeValues(Case currentCase, CorrelationCase singleCase) { Map<Integer, CommonAttributeValueList> findSingleInterCaseCommonAttributeValues(Case currentCase, CorrelationCase singleCase) {
try { try {
InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback(); InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback();
EamDb DbManager = EamDb.getInstance(); EamDb DbManager = EamDb.getInstance();
@ -188,7 +186,7 @@ final class InterCaseSearchResultsProcessor {
*/ */
private class InterCaseCommonAttributesCallback implements InstanceTableCallback { private class InterCaseCommonAttributesCallback implements InstanceTableCallback {
final Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = new HashMap<>(); final Map<Integer, CommonAttributeValueList> instanceCollatedCommonFiles = new HashMap<>();
private CommonAttributeValue commonAttributeValue = null; private CommonAttributeValue commonAttributeValue = null;
private String previousRowMd5 = ""; private String previousRowMd5 = "";
@ -234,10 +232,10 @@ final class InterCaseSearchResultsProcessor {
if (!corValue.equals(previousRowMd5)) { if (!corValue.equals(previousRowMd5)) {
int size = commonAttributeValue.getInstanceCount(); int size = commonAttributeValue.getInstanceCount();
if (instanceCollatedCommonFiles.containsKey(size)) { if (instanceCollatedCommonFiles.containsKey(size)) {
instanceCollatedCommonFiles.get(size).add(commonAttributeValue); instanceCollatedCommonFiles.get(size).addMetadataToList(commonAttributeValue);
} else { } else {
ArrayList<CommonAttributeValue> value = new ArrayList<>(); CommonAttributeValueList value = new CommonAttributeValueList();
value.add(commonAttributeValue); value.addMetadataToList(commonAttributeValue);
instanceCollatedCommonFiles.put(size, value); instanceCollatedCommonFiles.put(size, value);
} }
@ -251,7 +249,7 @@ final class InterCaseSearchResultsProcessor {
commonAttributeValue.addInstance(searchResult); commonAttributeValue.addInstance(searchResult);
} }
Map<Integer, List<CommonAttributeValue>> getInstanceCollatedCommonFiles() { Map<Integer, CommonAttributeValueList> getInstanceCollatedCommonFiles() {
return Collections.unmodifiableMap(instanceCollatedCommonFiles); return Collections.unmodifiableMap(instanceCollatedCommonFiles);
} }
} }

View File

@ -128,7 +128,7 @@ public abstract class IntraCaseCommonAttributeSearcher extends AbstractCommonAtt
} }
} }
Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = collateMatchesByNumberOfInstances(commonFiles); Map<Integer, CommonAttributeValueList> instanceCollatedCommonFiles = collateMatchesByNumberOfInstances(commonFiles);
return new CommonAttributeSearchResults(instanceCollatedCommonFiles, this.frequencyPercentageThreshold); return new CommonAttributeSearchResults(instanceCollatedCommonFiles, this.frequencyPercentageThreshold);
} }

View File

@ -75,7 +75,7 @@ public class SingleInterCaseCommonAttributeSearcher extends InterCaseCommonAttri
CommonAttributeSearchResults findFiles(CorrelationCase correlationCase) throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException { CommonAttributeSearchResults findFiles(CorrelationCase correlationCase) throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), corAttrType); InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), corAttrType);
Map<Integer, List<CommonAttributeValue>> interCaseCommonFiles = eamDbAttrInst.findSingleInterCaseCommonAttributeValues(Case.getCurrentCase(), correlationCase); Map<Integer, CommonAttributeValueList> interCaseCommonFiles = eamDbAttrInst.findSingleInterCaseCommonAttributeValues(Case.getCurrentCase(), correlationCase);
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold); return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold);
} }

View File

@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openide.util.NbBundle;
/** /**
* Manager for present state of errors on the Common Files Search. * Manager for present state of errors on the Common Files Search.
@ -39,14 +40,17 @@ class UserInputErrorManager {
* of all known error states, retrieve error messages, and determine if * of all known error states, retrieve error messages, and determine if
* anything is in an error state. * anything is in an error state.
*/ */
@NbBundle.Messages({
"UserInputErrorManager.frequency=Invalid Frequency Percentage: 0 < % < 100.",
"UserInputErrorManager.categories=No file categories are included in the search."})
UserInputErrorManager (){ UserInputErrorManager (){
//when new errors are needed for the dialog, define a key and a value //when new errors are needed for the dialog, define a key and a value
// and add them to the map. // and add them to the map.
this.currentErrors = new HashMap<>(); this.currentErrors = new HashMap<>();
this.currentErrors.put(FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, new ErrorMessage("Frequency percentage must be greater than zero and less than or equal to 100.")); this.currentErrors.put(FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, new ErrorMessage(Bundle.UserInputErrorManager_frequency()));
this.currentErrors.put(NO_FILE_CATEGORIES_SELECTED_KEY, new ErrorMessage("No file categories are included in the search.")); this.currentErrors.put(NO_FILE_CATEGORIES_SELECTED_KEY, new ErrorMessage(Bundle.UserInputErrorManager_categories()));
} }
/** /**

View File

@ -29,6 +29,7 @@
<Container class="org.openide.explorer.view.OutlineView" name="outlineView"> <Container class="org.openide.explorer.view.OutlineView" name="outlineView">
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/> <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues> </AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>

View File

@ -102,6 +102,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
public DataResultViewerTable() { public DataResultViewerTable() {
this(null, Bundle.DataResultViewerTable_title()); this(null, Bundle.DataResultViewerTable_title());
} }
/** /**
* Constructs a tabular result viewer that displays the children of a given * Constructs a tabular result viewer that displays the children of a given
@ -179,13 +180,14 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
/** /**
* Gets the title of this tabular result viewer. * Gets the title of this tabular result viewer.
* @return title of tab. * @return
*/ */
@Override @Override
@NbBundle.Messages("DataResultViewerTable.title=Table") @NbBundle.Messages("DataResultViewerTable.title=Table")
public String getTitle() { public String getTitle() {
return title; return title;
} }
/** /**
* Indicates whether a given node is supported as a root node for this * Indicates whether a given node is supported as a root node for this
@ -837,7 +839,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private org.openide.explorer.view.OutlineView outlineView; protected org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -0,0 +1,54 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2018 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.corecomponents;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import org.openide.explorer.view.Visualizer;
import org.openide.nodes.Node;
/**
* A tree expansion listener that will trigger a recreation of childs through
* its child factory on re-expansion of a node (causes to recreate the
* ChildFactory for this purpose.).
*/
public final class DelayedLoadChildNodesOnTreeExpansion implements TreeExpansionListener {
/**
* A flag for avoiding endless recursion inside the expansion listener that
* could trigger collapsing and (re-)expanding nodes again.
* @param event
*/
@Override
public synchronized void treeCollapsed(final TreeExpansionEvent event) {
// Do nothing on collapse. Netbeans should manage nodes falling out of scope and GC.
}
@Override
public synchronized void treeExpanded(final TreeExpansionEvent event) {
Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent());
if (eventNode instanceof TableFilterNode) {
final TableFilterNode node = (TableFilterNode) eventNode;
node.refresh();
}
}
}

View File

@ -128,6 +128,16 @@ public class TableFilterNode extends FilterNode {
return null; return null;
} }
} }
/**
* Refreshes the inner node, which depending on the actual node type that was wrapped
* could trigger a dynamic refresh of the children, if supported.
*/
void refresh() {
DataResultFilterNode innerNode = getLookup().lookup(DataResultFilterNode.class);
innerNode.refresh();
}
/** /**
* @return the column order key, which allows custom column ordering to be * @return the column order key, which allows custom column ordering to be

View File

@ -132,26 +132,38 @@ public class DataResultFilterNode extends FilterNode {
* wrapped node and may filter out some of its children. * wrapped node and may filter out some of its children.
* *
* @param node The node to wrap. * @param node The node to wrap.
* @param em The ExplorerManager for the component that is creating the * @param em The ExplorerManager for the component that is creating the
* node. * node.
*/ */
public DataResultFilterNode(Node node, ExplorerManager em) { public DataResultFilterNode(Node node, ExplorerManager em) {
super(node, new DataResultFilterChildren(node, em)); super(node, new DataResultFilterChildren(node, em));
this.sourceEm = em; this.sourceEm = em;
} }
/**
* Refreshes the inner node. If the actual underlying node is an InstanceCountNode,
* refresh() that node, which refreshes the children.
*
*/
public void refresh() {
if (getOriginal() instanceof InstanceCountNode) {
InstanceCountNode innerNode = getLookup().lookup(InstanceCountNode.class);
innerNode.refresh();
}
}
/** /**
* Constructs a node used to wrap another node before passing it to the * Constructs a node used to wrap another node before passing it to the
* result viewers. The wrapper node defines the actions associated with the * result viewers. The wrapper node defines the actions associated with the
* wrapped node and may filter out some of its children. * wrapped node and may filter out some of its children.
* *
* @param node The node to wrap. * @param node The node to wrap.
* @param em The ExplorerManager for the component that is creating * @param em The ExplorerManager for the component that is creating the
* the node. * node.
* @param filterKnown Whether or not to filter out children that represent * @param filterKnown Whether or not to filter out children that represent
* known files. * known files.
* @param filterSlack Whether or not to filter out children that represent * @param filterSlack Whether or not to filter out children that represent
* virtual slack space files. * virtual slack space files.
*/ */
private DataResultFilterNode(Node node, ExplorerManager em, boolean filterKnown, boolean filterSlack) { private DataResultFilterNode(Node node, ExplorerManager em, boolean filterKnown, boolean filterSlack) {
super(node, new DataResultFilterChildren(node, em, filterKnown, filterSlack)); super(node, new DataResultFilterChildren(node, em, filterKnown, filterSlack));
@ -261,7 +273,7 @@ public class DataResultFilterNode extends FilterNode {
* selected. * selected.
* *
* @return The child node selection information, or null if no child should * @return The child node selection information, or null if no child should
* be selected. * be selected.
*/ */
public NodeSelectionInfo getChildNodeSelectionInfo() { public NodeSelectionInfo getChildNodeSelectionInfo() {
if (getOriginal() instanceof DisplayableItemNode) { if (getOriginal() instanceof DisplayableItemNode) {
@ -390,14 +402,14 @@ public class DataResultFilterNode extends FilterNode {
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c)); NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
} }
// action to go to the source file of the artifact // action to go to the source file of the artifact
// action to go to the source file of the artifact // action to go to the source file of the artifact
Content fileContent = ban.getLookup().lookup(AbstractFile.class); Content fileContent = ban.getLookup().lookup(AbstractFile.class);
if (fileContent == null) { if (fileContent == null) {
Content content = ban.getLookup().lookup(Content.class); Content content = ban.getLookup().lookup(Content.class);
actionsList.add(new ViewContextAction("View Source Content in Directory", content)); actionsList.add(new ViewContextAction("View Source Content in Directory", content));
} else { } else {
actionsList.add(new ViewContextAction( actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban)); NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban));
} }
} }
Content c = ban.getLookup().lookup(File.class); Content c = ban.getLookup().lookup(File.class);
@ -524,21 +536,21 @@ public class DataResultFilterNode extends FilterNode {
*/ */
private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default<AbstractAction> { private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default<AbstractAction> {
@Override @Override
public AbstractAction visit(InstanceCountNode icn){ public AbstractAction visit(InstanceCountNode icn) {
return null; return null;
} }
@Override @Override
public AbstractAction visit(CommonAttributeValueNode md5n){ public AbstractAction visit(CommonAttributeValueNode md5n){
return null; return null;
} }
@Override @Override
public AbstractAction visit(CaseDBCommonAttributeInstanceNode fin){ public AbstractAction visit(CaseDBCommonAttributeInstanceNode fin){
return null; return null;
} }
@Override @Override
public AbstractAction visit(CentralRepoCommonAttributeInstanceNode iccan){ public AbstractAction visit(CentralRepoCommonAttributeInstanceNode iccan){
return null; return null;

View File

@ -57,64 +57,36 @@ import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstance
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader; import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/** /**
* Utilities for testing intercase correlation feature. * Utilities for testing intercase correlation feature.
* *
* This will be more useful when we add more flush out the intercase * This will be more useful when we add more flush out the intercase correlation
* correlation features and need to add more tests. In particular, * features and need to add more tests. In particular, testing scenarios where
* testing scenarios where we need different cases to be the current case * we need different cases to be the current case will suggest that we create
* will suggest that we create additional test classes, and we will want to * additional test classes, and we will want to import this utility in each new
* import this utility in each new intercase test file. * intercase test file.
* *
* Description of Test Data: * Description of Test Data: (Note: files of the same name and extension are
(Note: files of the same name and extension are identical; * identical; files of the same name and differing extension are not identical.)
files of the same name and differing extension are not identical.) *
* Case 1 +Data Set 1 - Hash-0.dat [testFile of size 0] - Hash-A.jpg -
Case 1 * Hash-A.pdf +Data Set2 - Hash-0.dat [testFile of size 0] - Hash-A.jpg -
+Data Set 1 * Hash-A.pdf Case 2 +Data Set 1 - Hash-B.jpg - Hash-B.pdf +Data Set 2 -
- Hash-0.dat [testFile of size 0] * Hash-A.jpg - Hash-A.pdf - Hash_D.doc Case 3 +Data Set 1 - Hash-A.jpg -
- Hash-A.jpg * Hash-A.pdf - Hash-C.jpg - Hash-C.pdf - Hash-D.jpg +Data Set 2 - Hash-C.jpg -
- Hash-A.pdf * Hash-C.pdf - Hash-D.doc
+Data Set2 *
- Hash-0.dat [testFile of size 0] * Frequency Breakdown (ratio of datasources a given file appears in to total
- Hash-A.jpg * number of datasources):
- Hash-A.pdf *
Case 2 * Hash-0.dat - moot; these are always excluded Hash-A.jpg - 4/6 Hash-A.pdf -
+Data Set 1 * 4/6 Hash-B.jpg - 1/6 Hash-B.pdf - 1/6 Hash-C.jpg - 2/6 Hash-C.pdf - 2/6
- Hash-B.jpg * Hash_D.doc - 2/6 Hash-D.jpg - 1/6
- Hash-B.pdf *
+Data Set 2
- Hash-A.jpg
- Hash-A.pdf
- Hash_D.doc
Case 3
+Data Set 1
- Hash-A.jpg
- Hash-A.pdf
- Hash-C.jpg
- Hash-C.pdf
- Hash-D.jpg
+Data Set 2
- Hash-C.jpg
- Hash-C.pdf
- Hash-D.doc
*
* Frequency Breakdown
* (ratio of datasources a given file appears in to total number of datasources):
*
* Hash-0.dat - moot; these are always excluded
* Hash-A.jpg - 4/6
* Hash-A.pdf - 4/6
* Hash-B.jpg - 1/6
* Hash-B.pdf - 1/6
* Hash-C.jpg - 2/6
* Hash-C.pdf - 2/6
* Hash_D.doc - 2/6
* Hash-D.jpg - 1/6
*
*/ */
class InterCaseTestUtils { class InterCaseTestUtils {
@ -187,21 +159,21 @@ class InterCaseTestUtils {
this.dataSourceLoader = new DataSourceLoader(); this.dataSourceLoader = new DataSourceLoader();
} }
void clearTestDir(){ void clearTestDir() {
if(CASE_DIRECTORY_PATH.toFile().exists()){ if (CASE_DIRECTORY_PATH.toFile().exists()) {
try{ try {
if(EamDb.isEnabled()) { if (EamDb.isEnabled()) {
EamDb.getInstance().shutdownConnections(); EamDb.getInstance().shutdownConnections();
} }
FileUtils.deleteDirectory(CASE_DIRECTORY_PATH.toFile()); FileUtils.deleteDirectory(CASE_DIRECTORY_PATH.toFile());
} catch(IOException | EamDbException ex){ } catch (IOException | EamDbException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
} }
} }
CASE_DIRECTORY_PATH.toFile().exists(); CASE_DIRECTORY_PATH.toFile().exists();
} }
Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException { Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException {
return this.dataSourceLoader.getDataSourceMap(); return this.dataSourceLoader.getDataSourceMap();
} }
@ -238,7 +210,7 @@ class InterCaseTestUtils {
if (!crSettings.dbDirectoryExists()) { if (!crSettings.dbDirectoryExists()) {
crSettings.createDbDirectory(); crSettings.createDbDirectory();
} }
crSettings.initializeDatabaseSchema(); crSettings.initializeDatabaseSchema();
crSettings.insertDefaultDatabaseContent(); crSettings.insertDefaultDatabaseContent();
@ -317,59 +289,59 @@ class InterCaseTestUtils {
return null; return null;
} }
} }
static boolean verifyInstanceExistanceAndCount(CommonAttributeSearchResults searchDomain, String fileName, String dataSource, String crCase, int instanceCount){ static boolean verifyInstanceExistanceAndCount(CommonAttributeSearchResults searchDomain, String fileName, String dataSource, String crCase, int instanceCount) {
try { try {
int tally = 0; int tally = 0;
for(Map.Entry<Integer, List<CommonAttributeValue>> entry : searchDomain.getMetadata().entrySet()){ for (Map.Entry<Integer, CommonAttributeValueList> entry : searchDomain.getMetadata().entrySet()) {
entry.getValue().displayDelayedMetadata();
for(CommonAttributeValue value : entry.getValue()){ for (CommonAttributeValue value : entry.getValue().getMetadataList()) {
for(AbstractCommonAttributeInstance commonAttribute : value.getInstances()){ for (AbstractCommonAttributeInstance commonAttribute : value.getInstances()) {
if(commonAttribute instanceof CentralRepoCommonAttributeInstance){ if (commonAttribute instanceof CentralRepoCommonAttributeInstance) {
CentralRepoCommonAttributeInstance results = (CentralRepoCommonAttributeInstance) commonAttribute; CentralRepoCommonAttributeInstance results = (CentralRepoCommonAttributeInstance) commonAttribute;
for (DisplayableItemNode din : results.generateNodes()){ for (DisplayableItemNode din : results.generateNodes()) {
if(din instanceof CentralRepoCommonAttributeInstanceNode){ if (din instanceof CentralRepoCommonAttributeInstanceNode) {
CentralRepoCommonAttributeInstanceNode node = (CentralRepoCommonAttributeInstanceNode) din; CentralRepoCommonAttributeInstanceNode node = (CentralRepoCommonAttributeInstanceNode) din;
CorrelationAttributeInstance instance = node.getCorrelationAttributeInstance(); CorrelationAttributeInstance instance = node.getCorrelationAttributeInstance();
final String fullPath = instance.getFilePath(); final String fullPath = instance.getFilePath();
final File testFile = new File(fullPath); final File testFile = new File(fullPath);
final String testCaseName = instance.getCorrelationCase().getDisplayName(); final String testCaseName = instance.getCorrelationCase().getDisplayName();
final String testFileName = testFile.getName(); final String testFileName = testFile.getName();
final String testDataSource = instance.getCorrelationDataSource().getName(); final String testDataSource = instance.getCorrelationDataSource().getName();
boolean sameFileName = testFileName.equalsIgnoreCase(fileName); boolean sameFileName = testFileName.equalsIgnoreCase(fileName);
boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource); boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource);
boolean sameCrCase = testCaseName.equalsIgnoreCase(crCase); boolean sameCrCase = testCaseName.equalsIgnoreCase(crCase);
if( sameFileName && sameDataSource && sameCrCase){ if (sameFileName && sameDataSource && sameCrCase) {
tally++; tally++;
} }
} }
if(din instanceof CaseDBCommonAttributeInstanceNode){ if (din instanceof CaseDBCommonAttributeInstanceNode) {
CaseDBCommonAttributeInstanceNode node = (CaseDBCommonAttributeInstanceNode) din; CaseDBCommonAttributeInstanceNode node = (CaseDBCommonAttributeInstanceNode) din;
AbstractFile file = node.getContent(); AbstractFile file = node.getContent();
final String testFileName = file.getName(); final String testFileName = file.getName();
final String testCaseName = node.getCase(); final String testCaseName = node.getCase();
final String testDataSource = node.getDataSource(); final String testDataSource = node.getDataSource();
boolean sameFileName = testFileName.equalsIgnoreCase(fileName); boolean sameFileName = testFileName.equalsIgnoreCase(fileName);
boolean sameCaseName = testCaseName.equalsIgnoreCase(crCase); boolean sameCaseName = testCaseName.equalsIgnoreCase(crCase);
boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource); boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource);
if(sameFileName && sameDataSource && sameCaseName){ if (sameFileName && sameDataSource && sameCaseName) {
tally++; tally++;
} }
} }
@ -378,10 +350,11 @@ class InterCaseTestUtils {
Assert.fail("Unable to cast AbstractCommonAttributeInstanceNode to InterCaseCommonAttributeSearchResults."); Assert.fail("Unable to cast AbstractCommonAttributeInstanceNode to InterCaseCommonAttributeSearchResults.");
} }
} }
} }
} }
return tally == instanceCount; return tally == instanceCount;
} catch (EamDbException ex) { } catch (EamDbException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
@ -394,13 +367,13 @@ class InterCaseTestUtils {
* central repo db. * central repo db.
*/ */
void tearDown() { void tearDown() {
CaseUtils.closeCurrentCase(false); CaseUtils.closeCurrentCase(false);
String[] cases = new String[]{CASE1,CASE2,CASE3}; String[] cases = new String[]{CASE1, CASE2, CASE3};
try { try {
for(String caze : cases){ for (String caze : cases) {
CaseUtils.deleteCaseDir(new File(caze)); CaseUtils.deleteCaseDir(new File(caze));
} }
} catch (IOException ex) { } catch (IOException ex) {

View File

@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader; import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.testutils.CaseUtils; import org.sleuthkit.autopsy.testutils.CaseUtils;
import org.sleuthkit.autopsy.testutils.IngestUtils; import org.sleuthkit.autopsy.testutils.IngestUtils;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -50,24 +51,14 @@ import org.sleuthkit.datamodel.TskCoreException;
* *
* Data set definitions: * Data set definitions:
* *
* set 1 * set 1 + file1 - IMG_6175.jpg + file2 - IMG_6175.jpg + file3 -
* + file1 * BasicStyleGuide.doc
* - IMG_6175.jpg
* + file2
* - IMG_6175.jpg
* + file3
* - BasicStyleGuide.doc
* *
* set 2 * set 2 - adsf.pdf - IMG_6175.jpg
* - adsf.pdf
* - IMG_6175.jpg
* *
* set 3 * set 3 - BasicStyleGuide.doc - IMG_6175.jpg
* - BasicStyleGuide.doc
* - IMG_6175.jpg
* *
* set 4 * set 4 - file.dat (empty file)
* - file.dat (empty file)
*/ */
class IntraCaseTestUtils { class IntraCaseTestUtils {
@ -92,13 +83,13 @@ class IntraCaseTestUtils {
private final DataSourceLoader dataSourceLoader; private final DataSourceLoader dataSourceLoader;
private final String caseName; private final String caseName;
IntraCaseTestUtils(NbTestCase nbTestCase, String caseName){ IntraCaseTestUtils(NbTestCase nbTestCase, String caseName) {
this.imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1); this.imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1);
this.imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2); this.imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2);
this.imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3); this.imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3);
this.imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4); this.imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4);
this.dataSourceLoader = new DataSourceLoader(); this.dataSourceLoader = new DataSourceLoader();
this.caseName = caseName; this.caseName = caseName;
@ -197,24 +188,25 @@ class IntraCaseTestUtils {
} }
/** /**
* Create a convenience lookup table mapping file instance object ids to * Create a convenience lookup table mapping file instance object ids to the
* the data source they appear in. * data source they appear in.
* *
* @param metadata object returned by the code under test * @param metadata object returned by the code under test
* @return mapping of objectId to data source name * @return mapping of objectId to data source name
*/ */
static Map<Long, String> mapFileInstancesToDataSources(CommonAttributeSearchResults metadata) { static Map<Long, String> mapFileInstancesToDataSources(CommonAttributeSearchResults metadata) {
Map<Long, String> instanceIdToDataSource = new HashMap<>(); Map<Long, String> instanceIdToDataSource = new HashMap<>();
try { try {
for (Map.Entry<Integer, List<CommonAttributeValue>> entry : metadata.getMetadata().entrySet()) { for (Map.Entry<Integer, CommonAttributeValueList> entry : metadata.getMetadata().entrySet()) {
for (CommonAttributeValue md : entry.getValue()) { entry.getValue().displayDelayedMetadata();
for (CommonAttributeValue md : entry.getValue().getMetadataList()) {
for (AbstractCommonAttributeInstance fim : md.getInstances()) { for (AbstractCommonAttributeInstance fim : md.getInstances()) {
instanceIdToDataSource.put(fim.getAbstractFileObjectId(), fim.getDataSource()); instanceIdToDataSource.put(fim.getAbstractFileObjectId(), fim.getDataSource());
} }
} }
} }
return instanceIdToDataSource; return instanceIdToDataSource;
} catch (EamDbException ex) { } catch (EamDbException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
@ -223,7 +215,6 @@ class IntraCaseTestUtils {
} }
} }
static List<AbstractFile> getFiles(Set<Long> objectIds) { static List<AbstractFile> getFiles(Set<Long> objectIds) {
List<AbstractFile> files = new ArrayList<>(objectIds.size()); List<AbstractFile> files = new ArrayList<>(objectIds.size());

View File

@ -1398,10 +1398,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
AutoIngestJob job; AutoIngestJob job;
if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) { if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) {
job = new AutoIngestJob(nodeData); job = new AutoIngestJob(nodeData);
Path caseDirectory = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName());
if (null != caseDirectory) {
job.setCaseDirectoryPath(caseDirectory);
}
} else { } else {
job = new AutoIngestJob(manifest); job = new AutoIngestJob(manifest);
job.setPriority(nodeData.getPriority()); // Retain priority, present in all versions of the node data. job.setPriority(nodeData.getPriority()); // Retain priority, present in all versions of the node data.
@ -1431,10 +1427,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
sysLogger.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex); sysLogger.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex);
} }
} }
Path caseDirectory = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName());
if (null != caseDirectory) {
job.setCaseDirectoryPath(caseDirectory);
}
newPendingJobsList.add(job); newPendingJobsList.add(job);
} }
@ -1595,54 +1587,53 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
* @throws InterruptedException * @throws InterruptedException
*/ */
private void addCompletedJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws CoordinationServiceException, InterruptedException, AutoIngestJobException { private void addCompletedJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws CoordinationServiceException, InterruptedException, AutoIngestJobException {
Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); Path caseDirectoryPath = nodeData.getCaseDirectoryPath();
if (null != caseDirectoryPath) { if (!caseDirectoryPath.toFile().exists()) {
AutoIngestJob job; sysLogger.log(Level.WARNING, String.format("Job completed for %s, but cannot find case directory %s, ignoring job", nodeData.getManifestFilePath(), caseDirectoryPath.toString()));
if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) { return;
job = new AutoIngestJob(nodeData); }
job.setCaseDirectoryPath(caseDirectoryPath);
} else {
/**
* Use the manifest rather than the node data here to create
* a new AutoIngestJob instance because the AutoIngestJob
* constructor that takes a node data object expects the
* node data to have fields that do not exist in earlier
* versions.
*/
job = new AutoIngestJob(manifest);
job.setCaseDirectoryPath(caseDirectoryPath);
/** AutoIngestJob job;
* Update the job with the fields that exist in all versions if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) {
* of the nodeData. job = new AutoIngestJob(nodeData);
*/ job.setCaseDirectoryPath(caseDirectoryPath);
job.setCompletedDate(nodeData.getCompletedDate()); } else {
job.setErrorsOccurred(nodeData.getErrorsOccurred()); /**
job.setPriority(nodeData.getPriority()); * Use the manifest rather than the node data here to create a
job.setNumberOfCrashes(nodeData.getNumberOfCrashes()); * new AutoIngestJob instance because the AutoIngestJob
job.setProcessingStage(AutoIngestJob.Stage.COMPLETED, nodeData.getCompletedDate()); * constructor that takes a node data object expects the node
job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); * data to have fields that do not exist in earlier versions.
*/
job = new AutoIngestJob(manifest);
job.setCaseDirectoryPath(caseDirectoryPath);
/* /**
* Update the job with the fields that exist in all versions of
* the nodeData.
*/
job.setCompletedDate(nodeData.getCompletedDate());
job.setErrorsOccurred(nodeData.getErrorsOccurred());
job.setPriority(nodeData.getPriority());
job.setNumberOfCrashes(nodeData.getNumberOfCrashes());
job.setProcessingStage(AutoIngestJob.Stage.COMPLETED, nodeData.getCompletedDate());
job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED);
/*
* Try to upgrade/update the coordination service manifest * Try to upgrade/update the coordination service manifest
* node data for the job. It is possible that two hosts will * node data for the job. It is possible that two hosts will
* both try to obtain the lock to do the upgrade operation * both try to obtain the lock to do the upgrade operation
* at the same time. If this happens, the host that is * at the same time. If this happens, the host that is
* holding the lock will complete the upgrade operation. * holding the lock will complete the upgrade operation.
*/ */
try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) {
if (null != manifestLock) { if (null != manifestLock) {
updateCoordinationServiceManifestNode(job); updateCoordinationServiceManifestNode(job);
}
} catch (CoordinationServiceException ex) {
sysLogger.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex);
} }
} catch (CoordinationServiceException ex) {
sysLogger.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex);
} }
newCompletedJobsList.add(job);
} else {
sysLogger.log(Level.WARNING, String.format("Job completed for %s, but cannot find case directory, ignoring job", nodeData.getManifestFilePath()));
} }
newCompletedJobsList.add(job);
} }
/** /**
@ -2456,6 +2447,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
Thread.sleep(AutoIngestUserPreferences.getSecondsToSleepBetweenCases() * 1000); Thread.sleep(AutoIngestUserPreferences.getSecondsToSleepBetweenCases() * 1000);
} }
currentJob.setCaseDirectoryPath(caseDirectoryPath); currentJob.setCaseDirectoryPath(caseDirectoryPath);
updateCoordinationServiceManifestNode(currentJob); // update case directory path
Case caseForJob = Case.getCurrentCase(); Case caseForJob = Case.getCurrentCase();
sysLogger.log(Level.INFO, "Opened case {0} for {1}", new Object[]{caseForJob.getName(), manifest.getFilePath()}); sysLogger.log(Level.INFO, "Opened case {0} for {1}", new Object[]{caseForJob.getName(), manifest.getFilePath()});
return caseForJob; return caseForJob;