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)