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_INTERESTING_ITEM;
64 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT;
65 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT;
66 import static org.
sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT;
89 BaseArtifactNode(Children children, String icon, String name, String displayName) {
90 super(children, Lookups.singleton(name));
92 super.setDisplayName(displayName);
93 this.setIconBaseWithExtension(icon);
97 public boolean isLeafTypeNode() {
103 return visitor.
visit(
this);
107 protected Sheet createSheet() {
108 Sheet sheet = super.createSheet();
109 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
110 if (sheetSet == null) {
111 sheetSet = Sheet.createPropertiesSet();
115 sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(),
"ExtractedContentNode.createSheet.name.name"),
116 NbBundle.getMessage(
this.getClass(),
"ExtractedContentNode.createSheet.name.displayName"),
117 NbBundle.getMessage(
this.getClass(),
"ExtractedContentNode.createSheet.name.desc"),
118 super.getDisplayName()));
123 public String getItemType() {
124 return getClass().getName();
144 TypeNodeKey(BlackboardArtifact.Type type,
long dsObjId) {
145 this(
new TypeNode(type, dsObjId), type);
156 this.node = typeNode;
158 .filter(t -> t != null)
159 .collect(Collectors.toSet());
176 Set<BlackboardArtifact.Type> getApplicableTypes() {
195 if (getClass() != obj.getClass()) {
211 static class TypeFactory
extends ChildFactory.Detachable<TypeNodeKey> implements
RefreshThrottler.Refresher {
218 @SuppressWarnings(
"deprecation")
219 private static final Set<BlackboardArtifact.Type> IGNORED_TYPES = Sets.newHashSet(
221 TSK_DATA_SOURCE_USAGE,
223 new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE),
226 TSK_ASSOCIATED_OBJECT
243 @SuppressWarnings("deprecation")
244 private static TypeNodeKey getTypeKey(BlackboardArtifact.Type type, SleuthkitCase skCase,
long dsObjId) {
245 int typeId = type.getTypeID();
246 if (TSK_EMAIL_MSG.getTypeID() == typeId) {
248 return new TypeNodeKey(emailNode, TSK_EMAIL_MSG);
250 }
else if (TSK_ACCOUNT.getTypeID() == typeId) {
251 Accounts.AccountsRootNode accountsNode =
new Accounts(dsObjId).new AccountsRootNode();
252 return new TypeNodeKey(accountsNode, TSK_ACCOUNT);
254 }
else if (TSK_KEYWORD_HIT.getTypeID() == typeId) {
255 KeywordHits.RootNode keywordsNode =
new KeywordHits(skCase, dsObjId).new RootNode();
256 return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT);
258 }
else if (TSK_INTERESTING_ITEM.getTypeID() == typeId) {
259 InterestingHits.RootNode interestingHitsNode =
new InterestingHits(skCase, TSK_INTERESTING_ITEM, dsObjId).new RootNode();
260 return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ITEM);
261 }
else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId) {
262 InterestingHits.RootNode interestingHitsNode =
new InterestingHits(skCase, TSK_INTERESTING_ARTIFACT_HIT, dsObjId).new RootNode();
263 return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ARTIFACT_HIT);
264 }
else if (TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) {
265 InterestingHits.RootNode interestingHitsNode =
new InterestingHits(skCase, TSK_INTERESTING_FILE_HIT, dsObjId).new RootNode();
266 return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_FILE_HIT);
267 }
else if (TSK_HASHSET_HIT.getTypeID() == typeId) {
268 HashsetHits.RootNode hashsetHits =
new HashsetHits(skCase, dsObjId).new RootNode();
269 return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT);
272 return new TypeNodeKey(type, dsObjId);
277 private final Map<BlackboardArtifact.Type, TypeNodeKey> typeNodeMap =
new HashMap<>();
278 private final long filteringDSObjId;
285 private final RefreshThrottler refreshThrottler =
new RefreshThrottler(
this);
286 private final Category category;
288 private final PropertyChangeListener weakPcl;
298 TypeFactory(Category category,
long filteringDSObjId) {
300 this.filteringDSObjId = filteringDSObjId;
301 this.category = category;
303 PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
304 String eventType = evt.getPropertyName();
305 if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
307 if (evt.getNewValue() == null) {
310 }
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
311 || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
319 Case.getCurrentCaseThrows();
321 }
catch (NoCurrentCaseException notUsed) {
329 weakPcl = WeakListeners.propertyChange(pcl, null);
333 protected void addNotify() {
335 refreshThrottler.registerForIngestModuleEvents();
337 Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
341 protected void finalize() throws Throwable {
343 refreshThrottler.unregisterEventListener();
344 IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
345 Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
350 protected boolean createKeys(List<TypeNodeKey> list) {
353 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
354 List<BlackboardArtifact.Type> types = (this.filteringDSObjId > 0)
355 ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId)
356 : skCase.getArtifactTypesInUse();
358 List<TypeNodeKey> allKeysSorted = types.stream()
360 .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp))
363 if (typeNodeMap.containsKey(tp)) {
364 TypeNodeKey typeKey = typeNodeMap.get(tp);
365 typeKey.getNode().updateDisplayName();
369 TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId);
370 for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) {
371 typeNodeMap.put(recordType, newTypeKey);
377 .filter(record -> record != null)
383 String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ?
"" : a.getNode().getDisplayName();
384 String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ?
"" : b.getNode().getDisplayName();
385 return aSafe.compareToIgnoreCase(bSafe);
387 .collect(Collectors.toList());
389 list.addAll(allKeysSorted);
391 }
catch (NoCurrentCaseException ex) {
392 logger.log(Level.WARNING,
"Trying to access case when no case is open.", ex);
393 }
catch (TskCoreException ex) {
394 logger.log(Level.SEVERE,
"Error getting list of artifacts in use: " + ex.getLocalizedMessage());
400 protected Node createNodeForKey(TypeNodeKey key) {
401 return key.getNode();
405 public void refresh() {
410 public boolean isRefreshRequired(PropertyChangeEvent evt) {
411 String eventType = evt.getPropertyName();
412 if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
419 Case.getCurrentCaseThrows();
425 final ModuleDataEvent
event = (ModuleDataEvent) evt.getOldValue();
426 if (null != event && category.equals(event.getBlackboardArtifactType().getCategory())
427 && !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) {
430 }
catch (NoCurrentCaseException notUsed) {
448 private final Set<BlackboardArtifact.Type>
types;
466 long filteringDSObjId, BlackboardArtifact.Type...
types) {
468 super(children, lookup);
469 this.
types = Stream.of(
types).collect(Collectors.toSet());
495 for (BlackboardArtifact.Type type :
this.types) {
496 if (filteringDSObjId > 0) {
497 count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(),
filteringDSObjId);
499 count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
509 void updateDisplayName() {
514 logger.log(Level.WARNING,
"Error fetching data when case closed.", ex);
515 }
catch (TskCoreException ex) {
516 logger.log(Level.WARNING,
"Error getting child count", ex);
518 super.setDisplayName(this.baseName +
" (" + this.childCount +
")");
528 static class TypeNode
extends UpdatableCountTypeNode {
530 private final BlackboardArtifact.Type type;
540 TypeNode(BlackboardArtifact.Type type,
long filteringDSObjId) {
541 super(Children.create(
new ArtifactFactory(type, filteringDSObjId),
true),
542 Lookups.singleton(type.getDisplayName()),
543 type.getDisplayName(),
547 super.setName(type.getTypeName());
549 String iconPath = IconsUtil.getIconFilePath(type.getTypeID());
550 setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) ==
'/' ? iconPath.substring(1) : iconPath);
554 protected Sheet createSheet() {
555 Sheet sheet = super.createSheet();
556 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
557 if (sheetSet == null) {
558 sheetSet = Sheet.createPropertiesSet();
562 sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.artType.name"),
563 NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.artType.displayName"),
564 NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.artType.desc"),
565 type.getDisplayName()));
567 sheetSet.put(
new NodeProperty<>(NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.childCnt.name"),
568 NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.childCnt.displayName"),
569 NbBundle.getMessage(
this.getClass(),
"ArtifactTypeNode.createSheet.childCnt.desc"),
576 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
577 return visitor.visit(
this);
581 public boolean isLeafTypeNode() {
586 public String getItemType() {
587 return getClass().getName() + type.getDisplayName();
597 private final BlackboardArtifact.Type
type;
616 super(type.getTypeName());
621 private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
622 String eventType = evt.getPropertyName();
642 private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
652 if (refreshThrottler != null) {
666 List<? extends BlackboardArtifact> arts;
668 switch (this.type.getCategory()) {
670 case ANALYSIS_RESULT:
671 arts = (filteringDSObjId > 0)
673 : blackboard.getAnalysisResultsByType(type.getTypeID());
677 arts = (filteringDSObjId > 0)
679 : blackboard.getDataArtifacts(type.getTypeID());
683 for (BlackboardArtifact art : arts) {
689 @SuppressWarnings(
"unchecked")
690 List<BlackboardArtifact> toRet = (List<BlackboardArtifact>) (List<?>) arts;
693 logger.log(Level.WARNING,
"Trying to access case when no case is open.", ex);
694 }
catch (TskCoreException ex) {
695 logger.log(Level.SEVERE,
"Couldn't get blackboard artifacts from database", ex);
697 return Collections.emptyList();
707 String eventType = evt.getPropertyName();
725 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)