Tag Events

- created new Case.Event enum values for BlackBoard/Content tags added/deleted
- created new PropertyChangeEvent subclasses for  BlackBoard/Content tags added/deleted
- replaced ModuleDataEvent hack  with new Tag Events
- removed [in] from javadocs, other minor cleanup
This commit is contained in:
jmillman 2015-06-19 10:22:18 -04:00
parent f391e32f6b
commit ba81377eb0
11 changed files with 580 additions and 238 deletions

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,20 +19,18 @@
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.openide.util.NbBundle;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* An abstract base class for Actions that allow users to tag SleuthKit data
@ -98,12 +96,8 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup {
if (null != tagNames && !tagNames.isEmpty()) {
for (final TagName tagName : tagNames) {
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
tagNameItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addTag(tagName, NO_COMMENT);
refreshDirectoryTree();
}
tagNameItem.addActionListener((ActionEvent e) -> {
addTag(tagName, NO_COMMENT);
});
quickTagMenu.add(tagNameItem);
}
@ -120,14 +114,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup {
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TagName tagName = GetTagNameDialog.doDialog();
if (tagName != null) {
addTag(tagName, NO_COMMENT);
refreshDirectoryTree();
}
newTagMenuItem.addActionListener((ActionEvent e) -> {
TagName tagName = GetTagNameDialog.doDialog();
if (null != tagName) {
addTag(tagName, NO_COMMENT);
}
});
quickTagMenu.add(newTagMenuItem);
@ -137,14 +127,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup {
// optional comment and adds a tag with the resulting name.
JMenuItem tagAndCommentItem = new JMenuItem(
NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment"));
tagAndCommentItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
if (null != tagNameAndComment) {
addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment());
refreshDirectoryTree();
}
tagAndCommentItem.addActionListener((ActionEvent e) -> {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
if (null != tagNameAndComment) {
addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment());
}
});
add(tagAndCommentItem);

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,41 +20,26 @@ package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* Abstract base class for Actions involving tags.
*/
abstract class TagAction extends AbstractAction {
abstract class TagAction extends AbstractAction {
public TagAction(String menuText) {
super(menuText);
}
@Override
public void actionPerformed(ActionEvent event) {
doAction(event);
refreshDirectoryTree();
}
}
/**
* Derived classes must implement this Template Method for actionPerformed().
* @param event ActionEvent object passed to actionPerformed()
* Derived classes must implement this Template Method for
* actionPerformed().
*
* @param event ActionEvent object passed to actionPerformed()
*/
abstract protected void doAction(ActionEvent event);
/**
* Derived classes should call this method any time a tag is created, updated
* or deleted outside of an actionPerformed() call.
*/
@SuppressWarnings("deprecation")
protected void refreshDirectoryTree() {
/* Note: this is a hack. In an ideal world, TagsManager would fire events so
* that the directory tree would refresh. But, we haven't had a chance to add
* that so, we fire these events and the tree refreshes based on them.
*/
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS
}
}

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.Frame;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedInputStream;
@ -49,8 +50,19 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.datamodel.*;
import org.sleuthkit.autopsy.events.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.events.ContentTagDeletedEvent;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/**
* Stores all information for a given case. Only a single case can currently be
@ -126,7 +138,19 @@ public class Case implements SleuthkitCase.ErrorObserver {
* case. The old value supplied by the event object is null and the new
* value is a reference to a Report object representing the new report.
*/
REPORT_ADDED;
REPORT_ADDED,
/** Property name for the event when a new BlackBoardArtifactTag is
* added. The new value is tag added, the old value is empty */
BLACKBOARD_ARTIFACT_TAG_ADDED,
/** Property name for the event when a new BlackBoardArtifactTag is
* deleted. The new value is empty, the old value is the deleted tag */
BLACKBOARD_ARTIFACT_TAG_DELETED,
/** Property name for the event when a new ContentTag is
* added. The new value is tag added, the old value is empty */
CONTENT_TAG_ADDED,
/** Property name for the event when a new ContentTag is
* deleted. The new value is empty, the old value is the deleted tag */
CONTENT_TAG_DELETED;
};
private String name;
@ -267,12 +291,13 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* Creates a new case (create the XML config file and database)
*
* @param caseDir The directory to store case data in. Will be created if it
* doesn't already exist. If it exists, it should have all of the needed sub
* dirs that createCaseDirectory() will create.
* @param caseName the name of case
* @param caseDir The directory to store case data in. Will be created if
* it
* doesn't already exist. If it exists, it should have all of the needed sub
* dirs that createCaseDirectory() will create.
* @param caseName the name of case
* @param caseNumber the case number
* @param examiner the examiner for this case
* @param examiner the examiner for this case
*/
public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException {
logger.log(Level.INFO, "Creating new case.\ncaseDir: {0}\ncaseName: {1}", new Object[]{caseDir, caseName}); //NON-NLS
@ -418,7 +443,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* Sends out event and reopens windows if needed.
*
* @param imgPaths the paths of the image that being added
* @param imgId the ID of the image that being added
* @param imgId the ID of the image that being added
* @param timeZone the timeZone of the image where it's added
*/
@Deprecated
@ -476,6 +501,59 @@ public class Case implements SleuthkitCase.ErrorObserver {
CoreComponentControl.openCoreWindows();
}
/**
* Notifies the UI that a new ContentTag has been added.
*
* @param newTag new ContentTag added
*/
public void notifyContentTagAdded(ContentTag newTag) {
notify(new ContentTagAddedEvent(newTag));
}
/**
* Notifies the UI that a ContentTag has been deleted.
*
* @param deletedTag ContentTag deleted
*/
public void notifyContentTagDeleted(ContentTag deletedTag) {
notify(new ContentTagDeletedEvent(deletedTag));
}
/**
* Notifies the UI that a new BlackboardArtifactTag has been added.
*
* @param newTag new BlackboardArtifactTag added
*/
public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) {
notify(new BlackBoardArtifactTagAddedEvent(newTag));
}
/**
* Notifies the UI that a BlackboardArtifactTag has been.
*
* @param deletedTag BlackboardArtifactTag deleted
*/
public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) {
notify(new BlackBoardArtifactTagDeletedEvent(deletedTag));
}
/**
* Notifies the UI about a Case level event.
*
* @param propertyChangeEvent the event to distribute
*/
private void notify(final PropertyChangeEvent propertyChangeEvent) {
try {
pcs.firePropertyChange(propertyChangeEvent);
} catch (Exception e) {
logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"),
NbBundle.getMessage(this.getClass(),
"Case.changeCase.errListenToCaseUpdates.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
/**
* @return The Services object for this case.
*/
@ -540,9 +618,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
* Updates the case name.
*
* @param oldCaseName the old case name that wants to be updated
* @param oldPath the old path that wants to be updated
* @param oldPath the old path that wants to be updated
* @param newCaseName the new case name
* @param newPath the new path
* @param newPath the new path
*/
void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException {
try {
@ -801,6 +879,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* Get the data model Content objects in the root of this case's hierarchy.
*
* @return a list of the root objects
*
* @throws org.sleuthkit.datamodel.TskCoreException
*/
public List<Content> getDataSources() throws TskCoreException {
@ -934,7 +1013,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* to create the case directory
*
* @param caseDir Path to the case directory (typically base + case name)
* @param caseDir Path to the case directory (typically base + case name)
* @param caseName the case name (used only for error messages)
*
* @throws CaseActionException throw if could not create the case dir
@ -1154,12 +1233,14 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* Adds a report to the case.
*
* @param [in] localPath The path of the report file, must be in the case
* directory or one of its subdirectories.
* @param [in] sourceModuleName The name of the module that created the
* report.
* @param [in] reportName The report name, may be empty.
* @param localPath The path of the report file, must be in the case
* directory or one of its subdirectories.
* @param sourceModuleName The name of the module that created the
* report.
* @param reportName The report name, may be empty.
*
* @return A Report data transfer object (DTO) for the new row.
*
* @throws TskCoreException
*/
public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,9 +24,9 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
@ -37,28 +37,32 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A per case instance of this class functions as an Autopsy service that
* manages the creation, updating, and deletion of tags applied to content and
* blackboard artifacts by users.
* A per case instance of this class functions as an Autopsy service that
* manages the creation, updating, and deletion of tags applied to content and
* blackboard artifacts by users.
*/
public class TagsManager implements Closeable {
private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS
private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS
private final SleuthkitCase tskCase;
private final SleuthkitCase tskCase;
private final HashMap<String, TagName> uniqueTagNames = new HashMap<>();
private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
// Use this exception and the member hash map to manage uniqueness of hash
// names. This is deemed more proactive and informative than leaving this to
// the UNIQUE constraint on the display_name field of the tag_names table in
// the case database.
public class TagNameAlreadyExistsException extends Exception {
}
/**
* Package-scope constructor for use of the Services class. An instance of
* Use this exception and the member hash map to manage uniqueness of hash
* names. This is deemed more proactive and informative than leaving this to
* the UNIQUE constraint on the display_name field of the tag_names table in
* the case database.
*/
public static class TagNameAlreadyExistsException extends Exception {
}
/**
* Package-scope constructor for use of the Services class. An instance of
* TagsManager should be created for each case that is opened.
* @param [in] tskCase The SleuthkitCase object for the current case.
*
* @param tskCase The SleuthkitCase object for the current case.
*/
TagsManager(SleuthkitCase tskCase) {
this.tskCase = tskCase;
@ -67,38 +71,44 @@ public class TagsManager implements Closeable {
}
/**
* Gets a list of all tag names currently available for tagging content or
* Gets a list of all tag names currently available for tagging content or
* blackboard artifacts.
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @throws TskCoreException
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
*
* @throws TskCoreException
*/
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getAllTagNames();
}
/**
* Gets a list of all tag names currently used for tagging content or
* Gets a list of all tag names currently used for tagging content or
* blackboard artifacts.
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @throws TskCoreException
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
*
* @throws TskCoreException
*/
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getTagNamesInUse();
}
/**
* Checks whether a tag name with a given display name exists.
* @param [in] tagDisplayName The display name for which to check.
*
* @param tagDisplayName The display name for which to check.
*
* @return True if the tag name exists, false otherwise.
*/
public synchronized boolean tagNameExists(String tagDisplayName) {
@ -106,15 +116,19 @@ public class TagsManager implements Closeable {
if (!tagNamesInitialized) {
getExistingTagNames();
}
return uniqueTagNames.containsKey(tagDisplayName);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*
* @param displayName The display name for the new tag name.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
*
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, "", TagName.HTML_COLOR.NONE);
@ -122,10 +136,14 @@ public class TagsManager implements Closeable {
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @param [in] description The description for the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*
* @param displayName The display name for the new tag name.
* @param description The description for the new tag name.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
*
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, description, TagName.HTML_COLOR.NONE);
@ -133,82 +151,95 @@ public class TagsManager implements Closeable {
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @param [in] description The description for the new tag name.
* @param [in] color The HTML color to associate with the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*
* @param displayName The display name for the new tag name.
* @param description The description for the new tag name.
* @param color The HTML color to associate with the new tag name.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
*
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
if (uniqueTagNames.containsKey(displayName)) {
throw new TagNameAlreadyExistsException();
}
// Add the tag name to the case.
TagName newTagName = tskCase.addTagName(displayName, description, color);
TagName newTagName = tskCase.addTagName(displayName, description, color);
// Add the tag name to the tags settings.
uniqueTagNames.put(newTagName.getDisplayName(), newTagName);
saveTagNamesToTagsSettings();
saveTagNamesToTagsSettings();
return newTagName;
}
/**
* Tags a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
*
* @throws TskCoreException
*/
public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException {
return addContentTag(content, tagName, "", -1, -1);
}
}
/**
* Tags a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
* @param comment A comment to store with the tag.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
*
* @throws TskCoreException
*/
public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
return addContentTag(content, tagName, comment, -1, -1);
}
}
/**
* Tags a content object or a section of a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @param [in] beginByteOffset Designates the beginning of a tagged section.
* @param [in] endByteOffset Designates the end of a tagged section.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws IllegalArgumentException, TskCoreException
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
* @param comment A comment to store with the tag.
* @param beginByteOffset Designates the beginning of a tagged section.
* @param endByteOffset Designates the end of a tagged section.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
*
* @throws IllegalArgumentException, TskCoreException
*/
public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
if (beginByteOffset >= 0 && endByteOffset >= 1) {
if (beginByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(),
"TagsManager.addContentTag.exception.beginByteOffsetOOR.msg",
beginByteOffset, content.getSize() - 1));
"TagsManager.addContentTag.exception.beginByteOffsetOOR.msg",
beginByteOffset, content.getSize() - 1));
}
if (endByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg",
endByteOffset, content.getSize() - 1));
endByteOffset, content.getSize() - 1));
}
if (endByteOffset < beginByteOffset) {
@ -216,28 +247,34 @@ public class TagsManager implements Closeable {
NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg"));
}
}
return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
Case.getCurrentCase().notifyContentTagAdded(newContentTag);
return newContentTag;
}
/**
* Deletes a content tag.
* @param [in] tag The tag to delete.
* @throws TskCoreException
*
* @param tag The tag to delete.
*
* @throws TskCoreException
*/
public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
tskCase.deleteContentTag(tag);
Case.getCurrentCase().notifyContentTagDeleted(tag);
}
/**
* Gets all content tags for the current case.
*
* @return A list, possibly empty, of content tags.
* @throws TskCoreException
*
* @throws TskCoreException
*/
public List<ContentTag> getAllContentTags() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
@ -245,100 +282,126 @@ public class TagsManager implements Closeable {
getExistingTagNames();
}
return tskCase.getAllContentTags();
return tskCase.getAllContentTags();
}
/**
* Gets content tags count by tag name.
* @param [in] tagName The tag name of interest.
*
* @param tagName The tag name of interest.
*
* @return A count of the content tags with the specified tag name.
* @throws TskCoreException
*
* @throws TskCoreException
*/
public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsCountByTagName(tagName);
return tskCase.getContentTagsCountByTagName(tagName);
}
/**
* Gets content tags by tag name.
* @param [in] tagName The tag name of interest.
* @return A list, possibly empty, of the content tags with the specified tag name.
* @throws TskCoreException
*
* @param tagName The tag name of interest.
*
* @return A list, possibly empty, of the content tags with the specified
* tag name.
*
* @throws TskCoreException
*/
public synchronized List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsByTagName(tagName);
return tskCase.getContentTagsByTagName(tagName);
}
/**
* Gets content tags count by content.
* @param [in] content The content of interest.
* @return A list, possibly empty, of the tags that have been applied to the artifact.
* @throws TskCoreException
*
* @param content The content of interest.
*
* @return A list, possibly empty, of the tags that have been applied to the
* artifact.
*
* @throws TskCoreException
*/
public synchronized List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsByContent(content);
return tskCase.getContentTagsByContent(content);
}
/**
* Tags a blackboard artifact object.
* @param [in] artifact The blackboard artifact to tag.
* @param [in] tagName The name to use for the tag.
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*
* @param artifact The blackboard artifact to tag.
* @param tagName The name to use for the tag.
*
* @return A BlackboardArtifactTag data transfer object (DTO) representing
* the new tag.
*
* @throws TskCoreException
*/
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
return addBlackboardArtifactTag(artifact, tagName, "");
return addBlackboardArtifactTag(artifact, tagName, "");
}
/**
* Tags a blackboard artifact object.
* @param [in] artifact The blackboard artifact to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*
* @param artifact The blackboard artifact to tag.
* @param tagName The name to use for the tag.
* @param comment A comment to store with the tag.
*
* @return A BlackboardArtifactTag data transfer object (DTO) representing
* the new tag.
*
* @throws TskCoreException
*/
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag);
return addBlackboardArtifactTag;
}
/**
* Deletes a blackboard artifact tag.
* @param [in] tag The tag to delete.
* @throws TskCoreException
*
* @param tag The tag to delete.
*
* @throws TskCoreException
*/
public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
tskCase.deleteBlackboardArtifactTag(tag);
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag);
}
/**
* Gets all blackboard artifact tags for the current case.
*
* @return A list, possibly empty, of blackboard artifact tags.
* @throws TskCoreException
*
* @throws TskCoreException
*/
public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
@ -346,100 +409,110 @@ public class TagsManager implements Closeable {
getExistingTagNames();
}
return tskCase.getAllBlackboardArtifactTags();
return tskCase.getAllBlackboardArtifactTags();
}
/**
* Gets blackboard artifact tags count by tag name.
* @param [in] tagName The tag name of interest.
* @return A count of the blackboard artifact tags with the specified tag name.
* @throws TskCoreException
*
* @param tagName The tag name of interest.
*
* @return A count of the blackboard artifact tags with the specified tag
* name.
*
* @throws TskCoreException
*/
public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
}
/**
* Gets blackboard artifact tags by tag name.
* @param [in] tagName The tag name of interest.
* @return A list, possibly empty, of the blackboard artifact tags with the specified tag name.
* @throws TskCoreException
*
* @param tagName The tag name of interest.
*
* @return A list, possibly empty, of the blackboard artifact tags with the
* specified tag name.
*
* @throws TskCoreException
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsByTagName(tagName);
return tskCase.getBlackboardArtifactTagsByTagName(tagName);
}
/**
* Gets blackboard artifact tags for a particular blackboard artifact.
* @param [in] artifact The blackboard artifact of interest.
* @return A list, possibly empty, of the tags that have been applied to the artifact.
* @throws TskCoreException
*
* @param artifact The blackboard artifact of interest.
*
* @return A list, possibly empty, of the tags that have been applied to the
* artifact.
*
* @throws TskCoreException
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsByArtifact(artifact);
return tskCase.getBlackboardArtifactTagsByArtifact(artifact);
}
@Override
public void close() throws IOException {
saveTagNamesToTagsSettings();
}
public void close() throws IOException {
saveTagNamesToTagsSettings();
}
private void getExistingTagNames() {
getTagNamesFromCurrentCase();
getTagNamesFromTagsSettings();
getPredefinedTagNames();
saveTagNamesToTagsSettings();
saveTagNamesToTagsSettings();
tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
}
private void getTagNamesFromCurrentCase() {
try {
List<TagName> currentTagNames = tskCase.getAllTagNames();
for (TagName tagName : currentTagNames) {
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
}
catch (TskCoreException ex) {
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS
}
}
}
private void getTagNamesFromTagsSettings() {
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
if (null != setting && !setting.isEmpty()) {
if (null != setting && !setting.isEmpty()) {
// Read the tag name setting and break it into tag name tuples.
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
// Parse each tuple and add the tag names to the current case, one
// at a time to gracefully discard any duplicates or corrupt tuples.
for (String tagNameTuple : tagNameTuples) {
for (String tagNameTuple : tagNameTuples) {
String[] tagNameAttributes = tagNameTuple.split(",");
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
try {
TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
catch (TskCoreException ex) {
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS
}
}
}
}
}
}
private void getPredefinedTagNames() {
@ -448,13 +521,12 @@ public class TagsManager implements Closeable {
TagName tagName = tskCase.addTagName(
NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE);
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
catch (TskCoreException ex) {
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex); //NON-NLS
}
}
}
}
private void saveTagNamesToTagsSettings() {
if (!uniqueTagNames.isEmpty()) {
StringBuilder setting = new StringBuilder();
@ -466,7 +538,7 @@ public class TagsManager implements Closeable {
setting.append(tagName.getDescription()).append(",");
setting.append(tagName.getColor().name());
}
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
}
}
}
}

View File

@ -35,8 +35,6 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
@ -119,19 +117,14 @@ public class Tags implements AutopsyVisitableItem {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
@SuppressWarnings("deprecation")
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
/* Note: this is a hack. In an ideal world, TagsManager
* would fire events so that the directory tree would
* refresh. But, we haven't had a chance to add that so, we
* fire these events and the tree refreshes based on them. */
if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)
|| ((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) {
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())) {
refresh(true);
tagResults.update();
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
refresh(true);
tagResults.update();

View File

@ -0,0 +1,33 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
/**
*
*/
public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent<BlackboardArtifactTag> {
public BlackBoardArtifactTagAddedEvent(BlackboardArtifactTag newTag) {
super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag
);
}
}

View File

@ -0,0 +1,32 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
/**
*
*/
public class BlackBoardArtifactTagDeletedEvent extends TagDeletedEvent<BlackboardArtifactTag> {
public BlackBoardArtifactTagDeletedEvent(BlackboardArtifactTag oldValue) {
super(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), oldValue);
}
}

View File

@ -0,0 +1,35 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
/**
* An event that is fired when a ContentTag is added.
*/
@Immutable
public class ContentTagAddedEvent extends TagAddedEvent<ContentTag> {
public ContentTagAddedEvent(ContentTag newTag) {
super(Case.Events.CONTENT_TAG_ADDED.toString(), newTag);
}
}

View File

@ -0,0 +1,34 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
/**
* An event that is fired when a ContentTag is deleted.
*/
@Immutable
public class ContentTagDeletedEvent extends TagDeletedEvent<ContentTag> {
public ContentTagDeletedEvent(ContentTag deletedTag) {
super(Case.Events.CONTENT_TAG_DELETED.toString(), deletedTag);
}
}

View File

@ -0,0 +1,46 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import java.beans.PropertyChangeEvent;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.Tag;
/**
* Base Class for events that are fired when a Tag is added
*/
@Immutable
abstract class TagAddedEvent<T extends Tag> extends PropertyChangeEvent {
protected TagAddedEvent(String propertyName, T newValue) {
super(Case.class, propertyName, null, newValue);
}
/**
* get the Tag that was added
*
* @return the tTag
*/
@SuppressWarnings("unchecked")
public T getAddedTag() {
return (T) getNewValue();
}
}

View File

@ -0,0 +1,45 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.events;
import java.beans.PropertyChangeEvent;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.Tag;
/**
* Base Class for events that are fired when a Tag is deleted
*/
@Immutable
abstract class TagDeletedEvent<T extends Tag> extends PropertyChangeEvent {
protected TagDeletedEvent(String propertyName, T oldValue) {
super(Case.class, propertyName, oldValue, null);
}
/**
* get the Tag that was deleted
*
* @return the Tag
*/
@SuppressWarnings("unchecked")
public T getDeletedTag() {
return (T) getOldValue();
}
}