Autopsy  4.4
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-2016 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.HashMap;
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 org.openide.nodes.ChildFactory;
37 import org.openide.nodes.Children;
38 import org.openide.nodes.Node;
39 import org.openide.nodes.Sheet;
40 import org.openide.util.NbBundle;
41 import org.openide.util.lookup.Lookups;
46 import org.sleuthkit.datamodel.AbstractFile;
47 import org.sleuthkit.datamodel.BlackboardArtifact;
48 import org.sleuthkit.datamodel.BlackboardAttribute;
49 import org.sleuthkit.datamodel.SleuthkitCase;
50 import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
51 import org.sleuthkit.datamodel.TskCoreException;
52 import org.sleuthkit.datamodel.TskException;
53 
57 public class KeywordHits implements AutopsyVisitableItem {
58 
59  private SleuthkitCase skCase;
60  private static final Logger logger = Logger.getLogger(KeywordHits.class.getName());
61  private static final String KEYWORD_HITS = NbBundle.getMessage(KeywordHits.class, "KeywordHits.kwHits.text");
62  public static final String NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel();
63  public static final String SIMPLE_LITERAL_SEARCH = NbBundle
64  .getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
65  public static final String SIMPLE_REGEX_SEARCH = NbBundle
66  .getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
68  // String used in the instance MAP so that exact matches and substring can fit into the same
69  // data structure as regexps, even though they don't use instances.
70  private final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
71 
72  public KeywordHits(SleuthkitCase skCase) {
73  this.skCase = skCase;
74  keywordResults = new KeywordResults();
75  }
76 
77  /* All of these maps and code assume the following:
78  * Regexps will have an 'instance' layer that shows the specific words that matched the regexp
79  * Exact match and substring will not have the instance layer and instead will have the specific hits
80  * below their term.
81  */
82 
83  private final class KeywordResults extends Observable {
84 
85  // Map from listName/Type to Map of keywords/regexp to Map of instance terms to Set of artifact Ids
86  // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
87  private final Map<String, Map<String, Map<String, Set<Long>>>> topLevelMap = new LinkedHashMap<>();
88 
89  KeywordResults() {
90  update();
91  }
92 
96  List<String> getListNames() {
97  synchronized (topLevelMap) {
98  List<String> names = new ArrayList<>(topLevelMap.keySet());
99  // this causes the "Single ..." terms to be in the middle of the results,
100  // which is wierd. Make a custom comparator or do something else to maek them on top
101  //Collections.sort(names);
102  return names;
103  }
104  }
105 
113  List<String> getKeywords(String listName) {
114  List<String> keywords;
115  synchronized (topLevelMap) {
116  keywords = new ArrayList<>(topLevelMap.get(listName).keySet());
117  }
118  Collections.sort(keywords);
119  return keywords;
120  }
121 
131  List<String> getKeywordInstances(String listName, String keyword) {
132  List<String> instances;
133  synchronized (topLevelMap) {
134  instances = new ArrayList<>(topLevelMap.get(listName).get(keyword).keySet());
135  }
136  Collections.sort(instances);
137  return instances;
138  }
139 
147  Set<Long> getArtifactIds(String listName, String keyword, String keywordInstance) {
148  synchronized (topLevelMap) {
149  return topLevelMap.get(listName).get(keyword).get(keywordInstance);
150  }
151  }
152 
160  void addRegExpToList(Map<String, Map<String, Set<Long>>> listMap, String regExp, String keywordInstance, Long artifactId) {
161  if (listMap.containsKey(regExp) == false) {
162  listMap.put(regExp, new LinkedHashMap<>());
163  }
164  Map<String, Set<Long>> instanceMap = listMap.get(regExp);
165 
166  // get or create keyword instances entry.
167  if (instanceMap.containsKey(keywordInstance) == false) {
168  instanceMap.put(keywordInstance, new HashSet<>());
169  }
170 
171  // add this ID to the instance
172  instanceMap.get(keywordInstance).add(artifactId);
173  }
174 
175 
182  void addNonRegExpMatchToList(Map<String, Map<String, Set<Long>>> listMap, String keyWord, Long artifactId) {
183  if (listMap.containsKey(keyWord) == false) {
184  listMap.put(keyWord, new LinkedHashMap<>());
185  }
186  Map<String, Set<Long>> instanceMap = listMap.get(keyWord);
187 
188  // Use the default instance name, since we don't need that level in the tree
189  if (instanceMap.containsKey(DEFAULT_INSTANCE_NAME) == false) {
190  instanceMap.put(DEFAULT_INSTANCE_NAME, new HashSet<>());
191  }
192  instanceMap.get(DEFAULT_INSTANCE_NAME).add(artifactId);
193  }
194 
199  void populateTreeMaps(Map<Long, Map<Long, String>> artifactIds) {
200  synchronized (topLevelMap) {
201  topLevelMap.clear();
202 
203  // map of list name to keword to artifact IDs
204  Map<String, Map<String, Map<String, Set<Long>>>> listsMap = new LinkedHashMap<>();
205 
206  // Map from from literal keyword to instances (which will be empty) to artifact IDs
207  Map<String, Map<String, Set<Long>>> literalMap = new LinkedHashMap<>();
208 
209  // Map from regex keyword artifact to instances to artifact IDs
210  Map<String, Map<String, Set<Long>>> regexMap = new LinkedHashMap<>();
211 
212  // top-level nodes
213  topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
214  topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
215 
216  for (Map.Entry<Long, Map<Long, String>> art : artifactIds.entrySet()) {
217  long id = art.getKey();
218  Map<Long, String> attributes = art.getValue();
219 
220  // I think we can use attributes.remove(...) here?
221  String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
222  String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
223  String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
224  // new in 4.4
225  String kwType = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()));
226 
227  // part of a list
228  if (listName != null) {
229  // get or create list entry
230  if (listsMap.containsKey(listName) == false) {
231  listsMap.put(listName, new LinkedHashMap<>());
232  }
233  Map<String, Map<String, Set<Long>>> listMap = listsMap.get(listName);
234 
235  // substring, treated same as exact match
236  // Enum for "1" is defined in KeywordSearch.java
237  if ((kwType != null) && (kwType.equals("1"))) {
238  // original term should be stored in reg
239  if (reg != null) {
240  addNonRegExpMatchToList(listMap, reg, id);
241  } else {
242  addNonRegExpMatchToList(listMap, word, id);
243  }
244  }
245  else if (reg != null) {
246  addRegExpToList(listMap, reg, word, id);
247  } else {
248  addNonRegExpMatchToList(listMap, word, id);
249  }
250  } // regular expression, single term
251  else if (reg != null) {
252  // substring is treated same as exact
253  if ((kwType != null) && (kwType.equals("1"))) {
254  // original term should be stored in reg
255  addNonRegExpMatchToList(literalMap, reg, id);
256  } else {
257  addRegExpToList(regexMap, reg, word, id);
258  }
259  } // literal, single term
260  else {
261  addNonRegExpMatchToList(literalMap, word, id);
262  }
263  }
264  topLevelMap.putAll(listsMap);
265  }
266 
267  setChanged();
268  notifyObservers();
269  }
270 
271  @SuppressWarnings("deprecation")
272  public void update() {
273  // maps Artifact ID to map of attribute types to attribute values
274  Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
275 
276  if (skCase == null) {
277  return;
278  }
279 
280  // query attributes table for the ones that we need for the tree
281  int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
282  int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
283  int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID();
284  int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID();
285  String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.value_int32,"
286  + "blackboard_attributes.artifact_id," //NON-NLS
287  + "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
288  + "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
289  + "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
290  + ") AND (attribute_type_id=" + setId + " OR " //NON-NLS
291  + "attribute_type_id=" + wordId + " OR " //NON-NLS
292  + "attribute_type_id=" + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID() + " OR " //NON-NLS
293  + "attribute_type_id=" + regexId + ")"; //NON-NLS
294 
295  try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
296  ResultSet resultSet = dbQuery.getResultSet();
297  while (resultSet.next()) {
298  String valueStr = resultSet.getString("value_text"); //NON-NLS
299  long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
300  long typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
301  if (!artifactIds.containsKey(artifactId)) {
302  artifactIds.put(artifactId, new LinkedHashMap<Long, String>());
303  }
304  if (valueStr != null && !valueStr.equals("")) {
305  artifactIds.get(artifactId).put(typeId, valueStr);
306  } else {
307  // Keyword Search Type is an int
308  Long valueLong = resultSet.getLong("value_int32");
309  artifactIds.get(artifactId).put(typeId, valueLong.toString());
310  }
311  }
312  } catch (TskCoreException | SQLException ex) {
313  logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
314  }
315 
316  populateTreeMaps(artifactIds);
317  }
318  }
319 
320  @Override
321  public <T> T accept(AutopsyItemVisitor<T> v) {
322  return v.visit(this);
323  }
324 
325  // Created by CreateAutopsyNodeVisitor
326  public class RootNode extends DisplayableItemNode {
327 
328  public RootNode() {
329  super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS));
330  super.setName(NAME);
331  super.setDisplayName(KEYWORD_HITS);
332  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
333  }
334 
335  @Override
336  public boolean isLeafTypeNode() {
337  return false;
338  }
339 
340  @Override
341  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
342  return v.visit(this);
343  }
344 
345  @Override
346  protected Sheet createSheet() {
347  Sheet s = super.createSheet();
348  Sheet.Set ss = s.get(Sheet.PROPERTIES);
349  if (ss == null) {
350  ss = Sheet.createPropertiesSet();
351  s.put(ss);
352  }
353 
354  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.name.name"),
355  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.name.displayName"),
356  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.name.desc"),
357  getName()));
358 
359  return s;
360  }
361 
362  @Override
363  public String getItemType() {
364  return getClass().getName();
365  }
366  }
367 
371  private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
372 
373  private final PropertyChangeListener pcl = new PropertyChangeListener() {
374  @Override
375  public void propertyChange(PropertyChangeEvent evt) {
376  String eventType = evt.getPropertyName();
377  if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
384  try {
392  ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
393  if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
394  keywordResults.update();
395  }
396  } catch (IllegalStateException notUsed) {
400  }
401  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
402  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
409  try {
411  keywordResults.update();
412  } catch (IllegalStateException notUsed) {
416  }
417  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
418  // case was closed. Remove listeners so that we don't get called with a stale case handle
419  if (evt.getNewValue() == null) {
420  removeNotify();
421  skCase = null;
422  }
423  }
424  }
425  };
426 
427  @Override
428  protected void addNotify() {
432  keywordResults.update();
433  keywordResults.addObserver(this);
434  }
435 
436  @Override
437  protected void removeNotify() {
441  keywordResults.deleteObserver(this);
442  }
443 
444  @Override
445  protected boolean createKeys(List<String> list) {
446  list.addAll(keywordResults.getListNames());
447  return true;
448  }
449 
450  @Override
451  protected Node createNodeForKey(String key) {
452  return new ListNode(key);
453  }
454 
455  @Override
456  public void update(Observable o, Object arg) {
457  refresh(true);
458  }
459  }
460 
464  public class ListNode extends DisplayableItemNode implements Observer {
465 
466  private final String listName;
467 
468  public ListNode(String listName) {
469  super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName));
470  super.setName(listName);
471  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
472  this.listName = listName;
474  keywordResults.addObserver(this);
475  }
476 
477  private void updateDisplayName() {
478  int totalDescendants = 0;
479  for (String word : keywordResults.getKeywords(listName)) {
480  for (String instance : keywordResults.getKeywordInstances(listName, word)) {
481  Set<Long> ids = keywordResults.getArtifactIds(listName, word, instance);
482  totalDescendants += ids.size();
483  }
484  }
485  super.setDisplayName(listName + " (" + totalDescendants + ")");
486  }
487 
488  @Override
489  protected Sheet createSheet() {
490  Sheet s = super.createSheet();
491  Sheet.Set ss = s.get(Sheet.PROPERTIES);
492  if (ss == null) {
493  ss = Sheet.createPropertiesSet();
494  s.put(ss);
495  }
496 
497  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
498  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
499  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
500  listName));
501 
502  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.name"),
503  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.displayName"),
504  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.desc"),
505  keywordResults.getKeywords(listName).size()));
506 
507  return s;
508  }
509 
510  @Override
511  public boolean isLeafTypeNode() {
512  return false;
513  }
514 
515  @Override
516  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
517  return v.visit(this);
518  }
519 
520  @Override
521  public void update(Observable o, Object arg) {
523  }
524 
525  @Override
526  public String getItemType() {
527  return getClass().getName();
528  }
529  }
530 
534  private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
535 
536  private final String setName;
537 
538  private TermFactory(String setName) {
539  super();
540  this.setName = setName;
541  }
542 
543  @Override
544  protected void addNotify() {
545  keywordResults.addObserver(this);
546  }
547 
548  @Override
549  protected void removeNotify() {
550  keywordResults.deleteObserver(this);
551  }
552 
553  @Override
554  protected boolean createKeys(List<String> list) {
555  list.addAll(keywordResults.getKeywords(setName));
556  return true;
557  }
558 
559  @Override
560  protected Node createNodeForKey(String key) {
561  return new TermNode(setName, key);
562  }
563 
564  @Override
565  public void update(Observable o, Object arg) {
566  refresh(true);
567  }
568  }
569 
573  public class TermNode extends DisplayableItemNode implements Observer {
574 
575  private final String setName;
576  private final String keyword;
577 
578  public TermNode(String setName, String keyword) {
579  super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
580  super.setName(keyword);
581  this.setName = setName;
582  this.keyword = keyword;
583  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
585  keywordResults.addObserver(this);
586  }
587 
588  private void updateDisplayName() {
589  int totalDescendants = 0;
590 
591  for (String instance : keywordResults.getKeywordInstances(setName, keyword)) {
592  Set<Long> ids = keywordResults.getArtifactIds(setName, keyword, instance);
593  totalDescendants += ids.size();
594  }
595 
596  super.setDisplayName(keyword + " (" + totalDescendants + ")");
597  }
598 
599  @Override
600  public void update(Observable o, Object arg) {
602  }
603 
604  @Override
605  public boolean isLeafTypeNode() {
606  List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
607  // is this an exact/substring match (i.e. did we use the DEFAULT name)?
608  if (instances.size() == 1 && instances.get(0).equals(DEFAULT_INSTANCE_NAME)) {
609  return true;
610  }
611  else {
612  return false;
613  }
614  }
615 
616  @Override
617  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
618  return v.visit(this);
619  }
620 
621  @Override
622  protected Sheet createSheet() {
623  Sheet s = super.createSheet();
624  Sheet.Set ss = s.get(Sheet.PROPERTIES);
625  if (ss == null) {
626  ss = Sheet.createPropertiesSet();
627  s.put(ss);
628  }
629 
630  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
631  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
632  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
633  getDisplayName()));
634 
635  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
636  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
637  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
638  keywordResults.getKeywordInstances(setName, keyword).size()));
639 
640  return s;
641  }
642 
643  @Override
644  public String getItemType() {
645  return getClass().getName();
646  }
647  }
648 
649  // Allows us to pass in either longs or strings
650  // as they keys for different types of nodes at the
651  // same level. Probably a better way to do this, but
652  // it works.
653  class RegExpInstanceKey {
654  private final boolean isRegExp;
655  private String strKey;
656  private Long longKey;
657  public RegExpInstanceKey(String key) {
658  isRegExp = true;
659  strKey = key;
660  }
661  public RegExpInstanceKey(Long key) {
662  isRegExp = false;
663  longKey = key;
664  }
665  boolean isRegExp() {
666  return isRegExp;
667  }
668  Long getIdKey() {
669  return longKey;
670  }
671  String getRegExpKey() {
672  return strKey;
673  }
674  }
675 
679  public class RegExpInstancesFactory extends ChildFactory.Detachable<RegExpInstanceKey> implements Observer {
680  private final String keyword;
681  private final String setName;
682 
683  private Map<RegExpInstanceKey, DisplayableItemNode > nodesMap = new HashMap<>();
684 
685  public RegExpInstancesFactory(String setName, String keyword) {
686  super();
687  this.setName = setName;
688  this.keyword = keyword;
689  }
690 
691  @Override
692  protected void addNotify() {
693  keywordResults.addObserver(this);
694  }
695 
696  @Override
697  protected void removeNotify() {
698  keywordResults.deleteObserver(this);
699  }
700 
701  @Override
702  protected boolean createKeys(List<RegExpInstanceKey> list) {
703  List <String>instances = keywordResults.getKeywordInstances(setName, keyword);
704  // The keys are different depending on what we are displaying.
705  // regexp get another layer to show instances.
706  // Exact/substring matches don't.
707  if ((instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME))) {
708  for (Long id : keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME) ) {
709  RegExpInstanceKey key = new RegExpInstanceKey(id);
710  if (!nodesMap.containsKey(key)) {
711  nodesMap.put(key, createNode(key));
712  }
713  list.add(key);
714  }
715  } else {
716  for (String instance : instances) {
717  RegExpInstanceKey key = new RegExpInstanceKey(instance);
718  if (!nodesMap.containsKey(key)) {
719  nodesMap.put(key, createNode(key));
720  }
721  list.add(key);
722  }
723 
724  }
725  return true;
726  }
727 
728  @Override
729  protected Node createNodeForKey(RegExpInstanceKey key) {
730  return nodesMap.get(key);
731  }
732 
733  private DisplayableItemNode createNode(RegExpInstanceKey key) {
734  // if it isn't a regexp, then skip the 'instance' layer of the tree
735  if (key.isRegExp() == false) {
736  return createBlackboardArtifactNode(key.getIdKey());
737  } else {
738  return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
739  }
740 
741  }
742  @Override
743  public void update(Observable o, Object arg) {
744  refresh(true);
745  }
746 
747  }
748 
752  public class RegExpInstanceNode extends DisplayableItemNode implements Observer {
753 
754  private final String setName;
755  private final String keyword;
756  private final String instance;
757 
758  public RegExpInstanceNode(String setName, String keyword, String instance) {
759  super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(keyword));
760  super.setName(instance); //the instance represents the name of the keyword hit at this point as the keyword is the regex
761  this.setName = setName;
762  this.keyword = keyword;
763  this.instance = instance;
764  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
766  keywordResults.addObserver(this);
767  }
768 
769  private void updateDisplayName() {
770  int totalDescendants = keywordResults.getArtifactIds(setName, keyword, instance).size();
771  super.setDisplayName(instance + " (" + totalDescendants + ")");
772  }
773 
774  @Override
775  public void update(Observable o, Object arg) {
777  }
778 
779  @Override
780  public boolean isLeafTypeNode() {
781  return true;
782  }
783 
784  @Override
785  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
786  return v.visit(this);
787  }
788 
789  @Override
790  protected Sheet createSheet() {
791  Sheet s = super.createSheet();
792  Sheet.Set ss = s.get(Sheet.PROPERTIES);
793  if (ss == null) {
794  ss = Sheet.createPropertiesSet();
795  s.put(ss);
796  }
797 
798  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
799  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
800  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
801  getDisplayName()));
802 
803  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
804  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
805  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
806  keywordResults.getKeywordInstances(setName, keyword).size()));
807 
808  return s;
809  }
810 
811  @Override
812  public String getItemType() {
813  return getClass().getName();
814  }
815  }
816 
823  if (skCase == null) {
824  return null;
825  }
826 
827  try {
828  BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
830  AbstractFile file;
831  try {
832  file = skCase.getAbstractFileById(art.getObjectID());
833  } catch (TskCoreException ex) {
834  logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
835  return n;
836  }
837 
838  // It is possible to get a keyword hit on artifacts generated
839  // for the underlying image in which case MAC times are not
840  // available/applicable/useful.
841  if (file == null) {
842  return n;
843  }
844 
846  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
847  NbBundle.getMessage(this.getClass(),
848  "KeywordHits.createNodeForKey.modTime.displayName"),
849  NbBundle.getMessage(this.getClass(),
850  "KeywordHits.createNodeForKey.modTime.desc"),
851  ContentUtils.getStringTime(file.getMtime(), file)));
853  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
854  NbBundle.getMessage(this.getClass(),
855  "KeywordHits.createNodeForKey.accessTime.displayName"),
856  NbBundle.getMessage(this.getClass(),
857  "KeywordHits.createNodeForKey.accessTime.desc"),
858  ContentUtils.getStringTime(file.getAtime(), file)));
860  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
861  NbBundle.getMessage(this.getClass(),
862  "KeywordHits.createNodeForKey.chgTime.displayName"),
863  NbBundle.getMessage(this.getClass(),
864  "KeywordHits.createNodeForKey.chgTime.desc"),
865  ContentUtils.getStringTime(file.getCtime(), file)));
866  return n;
867  } catch (TskException ex) {
868  logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
869  }
870  return null;
871  }
872 
876  public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
877 
878  private final String keyword;
879  private final String setName;
880  private final String instance;
881 
882  private Map<Long, BlackboardArtifactNode > nodesMap = new HashMap<>();
883 
884  public HitsFactory(String setName, String keyword, String instance) {
885  super();
886  this.setName = setName;
887  this.keyword = keyword;
888  this.instance = instance;
889  }
890 
891  @Override
892  protected void addNotify() {
893  keywordResults.addObserver(this);
894  }
895 
896  @Override
897  protected void removeNotify() {
898  keywordResults.deleteObserver(this);
899  }
900 
901  @Override
902  protected boolean createKeys(List<Long> list) {
903  for (Long id : keywordResults.getArtifactIds(setName, keyword, instance) ) {
904  if (!nodesMap.containsKey(id)) {
905  nodesMap.put(id, createBlackboardArtifactNode(id));
906  }
907  list.add(id);
908  }
909  return true;
910  }
911 
912  @Override
913  protected Node createNodeForKey(Long artifactId) {
914  return nodesMap.get(artifactId);
915  }
916 
917  @Override
918  public void update(Observable o, Object arg) {
919  refresh(true);
920  }
921  }
922 }
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static synchronized IngestManager getInstance()
static void removePropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:369
Map< Long, BlackboardArtifactNode > nodesMap
DisplayableItemNode createNode(RegExpInstanceKey key)
Map< RegExpInstanceKey, DisplayableItemNode > nodesMap
BlackboardArtifactNode createBlackboardArtifactNode(Long artifactId)
final Map< String, Map< String, Map< String, Set< Long > > > > topLevelMap
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
static void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:357
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
HitsFactory(String setName, String keyword, String instance)
RegExpInstanceNode(String setName, String keyword, String instance)

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