Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractedContentViewer.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.keywordsearch;
20 
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.logging.Level;
29 import org.openide.nodes.Node;
30 import org.openide.util.Exceptions;
31 import org.openide.util.Lookup;
32 import org.openide.util.NbBundle;
33 import org.openide.util.lookup.ServiceProvider;
44 
49 @ServiceProvider(service = DataContentViewer.class, position = 4)
50 public class ExtractedContentViewer implements DataContentViewer {
51 
52  private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
53 
54  private static final long INVALID_DOCUMENT_ID = 0L;
55  private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
56 
57  private ExtractedContentPanel panel;
58  private volatile Node currentNode = null;
59  private IndexedText currentSource = null;
60 
67  }
68 
74  @Override
75  public void setNode(final Node node) {
76  // Clear the viewer.
77  if (node == null) {
78  currentNode = null;
79  resetComponent();
80  return;
81  }
82 
83  /*
84  * This deals with the known bug with an unknown cause where setNode is
85  * sometimes called twice for the same node.
86  */
87  if (node == currentNode) {
88  return;
89  } else {
90  currentNode = node;
91  }
92 
93  Lookup nodeLookup = node.getLookup();
94  Content content = nodeLookup.lookup(Content.class);
95 
96  /*
97  * Assemble a collection of all of the indexed text "sources" for the
98  * node.
99  */
100  List<IndexedText> sources = new ArrayList<>();
101  IndexedText highlightedHitText = null;
102  IndexedText rawContentText = null;
103 
104  if (null != content && solrHasContent(content.getId())) {
105  QueryResults hits = nodeLookup.lookup(QueryResults.class);
106  BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class);
107  if (hits != null) {
108  /*
109  * if there is a QueryReslt object, in the lookup use that. This
110  * happens when a user selects a row in an ad-hoc search result
111  */
112  highlightedHitText = new HighlightedText(content.getId(), hits);
113  } else if (artifact != null
114  && artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
115  try {
116  // if the artifact is an account artifact, get an account text .
117  highlightedHitText = getAccountsText(content, nodeLookup);
118  } catch (TskCoreException ex) {
119  logger.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS
120 
121  }
122  } else if (artifact != null
123  && artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
124  try {
125  //if there is kwh artifact use that to construct the HighlightedText
126  highlightedHitText = new HighlightedText(artifact);
127  } catch (TskCoreException ex) {
128  logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS
129  }
130  }
131 
132  if (highlightedHitText != null) {
133  sources.add(highlightedHitText);
134  }
135 
136  /*
137  * Next, add the "raw" (not highlighted) text, if any, for any
138  * content associated with the node.
139  */
140  rawContentText = new RawText(content, content.getId());
141  sources.add(rawContentText);
142  }
143 
144  /*
145  * Finally, add the "raw" (not highlighted) text, if any, for any
146  * artifact associated with the node.
147  */
148  IndexedText rawArtifactText = null;
149  try {
150  rawArtifactText = getRawArtifactText(nodeLookup);
151  } catch (TskCoreException ex) {
152  logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS
153 
154  }
155  if (rawArtifactText != null) {
156  sources.add(rawArtifactText);
157  }
158 
159  // Now set the default source to be displayed.
160  if (null != highlightedHitText) {
161  currentSource = highlightedHitText;
162  } else if (null != rawContentText) {
163  currentSource = rawContentText;
164  } else {
165  currentSource = rawArtifactText;
166  }
167 
168  // Push the text sources into the panel.
169  for (IndexedText source : sources) {
170  int currentPage = source.getCurrentPage();
171  if (currentPage == 0 && source.hasNextPage()) {
172  source.nextPage();
173  }
174  }
175  panel.updateControls(currentSource);
176  setPanel(sources);
177  }
178 
179  static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
180  IndexedText rawArtifactText = null;
181  BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class);
182  if (null != artifact) {
183  /*
184  * For keyword hit artifacts, add the text of the artifact that hit,
185  * not the hit artifact; otherwise add the text for the artifact.
186  */
187  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()
188  || artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
189 
190  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
191  if (attribute != null) {
192  long artifactId = attribute.getValueLong();
193  BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactId);
194  rawArtifactText = new RawText(associatedArtifact, associatedArtifact.getArtifactID());
195 
196  }
197 
198  } else {
199  rawArtifactText = new RawText(artifact, artifact.getArtifactID());
200  }
201  }
202  return rawArtifactText;
203  }
204 
205  static private IndexedText getAccountsText(Content content, Lookup nodeLookup) throws TskCoreException {
206  /*
207  * get all the credit card artifacts
208  */
209  //if the node had artifacts in the lookup use them, other wise look up all credit card artifacts for the content.
210  Collection<? extends BlackboardArtifact> artifacts = nodeLookup.lookupAll(BlackboardArtifact.class);
211  artifacts = (artifacts == null || artifacts.isEmpty())
212  ? content.getArtifacts(TSK_ACCOUNT)
213  : artifacts;
214 
215  return new AccountsText(content.getId(), artifacts);
216  }
217 
218  private void scrollToCurrentHit() {
219  final IndexedText source = panel.getSelectedSource();
220  if (source == null || !source.isSearchable()) {
221  return;
222  }
223 
224  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(source.currentItem()));
225  }
226 
227  @Override
228  public String getTitle() {
229  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.getTitle");
230  }
231 
232  @Override
233  public String getToolTip() {
234  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.toolTip");
235  }
236 
237  @Override
238  public DataContentViewer createInstance() {
239  return new ExtractedContentViewer();
240  }
241 
242  @Override
243  public synchronized Component getComponent() {
244  if (panel == null) {
245  panel = new ExtractedContentPanel();
246  panel.addPrevMatchControlListener(new PrevFindActionListener());
247  panel.addNextMatchControlListener(new NextFindActionListener());
248  panel.addPrevPageControlListener(new PrevPageActionListener());
249  panel.addNextPageControlListener(new NextPageActionListener());
250  panel.addSourceComboControlListener(new SourceChangeActionListener());
251  }
252  return panel;
253  }
254 
255  @Override
256  public void resetComponent() {
257  setPanel(new ArrayList<>());
258  panel.resetDisplay();
259  currentNode = null;
260  currentSource = null;
261  }
262 
263  @Override
264  public boolean isSupported(Node node) {
265  if (node == null) {
266  return false;
267  }
268 
269  /*
270  * Is there a credit card artifact in the lookup
271  */
272  Collection<? extends BlackboardArtifact> artifacts = node.getLookup().lookupAll(BlackboardArtifact.class);
273  if (artifacts != null) {
274  for (BlackboardArtifact art : artifacts) {
275  final int artifactTypeID = art.getArtifactTypeID();
276  if (artifactTypeID == TSK_ACCOUNT.getTypeID()
277  || artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) {
278  return true;
279  }
280  }
281  }
282 
283  /*
284  * No highlighted text for a keyword hit, so is there any indexed text
285  * at all for this node?
286  */
287  long documentID = getDocumentId(node);
288  if (INVALID_DOCUMENT_ID == documentID) {
289  return false;
290  }
291 
292  return solrHasContent(documentID);
293  }
294 
295  @Override
296  public int isPreferred(Node node) {
297  BlackboardArtifact art = node.getLookup().lookup(BlackboardArtifact.class);
298 
299  if (art == null) {
300  return 4;
301  } else if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
303  return 6;
304  } else {
305  return 4;
306  }
307  }
308 
315  private void setPanel(List<IndexedText> sources) {
316  if (panel != null) {
317  panel.setSources(sources);
318  }
319  }
320 
328  private boolean solrHasContent(Long objectId) {
329  final Server solrServer = KeywordSearch.getServer();
330  if (solrServer.coreIsOpen() == false)
331  return false;
332 
333  try {
334  return solrServer.queryIsIndexed(objectId);
336  logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS
337  return false;
338  }
339  }
340 
349  private Long getDocumentId(Node node) {
358  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
359  if (null != artifact) {
360  if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
361  return artifact.getArtifactID();
362  } else {
363  try {
364  // Get the associated artifact attribute and return its value as the ID
365  BlackboardAttribute blackboardAttribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
366  if (blackboardAttribute != null) {
367  return blackboardAttribute.getValueLong();
368  }
369  } catch (TskCoreException ex) {
370  logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS
371  }
372  }
373  }
374 
375  /*
376  * For keyword search hit artifact nodes and all other nodes, the
377  * document ID for the extracted text is the ID of the associated
378  * content, if any, unless there is an associated artifact, which is
379  * handled above.
380  */
381  Content content = node.getLookup().lookup(Content.class);
382  if (content != null) {
383  return content.getId();
384  }
385 
386  /*
387  * No extracted text, return an invalid docuemnt ID.
388  */
389  return 0L;
390  }
391 
392  private class NextFindActionListener implements ActionListener {
393 
394  @Override
395  public void actionPerformed(ActionEvent e) {
396  IndexedText source = panel.getSelectedSource();
397  if (source == null) {
398  // reset
399  panel.updateControls(null);
400  return;
401  }
402  final boolean hasNextItem = source.hasNextItem();
403  final boolean hasNextPage = source.hasNextPage();
404  int indexVal;
405  if (hasNextItem || hasNextPage) {
406  if (!hasNextItem) {
407  //flip the page
408  nextPage();
409  indexVal = source.currentItem();
410  } else {
411  indexVal = source.nextItem();
412  }
413 
414  //scroll
415  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
416 
417  //update display
418  panel.updateCurrentMatchDisplay(source.currentItem());
419  panel.updateTotaMatcheslDisplay(source.getNumberHits());
420 
421  //update controls if needed
422  if (!source.hasNextItem() && !source.hasNextPage()) {
423  panel.enableNextMatchControl(false);
424  }
425  if (source.hasPreviousItem() || source.hasPreviousPage()) {
426  panel.enablePrevMatchControl(true);
427  }
428  }
429  }
430  }
431 
432  private class PrevFindActionListener implements ActionListener {
433 
434  @Override
435  public void actionPerformed(ActionEvent e) {
436  IndexedText source = panel.getSelectedSource();
437  final boolean hasPreviousItem = source.hasPreviousItem();
438  final boolean hasPreviousPage = source.hasPreviousPage();
439  int indexVal;
440  if (hasPreviousItem || hasPreviousPage) {
441  if (!hasPreviousItem) {
442  //flip the page
443  previousPage();
444  indexVal = source.currentItem();
445  } else {
446  indexVal = source.previousItem();
447  }
448 
449  //scroll
450  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
451 
452  //update display
453  panel.updateCurrentMatchDisplay(source.currentItem());
454  panel.updateTotaMatcheslDisplay(source.getNumberHits());
455 
456  //update controls if needed
457  if (!source.hasPreviousItem() && !source.hasPreviousPage()) {
458  panel.enablePrevMatchControl(false);
459  }
460  if (source.hasNextItem() || source.hasNextPage()) {
461  panel.enableNextMatchControl(true);
462  }
463  }
464  }
465  }
466 
467  private class SourceChangeActionListener implements ActionListener {
468 
469  @Override
470  public void actionPerformed(ActionEvent e) {
471  currentSource = panel.getSelectedSource();
472 
473  if (currentSource == null) {
474  //TODO might need to reset something
475  return;
476  }
477 
478  panel.updateControls(currentSource);
479  panel.updateSearchControls(currentSource);
480  }
481  }
482 
483  private void nextPage() {
484  // we should never have gotten here -- reset
485  if (currentSource == null) {
486  panel.updateControls(null);
487  return;
488  }
489 
490  if (currentSource.hasNextPage()) {
491  currentSource.nextPage();
492 
493  //set new text
494  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
495  panel.refreshCurrentMarkup();
496  panel.setCursor(null);
497 
498  //update display
499  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
500 
501  //scroll to current selection
503 
504  //update controls if needed
505  if (!currentSource.hasNextPage()) {
506  panel.enableNextPageControl(false);
507  }
508  if (currentSource.hasPreviousPage()) {
509  panel.enablePrevPageControl(true);
510  }
511 
512  panel.updateSearchControls(currentSource);
513  }
514  }
515 
516  private void previousPage() {
517  // reset, we should have never gotten here if null
518  if (currentSource == null) {
519  panel.updateControls(null);
520  return;
521  }
522 
523  if (currentSource.hasPreviousPage()) {
524  currentSource.previousPage();
525 
526  //set new text
527  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
528  panel.refreshCurrentMarkup();
529  panel.setCursor(null);
530 
531  //update display
532  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
533 
534  //scroll to current selection
536 
537  //update controls if needed
538  if (!currentSource.hasPreviousPage()) {
539  panel.enablePrevPageControl(false);
540  }
541  if (currentSource.hasNextPage()) {
542  panel.enableNextPageControl(true);
543  }
544 
545  panel.updateSearchControls(currentSource);
546 
547  }
548  }
549 
550  private class NextPageActionListener implements ActionListener {
551 
552  @Override
553  public void actionPerformed(ActionEvent e) {
554  nextPage();
555  }
556  }
557 
558  private class PrevPageActionListener implements ActionListener {
559 
560  @Override
561  public void actionPerformed(ActionEvent e) {
562  previousPage();
563  }
564  }
565 }
static IndexedText getAccountsText(Content content, Lookup nodeLookup)
BlackboardArtifact getBlackboardArtifact(long artifactID)
BlackboardAttribute getAttribute(BlackboardAttribute.Type attributeType)
boolean queryIsIndexed(long contentID)
Definition: Server.java:953
synchronized static Logger getLogger(String name)
Definition: Logger.java:161

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.