diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index cd0b03fd98..3f08b3f0bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -250,18 +250,16 @@ public class Artifacts { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT); - } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId - || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { - - InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(interestingHitsNode, - TSK_INTERESTING_ARTIFACT_HIT, - TSK_INTERESTING_FILE_HIT); - + } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_ARTIFACT_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ARTIFACT_HIT); + } else if (TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_FILE_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_FILE_HIT); } else if (TSK_HASHSET_HIT.getTypeID() == typeId) { HashsetHits.RootNode hashsetHits = new HashsetHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT); - + } else { return new TypeNodeKey(type, dsObjId); } @@ -278,7 +276,7 @@ public class Artifacts { */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; - + private final PropertyChangeListener weakPcl; /** @@ -293,7 +291,7 @@ public class Artifacts { super(); this.filteringDSObjId = filteringDSObjId; this.category = category; - + PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -322,9 +320,9 @@ public class Artifacts { weakPcl = WeakListeners.propertyChange(pcl, null); } - + @Override - protected void addNotify() { + protected void addNotify() { super.addNotify(); refreshThrottler.registerForIngestModuleEvents(); IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); @@ -632,7 +630,7 @@ public class Artifacts { } } }; - + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override @@ -643,7 +641,7 @@ public class Artifacts { @Override protected void onRemove() { - if(refreshThrottler != null) { + if (refreshThrottler != null) { refreshThrottler.unregisterEventListener(); } IngestManager.getInstance().removeIngestJobEventListener(weakPcl); @@ -663,14 +661,14 @@ public class Artifacts { case ANALYSIS_RESULT: arts = (filteringDSObjId > 0) - ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) - : blackboard.getAnalysisResultsByType(type.getTypeID()); + ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) + : blackboard.getAnalysisResultsByType(type.getTypeID()); break; case DATA_ARTIFACT: default: arts = (filteringDSObjId > 0) - ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) - : blackboard.getDataArtifacts(type.getTypeID()); + ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) + : blackboard.getDataArtifacts(type.getTypeID()); break; } @@ -679,9 +677,9 @@ public class Artifacts { //See JIRA-5969 art.getAttributes(); } - + @SuppressWarnings("unchecked") - List toRet = (List)(List)arts; + List toRet = (List) (List) arts; return toRet; } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 47db7732ea..1acce2bb7e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -181,15 +181,13 @@ public interface DisplayableItemNodeVisitor { T visit(EmptyNode.MessageNode emptyNode); - T visit(InterestingHits.InterestingItemTypeNode aThis); - /* * Attachments */ T visit(AttachmentNode node); - + T visit(OsAccounts.OsAccountNode node); - + T visit(OsAccounts.OsAccountListNode node); T visit(PersonNode node); @@ -197,12 +195,12 @@ public interface DisplayableItemNodeVisitor { T visit(HostNode node); T visit(DataSourcesNode node); - + /* * Unsupported node */ T visit(UnsupportedContentNode ucn); - + T visit(LocalFilesDataSourceNode lfdsn); /** @@ -332,11 +330,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ftByMimeTypeEmptyNode); } - @Override - public T visit(InterestingHits.InterestingItemTypeNode interestingItemTypeNode) { - return defaultVisit(interestingItemTypeNode); - } - @Override public T visit(DeletedContentNode dcn) { return defaultVisit(dcn); @@ -546,12 +539,12 @@ public interface DisplayableItemNodeVisitor { public T visit(AttachmentNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountListNode node) { return defaultVisit(node); @@ -571,12 +564,12 @@ public interface DisplayableItemNodeVisitor { public T visit(PersonNode node) { return defaultVisit(node); } - + @Override public T visit(UnsupportedContentNode node) { return defaultVisit(node); } - + @Override public T visit(LocalFilesDataSourceNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index f636264082..c22d095726 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -51,70 +51,95 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; import org.sleuthkit.datamodel.AnalysisResult; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; public class InterestingHits implements AutopsyVisitableItem { - private static final String INTERESTING_ITEMS = NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"); - private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text"); private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source + private final BlackboardArtifact.Type artifactType; /** * Constructor * - * @param skCase Case DB + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). * */ - public InterestingHits(SleuthkitCase skCase) { - this(skCase, 0); + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType) { + this(skCase, artifactType, 0); } /** * Constructor * - * @param skCase Case DB - * @param objId Object id of the data source + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). + * @param objId Object id of the data source * */ - public InterestingHits(SleuthkitCase skCase, long objId) { + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, long objId) { this.skCase = skCase; + this.artifactType = artifactType; this.filteringDSObjId = objId; interestingResults.update(); } + /** + * Cache of result ids mapped by artifact type -> set name -> artifact id. + */ private class InterestingResults extends Observable { // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized - private final Map>> interestingItemsMap = new LinkedHashMap<>(); + private final Map> interestingItemsMap = new LinkedHashMap<>(); - public List getSetNames() { + /** + * Returns all the set names for a given interesting item type. + * + * @param type The interesting item type. + * + * @return The set names. + */ + List getSetNames() { List setNames; synchronized (interestingItemsMap) { setNames = new ArrayList<>(interestingItemsMap.keySet()); } - Collections.sort(setNames); + Collections.sort(setNames, (a, b) -> a.compareToIgnoreCase(b)); return setNames; } - public Set getArtifactIds(String setName, String typeName) { + /** + * Returns all artifact ids belonging to the specified interesting item + * type and set name. + * + * @param type The interesting item type. + * @param setName The set name. + * + * @return The artifact ids in that set name and type. + */ + Set getArtifactIds(String setName) { synchronized (interestingItemsMap) { - return interestingItemsMap.get(setName).get(typeName); + return new HashSet<>(interestingItemsMap.getOrDefault(setName, Collections.emptySet())); } } - public void update() { + /** + * Triggers a fetch from the database to update this cache. + */ + void update() { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); + loadArtifacts(); setChanged(); notifyObservers(); } @@ -124,18 +149,18 @@ public class InterestingHits implements AutopsyVisitableItem { * the interestingItemsMap */ @SuppressWarnings("deprecation") - private void loadArtifacts(BlackboardArtifact.Type artType) { + private void loadArtifacts() { if (skCase == null) { return; } int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = artType.getTypeID(); - String query = "SELECT value_text,blackboard_artifacts.artifact_obj_id,attribute_type_id " //NON-NLS + + String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id " //NON-NLS + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS - + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + + " AND blackboard_artifacts.artifact_type_id = " + artifactType.getTypeID(); //NON-NLS if (filteringDSObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } @@ -146,12 +171,9 @@ public class InterestingHits implements AutopsyVisitableItem { while (resultSet.next()) { String value = resultSet.getString("value_text"); //NON-NLS long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS - if (!interestingItemsMap.containsKey(value)) { - interestingItemsMap.put(value, new LinkedHashMap<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); - } - interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactObjId); + interestingItemsMap + .computeIfAbsent(value, (k) -> new HashSet<>()) + .add(artifactObjId); } } } catch (TskCoreException | SQLException ex) { @@ -166,54 +188,8 @@ public class InterestingHits implements AutopsyVisitableItem { } /** - * Node for the interesting items + * Creates nodes for all sets for a specified interesting item type. */ - public class RootNode extends UpdatableCountTypeNode { - - public RootNode() { - super(Children.create(new SetNameFactory(), true), - Lookups.singleton(DISPLAY_NAME), - DISPLAY_NAME, - filteringDSObjId, - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, - BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - super.setName(INTERESTING_ITEMS); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.displayName"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public String getItemType() { - return getClass().getName(); - } - } - private class SetNameFactory extends ChildFactory.Detachable implements Observer { /* @@ -239,8 +215,7 @@ public class InterestingHits implements AutopsyVisitableItem { * event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID())) { + if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == artifactType.getTypeID())) { interestingResults.update(); } } catch (NoCurrentCaseException notUsed) { @@ -272,26 +247,8 @@ public class InterestingHits implements AutopsyVisitableItem { } } }; - - private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - - @Override - protected void addNotify() { - IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.update(); - interestingResults.addObserver(this); - } - @Override - protected void finalize() throws Throwable { - super.finalize(); - IngestManager.getInstance().removeIngestJobEventListener(weakPcl); - IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); - Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.deleteObserver(this); - } + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override protected boolean createKeys(List list) { @@ -308,14 +265,35 @@ public class InterestingHits implements AutopsyVisitableItem { public void update(Observable o, Object arg) { refresh(true); } + + @Override + protected void addNotify() { + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); + IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.addObserver(this); + interestingResults.update(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + IngestManager.getInstance().removeIngestJobEventListener(weakPcl); + IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.deleteObserver(this); + } } + /** + * A node for a set to be displayed in the tree. + */ public class SetNameNode extends DisplayableItemNode implements Observer { private final String setName; public SetNameNode(String setName) {//, Set children) { - super(Children.create(new HitTypeFactory(setName), true), Lookups.singleton(setName)); + super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName)); this.setName = setName; super.setName(setName); updateDisplayName(); @@ -324,111 +302,81 @@ public class InterestingHits implements AutopsyVisitableItem { } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() - + interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); + int sizeOfSet = interestingResults.getArtifactIds(setName).size(); super.setDisplayName(setName + " (" + sizeOfSet + ")"); } + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), + getName())); + + return sheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + + @Override + public String getItemType() { + /** + * For custom settings for each rule set, return + * getClass().getName() + setName instead. + */ + return getClass().getName(); + } + } + + /** + * Parent node for interesting item type that shows child set nodes. + */ + public class RootNode extends UpdatableCountTypeNode { + + /** + * Main constructor. + */ + public RootNode() { + super(Children.create(new SetNameFactory(), true), + Lookups.singleton(artifactType), + artifactType.getDisplayName(), + filteringDSObjId, + artifactType); + + /** + * We use the combination of setName and typeName as the name of the + * node to ensure that nodes have a unique name. This comes into + * play when associating paging state with the node. + */ + setName(artifactType.getDisplayName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS + } + @Override public boolean isLeafTypeNode() { return false; } - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - - @Override - public String getItemType() { - /** - * For custom settings for each rule set, return - * getClass().getName() + setName instead. - */ - return getClass().getName(); - } - } - - private class HitTypeFactory extends ChildFactory implements Observer { - - private final String setName; - private final Map artifactHits = new HashMap<>(); - - private HitTypeFactory(String setName) { - super(); - this.setName = setName; - interestingResults.addObserver(this); - } - - @Override - protected boolean createKeys(List list) { - list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()); - list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new InterestingItemTypeNode(setName, key); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - - public class InterestingItemTypeNode extends DisplayableItemNode implements Observer { - - private final String typeName; - private final String setName; - - private InterestingItemTypeNode(String setName, String typeName) { - super(Children.create(new HitFactory(setName, typeName), true), Lookups.singleton(setName)); - this.typeName = typeName; - this.setName = setName; - /** - * We use the combination of setName and typeName as the name of the - * node to ensure that nodes have a unique name. This comes into - * play when associating paging state with the node. - */ - super.setName(setName + "_" + typeName); - updateDisplayName(); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - interestingResults.addObserver(this); - } - - private void updateDisplayName() { - super.setDisplayName(typeName + " (" + interestingResults.getArtifactIds(setName, typeName).size() + ")"); - } - - @Override - public boolean isLeafTypeNode() { - return true; - } - @Override protected Sheet createSheet() { Sheet sheet = super.createSheet(); @@ -449,11 +397,6 @@ public class InterestingHits implements AutopsyVisitableItem { return visitor.visit(this); } - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - @Override public String getItemType() { /** @@ -464,21 +407,27 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Factory for creating individual interesting item BlackboardArtifactNodes. + */ private class HitFactory extends BaseChildFactory implements Observer { private final String setName; - private final String typeName; private final Map artifactHits = new HashMap<>(); - private HitFactory(String setName, String typeName) { + /** + * Main constructor. + * + * @param setName The set name of artifacts to be displayed. + */ + private HitFactory(String setName) { /** * The node name passed to the parent constructor must be the same * as the name set in the InterestingItemTypeNode constructor, i.e. * setName underscore typeName */ - super(setName + "_" + typeName); + super(setName); this.setName = setName; - this.typeName = typeName; interestingResults.addObserver(this); } @@ -486,7 +435,7 @@ public class InterestingHits implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { - interestingResults.getArtifactIds(setName, typeName).forEach((id) -> { + interestingResults.getArtifactIds(setName).forEach((id) -> { try { if (!artifactHits.containsKey(id)) { AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 975a659aa7..70c70fe45b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1271,9 +1271,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat treeNode = getHashsetNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { treeNode = getKeywordHitNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID() - || typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - treeNode = getInterestingItemNode(typesChildren, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, art); } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) { @@ -1401,42 +1402,46 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * * @param typesChildren The children object of the same category as * interesting item. + * @param artifactType The type of the artifact (interesting hit or + * artifact). * @param art The artifact. * * @return The interesting item artifact's parent node or null if cannot be * found. */ - private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { - Node interestingItemsRootNode = typesChildren.findChild(NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); + private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact.Type artifactType, BlackboardArtifact art) { + Node interestingItemsRootNode = typesChildren.findChild(artifactType.getDisplayName()); + Children setNodeChildren = (interestingItemsRootNode == null) ? null : interestingItemsRootNode.getChildren(); + + // set node children for type could not be found, so return null. + if (setNodeChildren == null) { + return null; + } + + String setName = null; try { - String setName = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - setName = att.getValueString(); - } - } - Node setNode = interestingItemsRootChildren.findChild(setName); - if (setNode == null) { - return null; - } + setName = art.getAttributes().stream() + .filter(attr -> attr.getAttributeType().getTypeID() == BlackboardAttribute.Type.TSK_SET_NAME.getTypeID()) + .map(attr -> attr.getValueString()) + .findFirst() + .orElse(null); - Children fileArtifactChildren = setNode.getChildren(); - Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); - if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { - return null; - } - - return (art.getArtifactTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) - ? fileArtifactNodes[0] - : fileArtifactNodes[1]; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS return null; } + + // if no set name, no set node will be identified. + if (setName == null) { + return null; + } + + // make sure data is fully loaded + final String finalSetName = setName; + return Stream.of(setNodeChildren.getNodes(true)) + .filter(setNode -> finalSetName.equals(setNode.getLookup().lookup(String.class))) + .findFirst() + .orElse(null); } /**