19 package org.sleuthkit.autopsy.datamodel;
 
   21 import java.beans.PropertyChangeEvent;
 
   22 import java.beans.PropertyChangeListener;
 
   23 import java.util.Collections;
 
   24 import java.util.EnumSet;
 
   25 import java.util.HashMap;
 
   26 import java.util.List;
 
   28 import java.util.Objects;
 
   30 import java.util.logging.Level;
 
   31 import java.util.stream.Collectors;
 
   32 import java.util.stream.Stream;
 
   33 import org.openide.nodes.ChildFactory;
 
   34 import org.openide.nodes.Children;
 
   35 import org.openide.nodes.Node;
 
   36 import org.openide.nodes.Sheet;
 
   37 import org.openide.util.Lookup;
 
   38 import org.openide.util.NbBundle;
 
   39 import org.openide.util.WeakListeners;
 
   40 import org.openide.util.lookup.Lookups;
 
   52 import org.
sleuthkit.datamodel.BlackboardArtifact.Category;
 
   53 import org.python.google.common.collect.Sets;
 
   55 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT;
 
   56 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_DATA_SOURCE_USAGE;
 
   57 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG;
 
   58 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT;
 
   59 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT;
 
   60 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT;
 
   61 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_GEN_INFO;
 
   62 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
 
   63 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT;
 
   64 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT;
 
   65 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT;
 
   88         BaseArtifactNode(Children children, String icon, String name, String displayName) {
 
   89             super(children, Lookups.singleton(name));
 
   91             super.setDisplayName(displayName);
 
   92             this.setIconBaseWithExtension(icon); 
 
   96         public boolean isLeafTypeNode() {
 
  102             return visitor.
visit(
this);
 
  106         protected Sheet createSheet() {
 
  107             Sheet sheet = super.createSheet();
 
  108             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  109             if (sheetSet == null) {
 
  110                 sheetSet = Sheet.createPropertiesSet();
 
  114             sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(), 
"ExtractedContentNode.createSheet.name.name"),
 
  115                     NbBundle.getMessage(
this.getClass(), 
"ExtractedContentNode.createSheet.name.displayName"),
 
  116                     NbBundle.getMessage(
this.getClass(), 
"ExtractedContentNode.createSheet.name.desc"),
 
  117                     super.getDisplayName()));
 
  122         public String getItemType() {
 
  123             return getClass().getName();
 
  143         TypeNodeKey(BlackboardArtifact.Type type, 
long dsObjId) {
 
  144             this(
new TypeNode(type, dsObjId), type);
 
  155             this.node = typeNode;
 
  157                     .filter(t -> t != null)
 
  158                     .collect(Collectors.toSet());
 
  175         Set<BlackboardArtifact.Type> getApplicableTypes() {
 
  194             if (getClass() != obj.getClass()) {
 
  210     static class TypeFactory 
extends ChildFactory.Detachable<TypeNodeKey> implements 
RefreshThrottler.Refresher {
 
  217         @SuppressWarnings(
"deprecation")
 
  218         private static final Set<BlackboardArtifact.
Type> IGNORED_TYPES = Sets.newHashSet(
 
  220                 TSK_DATA_SOURCE_USAGE,
 
  222                 new BlackboardArtifact.
Type(TSK_DOWNLOAD_SOURCE),
 
  225                 TSK_ASSOCIATED_OBJECT
 
  239         private static TypeNodeKey getTypeKey(BlackboardArtifact.
Type type, SleuthkitCase skCase, 
long dsObjId) {
 
  240             int typeId = type.getTypeID();
 
  241             if (TSK_EMAIL_MSG.getTypeID() == typeId) {
 
  243                 return new TypeNodeKey(emailNode, TSK_EMAIL_MSG);
 
  245             } 
else if (TSK_ACCOUNT.getTypeID() == typeId) {
 
  246                 Accounts.AccountsRootNode accountsNode = 
new Accounts(skCase, dsObjId).new AccountsRootNode();
 
  247                 return new TypeNodeKey(accountsNode, TSK_ACCOUNT);
 
  249             } 
else if (TSK_KEYWORD_HIT.getTypeID() == typeId) {
 
  250                 KeywordHits.RootNode keywordsNode = 
new KeywordHits(skCase, dsObjId).new RootNode();
 
  251                 return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT);
 
  253             } 
else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId) {
 
  254                 InterestingHits.RootNode interestingHitsNode = 
new InterestingHits(skCase, TSK_INTERESTING_ARTIFACT_HIT, dsObjId).new RootNode();
 
  255                 return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ARTIFACT_HIT);
 
  256             } 
else if (TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) {
 
  257                 InterestingHits.RootNode interestingHitsNode = 
new InterestingHits(skCase, TSK_INTERESTING_FILE_HIT, dsObjId).new RootNode();
 
  258                 return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_FILE_HIT);
 
  259             } 
else if (TSK_HASHSET_HIT.getTypeID() == typeId) {
 
  260                 HashsetHits.RootNode hashsetHits = 
new HashsetHits(skCase, dsObjId).new RootNode();
 
  261                 return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT);
 
  264                 return new TypeNodeKey(type, dsObjId);
 
  269         private final Map<BlackboardArtifact.Type, TypeNodeKey> typeNodeMap = 
new HashMap<>();
 
  270         private final long filteringDSObjId;
 
  277         private final RefreshThrottler refreshThrottler = 
new RefreshThrottler(
this);
 
  278         private final Category category;
 
  280         private final PropertyChangeListener weakPcl;
 
  290         TypeFactory(Category category, 
long filteringDSObjId) {
 
  292             this.filteringDSObjId = filteringDSObjId;
 
  293             this.category = category;
 
  295             PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
 
  296                 String eventType = evt.getPropertyName();
 
  297                 if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
 
  299                     if (evt.getNewValue() == null) {
 
  302                 } 
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
 
  303                         || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
 
  311                         Case.getCurrentCaseThrows();
 
  313                     } 
catch (NoCurrentCaseException notUsed) {
 
  321             weakPcl = WeakListeners.propertyChange(pcl, null);
 
  325         protected void addNotify() {
 
  327             refreshThrottler.registerForIngestModuleEvents();
 
  329             Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
 
  333         protected void finalize() throws Throwable {
 
  335             refreshThrottler.unregisterEventListener();
 
  336             IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
 
  337             Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
 
  342         protected boolean createKeys(List<TypeNodeKey> list) {
 
  345                 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
 
  346                 List<BlackboardArtifact.Type> types = (this.filteringDSObjId > 0)
 
  347                         ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId)
 
  348                         : skCase.getArtifactTypesInUse();
 
  350                 List<TypeNodeKey> allKeysSorted = types.stream()
 
  352                         .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp))
 
  355                             if (typeNodeMap.containsKey(tp)) {
 
  356                                 TypeNodeKey typeKey = typeNodeMap.get(tp);
 
  357                                 typeKey.getNode().updateDisplayName();
 
  361                                 TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId);
 
  362                                 for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) {
 
  363                                     typeNodeMap.put(recordType, newTypeKey);
 
  369                         .filter(record -> record != null)
 
  375                             String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? 
"" : a.getNode().getDisplayName();
 
  376                             String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? 
"" : b.getNode().getDisplayName();
 
  377                             return aSafe.compareToIgnoreCase(bSafe);
 
  379                         .collect(Collectors.toList());
 
  381                 list.addAll(allKeysSorted);
 
  383             } 
catch (NoCurrentCaseException ex) {
 
  384                 logger.log(Level.WARNING, 
"Trying to access case when no case is open.", ex); 
 
  385             } 
catch (TskCoreException ex) {
 
  386                 logger.log(Level.SEVERE, 
"Error getting list of artifacts in use: " + ex.getLocalizedMessage()); 
 
  392         protected Node createNodeForKey(TypeNodeKey key) {
 
  393             return key.getNode();
 
  397         public void refresh() {
 
  402         public boolean isRefreshRequired(PropertyChangeEvent evt) {
 
  403             String eventType = evt.getPropertyName();
 
  404             if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
 
  411                     Case.getCurrentCaseThrows();
 
  417                     final ModuleDataEvent 
event = (ModuleDataEvent) evt.getOldValue();
 
  418                     if (null != event && category.equals(event.getBlackboardArtifactType().getCategory())
 
  419                             && !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) {
 
  422                 } 
catch (NoCurrentCaseException notUsed) {
 
  440         private final Set<BlackboardArtifact.Type> 
types;
 
  458                 long filteringDSObjId, BlackboardArtifact.Type... 
types) {
 
  460             super(children, lookup);
 
  461             this.
types = Stream.of(
types).collect(Collectors.toSet());
 
  487             for (BlackboardArtifact.Type type : 
this.types) {
 
  488                 if (filteringDSObjId > 0) {
 
  489                     count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), 
filteringDSObjId);
 
  491                     count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
 
  501         void updateDisplayName() {
 
  506                 logger.log(Level.WARNING, 
"Error fetching data when case closed.", ex);
 
  507             } 
catch (TskCoreException ex) {
 
  508                 logger.log(Level.WARNING, 
"Error getting child count", ex); 
 
  510             super.setDisplayName(this.baseName + 
" \u200E(\u200E" + this.childCount + 
")\u200E");
 
  520     static class TypeNode 
extends UpdatableCountTypeNode {
 
  522         private final BlackboardArtifact.Type type;
 
  532         TypeNode(BlackboardArtifact.Type type, 
long filteringDSObjId) {
 
  533             super(Children.create(
new ArtifactFactory(type, filteringDSObjId), 
true),
 
  534                     Lookups.singleton(type.getDisplayName()),
 
  535                     type.getDisplayName(),
 
  539             super.setName(type.getTypeName());
 
  541             String iconPath = IconsUtil.getIconFilePath(type.getTypeID());
 
  542             setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == 
'/' ? iconPath.substring(1) : iconPath);
 
  546         protected Sheet createSheet() {
 
  547             Sheet sheet = super.createSheet();
 
  548             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  549             if (sheetSet == null) {
 
  550                 sheetSet = Sheet.createPropertiesSet();
 
  554             sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.name"),
 
  555                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.displayName"),
 
  556                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.desc"),
 
  557                     type.getDisplayName()));
 
  559             sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.name"),
 
  560                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.displayName"),
 
  561                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.desc"),
 
  568         public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
 
  569             return visitor.visit(
this);
 
  573         public boolean isLeafTypeNode() {
 
  578         public String getItemType() {
 
  579             return getClass().getName() + type.getDisplayName();
 
  589         private final BlackboardArtifact.Type 
type;
 
  608             super(type.getTypeName());
 
  613         private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
 
  614             String eventType = evt.getPropertyName();
 
  634         private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
 
  644             if (refreshThrottler != null) {
 
  658                 List<? extends BlackboardArtifact> arts;
 
  660                 switch (this.type.getCategory()) {
 
  662                     case ANALYSIS_RESULT:
 
  663                         arts = (filteringDSObjId > 0)
 
  665                                 : blackboard.getAnalysisResultsByType(type.getTypeID());
 
  669                         arts = (filteringDSObjId > 0)
 
  671                                 : blackboard.getDataArtifacts(type.getTypeID());
 
  675                 for (BlackboardArtifact art : arts) {
 
  681                 @SuppressWarnings(
"unchecked")
 
  682                 List<BlackboardArtifact> toRet = (List<BlackboardArtifact>) (List<?>) arts;
 
  685                 logger.log(Level.WARNING, 
"Trying to access case when no case is open.", ex); 
 
  686             } 
catch (TskCoreException ex) {
 
  687                 logger.log(Level.SEVERE, 
"Couldn't get blackboard artifacts from database", ex); 
 
  689             return Collections.emptyList();
 
  699             String eventType = evt.getPropertyName();
 
  717                     if (null != event && event.getBlackboardArtifactType().equals(type)) {
 
void registerForIngestModuleEvents()
 
final long filteringDSObjId
 
static synchronized IngestManager getInstance()
 
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
 
void unregisterEventListener()
 
void removeIngestJobEventListener(final PropertyChangeListener listener)
 
List< BlackboardArtifact > makeKeys()
 
final long filteringDSObjId
 
void addIngestJobEventListener(final PropertyChangeListener listener)
 
final UpdatableCountTypeNode node
 
final Set< BlackboardArtifact.Type > types
 
final Set< BlackboardArtifact.Type > applicableTypes
 
boolean isRefreshRequired(PropertyChangeEvent evt)
 
UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type...types)
 
SleuthkitCase getSleuthkitCase()
 
final BlackboardArtifact.Type type
 
T visit(DataSourceFilesNode in)
 
long fetchChildCount(SleuthkitCase skCase)
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
boolean equals(Object obj)
 
Node createNodeForKey(BlackboardArtifact key)