diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactNodev2.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactNodev2.java index dbc67007c8..49deb2beba 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactNodev2.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifactNodev2.java @@ -19,11 +19,8 @@ package org.sleuthkit.autopsy.datamodel; import com.google.common.collect.ImmutableSet; -import java.beans.PropertyChangeListener; import org.sleuthkit.autopsy.actions.ViewArtifactAction; import org.sleuthkit.autopsy.actions.ViewOsAccountAction; -import java.lang.ref.WeakReference; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -33,13 +30,11 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.Action; -import javax.swing.SwingUtilities; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.Lookup; @@ -51,13 +46,8 @@ import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; -import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; @@ -66,19 +56,14 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; -import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR; import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactRow; import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableDTO; import org.sleuthkit.autopsy.texttranslation.TextTranslationService; -import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask; import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; @@ -97,13 +82,9 @@ import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; -import org.sleuthkit.datamodel.Tag; -/** - * An AbstractNode implementation that can be used to represent an data artifact - * or analysis result of any type. - */ -public class DataArtifactNodev2 extends AbstractContentNode { + +public class DataArtifactNodev2 extends AbstractNode { private static final Logger logger = Logger.getLogger(DataArtifactNodev2.class.getName()); @@ -122,40 +103,12 @@ public class DataArtifactNodev2 extends AbstractContentNode private final boolean hasSupportedTimeStamp; private String translatedSourceName = null; - private final PropertyChangeListener fileNameTranslationListener = (evt) -> { - String eventType = evt.getPropertyName(); - if (eventType.equals(FileNameTransTask.getPropertyName())) { - /* - * Replace the value of the Source File property with the - * translated name via setDisplayName (see note in createSheet), - * and put the untranslated name in the Original Name property - * and in the tooltip. - */ - String originalName = evt.getOldValue().toString(); - translatedSourceName = evt.getNewValue().toString(); - setDisplayName(translatedSourceName); - setShortDescription(originalName); - updateSheet(new NodeProperty<>( - Bundle.BlackboardArtifactNode_createSheet_srcFile_origName(), - Bundle.BlackboardArtifactNode_createSheet_srcFile_origDisplayName(), - NO_DESCR, - originalName)); - } - }; - - private final PropertyChangeListener scoListener = (evt) -> { - String eventType = evt.getPropertyName(); - if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) { - updateSCOColumns((SCOData) evt.getNewValue()); - } - }; - public DataArtifactNodev2(DataArtifactTableDTO tableData, DataArtifactRow artifactRow) { this(tableData, artifactRow, IconsUtil.getIconFilePath(tableData.getArtifactType().getTypeID())); } public DataArtifactNodev2(DataArtifactTableDTO tableData, DataArtifactRow artifactRow, String iconPath) { - super(artifactRow.getDataArtifact(), createLookup(artifactRow)); + super(Children.LEAF, createLookup(artifactRow)); setDisplayName(artifactRow.getSrcContent().getName()); setShortDescription(getDisplayName()); @@ -204,7 +157,10 @@ public class DataArtifactNodev2 extends AbstractContentNode )); // view associated file (TSK_PATH_ID attr) in directory and timeline - actionsLists.add(getAssociatedFileActions(artifact, this.artifactType)); + AbstractFile associatedFile = this.artifactRow.getLinkedFile() instanceof AbstractFile + ? (AbstractFile) this.artifactRow.getLinkedFile() + : null; + actionsLists.add(getAssociatedFileActions(associatedFile, this.artifactType)); // view source content in directory and timeline actionsLists.add(getNonNull( @@ -296,41 +252,27 @@ public class DataArtifactNodev2 extends AbstractContentNode } } - /** - * Returns actions for navigating to an associated file in the directory or - * in the timeline. - * - * @param artifact The artifact whose associated file will be - * identified. - * @param artifactType The type of artifact. - * - * @return The actions or an empty list. - */ @Messages({ "# {0} - type", "DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileAction=View {0} in Directory", "# {0} - type", "DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileInTimelineAction=View {0} in Timeline..." }) - private List getAssociatedFileActions(BlackboardArtifact artifact, BlackboardArtifact.Type artifactType) { - try { - AbstractFile associatedFile = findLinked(artifact); - if (associatedFile != null) { - return Arrays.asList( - new ViewContextAction( - Bundle.DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileAction( - getAssociatedTypeStr(artifactType)), - associatedFile), - new ViewFileInTimelineAction(associatedFile, - Bundle.DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileInTimelineAction( - getAssociatedTypeStr(artifactType))) - ); - } - - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS + private List getAssociatedFileActions(AbstractFile associatedFile, BlackboardArtifact.Type artifactType) { + if (associatedFile != null) { + return Arrays.asList( + new ViewContextAction( + Bundle.DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileAction( + getAssociatedTypeStr(artifactType)), + associatedFile), + new ViewFileInTimelineAction(associatedFile, + Bundle.DataArtifactNodev2_getAssociatedFileActions_viewAssociatedFileInTimelineAction( + getAssociatedTypeStr(artifactType))) + ); + } else { + return Collections.emptyList(); } - return Collections.emptyList(); + } /** @@ -563,12 +505,6 @@ public class DataArtifactNodev2 extends AbstractContentNode Bundle.DataArtifactNodev2_createSheet_srcFile_origDisplayName(), NO_DESCR, translatedSourceName != null ? srcContent.getName() : "")); - if (translatedSourceName == null) { - /* - * NOTE: The task makes its own weak reference to the listener. - */ - new FileNameTransTask(srcContent.getName(), this, fileNameTranslationListener).submit(); - } } /* @@ -594,10 +530,6 @@ public class DataArtifactNodev2 extends AbstractContentNode dataSourceStr)); } - if (scoTask != null) { - backgroundTasksPool.submit(scoTask); - } - return sheet; } @@ -703,16 +635,6 @@ public class DataArtifactNodev2 extends AbstractContentNode } } - @Override - public boolean isLeafTypeNode() { - return true; - } - - @Override - public String getItemType() { - return getClass().getName(); - } - @Messages({ "DataArtifactNodev2.createSheet.comment.displayName=C", "DataArtifactNodev2.createSheet.comment.name=C", @@ -738,152 +660,22 @@ public class DataArtifactNodev2 extends AbstractContentNode sheetSet.put(new NodeProperty<>( Bundle.DataArtifactNodev2_createSheet_score_name(), Bundle.DataArtifactNodev2_createSheet_score_displayName(), - VALUE_LOADING, + "" /* VALUE_LOADING */, "")); sheetSet.put(new NodeProperty<>( Bundle.DataArtifactNodev2_createSheet_comment_name(), Bundle.DataArtifactNodev2_createSheet_comment_displayName(), - VALUE_LOADING, + "" /* VALUE_LOADING */, "")); if (CentralRepository.isEnabled()) { sheetSet.put(new NodeProperty<>( Bundle.DataArtifactNodev2_createSheet_count_name(), Bundle.DataArtifactNodev2_createSheet_count_displayName(), - VALUE_LOADING, + "" /* VALUE_LOADING */, "")); } - return new GetSCOTask(new WeakReference<>(this), scoListener); + //return new GetSCOTask(new WeakReference<>(this), scoListener); } return null; } - - /** - * Update the SCO columns with the data retrieved in the background thread. - * - * @param scoData The data for the SCO columns. - */ - private void updateSCOColumns(final SCOData scoData) { - // Make sure this happens in the EDT - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (scoData.getScoreAndDescription() != null) { - updateSheet(new NodeProperty<>( - Bundle.DataArtifactNodev2_createSheet_score_name(), - Bundle.DataArtifactNodev2_createSheet_score_displayName(), - scoData.getScoreAndDescription().getRight(), - scoData.getScoreAndDescription().getLeft())); - } - if (scoData.getComment() != null) { - updateSheet(new NodeProperty<>( - Bundle.DataArtifactNodev2_createSheet_comment_name(), - Bundle.DataArtifactNodev2_createSheet_comment_displayName(), - NO_DESCR, scoData.getComment())); - } - if (scoData.getCountAndDescription() != null) { - updateSheet(new NodeProperty<>( - Bundle.DataArtifactNodev2_createSheet_count_name(), - Bundle.DataArtifactNodev2_createSheet_count_displayName(), - scoData.getCountAndDescription().getRight(), - scoData.getCountAndDescription().getLeft())); - } - } - }); - } - - /** - * Gets all of the tags applied to the artifact represented by this node and - * its source content. - * - * @return The tags. - */ - @Override - protected final List getAllTagsFromDatabase() { - List tags = new ArrayList<>(); - try { - tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(this.artifactRow.getDataArtifact())); - tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(this.artifactRow.getSrcContent())); - } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting tags for artifact and its source content (artifact objID={0})", this.artifactRow.getDataArtifact().getId()), ex); - } - return tags; - } - - /** - * Computes the value of the comment property ("C" in S, C, O) for the - * artifact represented by this node. - * - * An icon is displayed in the property sheet if a commented tag has been - * applied to the artifact or its source content, or if there is a - * corresponding commented correlation attribute instance in the central - * repository. - * - * @param tags The tags applied to the artifact and its source - * content. - * @param attributes A correlation attribute instance for the central - * repository lookup. - * - * @return The value of the comment property. - */ - @Override - protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, List attributes) { - /* - * Has a tag with a comment been applied to the artifact or its source - * content? - */ - DataResultViewerTable.HasCommentStatus status = tags.size() > 0 ? DataResultViewerTable.HasCommentStatus.TAG_NO_COMMENT : DataResultViewerTable.HasCommentStatus.NO_COMMENT; - for (Tag tag : tags) { - if (!StringUtils.isBlank(tag.getComment())) { - status = DataResultViewerTable.HasCommentStatus.TAG_COMMENT; - break; - } - } - /* - * Is there a comment in the CR for anything that matches the value and - * type of the specified attributes. - */ - try { - if (CentralRepoDbUtil.commentExistsOnAttributes(attributes)) { - if (status == DataResultViewerTable.HasCommentStatus.TAG_COMMENT) { - status = DataResultViewerTable.HasCommentStatus.CR_AND_TAG_COMMENTS; - } else { - status = DataResultViewerTable.HasCommentStatus.CR_COMMENT; - } - } - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Attempted to Query CR for presence of comments in a Blackboard Artifact node and was unable to perform query, comment column will only reflect caseDB", ex); - } - return status; - } - - @Override - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) { - Long count = -1L; - String description = defaultDescription; - try { - if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) { - count = CentralRepository.getInstance().getCountCasesWithOtherInstances(attribute); - description = Bundle.DataArtifactNodev2_createSheet_count_description(count, attribute.getCorrelationType().getDisplayName()); - } else if (attribute != null) { - description = Bundle.DataArtifactNodev2_createSheet_count_noCorrelationValues_description(); - } - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error querying central repository for other occurences count (artifact objID={0}, corrAttrType={1}, corrAttrValue={2})", - this.artifactRow.getDataArtifact().getId(), attribute.getCorrelationType(), attribute.getCorrelationValue()), ex); - } catch (CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error normalizing correlation attribute for central repository query (artifact objID={0}, corrAttrType={2}, corrAttrValue={3})", - this.artifactRow.getDataArtifact().getId(), attribute.getCorrelationType(), attribute.getCorrelationValue()), ex); - } - return Pair.of(count, description); - } - - @Override - public T accept(ContentNodeVisitor visitor) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } }