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                     || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) {
 
  256                 InterestingHits.RootNode interestingHitsNode = 
new InterestingHits(skCase, dsObjId).new RootNode();
 
  257                 return new TypeNodeKey(interestingHitsNode,
 
  258                         TSK_INTERESTING_ARTIFACT_HIT,
 
  259                         TSK_INTERESTING_FILE_HIT);
 
  261             } 
else if (TSK_HASHSET_HIT.getTypeID() == typeId) {
 
  262                 HashsetHits.RootNode hashsetHits = 
new HashsetHits(skCase, dsObjId).new RootNode();
 
  263                 return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT);
 
  266                 return new TypeNodeKey(type, dsObjId);
 
  271         private final Map<BlackboardArtifact.Type, TypeNodeKey> typeNodeMap = 
new HashMap<>();
 
  272         private final long filteringDSObjId;
 
  279         private final RefreshThrottler refreshThrottler = 
new RefreshThrottler(
this);
 
  280         private final Category category;
 
  282         private final PropertyChangeListener weakPcl;
 
  292         TypeFactory(Category category, 
long filteringDSObjId) {
 
  294             this.filteringDSObjId = filteringDSObjId;
 
  295             this.category = category;
 
  297             PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
 
  298                 String eventType = evt.getPropertyName();
 
  299                 if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
 
  301                     if (evt.getNewValue() == null) {
 
  304                 } 
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
 
  305                         || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
 
  313                         Case.getCurrentCaseThrows();
 
  315                     } 
catch (NoCurrentCaseException notUsed) {
 
  323             weakPcl = WeakListeners.propertyChange(pcl, null);
 
  327         protected void addNotify() { 
 
  329             refreshThrottler.registerForIngestModuleEvents();
 
  331             Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
 
  335         protected void finalize() throws Throwable {
 
  337             refreshThrottler.unregisterEventListener();
 
  338             IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
 
  339             Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
 
  344         protected boolean createKeys(List<TypeNodeKey> list) {
 
  347                 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
 
  348                 List<BlackboardArtifact.Type> types = (this.filteringDSObjId > 0)
 
  349                         ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId)
 
  350                         : skCase.getArtifactTypesInUse();
 
  352                 List<TypeNodeKey> allKeysSorted = types.stream()
 
  354                         .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp))
 
  357                             if (typeNodeMap.containsKey(tp)) {
 
  358                                 TypeNodeKey typeKey = typeNodeMap.get(tp);
 
  359                                 typeKey.getNode().updateDisplayName();
 
  363                                 TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId);
 
  364                                 for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) {
 
  365                                     typeNodeMap.put(recordType, newTypeKey);
 
  371                         .filter(record -> record != null)
 
  377                             String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? 
"" : a.getNode().getDisplayName();
 
  378                             String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? 
"" : b.getNode().getDisplayName();
 
  379                             return aSafe.compareToIgnoreCase(bSafe);
 
  381                         .collect(Collectors.toList());
 
  383                 list.addAll(allKeysSorted);
 
  385             } 
catch (NoCurrentCaseException ex) {
 
  386                 logger.log(Level.WARNING, 
"Trying to access case when no case is open.", ex); 
 
  387             } 
catch (TskCoreException ex) {
 
  388                 logger.log(Level.SEVERE, 
"Error getting list of artifacts in use: " + ex.getLocalizedMessage()); 
 
  394         protected Node createNodeForKey(TypeNodeKey key) {
 
  395             return key.getNode();
 
  399         public void refresh() {
 
  404         public boolean isRefreshRequired(PropertyChangeEvent evt) {
 
  405             String eventType = evt.getPropertyName();
 
  406             if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
 
  413                     Case.getCurrentCaseThrows();
 
  419                     final ModuleDataEvent 
event = (ModuleDataEvent) evt.getOldValue();
 
  420                     if (null != event && category.equals(event.getBlackboardArtifactType().getCategory())
 
  421                             && !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) {
 
  424                 } 
catch (NoCurrentCaseException notUsed) {
 
  442         private final Set<BlackboardArtifact.Type> 
types;
 
  460                 long filteringDSObjId, BlackboardArtifact.Type... 
types) {
 
  462             super(children, lookup);
 
  463             this.
types = Stream.of(
types).collect(Collectors.toSet());
 
  489             for (BlackboardArtifact.Type type : 
this.types) {
 
  490                 if (filteringDSObjId > 0) {
 
  491                     count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), 
filteringDSObjId);
 
  493                     count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
 
  503         void updateDisplayName() {
 
  508                 logger.log(Level.WARNING, 
"Error fetching data when case closed.", ex);
 
  509             } 
catch (TskCoreException ex) {
 
  510                 logger.log(Level.WARNING, 
"Error getting child count", ex); 
 
  512             super.setDisplayName(this.baseName + 
" \u200E(\u200E" + this.childCount + 
")\u200E");
 
  522     static class TypeNode 
extends UpdatableCountTypeNode {
 
  524         private final BlackboardArtifact.Type type;
 
  534         TypeNode(BlackboardArtifact.Type type, 
long filteringDSObjId) {
 
  535             super(Children.create(
new ArtifactFactory(type, filteringDSObjId), 
true),
 
  536                     Lookups.singleton(type.getDisplayName()),
 
  537                     type.getDisplayName(),
 
  541             super.setName(type.getTypeName());
 
  543             String iconPath = IconsUtil.getIconFilePath(type.getTypeID());
 
  544             setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == 
'/' ? iconPath.substring(1) : iconPath);
 
  548         protected Sheet createSheet() {
 
  549             Sheet sheet = super.createSheet();
 
  550             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  551             if (sheetSet == null) {
 
  552                 sheetSet = Sheet.createPropertiesSet();
 
  556             sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.name"),
 
  557                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.displayName"),
 
  558                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.artType.desc"),
 
  559                     type.getDisplayName()));
 
  561             sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.name"),
 
  562                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.displayName"),
 
  563                     NbBundle.getMessage(
this.getClass(), 
"ArtifactTypeNode.createSheet.childCnt.desc"),
 
  570         public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
 
  571             return visitor.visit(
this);
 
  575         public boolean isLeafTypeNode() {
 
  580         public String getItemType() {
 
  581             return getClass().getName() + type.getDisplayName();
 
  591         private final BlackboardArtifact.Type 
type;
 
  610             super(type.getTypeName());
 
  615         private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
 
  616             String eventType = evt.getPropertyName();
 
  636         private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
 
  646             if(refreshThrottler != null) {
 
  660                 List<? extends BlackboardArtifact> arts;
 
  662                 switch (this.type.getCategory()) {
 
  664                     case ANALYSIS_RESULT:
 
  665                         arts = (filteringDSObjId > 0)
 
  667                             : blackboard.getAnalysisResultsByType(type.getTypeID());
 
  671                         arts = (filteringDSObjId > 0)
 
  673                             : blackboard.getDataArtifacts(type.getTypeID());
 
  677                 for (BlackboardArtifact art : arts) {
 
  683                 @SuppressWarnings(
"unchecked")
 
  684                 List<BlackboardArtifact> toRet = (List<BlackboardArtifact>)(List<?>)arts;    
 
  687                 logger.log(Level.WARNING, 
"Trying to access case when no case is open.", ex); 
 
  688             } 
catch (TskCoreException ex) {
 
  689                 logger.log(Level.SEVERE, 
"Couldn't get blackboard artifacts from database", ex); 
 
  691             return Collections.emptyList();
 
  701             String eventType = evt.getPropertyName();
 
  719                     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)