Merge branch 'commonfiles' of https://github.com/briangsweeney/autopsy into 3788-intercase-intracase-merge

# Conflicts:
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributeSearchResultRootNode.java
#	Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributeSearchResults.java
#	Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/InterCaseUtils.java
This commit is contained in:
Brian Sweeney 2018-07-23 15:28:10 -06:00
commit d8b4fc878e
21 changed files with 168 additions and 235 deletions

View File

@ -26,6 +26,10 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Represents an instance in either the CaseDB or CR that had a common match.
* Different implementations know how to get the instance details from either
* CaseDB or CR.
*
* Defines leaf-type nodes used in the Common Files Search results tree. Leaf
* nodes, may describe common attributes which exist in the current case DB or
* in the Central Repo. When a reference to the AbstractFile is lacking (such as
@ -34,9 +38,10 @@ import org.sleuthkit.datamodel.TskCoreException;
* multiple types of leaf nodes are required to represent Common Attribute
* Instance nodes.
*/
public abstract class AbstractCommonAttributeInstanceNode {
public abstract class AbstractCommonAttributeInstance {
private final Long abstractFileObjectId;
// maps object ID to file
private final Map<Long, AbstractFile> cachedFiles;
private final String caseName;
private final String dataSource;
@ -51,7 +56,7 @@ public abstract class AbstractCommonAttributeInstanceNode {
* @param dataSource datasource where this attribute appears
* @param caseName case where this attribute appears
*/
AbstractCommonAttributeInstanceNode(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource, String caseName) {
AbstractCommonAttributeInstance(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource, String caseName) {
this.abstractFileObjectId = abstractFileReference;
this.cachedFiles = cachedFiles;
this.caseName = caseName;
@ -65,7 +70,7 @@ public abstract class AbstractCommonAttributeInstanceNode {
* @param cachedFiles storage for abstract files which have been used
* already so we can avoid extra roundtrips to the case db
*/
AbstractCommonAttributeInstanceNode(Map<Long, AbstractFile> cachedFiles) {
AbstractCommonAttributeInstance(Map<Long, AbstractFile> cachedFiles) {
this.abstractFileObjectId = -1L;
this.cachedFiles = cachedFiles;
this.caseName = "";
@ -79,11 +84,11 @@ public abstract class AbstractCommonAttributeInstanceNode {
* @return AbstractFile which is identical to the file instance generated by
* implementations of this object
*/
AbstractFile lookupOrLoadAbstractFile() {
protected AbstractFile lookupOrLoadAbstractFile() {
if (this.cachedFiles.containsKey(this.getAbstractFileObjectId())) {
return this.cachedFiles.get(this.getAbstractFileObjectId());
} else {
AbstractFile file = this.loadFileFromSleuthkitCase();
AbstractFile file = this.getAbstractFile();
final long abstractFileId = file.getId();
this.cachedFiles.put(abstractFileId, file);
return file;
@ -91,14 +96,14 @@ public abstract class AbstractCommonAttributeInstanceNode {
}
/**
* Implement this in subclasses to find the AbstractFile by whatever means
* available. This will be called by this.lookupOrLoadAbstractFile. In some
* cases we may have the object abstractFileId, in other cases we may need
* to use the file name.
* Get an AbstractFile for this instance if it can be retrieved from
* the CaseDB.
*
* @return AbstractFile corresponding to this common attribute
* @return AbstractFile corresponding to this common attribute or null if
* it cannot be found
* @@@ Consider throwing exception instead of NULL
*/
abstract AbstractFile loadFileFromSleuthkitCase();
abstract AbstractFile getAbstractFile();
/**
* Create a list of leaf nodes, to be used to display a row in the tree
@ -183,9 +188,9 @@ public abstract class AbstractCommonAttributeInstanceNode {
final boolean sameDataSource = attributeDataSourceName.equalsIgnoreCase(abstractFileDataSourceName);
if (sameCase && sameFileName && sameDataSource) {
leafNode = new IntraCaseCommonAttributeInstanceNode(equivalentAbstractFile, currentCaseName, abstractFileDataSourceName);
leafNode = new CaseDBCommonAttributeInstanceNode(equivalentAbstractFile, currentCaseName, abstractFileDataSourceName);
} else {
leafNode = new InterCaseCommonAttributeInstanceNode(attributeInstance, equivalentAbstractFile);
leafNode = new CentralRepoCommonAttributeInstanceNode(attributeInstance, equivalentAbstractFile);
}
return leafNode;
}

View File

@ -97,7 +97,7 @@ public abstract class AbstractCommonAttributeSearcher {
//collate matches by number of matching instances - doing this in sql doesnt seem efficient
Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = new TreeMap<>();
for(CommonAttributeValue md5Metadata : commonFiles.values()){
Integer size = md5Metadata.size();
Integer size = md5Metadata.getInstanceCount();
if(instanceCollatedCommonFiles.containsKey(size)){
instanceCollatedCommonFiles.get(size).add(md5Metadata);

View File

@ -31,11 +31,11 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Encapsulates data required to instantiate a <code>FileInstanceNode</code>.
* Encapsulates data required to instantiate a <code>FileInstanceNode</code> for an instance in the CaseDB
*/
final public class IntraCaseCommonAttributeSearchResults extends AbstractCommonAttributeInstanceNode {
final public class CaseDBCommonAttributeInstance extends AbstractCommonAttributeInstance {
private static final Logger LOGGER = Logger.getLogger(IntraCaseCommonAttributeSearchResults.class.getName());
private static final Logger LOGGER = Logger.getLogger(CaseDBCommonAttributeInstance.class.getName());
/**
@ -45,18 +45,18 @@ final public class IntraCaseCommonAttributeSearchResults extends AbstractCommonA
* @param objectId id of abstract file to find
* @param dataSourceName name of datasource where the object is found
*/
IntraCaseCommonAttributeSearchResults(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource, String caseName) {
CaseDBCommonAttributeInstance(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource, String caseName) {
super(abstractFileReference, cachedFiles, dataSource, caseName);
}
@Override
public DisplayableItemNode[] generateNodes() {
final IntraCaseCommonAttributeInstanceNode intraCaseCommonAttributeInstanceNode = new IntraCaseCommonAttributeInstanceNode(this.lookupOrLoadAbstractFile(), this.getCaseName(), this.getDataSource());
final CaseDBCommonAttributeInstanceNode intraCaseCommonAttributeInstanceNode = new CaseDBCommonAttributeInstanceNode(this.lookupOrLoadAbstractFile(), this.getCaseName(), this.getDataSource());
return Arrays.asList(intraCaseCommonAttributeInstanceNode).toArray(new DisplayableItemNode[1]);
}
@Override
AbstractFile loadFileFromSleuthkitCase() {
AbstractFile getAbstractFile() {
Case currentCase;
try {

View File

@ -26,15 +26,10 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Used by the Common Files search feature to encapsulate instances of a given
* MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
*
* Use this type for files which are in the current case. Contrast with
* <code>CentralRepositoryFileInstanceNode</code> which should be used when the
* FileInstance was found in some case not presently open in Autopsy, but present
* in the Central Repository.
* Node that wraps CaseDBCommonAttributeInstance to represent a file instance stored
* in the CaseDB.
*/
public class IntraCaseCommonAttributeInstanceNode extends FileNode {
public class CaseDBCommonAttributeInstanceNode extends FileNode {
private final String caseName;
private final String dataSource;
@ -46,7 +41,7 @@ public class IntraCaseCommonAttributeInstanceNode extends FileNode {
* @param fsContent
* @param dataSource
*/
public IntraCaseCommonAttributeInstanceNode(AbstractFile fsContent, String caseName, String dataSource) {
public CaseDBCommonAttributeInstanceNode(AbstractFile fsContent, String caseName, String dataSource) {
super(fsContent);
this.caseName = caseName;
this.dataSource = dataSource;

View File

@ -35,15 +35,17 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Represents that a row in the CR was found in multiple cases.
*
* Generates a DisplayableItmeNode using a CentralRepositoryFile.
*/
final public class InterCaseCommonAttributeSearchResults extends AbstractCommonAttributeInstanceNode {
final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttributeInstance {
private static final Logger LOGGER = Logger.getLogger(InterCaseCommonAttributeSearchResults.class.getName());
private static final Logger LOGGER = Logger.getLogger(CentralRepoCommonAttributeInstance.class.getName());
private final Integer crFileId;
private CorrelationAttributeInstance currentAttributeInstance;
InterCaseCommonAttributeSearchResults(Integer attrInstId, Map<Long, AbstractFile> cachedFiles) {
CentralRepoCommonAttributeInstance(Integer attrInstId, Map<Long, AbstractFile> cachedFiles) {
super(cachedFiles);
this.crFileId = attrInstId;
}
@ -53,9 +55,10 @@ final public class InterCaseCommonAttributeSearchResults extends AbstractCommonA
}
@Override
AbstractFile loadFileFromSleuthkitCase() {
AbstractFile getAbstractFile() {
Case currentCase;
// @@@ Need to CHeck for NULL. This seems to depend on generateNodes to be called first
String currentFullPath = this.currentAttributeInstance.getFilePath();
try {
@ -79,18 +82,21 @@ final public class InterCaseCommonAttributeSearchResults extends AbstractCommonA
@Override
public DisplayableItemNode[] generateNodes() {
// @@@ We should be doing more of this work in teh generateKeys method. We want to do as little as possible in generateNodes
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor();
CorrelationAttribute corrAttr = eamDbAttrInst.findSingleCorrelationAttribute(crFileId);
List<DisplayableItemNode> attrInstNodeList = new ArrayList<>(0);
String currCaseDbName = Case.getCurrentCase().getDisplayName();
// @@@ This seems wrong that we are looping here, but only setting one attrInst in the class, which is then used by getAbstractFile().
for (CorrelationAttributeInstance attrInst : corrAttr.getInstances()) {
try {
this.setCurrentAttributeInst(attrInst);
AbstractFile equivalentAbstractFile = this.lookupOrLoadAbstractFile();
DisplayableItemNode generatedInstNode = AbstractCommonAttributeInstanceNode.createInstance(attrInst, equivalentAbstractFile, currCaseDbName);
DisplayableItemNode generatedInstNode = AbstractCommonAttributeInstance.createInstance(attrInst, equivalentAbstractFile, currCaseDbName);
attrInstNodeList.add(generatedInstNode);

View File

@ -42,7 +42,7 @@ import org.sleuthkit.datamodel.Content;
* Central Repo. Contrast with <code>SleuthkitCase</code> which should be used
* when the FileInstance was found in the case presently open in Autopsy.
*/
public class InterCaseCommonAttributeInstanceNode extends DisplayableItemNode {
public class CentralRepoCommonAttributeInstanceNode extends DisplayableItemNode {
private final CorrelationAttributeInstance crFile;
@ -50,7 +50,7 @@ public class InterCaseCommonAttributeInstanceNode extends DisplayableItemNode {
// and we can use this to support certain actions in the tree table and crFile viewer
private final AbstractFile md5Reference;
InterCaseCommonAttributeInstanceNode(CorrelationAttributeInstance content, AbstractFile md5Reference) {
CentralRepoCommonAttributeInstanceNode(CorrelationAttributeInstance content, AbstractFile md5Reference) {
super(Children.LEAF, Lookups.fixed(content)); // Using md5Reference enables Other Occurances, but for the current file path
this.crFile = content;
this.setDisplayName(new File(this.crFile.getFilePath()).getName());
@ -88,7 +88,7 @@ public class InterCaseCommonAttributeInstanceNode extends DisplayableItemNode {
public String getItemType() {
//objects of type FileNode will co-occur in the treetable with objects
// of this type and they will need to provide the same key
return IntraCaseCommonAttributeInstanceNode.class.getName();
return CaseDBCommonAttributeInstanceNode.class.getName();
}
@Override

View File

@ -1,89 +0,0 @@
/*
* 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 org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Used by the Common Files search feature to encapsulate instances of a given
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
*/
public class CommonAttributeInstanceNode extends FileNode {
private final String dataSource;
/**
* Create a node which can be used in a multilayer tree table and is based
* on an <code>AbstractFile</code>.
*
* @param fsContent
* @param dataSource
*/
public CommonAttributeInstanceNode(AbstractFile fsContent, String dataSource) {
super(fsContent);
this.dataSource = dataSource;
this.setDisplayName(fsContent.getName());
}
@Override
public boolean isLeafTypeNode(){
//Not used atm - could maybe be leveraged for better use in Children objects
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
String getDataSource() {
return this.dataSource;
}
@NbBundle.Messages({"FileInstanceNode.createSheet.noDescription= "})
@Override
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent())));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
this.addTagProperty(sheetSet);
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, Case.getCurrentCase().getDisplayName()));
return sheet;
}
}

View File

@ -11,9 +11,6 @@
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 350]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 350]"/>
</Property>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>

View File

@ -185,9 +185,9 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
CommonAttributeSearchResults metadata = this.get();
CommonAttributeSearchResultNode commonFilesNode = new CommonAttributeSearchResultNode(metadata);
CommonAttributeSearchResultRootNode commonFilesNode = new CommonAttributeSearchResultRootNode(metadata);
// #VIK-3969
// -3969
DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonAttributePanel.this));
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode, 3);

View File

@ -27,13 +27,14 @@ import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
/**
* Wrapper node for <code>Md5Node</code> used to display common files search
* results in the top right pane. Calls <code>InstanceCountNodeFactory</code>.
* Top-level node to store common file search results. Current structure is:
* - node for number of matches
* -- node for MD5/commmon attribute
* --- node for instance.
*/
final public class CommonAttributeSearchResultNode extends DisplayableItemNode {
final public class CommonAttributeSearchResultRootNode extends DisplayableItemNode {
CommonAttributeSearchResultNode(CommonAttributeSearchResults metadataList) {
CommonAttributeSearchResultRootNode(CommonAttributeSearchResults metadataList) {
super(Children.create(new InstanceCountNodeFactory(metadataList), true));
}
@ -64,27 +65,27 @@ final public class CommonAttributeSearchResultNode extends DisplayableItemNode {
*/
static class InstanceCountNodeFactory extends ChildFactory<Integer>{
private final CommonAttributeSearchResults metadata;
private final CommonAttributeSearchResults searchResults;
/**
* Build a factory which converts a <code>CommonAttributeSearchResults</code>
* object into <code>DisplayableItemNode</code>s.
* @param metadata
* @param searchResults
*/
InstanceCountNodeFactory(CommonAttributeSearchResults metadata){
this.metadata = metadata;
InstanceCountNodeFactory(CommonAttributeSearchResults searchResults){
this.searchResults = searchResults;
}
@Override
protected boolean createKeys(List<Integer> list) {
list.addAll(this.metadata.getValues().keySet());
list.addAll(this.searchResults.getMetadata().keySet());
return true;
}
@Override
protected Node createNodeForKey(Integer instanceCount){
List<CommonAttributeValue> md5Metadata = this.metadata.getValuesByChildSize(instanceCount);
return new InstanceCountNode(instanceCount, md5Metadata);
List<CommonAttributeValue> attributeValues = this.searchResults.getAttributeValuesForInstanceCount(instanceCount);
return new InstanceCountNode(instanceCount, attributeValues);
}
}
}

View File

@ -24,12 +24,13 @@ import java.util.List;
import java.util.Map;
/**
* Utility and wrapper model around data required for Common Files Search results.
* Subclass this to implement different selections of files from the case.
* Stores the results from the various types of common attribute searching
* Stores results based on how they are currently displayed in the UI
*/
final public class CommonAttributeSearchResults {
private final Map<Integer, List<CommonAttributeValue>> values;
// maps instance count to list of attribute values.
private final Map<Integer, List<CommonAttributeValue>> instanceCountToAttributeValues;
/**
* Create a values object which can be handed off to the node factories.
@ -37,8 +38,8 @@ final public class CommonAttributeSearchResults {
* @param values list of CommonAttributeValue indexed by size of
* CommonAttributeValue
*/
CommonAttributeSearchResults(Map<Integer, List<CommonAttributeValue>> values){
this.values = values;
CommonAttributeSearchResults(Map<Integer, List<CommonAttributeValue>> metadata){
this.instanceCountToAttributeValues = metadata;
}
/**
@ -50,8 +51,8 @@ final public class CommonAttributeSearchResults {
* @param isntanceCound key
* @return list of values which represent matches
*/
List<CommonAttributeValue> getValuesByChildSize(Integer instanceCount) {
return this.values.get(instanceCount);
List<CommonAttributeValue> getAttributeValuesForInstanceCount(Integer instanceCount) {
return this.instanceCountToAttributeValues.get(instanceCount);
}
/**
@ -60,8 +61,8 @@ final public class CommonAttributeSearchResults {
* search.
* @return map of sizes of children to list of matches
*/
public Map<Integer, List<CommonAttributeValue>> getValues() {
return Collections.unmodifiableMap(this.values);
public Map<Integer, List<CommonAttributeValue>> getMetadata() {
return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
}
/**
@ -71,9 +72,9 @@ final public class CommonAttributeSearchResults {
public int size() {
int count = 0;
for (List<CommonAttributeValue> data : this.values.values()) {
for(CommonAttributeValue value : data){
count += value.size();
for (List<CommonAttributeValue> data : this.instanceCountToAttributeValues.values()) {
for(CommonAttributeValue md5 : data){
count += md5.getInstanceCount();
}
}
return count;

View File

@ -28,14 +28,15 @@ import java.util.Set;
import java.util.stream.Collectors;
/**
* Encapsulates data required to instantiate an <code>Md5Node</code>.
* Defines a value that was in the common file search results
* as well as information about its instances.
*/
final public class CommonAttributeValue {
private final String md5;
private final List<AbstractCommonAttributeInstanceNode> fileInstances;
private final List<AbstractCommonAttributeInstance> fileInstances;
CommonAttributeValue(String md5, List<AbstractCommonAttributeInstanceNode> fileInstances) {
CommonAttributeValue(String md5, List<AbstractCommonAttributeInstance> fileInstances) {
this.md5 = md5;
this.fileInstances = fileInstances;
}
@ -45,18 +46,23 @@ final public class CommonAttributeValue {
this.fileInstances = new ArrayList<>();
}
public String getMd5() {
public String getValue() {
return this.md5;
}
/**
* concatenate cases this value was seen into a single string
*
* @return
*/
public String getCases() {
final String cases = this.fileInstances.stream().map(AbstractCommonAttributeInstanceNode::getCaseName).collect(Collectors.joining(", "));
final String cases = this.fileInstances.stream().map(AbstractCommonAttributeInstance::getCaseName).collect(Collectors.joining(", "));
return cases;
}
public String getDataSources() {
Set<String> sources = new HashSet<>();
for (AbstractCommonAttributeInstanceNode data : this.fileInstances) {
for (AbstractCommonAttributeInstance data : this.fileInstances) {
sources.add(data.getDataSource());
}
@ -64,15 +70,16 @@ final public class CommonAttributeValue {
return dataSources;
}
void addFileInstanceMetadata(AbstractCommonAttributeInstanceNode metadata) {
void addInstance(AbstractCommonAttributeInstance metadata) {
this.fileInstances.add(metadata);
}
void addFileInstanceMetadata(AbstractCommonAttributeInstanceNode metadata, String caseName) {
void addFileInstanceMetadata(AbstractCommonAttributeInstance metadata, String caseName) {
this.fileInstances.add(metadata);
// @@@ Why are we ignoring caseName?
}
public Collection<AbstractCommonAttributeInstanceNode> getMetadata() {
public Collection<AbstractCommonAttributeInstance> getInstances() {
return Collections.unmodifiableCollection(this.fileInstances);
}
@ -82,7 +89,7 @@ final public class CommonAttributeValue {
*
* @return number of instances
*/
public int size() {
public int getInstanceCount() {
return this.fileInstances.size();
}
}

View File

@ -31,16 +31,14 @@ import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
/**
* Represents a common files match - two or more files which appear to be the
* same file and appear as children of this node. This node will simply contain
* the MD5 of the matched files, the data sources those files were found within,
* and a count of the instances represented by the md5.
* Represents the layer in the tree for the value (such as MD5) that was in multiple places.
* Children are instances of that value.
*/
public class CommonAttributeValueNode extends DisplayableItemNode {
private static final Logger LOGGER = Logger.getLogger(CommonAttributeValueNode.class.getName());
private final String md5Hash;
private final String value;
private final int commonFileCount;
private final String cases;
private final String dataSources;
@ -56,12 +54,13 @@ public class CommonAttributeValueNode extends DisplayableItemNode {
super(Children.create(
new FileInstanceNodeFactory(data), true));
this.commonFileCount = data.size();
this.commonFileCount = data.getInstanceCount();
this.cases = data.getCases();
// @@ We seem to be doing this string concat twice. We also do it in getDataSources()
this.dataSources = String.join(", ", data.getDataSources());
this.md5Hash = data.getMd5();
this.value = data.getValue();
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.md5Hash));
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.value));
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
}
@ -89,8 +88,8 @@ public class CommonAttributeValueNode extends DisplayableItemNode {
* MD5 which is common to these matches
* @return string md5 hash
*/
public String getMd5() {
return this.md5Hash;
public String getValue() {
return this.value;
}
@NbBundle.Messages({"Md5Node.createSheet.noDescription= "})
@ -132,7 +131,7 @@ public class CommonAttributeValueNode extends DisplayableItemNode {
* Child generator for <code>SleuthkitCaseFileInstanceNode</code> of
* <code>CommonAttributeValueNode</code>.
*/
static class FileInstanceNodeFactory extends ChildFactory<AbstractCommonAttributeInstanceNode> {
static class FileInstanceNodeFactory extends ChildFactory<AbstractCommonAttributeInstance> {
private final CommonAttributeValue descendants;
@ -141,14 +140,16 @@ public class CommonAttributeValueNode extends DisplayableItemNode {
}
@Override
protected Node[] createNodesForKey(AbstractCommonAttributeInstanceNode file) {
return file.generateNodes();
protected boolean createKeys(List<AbstractCommonAttributeInstance> list) {
list.addAll(this.descendants.getInstances());
return true;
}
@Override
protected boolean createKeys(List<AbstractCommonAttributeInstanceNode> list) {
list.addAll(this.descendants.getMetadata());
return true;
}
protected Node[] createNodesForKey(AbstractCommonAttributeInstance searchResult) {
return searchResult.generateNodes();
}
}
}

View File

@ -40,24 +40,24 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty;
final public class InstanceCountNode extends DisplayableItemNode {
final private int instanceCount;
final private List<CommonAttributeValue> metadataList;
final private List<CommonAttributeValue> attributeValues;
/**
* Create a node with the given number of instances, and the given
* selection of metadata.
* @param instanceCount
* @param md5Metadata
* @param attributeValues
*/
@NbBundle.Messages({
"InstanceCountNode.displayName=Files with %s instances (%s)"
})
public InstanceCountNode(int instanceCount, List<CommonAttributeValue> md5Metadata) {
super(Children.create(new Md5NodeFactory(md5Metadata), true));
public InstanceCountNode(int instanceCount, List<CommonAttributeValue> attributeValues) {
super(Children.create(new CommonAttributeValueNodeFactory(attributeValues), true));
this.instanceCount = instanceCount;
this.metadataList = md5Metadata;
this.attributeValues = attributeValues;
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), attributeValues.size()));
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
}
@ -73,8 +73,8 @@ final public class InstanceCountNode extends DisplayableItemNode {
* Get a list of metadata for the MD5s which are children of this object.
* @return List<Md5Metadata>
*/
List<CommonAttributeValue> getMetadata() {
return Collections.unmodifiableList(this.metadataList);
List<CommonAttributeValue> getAttributeValues() {
return Collections.unmodifiableList(this.attributeValues);
}
@Override
@ -113,34 +113,36 @@ final public class InstanceCountNode extends DisplayableItemNode {
* ChildFactory which builds CommonFileParentNodes from the
* CommonFilesMetaaData models.
*/
static class Md5NodeFactory extends ChildFactory<String> {
static class CommonAttributeValueNodeFactory extends ChildFactory<String> {
/**
* List of models, each of which is a parent node matching a single md5,
* containing children FileNodes.
*/
// maps sting version of value to value Object (??)
private final Map<String, CommonAttributeValue> metadata;
Md5NodeFactory(List<CommonAttributeValue> metadata) {
CommonAttributeValueNodeFactory(List<CommonAttributeValue> attributeValues) {
this.metadata = new HashMap<>();
Iterator<CommonAttributeValue> iterator = metadata.iterator();
Iterator<CommonAttributeValue> iterator = attributeValues.iterator();
while (iterator.hasNext()) {
CommonAttributeValue md5Metadata = iterator.next();
this.metadata.put(md5Metadata.getMd5(), md5Metadata);
CommonAttributeValue attributeValue = iterator.next();
this.metadata.put(attributeValue.getValue(), attributeValue);
}
}
@Override
protected Node createNodeForKey(String md5) {
CommonAttributeValue md5Metadata = this.metadata.get(md5);
return new CommonAttributeValueNode(md5Metadata);
}
@Override
protected boolean createKeys(List<String> list) {
// @@@ We should just use CommonAttributeValue as the key...
list.addAll(this.metadata.keySet());
return true;
}
@Override
protected Node createNodeForKey(String attributeValue) {
CommonAttributeValue md5Metadata = this.metadata.get(attributeValue);
return new CommonAttributeValueNode(md5Metadata);
}
}
}

View File

@ -56,17 +56,18 @@ abstract class InterCaseCommonAttributeSearcher extends AbstractCommonAttributeS
/**
* @param artifactInstances all 'common files' in central repo
* @param commonFiles matches must ultimately have appeared in this
* @param commonValues matches must ultimately have appeared in this
* collection
* @return collated map of instance counts to lists of matches
*/
Map<Integer, List<CommonAttributeValue>> gatherIntercaseResults(Map<Integer, String> commonFiles, Map<Integer, Integer> commonFileCases) {
Map<Integer, List<CommonAttributeValue>> gatherIntercaseResults(Map<Integer, String> commonValues, Map<Integer, Integer> commonFileCases) {
// keyis string of value
Map<String, CommonAttributeValue> interCaseCommonFiles = new HashMap<>();
for (int commonAttrId : commonFiles.keySet()) {
for (int commonAttrId : commonValues.keySet()) {
String md5 = commonFiles.get(commonAttrId);
String md5 = commonValues.get(commonAttrId);
if (md5 == null || HashUtility.isNoDataMd5(md5)) {
continue;
}
@ -82,15 +83,18 @@ abstract class InterCaseCommonAttributeSearcher extends AbstractCommonAttributeS
if (interCaseCommonFiles.containsKey(md5)) {
//Add to intercase metaData
final CommonAttributeValue md5Metadata = interCaseCommonFiles.get(md5);
AbstractCommonAttributeInstanceNode nodeGenerator = new InterCaseCommonAttributeSearchResults(commonAttrId, fileCache);
md5Metadata.addFileInstanceMetadata(nodeGenerator, correlationCaseDisplayName);
final CommonAttributeValue commonAttributeValue = interCaseCommonFiles.get(md5);
AbstractCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(commonAttrId, fileCache);
commonAttributeValue.addFileInstanceMetadata(searchResult, correlationCaseDisplayName);
} else {
CommonAttributeValue md5Metadata = new CommonAttributeValue(md5);
AbstractCommonAttributeInstanceNode nodeGenerator = new InterCaseCommonAttributeSearchResults(commonAttrId, fileCache);
md5Metadata.addFileInstanceMetadata(nodeGenerator, correlationCaseDisplayName);
interCaseCommonFiles.put(md5, md5Metadata);
CommonAttributeValue commonAttributeValue = new CommonAttributeValue(md5);
interCaseCommonFiles.put(md5, commonAttributeValue);
AbstractCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(commonAttrId, fileCache);
commonAttributeValue.addFileInstanceMetadata(searchResult, correlationCaseDisplayName);
}
} catch (Exception ex) {
LOGGER.log(Level.WARNING, "Error getting artifact instances from database.", ex); // NON-NLS

View File

@ -42,7 +42,9 @@ final class InterCaseSearchResultsProcessor {
private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName());
// maps row ID to value
private final Map<Integer, String> intercaseCommonValuesMap = new HashMap<>();
// maps row ID to case ID
private final Map<Integer, Integer> intercaseCommonCasesMap = new HashMap<>();
/**

View File

@ -124,12 +124,12 @@ public abstract class IntraCaseCommonAttributeSearcher extends AbstractCommonAtt
}
if (commonFiles.containsKey(md5)) {
final CommonAttributeValue md5Metadata = commonFiles.get(md5);
md5Metadata.addFileInstanceMetadata(new IntraCaseCommonAttributeSearchResults(objectId, fileCache, dataSource, caseName));
final CommonAttributeValue commonAttributeValue = commonFiles.get(md5);
commonAttributeValue.addInstance(new CaseDBCommonAttributeInstance(objectId, fileCache, dataSource, caseName));
} else {
final CommonAttributeValue md5Metadata = new CommonAttributeValue(md5);
md5Metadata.addFileInstanceMetadata(new IntraCaseCommonAttributeSearchResults(objectId, fileCache, dataSource, caseName));
commonFiles.put(md5, md5Metadata);
final CommonAttributeValue commonAttributeValue = new CommonAttributeValue(md5);
commonAttributeValue.addInstance(new CaseDBCommonAttributeInstance(objectId, fileCache, dataSource, caseName));
commonFiles.put(md5, commonAttributeValue);
}
}
}

View File

@ -18,11 +18,11 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.commonfilesearch.InterCaseCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResultNode;
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResultRootNode;
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueNode;
import org.sleuthkit.autopsy.commonfilesearch.IntraCaseCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
@ -118,11 +118,11 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(CommonAttributeValueNode mn);
T visit(CommonAttributeSearchResultNode cfn);
T visit(CommonAttributeSearchResultRootNode cfn);
T visit(IntraCaseCommonAttributeInstanceNode fin);
T visit(CaseDBCommonAttributeInstanceNode fin);
T visit(InterCaseCommonAttributeInstanceNode crfin);
T visit(CentralRepoCommonAttributeInstanceNode crfin);
T visit(InstanceCountNode icn);
@ -195,7 +195,7 @@ public interface DisplayableItemNodeVisitor<T> {
protected abstract T defaultVisit(DisplayableItemNode c);
@Override
public T visit(IntraCaseCommonAttributeInstanceNode fin) {
public T visit(CaseDBCommonAttributeInstanceNode fin) {
return defaultVisit(fin);
}
@ -205,7 +205,7 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(CommonAttributeSearchResultNode cfn) {
public T visit(CommonAttributeSearchResultRootNode cfn) {
return defaultVisit(cfn);
}
@ -215,7 +215,7 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(InterCaseCommonAttributeInstanceNode crfin){
public T visit(CentralRepoCommonAttributeInstanceNode crfin){
return defaultVisit(crfin);
}

View File

@ -56,14 +56,14 @@ import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueNode;
import org.sleuthkit.autopsy.commonfilesearch.InterCaseCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
import org.sleuthkit.autopsy.commonfilesearch.IntraCaseCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import static org.sleuthkit.autopsy.directorytree.Bundle.DataResultFilterNode_viewSourceArtifact_text;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
@ -535,12 +535,12 @@ public class DataResultFilterNode extends FilterNode {
}
@Override
public AbstractAction visit(IntraCaseCommonAttributeInstanceNode fin){
public AbstractAction visit(CaseDBCommonAttributeInstanceNode fin){
return null;
}
@Override
public AbstractAction visit(InterCaseCommonAttributeInstanceNode iccan){
public AbstractAction visit(CentralRepoCommonAttributeInstanceNode iccan){
return null;
}

View File

@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.InterCaseCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.InterCaseCommonAttributeSearchResults;

View File

@ -33,7 +33,7 @@ import org.python.icu.impl.Assert;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
@ -207,7 +207,7 @@ class IntraCaseUtils {
for (Map.Entry<Integer, List<CommonAttributeValue>> entry : metadata.getValues().entrySet()) {
for (CommonAttributeValue md : entry.getValue()) {
for (AbstractCommonAttributeInstanceNode fim : md.getMetadata()) {
for (AbstractCommonAttributeInstance fim : md.getInstances()) {
instanceIdToDataSource.put(fim.getAbstractFileObjectId(), fim.getDataSource());
}
}