Autopsy  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-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;
53 
57 public class KeywordHits implements AutopsyVisitableItem {
58 
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  nodesMap.put(key, createNode(key));
711  list.add(key);
712 
713  }
714  } else {
715  for (String instance : instances) {
716  RegExpInstanceKey key = new RegExpInstanceKey(instance);
717  nodesMap.put(key, createNode(key));
718  list.add(key);
719  }
720 
721  }
722  return true;
723  }
724 
725  @Override
726  protected Node createNodeForKey(RegExpInstanceKey key) {
727  return nodesMap.get(key);
728  }
729 
730  private DisplayableItemNode createNode(RegExpInstanceKey key) {
731  // if it isn't a regexp, then skip the 'instance' layer of the tree
732  if (key.isRegExp() == false) {
733  return createBlackboardArtifactNode(key.getIdKey());
734  } else {
735  return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
736  }
737 
738  }
739  @Override
740  public void update(Observable o, Object arg) {
741  refresh(true);
742  }
743 
744  }
745 
749  public class RegExpInstanceNode extends DisplayableItemNode implements Observer {
750 
751  private final String setName;
752  private final String keyword;
753  private final String instance;
754 
755  public RegExpInstanceNode(String setName, String keyword, String instance) {
756  super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(keyword));
757  super.setName(keyword);
758  this.setName = setName;
759  this.keyword = keyword;
760  this.instance = instance;
761  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
763  keywordResults.addObserver(this);
764  }
765 
766  private void updateDisplayName() {
767  int totalDescendants = keywordResults.getArtifactIds(setName, keyword, instance).size();
768  super.setDisplayName(instance + " (" + totalDescendants + ")");
769  }
770 
771  @Override
772  public void update(Observable o, Object arg) {
774  }
775 
776  @Override
777  public boolean isLeafTypeNode() {
778  return true;
779  }
780 
781  @Override
782  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
783  return v.visit(this);
784  }
785 
786  @Override
787  protected Sheet createSheet() {
788  Sheet s = super.createSheet();
789  Sheet.Set ss = s.get(Sheet.PROPERTIES);
790  if (ss == null) {
791  ss = Sheet.createPropertiesSet();
792  s.put(ss);
793  }
794 
795  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
796  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
797  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
798  getDisplayName()));
799 
800  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
801  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
802  NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
803  keywordResults.getKeywordInstances(setName, keyword).size()));
804 
805  return s;
806  }
807 
808  @Override
809  public String getItemType() {
810  return getClass().getName();
811  }
812  }
813 
820  if (skCase == null) {
821  return null;
822  }
823 
824  try {
825  BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
827  AbstractFile file;
828  try {
829  file = skCase.getAbstractFileById(art.getObjectID());
830  } catch (TskCoreException ex) {
831  logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
832  return n;
833  }
834 
835  // It is possible to get a keyword hit on artifacts generated
836  // for the underlying image in which case MAC times are not
837  // available/applicable/useful.
838  if (file == null) {
839  return n;
840  }
841 
843  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
844  NbBundle.getMessage(this.getClass(),
845  "KeywordHits.createNodeForKey.modTime.displayName"),
846  NbBundle.getMessage(this.getClass(),
847  "KeywordHits.createNodeForKey.modTime.desc"),
848  ContentUtils.getStringTime(file.getMtime(), file)));
850  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
851  NbBundle.getMessage(this.getClass(),
852  "KeywordHits.createNodeForKey.accessTime.displayName"),
853  NbBundle.getMessage(this.getClass(),
854  "KeywordHits.createNodeForKey.accessTime.desc"),
855  ContentUtils.getStringTime(file.getAtime(), file)));
857  NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
858  NbBundle.getMessage(this.getClass(),
859  "KeywordHits.createNodeForKey.chgTime.displayName"),
860  NbBundle.getMessage(this.getClass(),
861  "KeywordHits.createNodeForKey.chgTime.desc"),
862  ContentUtils.getStringTime(file.getCtime(), file)));
863  return n;
864  } catch (TskException ex) {
865  logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
866  }
867  return null;
868  }
869 
873  public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
874 
875  private final String keyword;
876  private final String setName;
877  private final String instance;
878 
879  private Map<Long, BlackboardArtifactNode > nodesMap = new HashMap<>();
880 
881  public 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 void addNotify() {
890  keywordResults.addObserver(this);
891  }
892 
893  @Override
894  protected void removeNotify() {
895  keywordResults.deleteObserver(this);
896  }
897 
898  @Override
899  protected boolean createKeys(List<Long> list) {
900  list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
901  for (Long id : keywordResults.getArtifactIds(setName, keyword, instance) ) {
902  nodesMap.put(id, createBlackboardArtifactNode(id));
903  list.add(id);
904  }
905  return true;
906  }
907 
908  @Override
909  protected Node createNodeForKey(Long artifactId) {
910  return nodesMap.get(artifactId);
911  }
912 
913  @Override
914  public void update(Observable o, Object arg) {
915  refresh(true);
916  }
917  }
918 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static synchronized IngestManager getInstance()
static void removePropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:384
Map< RegExpInstanceKey, DisplayableItemNode > nodesMap
BlackboardArtifactNode createBlackboardArtifactNode(Long artifactId)
final Map< String, Map< String, Map< String, Set< Long > > > > topLevelMap
BlackboardArtifact getBlackboardArtifact(long artifactID)
AbstractFile getAbstractFileById(long id)
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
static void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:372
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)
CaseDbQuery executeQuery(String query)

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