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)