Autopsy  4.0
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-2015 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 
30 import org.openide.util.NbBundle;
32 import org.openide.nodes.Node;
33 import org.openide.util.lookup.ServiceProvider;
35 import org.sleuthkit.datamodel.BlackboardArtifact;
36 import org.sleuthkit.datamodel.Content;
37 import org.sleuthkit.datamodel.ContentVisitor;
38 import org.sleuthkit.datamodel.Directory;
39 import org.sleuthkit.datamodel.TskCoreException;
40 import org.sleuthkit.datamodel.BlackboardAttribute;
41 
46 @ServiceProvider(service = DataContentViewer.class, position = 4)
47 public class ExtractedContentViewer implements DataContentViewer {
48 
49  private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
50  private static final long INVALID_DOCUMENT_ID = 0L;
51  private ExtractedContentPanel panel;
52  private volatile Node currentNode = null;
53  private IndexedText currentSource = null;
54  private final IsDirVisitor isDirVisitor = new IsDirVisitor();
55 
57  }
58 
59  @Override
60  public void setNode(final Node selectedNode) {
61  /*
62  * Clear the viewer.
63  */
64  if (selectedNode == null) {
65  currentNode = null;
66  resetComponent();
67  return;
68  }
69 
70  /*
71  * This deals with the known bug with an unknown cause where setNode is
72  * sometimes called twice for the same node.
73  */
74  if (selectedNode == currentNode) {
75  return;
76  } else {
77  currentNode = selectedNode;
78  }
79 
80  /*
81  * Assemble a collection of all of the "sources" of extracted and
82  * indexed text to present in a paged display. First look for the text
83  * marked up with HTML to highlight keyword hits that will be present if
84  * the node is a keyword hit blakcboard artifact.
85  */
86  final List<IndexedText> sources = new ArrayList<>();
87  sources.addAll(selectedNode.getLookup().lookupAll(IndexedText.class));
88 
89  /*
90  * Now look for the "raw" extracted text if this is a node for another
91  * type of artifact or for content.
92  */
93  long documentID = getDocumentId(currentNode);
94  if (INVALID_DOCUMENT_ID == documentID) {
95  setPanel(sources);
96  return;
97  }
98  IndexedText rawSource;
99  if (documentID > INVALID_DOCUMENT_ID) {
100  // Add a content item
101  Content content = currentNode.getLookup().lookup(Content.class);
102  rawSource = new RawText(content, content.getId());
103  } else {
104  // Add an artifact item
105  BlackboardArtifact blackboardArtifact = currentNode.getLookup().lookup(BlackboardArtifact.class);
106  rawSource = new RawText(blackboardArtifact, documentID);
107  }
108  currentSource = rawSource;
109  sources.add(rawSource);
110 
111  /*
112  * Initialize the pages for the sources. The first source in the list
113  * of sources will be displayed.
114  */
115  int currentPage = currentSource.getCurrentPage();
116  if (currentPage == 0 && currentSource.hasNextPage()) {
117  currentSource.nextPage();
118  }
119  updatePageControls();
120  setPanel(sources);
121  }
122 
123  private void scrollToCurrentHit() {
124  final IndexedText source = panel.getSelectedSource();
125  if (source == null || !source.isSearchable()) {
126  return;
127  }
128 
129  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(source.currentItem()));
130 
131  }
132 
133  @Override
134  public String getTitle() {
135  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.getTitle");
136  }
137 
138  @Override
139  public String getToolTip() {
140  return NbBundle.getMessage(this.getClass(), "ExtractedContentViewer.toolTip");
141  }
142 
143  @Override
144  public DataContentViewer createInstance() {
145  return new ExtractedContentViewer();
146  }
147 
148  @Override
149  public synchronized Component getComponent() {
150  if (panel == null) {
151  panel = new ExtractedContentPanel();
152  panel.addPrevMatchControlListener(new PrevFindActionListener());
153  panel.addNextMatchControlListener(new NextFindActionListener());
154  panel.addPrevPageControlListener(new PrevPageActionListener());
155  panel.addNextPageControlListener(new NextPageActionListener());
156  panel.addSourceComboControlListener(new SourceChangeActionListener());
157  }
158  return panel;
159  }
160 
161  @Override
162  public void resetComponent() {
163  setPanel(new ArrayList<IndexedText>());
164  panel.resetDisplay();
165  currentNode = null;
166  currentSource = null;
167  }
168 
169  @Override
170  public boolean isSupported(Node node) {
171  if (node == null) {
172  return false;
173  }
174 
181  Collection<? extends IndexedText> sources = node.getLookup().lookupAll(IndexedText.class);
182  if (sources.isEmpty() == false) {
183  return true;
184  }
185 
186  /*
187  * No highlighted text for a keyword hit, so is there any indexed text
188  * at all for this node?
189  */
190  long documentID = getDocumentId(node);
191  if (INVALID_DOCUMENT_ID == documentID) {
192  return false;
193  }
194 
195  return solrHasContent(documentID);
196  }
197 
198  @Override
199  public int isPreferred(Node node) {
200  BlackboardArtifact art = node.getLookup().lookup(BlackboardArtifact.class);
201 
202  if (art == null) {
203  return 4;
204  } else if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
205  return 6;
206  } else {
207  return 4;
208  }
209  }
210 
217  private void setPanel(List<IndexedText> sources) {
218  if (panel != null) {
219  panel.setSources(sources);
220  }
221  }
222 
223  private class IsDirVisitor extends ContentVisitor.Default<Boolean> {
224 
225  @Override
226  protected Boolean defaultVisit(Content cntnt) {
227  return false;
228  }
229 
230  @Override
231  public Boolean visit(Directory d) {
232  return true;
233  }
234  }
235 
243  private boolean solrHasContent(Long objectId) {
244  final Server solrServer = KeywordSearch.getServer();
245  try {
246  return solrServer.queryIsIndexed(objectId);
248  logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS
249  return false;
250  }
251  }
252 
261  private Long getDocumentId(Node node) {
270  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
271  if (null != artifact) {
272  if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
273  return artifact.getArtifactID();
274  } else {
275  try {
276  // Get the associated artifact attribute and return its value as the ID
277  BlackboardAttribute blackboardAttribute = artifact.getAttribute(
278  new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
279  if (blackboardAttribute != null) {
280  return blackboardAttribute.getValueLong();
281  }
282  } catch (TskCoreException ex) {
283  logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS
284  }
285  }
286  }
287 
288  /*
289  * For keyword search hit artifact nodes and all other nodes, the
290  * document ID for the extracted text is the ID of the associated
291  * content, if any, unless there is an associated artifact, which
292  * is handled above.
293  */
294  Content content = node.getLookup().lookup(Content.class);
295  if (content != null) {
296  return content.getId();
297  }
298 
299  /*
300  * No extracted text, return an invalid docuemnt ID.
301  */
302  return 0L;
303  }
304 
305  private class NextFindActionListener implements ActionListener {
306 
307  @Override
308  public void actionPerformed(ActionEvent e) {
309  IndexedText source = panel.getSelectedSource();
310  if (source == null) {
311  // reset
312  panel.updateControls(null);
313  return;
314  }
315  final boolean hasNextItem = source.hasNextItem();
316  final boolean hasNextPage = source.hasNextPage();
317  int indexVal = 0;
318  if (hasNextItem || hasNextPage) {
319  if (!hasNextItem) {
320  //flip the page
321  nextPage();
322  indexVal = source.currentItem();
323  } else {
324  indexVal = source.nextItem();
325  }
326 
327  //scroll
328  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
329 
330  //update display
331  panel.updateCurrentMatchDisplay(source.currentItem());
332  panel.updateTotaMatcheslDisplay(source.getNumberHits());
333 
334  //update controls if needed
335  if (!source.hasNextItem() && !source.hasNextPage()) {
336  panel.enableNextMatchControl(false);
337  }
338  if (source.hasPreviousItem() || source.hasPreviousPage()) {
339  panel.enablePrevMatchControl(true);
340  }
341  }
342  }
343  }
344 
345  private class PrevFindActionListener implements ActionListener {
346 
347  @Override
348  public void actionPerformed(ActionEvent e) {
349  IndexedText source = panel.getSelectedSource();
350  final boolean hasPreviousItem = source.hasPreviousItem();
351  final boolean hasPreviousPage = source.hasPreviousPage();
352  int indexVal = 0;
353  if (hasPreviousItem || hasPreviousPage) {
354  if (!hasPreviousItem) {
355  //flip the page
356  previousPage();
357  indexVal = source.currentItem();
358  } else {
359  indexVal = source.previousItem();
360  }
361 
362  //scroll
363  panel.scrollToAnchor(source.getAnchorPrefix() + Integer.toString(indexVal));
364 
365  //update display
366  panel.updateCurrentMatchDisplay(source.currentItem());
367  panel.updateTotaMatcheslDisplay(source.getNumberHits());
368 
369  //update controls if needed
370  if (!source.hasPreviousItem() && !source.hasPreviousPage()) {
371  panel.enablePrevMatchControl(false);
372  }
373  if (source.hasNextItem() || source.hasNextPage()) {
374  panel.enableNextMatchControl(true);
375  }
376  }
377  }
378  }
379 
380  private class SourceChangeActionListener implements ActionListener {
381 
382  @Override
383  public void actionPerformed(ActionEvent e) {
384 
385  currentSource = panel.getSelectedSource();
386 
387  if (currentSource == null) {
388  //TODO might need to reset something
389  return;
390  }
391 
392  updatePageControls();
393  updateSearchControls();
394 
395  }
396  }
397 
398  private void updateSearchControls() {
399  panel.updateSearchControls(currentSource);
400  }
401 
402  private void updatePageControls() {
403  panel.updateControls(currentSource);
404  }
405 
406  private void nextPage() {
407  // we should never have gotten here -- reset
408  if (currentSource == null) {
409  panel.updateControls(null);
410  return;
411  }
412 
413  if (currentSource.hasNextPage()) {
414  currentSource.nextPage();
415 
416  //set new text
417  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
418  panel.refreshCurrentMarkup();
419  panel.setCursor(null);
420 
421  //update display
422  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
423 
424  //scroll to current selection
426 
427  //update controls if needed
428  if (!currentSource.hasNextPage()) {
429  panel.enableNextPageControl(false);
430  }
431  if (currentSource.hasPreviousPage()) {
432  panel.enablePrevPageControl(true);
433  }
434 
435  updateSearchControls();
436  }
437  }
438 
439  private void previousPage() {
440  // reset, we should have never gotten here if null
441  if (currentSource == null) {
442  panel.updateControls(null);
443  return;
444  }
445 
446  if (currentSource.hasPreviousPage()) {
447  currentSource.previousPage();
448 
449  //set new text
450  panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
451  panel.refreshCurrentMarkup();
452  panel.setCursor(null);
453 
454  //update display
455  panel.updateCurrentPageDisplay(currentSource.getCurrentPage());
456 
457  //scroll to current selection
459 
460  //update controls if needed
461  if (!currentSource.hasPreviousPage()) {
462  panel.enablePrevPageControl(false);
463  }
464  if (currentSource.hasNextPage()) {
465  panel.enableNextPageControl(true);
466  }
467 
468  updateSearchControls();
469 
470  }
471  }
472 
473  class NextPageActionListener implements ActionListener {
474 
475  @Override
476  public void actionPerformed(ActionEvent e) {
477  nextPage();
478  }
479  }
480 
481  private class PrevPageActionListener implements ActionListener {
482 
483  @Override
484  public void actionPerformed(ActionEvent e) {
485  previousPage();
486  }
487  }
488 }
boolean queryIsIndexed(long contentID)
Definition: Server.java:819
synchronized static Logger getLogger(String name)
Definition: Logger.java:166

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