Autopsy  4.4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
KeywordHits.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2017 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.datamodel;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.EnumSet;
28 import java.util.HashSet;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Observable;
33 import java.util.Observer;
34 import java.util.Set;
35 import java.util.logging.Level;
36 import java.util.stream.Collectors;
37 import org.apache.commons.lang3.StringUtils;
38 import org.openide.nodes.ChildFactory;
39 import org.openide.nodes.Children;
40 import org.openide.nodes.Node;
41 import org.openide.nodes.Sheet;
42 import org.openide.util.Lookup;
43 import org.openide.util.NbBundle;
44 import org.openide.util.lookup.Lookups;
47 import static org.sleuthkit.autopsy.datamodel.Bundle.*;
50 import org.sleuthkit.datamodel.AbstractFile;
51 import org.sleuthkit.datamodel.BlackboardArtifact;
52 import org.sleuthkit.datamodel.BlackboardAttribute;
53 import org.sleuthkit.datamodel.SleuthkitCase;
54 import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
55 import org.sleuthkit.datamodel.TskCoreException;
56 
60 public class KeywordHits implements AutopsyVisitableItem {
61 
62  private static final Logger logger = Logger.getLogger(KeywordHits.class.getName());
63 
64  @NbBundle.Messages("KeywordHits.kwHits.text=Keyword Hits")
65  private static final String KEYWORD_HITS = KeywordHits_kwHits_text();
66  @NbBundle.Messages("KeywordHits.simpleLiteralSearch.text=Single Literal Keyword Search")
67  private static final String SIMPLE_LITERAL_SEARCH = KeywordHits_simpleLiteralSearch_text();
68  @NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search")
69  private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text();
70 
71  public static final String NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel();
72 
73  private SleuthkitCase skCase;
75 
81  private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
82 
86  private static final String KEYWORD_HIT_ATTRIBUTES_QUERY = "SELECT blackboard_attributes.value_text, "//NON-NLS
87  + "blackboard_attributes.value_int32, "//NON-NLS
88  + "blackboard_attributes.artifact_id, " //NON-NLS
89  + "blackboard_attributes.attribute_type_id "//NON-NLS
90  + "FROM blackboard_attributes, blackboard_artifacts "//NON-NLS
91  + "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "//NON-NLS
92  + " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() //NON-NLS
93  + " AND (attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()//NON-NLS
94  + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()//NON-NLS
95  + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()//NON-NLS
96  + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()//NON-NLS
97  + ")"; //NON-NLS
98 
99  static private boolean isOnlyDefaultInstance(List<String> instances) {
100  return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME));
101  }
102 
103  public KeywordHits(SleuthkitCase skCase) {
104  this.skCase = skCase;
105  keywordResults = new KeywordResults();
106  }
107 
108  /*
109  * All of these maps and code assume the following: Regexps will have an
110  * 'instance' layer that shows the specific words that matched the regexp
111  * Exact match and substring will not have the instance layer and instead
112  * will have the specific hits below their term.
113  */
114  private final class KeywordResults extends Observable {
115 
116  // Map from listName/Type to Map of keywords/regexp to Map of instance terms to Set of artifact Ids
117  // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
118  private final Map<String, Map<String, Map<String, Set<Long>>>> topLevelMap = new LinkedHashMap<>();
119 
120  KeywordResults() {
121  update();
122  }
123 
129  List<String> getListNames() {
130  synchronized (topLevelMap) {
131  List<String> names = new ArrayList<>(topLevelMap.keySet());
132  // this causes the "Single ..." terms to be in the middle of the results,
133  // which is wierd. Make a custom comparator or do something else to maek them on top
134  //Collections.sort(names);
135  return names;
136  }
137  }
138 
147  List<String> getKeywords(String listName) {
148  List<String> keywords;
149  synchronized (topLevelMap) {
150  keywords = new ArrayList<>(topLevelMap.get(listName).keySet());
151  }
152  Collections.sort(keywords);
153  return keywords;
154  }
155 
166  List<String> getKeywordInstances(String listName, String keyword) {
167  List<String> instances;
168  synchronized (topLevelMap) {
169  instances = new ArrayList<>(topLevelMap.get(listName).get(keyword).keySet());
170  }
171  Collections.sort(instances);
172  return instances;
173  }
174 
186  Set<Long> getArtifactIds(String listName, String keyword, String keywordInstance) {
187  synchronized (topLevelMap) {
188  return topLevelMap.get(listName).get(keyword).get(keywordInstance);
189  }
190  }
191 
201  void addRegExpToList(Map<String, Map<String, Set<Long>>> listMap, String regExp, String keywordInstance, Long artifactId) {
202  Map<String, Set<Long>> instanceMap = listMap.computeIfAbsent(regExp, r -> new LinkedHashMap<>());
203  // add this ID to the instances entry, creating one if needed
204  instanceMap.computeIfAbsent(keywordInstance, ki -> new HashSet<>()).add(artifactId);
205  }
206 
215  void addNonRegExpMatchToList(Map<String, Map<String, Set<Long>>> listMap, String keyWord, Long artifactId) {
216  Map<String, Set<Long>> instanceMap = listMap.computeIfAbsent(keyWord, k -> new LinkedHashMap<>());
217 
218  // Use the default instance name, since we don't need that level in the tree
219  instanceMap.computeIfAbsent(DEFAULT_INSTANCE_NAME, DIN -> new HashSet<>()).add(artifactId);
220  }
221 
229  void populateTreeMaps(Map<Long, Map<Long, String>> artifactIds) {
230  synchronized (topLevelMap) {
231  topLevelMap.clear();
232 
233  // map of list name to keword to artifact IDs
234  Map<String, Map<String, Map<String, Set<Long>>>> listsMap = new LinkedHashMap<>();
235 
236  // Map from from literal keyword to instances (which will be empty) to artifact IDs
237  Map<String, Map<String, Set<Long>>> literalMap = new LinkedHashMap<>();
238 
239  // Map from regex keyword artifact to instances to artifact IDs
240  Map<String, Map<String, Set<Long>>> regexMap = new LinkedHashMap<>();
241 
242  // top-level nodes
243  topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
244  topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
245 
246  for (Map.Entry<Long, Map<Long, String>> art : artifactIds.entrySet()) {
247  long id = art.getKey();
248  Map<Long, String> attributes = art.getValue();
249 
250  // I think we can use attributes.remove(...) here? - why should bwe use remove?
251  String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
252  String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
253  String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
254  String kwType = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()));
255 
256  if (listName != null) { // part of a list
257  // get or create list entry
258  Map<String, Map<String, Set<Long>>> listMap = listsMap.computeIfAbsent(listName, ln -> new LinkedHashMap<>());
259 
260  if ("1".equals(kwType) || reg == null) { //literal, substring or exact
261  /*
262  * Substring, treated same as exact match. "1" is
263  * the ordinal value for substring as defined in
264  * KeywordSearch.java. The original term should be
265  * stored in reg
266  */
267  word = (reg != null) ? reg : word; //use original term if it there.
268  addNonRegExpMatchToList(listMap, word, id);
269  } else {
270  addRegExpToList(listMap, reg, word, id);
271  }
272  } else {//single term
273  if ("1".equals(kwType) || reg == null) { //literal, substring or exact
274  /*
275  * Substring, treated same as exact match. "1" is
276  * the ordinal value for substring as defined in
277  * KeywordSearch.java. The original term should be
278  * stored in reg
279  */
280  word = (reg != null) ? reg : word; //use original term if it there.
281  addNonRegExpMatchToList(literalMap, word, id);
282  } else {
283  addRegExpToList(regexMap, reg, word, id);
284  }
285  }
286  }
287  topLevelMap.putAll(listsMap);
288  }
289 
290  setChanged();
291  notifyObservers();
292  }
293 
294  public void update() {
295  // maps Artifact ID to map of attribute types to attribute values
296  Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
297 
298  if (skCase == null) {
299  return;
300  }
301 
302  try (CaseDbQuery dbQuery = skCase.executeQuery(KEYWORD_HIT_ATTRIBUTES_QUERY)) {
303  ResultSet resultSet = dbQuery.getResultSet();
304  while (resultSet.next()) {
305  long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
306  long typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
307  String valueStr = resultSet.getString("value_text"); //NON-NLS
308 
309  //get the map of attributes for this artifact
310  Map<Long, String> attributesByTypeMap = artifactIds.computeIfAbsent(artifactId, ai -> new LinkedHashMap<>());
311  if (StringUtils.isNotEmpty(valueStr)) {
312  attributesByTypeMap.put(typeId, valueStr);
313  } else {
314  // Keyword Search Type is an int
315  Long valueLong = resultSet.getLong("value_int32");
316  attributesByTypeMap.put(typeId, valueLong.toString());
317  }
318  }
319  } catch (TskCoreException | SQLException ex) {
320  logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
321  }
322 
323  populateTreeMaps(artifactIds);
324  }
325  }
326 
327  @Override
328  public <T> T accept(AutopsyItemVisitor<T> v) {
329  return v.visit(this);
330  }
331 
332  // Created by CreateAutopsyNodeVisitor
333  public class RootNode extends DisplayableItemNode {
334 
335  public RootNode() {
336  super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS));
337  super.setName(NAME);
338  super.setDisplayName(KEYWORD_HITS);
339  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
340  }
341 
342  @Override
343  public boolean isLeafTypeNode() {
344  return false;
345  }
346 
347  @Override
348  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
349  return v.visit(this);
350  }
351 
352  @Override
353  @NbBundle.Messages({"KeywordHits.createSheet.name.name=Name",
354  "KeywordHits.createSheet.name.displayName=Name",
355  "KeywordHits.createSheet.name.desc=no description"})
356  protected Sheet createSheet() {
357  Sheet s = super.createSheet();
358  Sheet.Set ss = s.get(Sheet.PROPERTIES);
359  if (ss == null) {
360  ss = Sheet.createPropertiesSet();
361  s.put(ss);
362  }
363 
364  ss.put(new NodeProperty<>(
365  KeywordHits_createSheet_name_name(),
366  KeywordHits_createSheet_name_displayName(),
367  KeywordHits_createSheet_name_desc(),
368  getName()));
369 
370  return s;
371  }
372 
373  @Override
374  public String getItemType() {
375  return getClass().getName();
376  }
377  }
378 
379  private abstract class DetachableObserverChildFactory<X> extends ChildFactory.Detachable<X> implements Observer {
380 
381  @Override
382  protected void addNotify() {
383  keywordResults.addObserver(this);
384  }
385 
386  @Override
387  protected void removeNotify() {
388  keywordResults.deleteObserver(this);
389  }
390 
391  @Override
392  public void update(Observable o, Object arg) {
393  refresh(true);
394  }
395  }
396 
400  private class ListFactory extends DetachableObserverChildFactory<String> {
401 
402  private final PropertyChangeListener pcl = new PropertyChangeListener() {
403  @Override
404  public void propertyChange(PropertyChangeEvent evt) {
405  String eventType = evt.getPropertyName();
406  if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
413  try {
421  ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
422  if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
423  keywordResults.update();
424  }
425  } catch (IllegalStateException notUsed) {
426  // Case is closed, do nothing.
427  }
428  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
429  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
436  try {
438  keywordResults.update();
439  } catch (IllegalStateException notUsed) {
440  // Case is closed, do nothing.
441  }
442  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())
443  && evt.getNewValue() == null) {
444  /*
445  * Case was closed. Remove listeners so that we don't get
446  * called with a stale case handle
447  */
448  removeNotify();
449  skCase = null;
450  }
451 
452  }
453  };
454 
455  @Override
456  protected void addNotify() {
460  keywordResults.update();
461  super.addNotify();
462  }
463 
464  @Override
465  protected void removeNotify() {
469  super.removeNotify();
470  }
471 
472  @Override
473  protected boolean createKeys(List<String> list) {
474  list.addAll(keywordResults.getListNames());
475  return true;
476  }
477 
478  @Override
479  protected Node createNodeForKey(String key) {
480  return new ListNode(key);
481  }
482  }
483 
484  private abstract class KWHitsNodeBase extends DisplayableItemNode implements Observer {
485 
486  private KWHitsNodeBase(Children children, Lookup lookup) {
487  super(children, lookup);
488  }
489 
490  private KWHitsNodeBase(Children children) {
491  super(children);
492  }
493 
494  @Override
495  public String getItemType() {
496  return getClass().getName();
497  }
498 
499  @Override
500  public void update(Observable o, Object arg) {
501  updateDisplayName();
502  }
503 
504  final void updateDisplayName() {
505  super.setDisplayName(getName() + " (" + countTotalDescendants() + ")");
506  }
507 
508  abstract int countTotalDescendants();
509  }
510 
515  class ListNode extends KWHitsNodeBase {
516 
517  private final String listName;
518 
519  private ListNode(String listName) {
520  super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName));
521  super.setName(listName);
522  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
523  this.listName = listName;
524  updateDisplayName();
525  keywordResults.addObserver(this);
526  }
527 
528  @Override
529  public int countTotalDescendants() {
530  int totalDescendants = 0;
531 
532  for (String word : keywordResults.getKeywords(listName)) {
533  for (String instance : keywordResults.getKeywordInstances(listName, word)) {
534  Set<Long> ids = keywordResults.getArtifactIds(listName, word, instance);
535  totalDescendants += ids.size();
536  }
537  }
538  return totalDescendants;
539  }
540 
541  @Override
542  @NbBundle.Messages({"KeywordHits.createSheet.listName.name=List Name",
543  "KeywordHits.createSheet.listName.displayName=List Name",
544  "KeywordHits.createSheet.listName.desc=no description",
545  "KeywordHits.createSheet.numChildren.name=Number of Children",
546  "KeywordHits.createSheet.numChildren.displayName=Number of Children",
547  "KeywordHits.createSheet.numChildren.desc=no description"})
548  protected Sheet createSheet() {
549  Sheet s = super.createSheet();
550  Sheet.Set ss = s.get(Sheet.PROPERTIES);
551  if (ss == null) {
552  ss = Sheet.createPropertiesSet();
553  s.put(ss);
554  }
555 
556  ss.put(new NodeProperty<>(
557  KeywordHits_createSheet_listName_name(),
558  KeywordHits_createSheet_listName_displayName(),
559  KeywordHits_createSheet_listName_desc(),
560  listName));
561 
562  ss.put(new NodeProperty<>(
563  KeywordHits_createSheet_numChildren_name(),
564  KeywordHits_createSheet_numChildren_displayName(),
565  KeywordHits_createSheet_numChildren_desc(),
566  keywordResults.getKeywords(listName).size()));
567 
568  return s;
569  }
570 
571  @Override
572  public boolean isLeafTypeNode() {
573  return false;
574  }
575 
576  @Override
577  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
578  return v.visit(this);
579  }
580  }
581 
585  private class TermFactory extends DetachableObserverChildFactory<String> {
586 
587  private final String setName;
588 
589  private TermFactory(String setName) {
590  super();
591  this.setName = setName;
592  }
593 
594  @Override
595  protected boolean createKeys(List<String> list) {
596  list.addAll(keywordResults.getKeywords(setName));
597  return true;
598  }
599 
600  @Override
601  protected Node createNodeForKey(String key) {
602  return new TermNode(setName, key);
603  }
604  }
605 
609  class TermNode extends KWHitsNodeBase {
610 
611  private final String setName;
612  private final String keyword;
613 
614  private TermNode(String setName, String keyword) {
615  super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
616  super.setName(keyword);
617  this.setName = setName;
618  this.keyword = keyword;
619  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
620  updateDisplayName();
621  keywordResults.addObserver(this);
622  }
623 
624  @Override
625  int countTotalDescendants() {
626  return keywordResults.getKeywordInstances(setName, keyword).stream()
627  .mapToInt(instance -> keywordResults.getArtifactIds(setName, keyword, instance).size())
628  .sum();
629  }
630 
631  @Override
632  public boolean isLeafTypeNode() {
633  // is this an exact/substring match (i.e. did we use the DEFAULT name)?
634  return isOnlyDefaultInstance(keywordResults.getKeywordInstances(setName, keyword));
635  }
636 
637  @Override
638  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
639  return v.visit(this);
640  }
641 
642  @Override
643  @NbBundle.Messages({"KeywordHits.createSheet.filesWithHits.name=Files with Hits",
644  "KeywordHits.createSheet.filesWithHits.displayName=Files with Hits",
645  "KeywordHits.createSheet.filesWithHits.desc=no description"})
646  protected Sheet createSheet() {
647  Sheet s = super.createSheet();
648  Sheet.Set ss = s.get(Sheet.PROPERTIES);
649  if (ss == null) {
650  ss = Sheet.createPropertiesSet();
651  s.put(ss);
652  }
653  ss.put(new NodeProperty<>(
654  KeywordHits_createSheet_listName_name(),
655  KeywordHits_createSheet_listName_displayName(),
656  KeywordHits_createSheet_listName_desc(),
657  getDisplayName()));
658 
659  ss.put(new NodeProperty<>(
660  KeywordHits_createSheet_filesWithHits_name(),
661  KeywordHits_createSheet_filesWithHits_displayName(),
662  KeywordHits_createSheet_filesWithHits_desc(),
663  countTotalDescendants()));
664 
665  return s;
666  }
667  }
668 
674  private class RegExpInstanceKey {
675 
676  private final boolean isRegExp;
677  private String strKey;
678  private Long longKey;
679 
680  RegExpInstanceKey(String key) {
681  isRegExp = true;
682  strKey = key;
683  }
684 
685  RegExpInstanceKey(Long key) {
686  isRegExp = false;
687  longKey = key;
688  }
689 
690  boolean isRegExp() {
691  return isRegExp;
692  }
693 
694  Long getIdKey() {
695  return longKey;
696  }
697 
698  String getRegExpKey() {
699  return strKey;
700  }
701  }
702 
707  private class RegExpInstancesFactory extends DetachableObserverChildFactory<RegExpInstanceKey> {
708 
709  private final String keyword;
710  private final String setName;
711 
712  private RegExpInstancesFactory(String setName, String keyword) {
713  super();
714  this.setName = setName;
715  this.keyword = keyword;
716  }
717 
718  @Override
719  protected boolean createKeys(List<RegExpInstanceKey> list) {
720  List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
721  // The keys are different depending on what we are displaying.
722  // regexp get another layer to show instances.
723  // Exact/substring matches don't.
724  if (isOnlyDefaultInstance(instances)) {
725  list.addAll(keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME).stream()
726  .map(RegExpInstanceKey::new)
727  .collect(Collectors.toList()));
728  } else {
729  list.addAll(instances.stream()
730  .map(RegExpInstanceKey::new)
731  .collect(Collectors.toList()));
732  }
733  return true;
734  }
735 
736  @Override
737  protected Node createNodeForKey(RegExpInstanceKey key) {
738  if (key.isRegExp()) {
739  return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
740  } else {
741  // if it isn't a regexp, then skip the 'instance' layer of the tree
742  return createBlackboardArtifactNode(key.getIdKey());
743  }
744  }
745 
746  }
747 
751  class RegExpInstanceNode extends KWHitsNodeBase {
752 
753  private final String setName;
754  private final String keyword;
755  private final String instance;
756 
757  private RegExpInstanceNode(String setName, String keyword, String instance) {
758  super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(instance));
759  super.setName(instance); //the instance represents the name of the keyword hit at this point as the keyword is the regex
760  this.setName = setName;
761  this.keyword = keyword;
762  this.instance = instance;
763  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
764  updateDisplayName();
765  keywordResults.addObserver(this);
766  }
767 
768  @Override
769  int countTotalDescendants() {
770  return keywordResults.getArtifactIds(setName, keyword, instance).size();
771  }
772 
773  @Override
774  public boolean isLeafTypeNode() {
775  return true;
776  }
777 
778  @Override
779  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
780  return v.visit(this);
781  }
782 
783  @Override
784  protected Sheet createSheet() {
785  Sheet s = super.createSheet();
786  Sheet.Set ss = s.get(Sheet.PROPERTIES);
787  if (ss == null) {
788  ss = Sheet.createPropertiesSet();
789  s.put(ss);
790  }
791 
792  ss.put(new NodeProperty<>(
793  KeywordHits_createSheet_listName_name(),
794  KeywordHits_createSheet_listName_displayName(),
795  KeywordHits_createSheet_listName_desc(),
796  getDisplayName()));
797 
798  ss.put(new NodeProperty<>(
799  KeywordHits_createSheet_filesWithHits_name(),
800  KeywordHits_createSheet_filesWithHits_displayName(),
801  KeywordHits_createSheet_filesWithHits_desc(),
802  keywordResults.getArtifactIds(setName, keyword, instance).size()));
803 
804  return s;
805  }
806 
807  }
808 
816  @NbBundle.Messages({"KeywordHits.createNodeForKey.modTime.name=ModifiedTime",
817  "KeywordHits.createNodeForKey.modTime.displayName=Modified Time",
818  "KeywordHits.createNodeForKey.modTime.desc=Modified Time",
819  "KeywordHits.createNodeForKey.accessTime.name=AccessTime",
820  "KeywordHits.createNodeForKey.accessTime.displayName=Access Time",
821  "KeywordHits.createNodeForKey.accessTime.desc=Access Time",
822  "KeywordHits.createNodeForKey.chgTime.name=ChangeTime",
823  "KeywordHits.createNodeForKey.chgTime.displayName=Change Time",
824  "KeywordHits.createNodeForKey.chgTime.desc=Change Time"})
826  if (skCase == null) {
827  return null;
828  }
829 
830  try {
831  BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
833  AbstractFile file;
834  try {
835  file = skCase.getAbstractFileById(art.getObjectID());
836  } catch (TskCoreException ex) {
837  logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); //NON-NLS
838  return n;
839  }
840 
841  /*
842  * It is possible to get a keyword hit on artifacts generated for
843  * the underlying image in which case MAC times are not
844  * available/applicable/useful.
845  */
846  if (file == null) {
847  return n;
848  }
849 
851  KeywordHits_createNodeForKey_modTime_name(),
852  KeywordHits_createNodeForKey_modTime_displayName(),
853  KeywordHits_createNodeForKey_modTime_desc(),
854  ContentUtils.getStringTime(file.getMtime(), file)));
856  KeywordHits_createNodeForKey_accessTime_name(),
857  KeywordHits_createNodeForKey_accessTime_displayName(),
858  KeywordHits_createNodeForKey_accessTime_desc(),
859  ContentUtils.getStringTime(file.getAtime(), file)));
861  KeywordHits_createNodeForKey_chgTime_name(),
862  KeywordHits_createNodeForKey_chgTime_displayName(),
863  KeywordHits_createNodeForKey_chgTime_desc(),
864  ContentUtils.getStringTime(file.getCtime(), file)));
865  return n;
866  } catch (TskCoreException ex) {
867  logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
868  }
869  return null;
870  }
871 
875  private class HitsFactory extends DetachableObserverChildFactory<Long> {
876 
877  private final String keyword;
878  private final String setName;
879  private final String instance;
880 
881  private HitsFactory(String setName, String keyword, String instance) {
882  super();
883  this.setName = setName;
884  this.keyword = keyword;
885  this.instance = instance;
886  }
887 
888  @Override
889  protected boolean createKeys(List<Long> list) {
890  list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
891  return true;
892  }
893 
894  @Override
895  protected Node createNodeForKey(Long artifactId) {
896  return createBlackboardArtifactNode(artifactId);
897  }
898  }
899 }
static boolean isOnlyDefaultInstance(List< String > instances)
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static synchronized IngestManager getInstance()
BlackboardArtifactNode createBlackboardArtifactNode(Long artifactId)
final Map< String, Map< String, Map< String, Set< Long > > > > topLevelMap
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:395
HitsFactory(String setName, String keyword, String instance)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:440

Copyright © 2012-2016 Basis Technology. Generated on: Fri Sep 29 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.