Merge branch 'new_table_load' of github.com:sleuthkit/autopsy into 8235-hostPersonDaoDto

This commit is contained in:
Greg DiCristofaro 2022-02-17 20:07:54 -05:00
commit e05463e76b
12 changed files with 584 additions and 642 deletions

View File

@ -671,6 +671,38 @@ public class Case {
public void publishAnalysisResultDeleted(TskEvent.AnalysisResultsDeletedTskEvent event) {
eventPublisher.publish(new AnalysisResultDeletedEvent(event.getAnalysisResultObjectIds()));
}
@Subscribe
public void publishBlackboardArtifactTagDeleted(TskEvent.BlackboardArtifactTagsDeletedTskEvent event) {
List<BlackboardArtifactTag> tags = event.getTags();
for(BlackboardArtifactTag tag: tags) {
eventPublisher.publish(new BlackBoardArtifactTagDeletedEvent(tag));
}
}
@Subscribe
public void publishBlackboardTagAdded(TskEvent.BlackboardArtifactTagsAddedTskEvent event) {
List<BlackboardArtifactTag> tags = event.getTags();
for(BlackboardArtifactTag tag: tags) {
eventPublisher.publish(new BlackBoardArtifactTagAddedEvent(tag));
}
}
@Subscribe
public void publishContentTagAdded(TskEvent.ContentTagsAddedTskEvent event) {
List<ContentTag> tags = event.getTags();
for(ContentTag tag: tags) {
eventPublisher.publish(new ContentTagAddedEvent(tag));
}
}
@Subscribe
public void publishContentTagDeleted(TskEvent.ContentTagsDeletedTskEvent event) {
List<ContentTag> tags = event.getTags();
for(ContentTag tag: tags) {
eventPublisher.publish(new ContentTagDeletedEvent(tag));
}
}
}
/**
@ -1820,41 +1852,6 @@ public class Case {
eventPublisher.publish(new DataSourceNameChangedEvent(dataSource, newName));
}
/**
* Notifies case event subscribers that a content tag has been added.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param newTag new ContentTag added
*/
public void notifyContentTagAdded(ContentTag newTag) {
notifyContentTagAdded(newTag, null);
}
/**
* Notifies case event subscribers that a content tag has been added.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param newTag The added ContentTag.
* @param deletedTagList List of ContentTags that were removed as a result
* of the addition of newTag.
*/
public void notifyContentTagAdded(ContentTag newTag, List<ContentTag> deletedTagList) {
eventPublisher.publish(new ContentTagAddedEvent(newTag, deletedTagList));
}
/**
* Notifies case event subscribers that a content tag has been deleted.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param deletedTag ContentTag deleted
*/
public void notifyContentTagDeleted(ContentTag deletedTag) {
eventPublisher.publish(new ContentTagDeletedEvent(deletedTag));
}
/**
* Notifies case event subscribers that a tag definition has changed.
*
@ -1885,41 +1882,6 @@ public class Case {
}
}
/**
* Notifies case event subscribers that an artifact tag has been added.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param newTag new BlackboardArtifactTag added
*/
public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) {
notifyBlackBoardArtifactTagAdded(newTag, null);
}
/**
* Notifies case event subscribers that an artifact tag has been added.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param newTag The added ContentTag.
* @param removedTagList List of ContentTags that were removed as a result
* of the addition of newTag.
*/
public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag, List<BlackboardArtifactTag> removedTagList) {
eventPublisher.publish(new BlackBoardArtifactTagAddedEvent(newTag, removedTagList));
}
/**
* Notifies case event subscribers that an artifact tag has been deleted.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param deletedTag BlackboardArtifactTag deleted
*/
public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) {
eventPublisher.publish(new BlackBoardArtifactTagDeletedEvent(deletedTag));
}
/**
* Adds a report to the case.
*

View File

@ -319,7 +319,7 @@ public class TagsManager implements Closeable {
}
}
for(TagName tagName: caseDb.getAllTagNames()) {
for (TagName tagName : caseDb.getAllTagNames()) {
allTagNameMap.put(tagName.getDisplayName(), tagName);
}
@ -636,14 +636,6 @@ public class TagsManager implements Closeable {
*/
public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
TaggingManager.ContentTagChange tagChange = caseDb.getTaggingManager().addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
try {
Case currentCase = Case.getCurrentCaseThrows();
currentCase.notifyContentTagAdded(tagChange.getAddedTag(), tagChange.getRemovedTags().isEmpty() ? null : tagChange.getRemovedTags());
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Added a tag to a closed case", ex);
}
return tagChange.getAddedTag();
}
@ -657,11 +649,6 @@ public class TagsManager implements Closeable {
*/
public void deleteContentTag(ContentTag tag) throws TskCoreException {
caseDb.deleteContentTag(tag);
try {
Case.getCurrentCaseThrows().notifyContentTagDeleted(tag);
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Deleted a tag from a closed case", ex);
}
}
/**
@ -857,12 +844,6 @@ public class TagsManager implements Closeable {
*/
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
TaggingManager.BlackboardArtifactTagChange tagChange = caseDb.getTaggingManager().addArtifactTag(artifact, tagName, comment);
try {
Case currentCase = Case.getCurrentCaseThrows();
currentCase.notifyBlackBoardArtifactTagAdded(tagChange.getAddedTag(), tagChange.getRemovedTags().isEmpty() ? null : tagChange.getRemovedTags());
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Added a tag to a closed case", ex);
}
return tagChange.getAddedTag();
}
@ -876,11 +857,6 @@ public class TagsManager implements Closeable {
*/
public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
caseDb.deleteBlackboardArtifactTag(tag);
try {
Case.getCurrentCaseThrows().notifyBlackBoardArtifactTagDeleted(tag);
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Deleted a tag from a closed case", ex);
}
}
/**

View File

@ -91,12 +91,6 @@ public interface DisplayableItemNodeVisitor<T> {
*/
T visit(Tags.RootNode node);
T visit(Tags.TagNameNode node);
T visit(Tags.ContentTagTypeNode node);
T visit(Tags.BlackboardArtifactTagTypeNode node);
/*
* Reports
@ -270,21 +264,6 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(node);
}
@Override
public T visit(Tags.TagNameNode node) {
return defaultVisit(node);
}
@Override
public T visit(Tags.ContentTagTypeNode node) {
return defaultVisit(node);
}
@Override
public T visit(Tags.BlackboardArtifactTagTypeNode node) {
return defaultVisit(node);
}
@Override
public T visit(Reports.ReportsListNode node) {
return defaultVisit(node);

View File

@ -97,7 +97,7 @@ public class RootContentChildren extends Children.Keys<Object> {
public static Node createNode(Object key) {
if (key instanceof Tags) {
Tags tagsNodeKey = (Tags) key;
return tagsNodeKey.new RootNode(tagsNodeKey.filteringDataSourceObjId());
return new Tags.RootNode(tagsNodeKey.filteringDataSourceObjId());
} else if (key instanceof DataSources) {
DataSources dataSourcesKey = (DataSources) key;
return new DataSourceFilesNode(dataSourcesKey.filteringDataSourceObjId());

View File

@ -18,39 +18,12 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.mainui.datamodel.TagsSearchParams;
import static org.sleuthkit.autopsy.mainui.datamodel.TagsSearchParams.TagType.FILE;
import static org.sleuthkit.autopsy.mainui.datamodel.TagsSearchParams.TagType.RESULT;
import org.sleuthkit.autopsy.corecomponents.SelectionResponder;
import org.sleuthkit.autopsy.tags.TagUtils;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.mainui.nodes.TagNameFactory;
/**
* Instances of this class act as keys for use by instances of the
@ -58,16 +31,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* factory built on top of the NetBeans Children.Keys class.
*/
public class Tags {
// Creation of a RootNode object corresponding to a Tags object is done
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
// override of Children.Keys<T>.createNodes().
private final static String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text");
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
private final TagResults tagResults = new TagResults();
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
Tags() {
@ -91,34 +55,23 @@ public class Tags {
return this.filteringDSObjId;
}
/**
* This class largely does nothing except act as a top-level object that the
* other nodes can listen to. This mimics what other nodes have (keword
* search, etc.), but theirs stores data.
*/
private class TagResults extends Observable {
public void update() {
setChanged();
notifyObservers();
}
}
/**
* Instances of this class are the root nodes of tree that is a sub-tree of
* the Autopsy presentation of the SleuthKit data model. The sub-tree
* consists of content and blackboard artifact tags, grouped first by tag
* type, then by tag name.
*/
public class RootNode extends DisplayableItemNode {
public static class RootNode extends DisplayableItemNode {
public RootNode(long objId) {
super(Children.create(new TagNameNodeFactory(objId), true), Lookups.singleton(DISPLAY_NAME));
private final static String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final Long dataSourceObjId;
public RootNode(Long dsId) {
super(Children.create(new TagNameFactory(dsId != null && dsId> 0 ? dsId : null), true), Lookups.singleton(DISPLAY_NAME));
super.setName(DISPLAY_NAME);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH);
this.dataSourceObjId = dsId != null && dsId> 0 ? dsId : null;
}
@Override
@ -149,422 +102,15 @@ public class Tags {
return getClass().getName();
}
public Node clone() {
return new RootNode(dataSourceObjId);
}
/**
* Cause the contents of the RootNode and its children to be updated.
*/
public void refresh() {
tagResults.update();
}
}
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
Case.Events.CONTENT_TAG_ADDED,
Case.Events.CONTENT_TAG_DELETED,
Case.Events.CURRENT_CASE);
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString())
|| eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString())
|| eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())
|| eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
refresh(true);
tagResults.update();
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
refresh(true);
tagResults.update();
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that this can be garbage collected
if (evt.getNewValue() == null) {
removeNotify();
}
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
/**
* Constructor
*
* @param objId data source object id
*/
TagNameNodeFactory(long objId) {
this.filteringDSObjId = objId;
}
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
tagResults.update();
tagResults.addObserver(this);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
tagResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<TagName> keys) {
try {
List<TagName> tagNamesInUse;
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagNamesInUse = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(filteringDSObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName);
} else {
tagNamesInUse = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(filteringDSObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
}
Collections.sort(tagNamesInUse, new Comparator<TagName>() {
@Override
public int compare(TagName o1, TagName o2) {
return TagUtils.getDecoratedTagDisplayName(o1).compareTo(TagUtils.getDecoratedTagDisplayName(o2));
}
});
keys.addAll(tagNamesInUse);
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(TagName key) {
return new TagNameNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
/**
* Instances of this class are elements of Node hierarchies consisting of
* content and blackboard artifact tags, grouped first by tag type, then by
* tag name.
*/
public class TagNameNode extends DisplayableItemNode implements Observer {
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; //NON-NLS
private final TagName tagName;
public TagNameNode(TagName tagName) {
super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName())));
this.tagName = tagName;
setName(TagUtils.getDecoratedTagDisplayName(tagName));
updateDisplayName();
if (tagName.getDisplayName().equals(TagsManager.getBookmarkTagDisplayName())) {
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
} else {
setIconBaseWithExtension(ICON_PATH);
}
tagResults.addObserver(this);
}
private void updateDisplayName() {
long tagsCount = 0;
try {
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
if (filteringDSObjId > 0) {
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName);
} else {
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
}
} else {
if (filteringDSObjId > 0) {
tagsCount = tm.getContentTagsCountByTagName(tagName, filteringDSObjId);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId);
} else {
tagsCount = tm.getContentTagsCountByTagName(tagName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
}
}
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
setDisplayName(TagUtils.getDecoratedTagDisplayName(tagName) + " \u200E(\u200E" + tagsCount + ")\u200E");
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.displayName"), tagName.getDescription(), getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
// See classes derived from DisplayableItemNodeVisitor<AbstractNode>
// for behavior added using the Visitor pattern.
return visitor.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
@Override
public String getItemType() {
return getClass().getName();
}
}
/**
* Creates nodes for the two types of tags: file and artifact. Does not need
* observer / messages since it always has the same children
*/
private class TagTypeNodeFactory extends ChildFactory<String> {
private final TagName tagName;
private final String CONTENT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.contentTagTypeNodeKey.text");
private final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.bbArtTagTypeNodeKey.text");
TagTypeNodeFactory(TagName tagName) {
super();
this.tagName = tagName;
}
@Override
protected boolean createKeys(List<String> keys) {
keys.add(CONTENT_TAG_TYPE_NODE_KEY);
keys.add(BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY);
return true;
}
@Override
protected Node createNodeForKey(String key) {
if (CONTENT_TAG_TYPE_NODE_KEY.equals(key)) {
return new ContentTagTypeNode(tagName);
} else if (BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY.equals(key)) {
return new BlackboardArtifactTagTypeNode(tagName);
} else {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "{0} not a recognized key", key); //NON-NLS
return null;
}
}
}
private final String CONTENT_DISPLAY_NAME = NbBundle.getMessage(ContentTagTypeNode.class, "ContentTagTypeNode.displayName.text");
/**
* Node for the content tags. Children are specific tags. Instances of this
* class are are elements of a directory tree sub-tree consisting of content
* and blackboard artifact tags, grouped first by tag type, then by tag
* name.
*/
public class ContentTagTypeNode extends DisplayableItemNode implements Observer, SelectionResponder {
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final TagName tagName;
public ContentTagTypeNode(TagName tagName) {
super(Children.LEAF, Lookups.singleton(tagName.getDisplayName() + " " + CONTENT_DISPLAY_NAME));
this.tagName = tagName;
super.setName(CONTENT_DISPLAY_NAME);
updateDisplayName();
this.setIconBaseWithExtension(ICON_PATH);
tagResults.addObserver(this);
}
@Override
public void respondSelection(DataResultTopComponent dataResultPanel) {
dataResultPanel.displayTags(new TagsSearchParams(tagName, FILE,
filteringDataSourceObjId() > 0 ? filteringDataSourceObjId() : null));
}
private void updateDisplayName() {
long tagsCount = 0;
try {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagsCount = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName);
} else {
tagsCount = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, filteringDSObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
super.setDisplayName(CONTENT_DISPLAY_NAME + " (" + tagsCount + ")");
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.displayName"), "", getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
@Override
public String getItemType() {
return getClass().getName();
}
}
private final String ARTIFACT_DISPLAY_NAME = NbBundle.getMessage(BlackboardArtifactTagTypeNode.class, "BlackboardArtifactTagTypeNode.displayName.text");
/**
* Instances of this class are elements in a sub-tree of the Autopsy
* presentation of the SleuthKit data model. The sub-tree consists of
* content and blackboard artifact tags, grouped first by tag type, then by
* tag name.
*/
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode implements Observer, SelectionResponder {
private final TagName tagName;
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
public BlackboardArtifactTagTypeNode(TagName tagName) {
super(Children.LEAF, Lookups.singleton(tagName.getDisplayName() + " " + ARTIFACT_DISPLAY_NAME));
this.tagName = tagName;
super.setName(ARTIFACT_DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH);
updateDisplayName();
tagResults.addObserver(this);
}
@Override
public void respondSelection(DataResultTopComponent dataResultPanel) {
dataResultPanel.displayTags(new TagsSearchParams(tagName, RESULT,
filteringDataSourceObjId() > 0 ? filteringDataSourceObjId() : null));
}
private void updateDisplayName() {
long tagsCount = 0;
try {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagsCount = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
} else {
tagsCount = (filteringDSObjId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
super.setDisplayName(ARTIFACT_DISPLAY_NAME + " (" + tagsCount + ")");
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.displayName"), "", getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
@Override
public String getItemType() {
return getClass().getName();
this.refresh();
}
}
}

View File

@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.datamodel.VolumeNode;
@ -92,6 +93,9 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
} else if (origNode instanceof AnalysisResults.RootNode) {
Node cloned = ((AnalysisResults.RootNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof Tags.RootNode) {
Node cloned = ((Tags.RootNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof ViewsNode) {
Node cloned = ((ViewsNode) origNode).clone();
return new Node[]{cloned};

View File

@ -327,7 +327,7 @@ public class ExtractActionHelper {
@Override
protected ExtractFscContentVisitor<T, V> getChildVisitor(File childFile, ProgressHandle progress, SwingWorker<T, V> worker) {
return new UIExtractionVisitor(childFile, progress, worker, false);
return new UIExtractionVisitor<>(childFile, progress, worker, false);
}

View File

@ -117,3 +117,5 @@ TagsDAO.tagColumns.sourceNameColLbl=Source Name
TagsDAO.tagColumns.sourcePathColLbl=Source File Path
TagsDAO.tagColumns.typeColLbl=Result Type
TagsDAO.tagColumns.userNameColLbl=User Name
TagType_File_displayName=File Tags
TagType_Result_displayName=Result Tags

View File

@ -0,0 +1,86 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2022 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.mainui.datamodel;
import java.util.Objects;
import org.sleuthkit.datamodel.TagName;
/**
*
* Search param for a tag name.
*/
public class TagNameSearchParams {
private static final String TYPE_ID = "TAG_TYPE";
/**
* @return The type id for this search parameter.
*/
public static String getTypeId() {
return TYPE_ID;
}
private final TagName tagName;
private final Long dataSourceId;
public TagNameSearchParams(TagName tagName, Long dataSourceId) {
this.dataSourceId = dataSourceId;
this.tagName = tagName;
}
public TagName getTagName() {
return tagName;
}
public Long getDataSourceId() {
return dataSourceId;
}
@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.tagName);
hash = 67 * hash + Objects.hashCode(this.dataSourceId);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TagNameSearchParams other = (TagNameSearchParams) obj;
if (!Objects.equals(this.tagName, other.tagName)) {
return false;
}
if (!Objects.equals(this.dataSourceId, other.dataSourceId)) {
return false;
}
return true;
}
}

View File

@ -22,15 +22,20 @@ import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.beans.PropertyChangeEvent;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
@ -42,21 +47,29 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.datamodel.Tags;
import static org.sleuthkit.autopsy.mainui.datamodel.AbstractDAO.CACHE_DURATION;
import static org.sleuthkit.autopsy.mainui.datamodel.AbstractDAO.CACHE_DURATION_UNITS;
import static org.sleuthkit.autopsy.mainui.datamodel.AbstractDAO.CACHE_SIZE;
import org.sleuthkit.autopsy.mainui.datamodel.TagsSearchParams.TagType;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
import org.sleuthkit.autopsy.mainui.datamodel.events.TagsEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeCounts;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
import org.sleuthkit.autopsy.mainui.nodes.DAOFetcher;
import org.sleuthkit.autopsy.tags.TagUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.CaseDbAccessManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@ -85,6 +98,8 @@ import org.sleuthkit.datamodel.TskCoreException;
"TagsDAO.tagColumns.userNameColLbl=User Name"})
public class TagsDAO extends AbstractDAO {
private static final Logger logger = Logger.getLogger(TagsDAO.class.getName());
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
private static final List<ColumnKey> FILE_TAG_COLUMNS = Arrays.asList(
@ -122,14 +137,12 @@ public class TagsDAO extends AbstractDAO {
return new ColumnKey(name, name, Bundle.TagsDAO_fileColumns_noDescription());
}
private final Cache<SearchParams<TagsSearchParams>, SearchResultsDTO> searchParamsCache =
CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
private final Cache<SearchParams<TagsSearchParams>, SearchResultsDTO> searchParamsCache
= CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
private final TreeCounts<TagsEvent> treeCounts = new TreeCounts<>();
public SearchResultsDTO getTags(TagsSearchParams key, long startItem, Long maxCount) throws ExecutionException, IllegalArgumentException {
if (key.getTagName() == null) {
throw new IllegalArgumentException("Must have non-null tag name");
} else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) {
if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) {
throw new IllegalArgumentException("Data source id must be greater than 0 or null");
} else if (key.getTagType() == null) {
throw new IllegalArgumentException("Must have non-null tag type");
@ -175,13 +188,14 @@ public class TagsDAO extends AbstractDAO {
private SearchResultsDTO fetchResultTags(SearchParams<TagsSearchParams> cacheKey) throws NoCurrentCaseException, TskCoreException {
Long dataSourceId = cacheKey.getParamData().getDataSourceId();
TagName tagName = cacheKey.getParamData().getTagName();
TagName tagNameId = cacheKey.getParamData().getTagName();
TagsManager tm = Case.getCurrentCase().getServices().getTagsManager();
// get all tag results
List<BlackboardArtifactTag> allTags = new ArrayList<>();
List<BlackboardArtifactTag> artifactTags = (dataSourceId != null && dataSourceId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
? tm.getBlackboardArtifactTagsByTagName(tagNameId, dataSourceId)
: tm.getBlackboardArtifactTagsByTagName(tagNameId);
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
for (BlackboardArtifactTag tag : artifactTags) {
@ -233,13 +247,15 @@ public class TagsDAO extends AbstractDAO {
private SearchResultsDTO fetchFileTags(SearchParams<TagsSearchParams> cacheKey) throws NoCurrentCaseException, TskCoreException {
Long dataSourceId = cacheKey.getParamData().getDataSourceId();
TagName tagName = cacheKey.getParamData().getTagName();
TagName tagNameId = cacheKey.getParamData().getTagName();
TagsManager tm = Case.getCurrentCase().getServices().getTagsManager();
// get all tag results
List<ContentTag> allTags = new ArrayList<>();
List<ContentTag> contentTags = (dataSourceId != null && dataSourceId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
? tm.getContentTagsByTagName(tagNameId, dataSourceId)
: tm.getContentTagsByTagName(tagNameId);
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
for (ContentTag tag : contentTags) {
@ -345,9 +361,9 @@ public class TagsDAO extends AbstractDAO {
Collection<TagsEvent> daoEvents = Collections.singletonList(data);
Collection<TreeEvent> treeEvents = this.treeCounts.enqueueAll(daoEvents).stream()
.map(arEvt -> new TreeEvent(getTreeItem(arEvt, TreeResultsDTO.TreeDisplayCount.INDETERMINATE), false))
.collect(Collectors.toList());
Collection<TreeEvent> treeEvents = daoEvents.stream()
.map(arEvt -> new TreeEvent(getTreeItem(arEvt, TreeResultsDTO.TreeDisplayCount.UNSPECIFIED), true))
.collect(Collectors.toSet());
return Stream.of(daoEvents, treeEvents)
.flatMap(lst -> lst.stream())
@ -398,6 +414,208 @@ public class TagsDAO extends AbstractDAO {
return null;
}
/**
* Returns the counts of each tag name.
*
* @param dataSourceId The data source object id to filter on.
*
* @return The tree item results.
*
* @throws ExecutionException
*/
public TreeResultsDTO<? extends TagNameSearchParams> getNameCounts(Long dataSourceId) throws ExecutionException {
Set<TagName> indeterminateTagNameIds = this.treeCounts.getEnqueued().stream()
.filter(evt -> dataSourceId == null || evt.getDataSourceId() == dataSourceId)
.map(evt -> evt.getTagName())
.collect(Collectors.toSet());
Map<TagName, TreeDisplayCount> tagNameCount = new HashMap<>();
try {
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
List<TagName> tagNamesInUse;
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagNamesInUse = (dataSourceId != null)
? tm.getTagNamesInUseForUser(dataSourceId, userName)
: tm.getTagNamesInUseForUser(userName);
} else {
tagNamesInUse = (dataSourceId != null)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
}
for (TagName tagName : tagNamesInUse) {
if (indeterminateTagNameIds.contains(tagName)) {
tagNameCount.put(tagName, TreeDisplayCount.INDETERMINATE);
continue;
}
long tagsCount;
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
if (dataSourceId != null) {
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, dataSourceId, userName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, dataSourceId, userName);
} else {
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
}
} else {
if (dataSourceId != null) {
tagsCount = tm.getContentTagsCountByTagName(tagName, dataSourceId);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, dataSourceId);
} else {
tagsCount = tm.getContentTagsCountByTagName(tagName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
}
}
tagNameCount.put(tagName, TreeDisplayCount.getDeterminate(tagsCount));
}
} catch (NoCurrentCaseException | TskCoreException ex) {
throw new ExecutionException("An error occurred while fetching data artifact counts.", ex);
}
List<TreeResultsDTO.TreeItemDTO<TagNameSearchParams>> tagNameParams = tagNameCount.entrySet().stream()
.map(e -> createTagNameTreeItem(e.getKey(), dataSourceId, e.getValue()))
.collect(Collectors.toList());
// return results
return new TreeResultsDTO<>(tagNameParams);
}
/**
* Creates a tag name tree item.
*
* @param tagName The tag name.
* @param dataSourceId The data source object id or null if not present.
* @param treeDisplayCount The tree display count.
*
* @return The tree item dto.
*/
public TreeItemDTO<TagNameSearchParams> createTagNameTreeItem(TagName tagName, Long dataSourceId, TreeResultsDTO.TreeDisplayCount treeDisplayCount) {
return new TreeItemDTO<>(
TagNameSearchParams.getTypeId(),
new TagNameSearchParams(tagName, dataSourceId),
tagName.getId(),
tagName.getDisplayName(),
treeDisplayCount
);
}
/**
* The count of content tags.
*
* @param dataSourceId The data source id where the content tag should
* appear or null.
* @param tagName The tag name.
*
* @return The count.
*
* @throws NoCurrentCaseException
* @throws TskCoreException
*/
private long getContentTagCount(Long dataSourceId, TagName tagName) throws NoCurrentCaseException, TskCoreException {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
return (dataSourceId != null)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, dataSourceId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName);
} else {
return (dataSourceId != null)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
}
}
/**
* The count of result tags.
*
* @param dataSourceId The data source id where the result tag should appear
* or null.
* @param tagName The tag name.
*
* @return The count.
*
* @throws NoCurrentCaseException
* @throws TskCoreException
*/
private long getArtifactTagCount(Long dataSourceId, TagName tagName) throws NoCurrentCaseException, TskCoreException {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
return (dataSourceId != null)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, dataSourceId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
} else {
return (dataSourceId != null)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
}
}
/**
* Returns the counts of file and result type given the search params.
*
* @param searchParams The tag name search params.
*
* @return The tree item results.
*
* @throws ExecutionException
*/
public TreeResultsDTO<? extends TagsSearchParams> getTypeCounts(TagNameSearchParams searchParams) throws ExecutionException {
Long dataSourceId = searchParams.getDataSourceId();
TagName tagName = searchParams.getTagName();
Set<TagType> indeterminateTagTypes = this.treeCounts.getEnqueued().stream()
.filter(evt -> (dataSourceId == null || Objects.equals(evt.getDataSourceId(), dataSourceId)) && Objects.equals(tagName, evt.getTagName()))
.map(evt -> evt.getTagType())
.collect(Collectors.toSet());
try {
return new TreeResultsDTO<>(Arrays.asList(
createTagTypeTreeItem(
tagName,
TagType.FILE,
dataSourceId,
indeterminateTagTypes.contains(TagType.FILE)
? TreeDisplayCount.INDETERMINATE
: TreeDisplayCount.getDeterminate(getContentTagCount(dataSourceId, tagName))),
createTagTypeTreeItem(
tagName,
TagType.RESULT,
dataSourceId,
indeterminateTagTypes.contains(TagType.RESULT)
? TreeDisplayCount.INDETERMINATE
: TreeDisplayCount.getDeterminate(getArtifactTagCount(dataSourceId, tagName)))
));
} catch (NoCurrentCaseException | TskCoreException ex) {
throw new ExecutionException("An error occurred while fetching tag type counts.", ex);
}
}
/**
* Creates a tag type tree item.
*
* @param tagName The tag name.
* @param tagType The tag type.
* @param dataSourceId The data source object id or null if not present.
* @param treeDisplayCount The tree display count.
*
* @return The tree item dto.
*/
public TreeItemDTO<TagsSearchParams> createTagTypeTreeItem(TagName tagName, TagType tagType, Long dataSourceId, TreeResultsDTO.TreeDisplayCount treeDisplayCount) {
return new TreeItemDTO<>(
TagsSearchParams.getTypeId(),
new TagsSearchParams(tagName, tagType, dataSourceId),
tagName.getId() + "_" + tagType.name(),
tagType.getDisplayName(),
treeDisplayCount
);
}
/**
* Handles fetching and paging of data for allTags.
*/

View File

@ -19,12 +19,13 @@
package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Objects;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.TagName;
/**
* Key for accessing data about tags from the DAO.
*/
public class TagsSearchParams {
public class TagsSearchParams extends TagNameSearchParams {
private static final String TYPE_ID = "TAG";
@ -35,39 +36,40 @@ public class TagsSearchParams {
return TYPE_ID;
}
@Messages({
"TagType_File_displayName=File Tags",
"TagType_Result_displayName=Result Tags",})
public enum TagType {
FILE,
RESULT;
FILE(Bundle.TagType_File_displayName()),
RESULT(Bundle.TagType_Result_displayName());
private final String displayName;
TagType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
private final TagType type;
private final TagName tagName;
private final Long dataSourceId;
public TagsSearchParams(TagName tagName, TagType type, Long dataSourceId) {
this.tagName = tagName;
super(tagName, dataSourceId);
this.type = type;
this.dataSourceId = dataSourceId;
}
public TagName getTagName() {
return tagName;
}
public TagType getTagType() {
return type;
}
public Long getDataSourceId() {
return dataSourceId;
}
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + Objects.hashCode(this.tagName);
hash = 23 * hash + Objects.hashCode(this.type);
hash = 23 * hash + Objects.hashCode(this.dataSourceId);
int hash = 3;
hash = 97 * hash + Objects.hashCode(this.type);
hash = 97 * hash + super.hashCode();
return hash;
}
@ -83,16 +85,10 @@ public class TagsSearchParams {
return false;
}
final TagsSearchParams other = (TagsSearchParams) obj;
if (!Objects.equals(this.tagName, other.tagName)) {
if (this.type != other.type) {
return false;
}
if (!Objects.equals(this.dataSourceId, other.dataSourceId)) {
return false;
}
if (!Objects.equals(this.type, other.type)) {
return false;
}
return true;
return super.equals(obj);
}
}

View File

@ -0,0 +1,173 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.mainui.nodes;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import org.openide.nodes.Children;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.mainui.datamodel.MainDAO;
import org.sleuthkit.autopsy.mainui.datamodel.TagNameSearchParams;
import org.sleuthkit.autopsy.mainui.datamodel.TagsSearchParams;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
import org.sleuthkit.autopsy.mainui.datamodel.events.DAOAggregateEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.DeleteAnalysisResultEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
/**
* Factory for displaying analysis result types in the tree.
*/
public class TagNameFactory extends TreeChildFactory<TagNameSearchParams> {
private static final String TAG_ICON = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
private final Long dataSourceId;
/**
* Main constructor.
*
* @param dataSourceId The data source id to filter on or null if no filter.
*/
public TagNameFactory(Long dataSourceId) {
this.dataSourceId = dataSourceId;
}
@Override
protected TreeResultsDTO<? extends TagNameSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return MainDAO.getInstance().getTagsDAO().getNameCounts(dataSourceId);
}
@Override
protected TreeNode<TagNameSearchParams> createNewNode(TreeResultsDTO.TreeItemDTO<? extends TagNameSearchParams> rowData) {
return new TagNameNode(rowData);
}
@Override
protected TreeResultsDTO.TreeItemDTO<? extends TagNameSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
TreeResultsDTO.TreeItemDTO<TagNameSearchParams> originalTreeItem = super.getTypedTreeItem(treeEvt, TagNameSearchParams.class);
if (originalTreeItem != null
&& (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {
return MainDAO.getInstance().getTagsDAO().createTagNameTreeItem(
originalTreeItem.getSearchParams().getTagName(),
dataSourceId,
originalTreeItem.getDisplayCount());
}
return null;
}
@Override
public int compare(TreeItemDTO<? extends TagNameSearchParams> o1, TreeItemDTO<? extends TagNameSearchParams> o2) {
return Comparator.comparing((TreeItemDTO<? extends TagNameSearchParams> tagTreeItem) -> tagTreeItem.getDisplayName())
.compare(o1, o2);
}
@Override
protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) {
for (DAOEvent evt : aggEvt.getEvents()) {
if (evt instanceof DeleteAnalysisResultEvent && evt.getType() == DAOEvent.Type.TREE) {
super.update();
return;
}
}
super.handleDAOAggregateEvent(aggEvt);
}
/**
* A node for a tag name.
*/
static class TagNameNode extends TreeNode<TagNameSearchParams> {
public TagNameNode(TreeResultsDTO.TreeItemDTO<? extends TagNameSearchParams> rowData) {
super(TagNameSearchParams.getTypeId() + "_" + Objects.toString(rowData.getId()),
TAG_ICON,
rowData,
Children.create(new TagTypeFactory(rowData.getSearchParams()), false),
getDefaultLookup(rowData));
}
}
/**
* Factory displaying file type or result type underneath a tag name node.
*/
static class TagTypeFactory extends TreeChildFactory<TagsSearchParams> {
private final TagNameSearchParams searchParams;
TagTypeFactory(TagNameSearchParams searchParams) {
this.searchParams = searchParams;
}
@Override
protected TreeNode<TagsSearchParams> createNewNode(TreeItemDTO<? extends TagsSearchParams> rowData) {
return new TagsTypeNode(rowData);
}
@Override
protected TreeResultsDTO<? extends TagsSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return MainDAO.getInstance().getTagsDAO().getTypeCounts(searchParams);
}
@Override
protected TreeItemDTO<? extends TagsSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
TreeResultsDTO.TreeItemDTO<TagsSearchParams> originalTreeItem = super.getTypedTreeItem(treeEvt, TagsSearchParams.class);
if (originalTreeItem != null
&& Objects.equals(this.searchParams.getTagName(), originalTreeItem.getSearchParams().getTagName())
&& (this.searchParams.getDataSourceId() == null || Objects.equals(this.searchParams.getDataSourceId(), originalTreeItem.getSearchParams().getDataSourceId()))) {
return MainDAO.getInstance().getTagsDAO().createTagTypeTreeItem(
searchParams.getTagName(),
originalTreeItem.getSearchParams().getTagType(),
searchParams.getDataSourceId(),
originalTreeItem.getDisplayCount());
}
return null;
}
@Override
public int compare(TreeItemDTO<? extends TagsSearchParams> o1, TreeItemDTO<? extends TagsSearchParams> o2) {
return Comparator.comparing((TreeItemDTO<? extends TagsSearchParams> rowData) -> rowData.getSearchParams().getTagType() == TagsSearchParams.TagType.FILE ? 0 : 1)
.compare(o1, o2);
}
}
/**
* A tag type (i.e. File/Result) tree node. Clicking on this will go to
* results.
*/
static class TagsTypeNode extends TreeNode<TagsSearchParams> {
private TagsTypeNode(TreeItemDTO<? extends TagsSearchParams> rowData) {
super(TagsSearchParams.getTypeId() + "_" + Objects.toString(rowData.getId()), TAG_ICON, rowData);
}
@Override
public void respondSelection(DataResultTopComponent dataResultPanel) {
dataResultPanel.displayTags(this.getItemData().getSearchParams());
}
}
}