Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataContentViewerOtherCases.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2017-2020 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.centralrepository.contentviewer;
20 
21 import java.awt.Component;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.ComponentAdapter;
25 import java.awt.event.ComponentEvent;
26 import java.io.BufferedWriter;
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.text.DateFormat;
31 import java.text.ParseException;
32 import java.text.SimpleDateFormat;
33 import java.util.ArrayList;
34 import java.util.Calendar;
35 import java.util.Collection;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Locale;
40 import java.util.Map;
41 import java.util.Objects;
42 import java.util.Set;
43 import java.util.logging.Level;
45 import javax.swing.JFileChooser;
46 import javax.swing.JMenuItem;
47 import javax.swing.JOptionPane;
48 import static javax.swing.JOptionPane.DEFAULT_OPTION;
49 import static javax.swing.JOptionPane.PLAIN_MESSAGE;
50 import static javax.swing.JOptionPane.ERROR_MESSAGE;
51 import javax.swing.JPanel;
52 import javax.swing.filechooser.FileNameExtensionFilter;
53 import javax.swing.table.TableModel;
54 import javax.swing.table.TableRowSorter;
55 import org.joda.time.DateTimeZone;
56 import org.joda.time.LocalDateTime;
57 import org.openide.nodes.Node;
58 import org.openide.util.NbBundle.Messages;
59 import org.openide.util.lookup.ServiceProvider;
69 import org.sleuthkit.datamodel.AbstractFile;
70 import org.sleuthkit.datamodel.BlackboardArtifact;
71 import org.sleuthkit.datamodel.BlackboardArtifactTag;
72 import org.sleuthkit.datamodel.Content;
73 import org.sleuthkit.datamodel.ContentTag;
74 import org.sleuthkit.datamodel.TskCoreException;
75 import org.sleuthkit.datamodel.TskException;
76 import org.sleuthkit.datamodel.SleuthkitCase;
77 import org.sleuthkit.datamodel.TskData;
79 
83 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
84 @ServiceProvider(service = DataContentViewer.class, position = 9)
85 @Messages({"DataContentViewerOtherCases.title=Other Occurrences",
86  "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",
87  "DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search.",
88  "DataContentViewerOtherCases.table.noResultsFound=No results found."})
89 public class DataContentViewerOtherCases extends JPanel implements DataContentViewer {
90 
91  private static final long serialVersionUID = -1L;
92  private static final String UUID_PLACEHOLDER_STRING = "NoCorrelationAttributeInstance";
93  private static final Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName());
94  private static final CorrelationCaseWrapper NO_ARTIFACTS_CASE = new CorrelationCaseWrapper(Bundle.DataContentViewerOtherCases_table_noArtifacts());
95  private static final CorrelationCaseWrapper NO_RESULTS_CASE = new CorrelationCaseWrapper(Bundle.DataContentViewerOtherCases_table_noResultsFound());
98  private final OtherOccurrencesDataSourcesTableModel dataSourcesTableModel;
99  private OccurrencePanel occurrencePanel;
100  private final Collection<CorrelationAttributeInstance> correlationAttributes;
101  private String dataSourceName = ""; //the data source of the file which the content viewer is being populated for
102  private String deviceId = ""; //the device id of the data source for the file which the content viewer is being populated for
106  private AbstractFile file; //the file which the content viewer is being populated for
107 
112  this.filesTableModel = new OtherOccurrencesFilesTableModel();
113  this.casesTableModel = new OtherOccurrencesCasesTableModel();
114  this.dataSourcesTableModel = new OtherOccurrencesDataSourcesTableModel();
115  this.correlationAttributes = new ArrayList<>();
116  occurrencePanel = new OccurrencePanel();
117  initComponents();
118  customizeComponents();
119 
120  detailsPanelScrollPane.addComponentListener(new ComponentAdapter() {
121  @Override
122  public void componentResized(ComponentEvent componentEvent) {
123  //when its resized make sure the width of the panel resizes to match the scroll pane width to avoid a horizontal scroll bar
124  occurrencePanel.setPreferredSize(new java.awt.Dimension(detailsPanelScrollPane.getPreferredSize().width, occurrencePanel.getPreferredSize().height));
125  detailsPanelScrollPane.setViewportView(occurrencePanel);
126  }
127  });
128  reset();
129  }
130 
137  static String getPlaceholderUUID() {
138  return UUID_PLACEHOLDER_STRING;
139  }
140 
141  private void customizeComponents() {
142  ActionListener actList = (ActionEvent e) -> {
143  JMenuItem jmi = (JMenuItem) e.getSource();
144  if (jmi.equals(showCaseDetailsMenuItem)) {
145  showCaseDetails(filesTable.getSelectedRow());
146  } else if (jmi.equals(exportToCSVMenuItem)) {
147  try {
148  saveToCSV();
149  } catch (NoCurrentCaseException ex) {
150  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
151  }
152  } else if (jmi.equals(showCommonalityMenuItem)) {
153  showCommonalityDetails();
154  }
155  };
156 
157  exportToCSVMenuItem.addActionListener(actList);
158  showCaseDetailsMenuItem.addActionListener(actList);
159  showCommonalityMenuItem.addActionListener(actList);
160 
161  // Configure column sorting.
162  TableRowSorter<TableModel> sorter = new TableRowSorter<>(filesTable.getModel());
163  filesTable.setRowSorter(sorter);
164  casesTable.getSelectionModel().addListSelectionListener((e) -> {
165  if (Case.isCaseOpen()) {
166  updateOnCaseSelection();
167  }
168  });
169  dataSourcesTable.getSelectionModel().addListSelectionListener((e) -> {
170  if (Case.isCaseOpen()) {
171  updateOnDataSourceSelection();
172  }
173  });
174 
175  //alows resizing of the 4th section
176  filesTable.getSelectionModel().addListSelectionListener((e) -> {
177  if (Case.isCaseOpen()) {
178  occurrencePanel = new OccurrencePanel();
179  updateOnFileSelection();
180  }
181  });
182  //sort tables alphabetically initially
183  casesTable.getRowSorter().toggleSortOrder(0);
184  dataSourcesTable.getRowSorter().toggleSortOrder(0);
185  filesTable.getRowSorter().toggleSortOrder(0);
186  }
187 
188  @Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
189  "# {0} - commonality percentage",
190  "# {1} - correlation type",
191  "# {2} - correlation value",
192  "DataContentViewerOtherCases.correlatedArtifacts.byType={0}% of data sources have {2} (type: {1})\n",
193  "DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
194  "DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
199  private void showCommonalityDetails() {
200  if (correlationAttributes.isEmpty()) {
201  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
202  Bundle.DataContentViewerOtherCases_correlatedArtifacts_isEmpty(),
203  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
204  DEFAULT_OPTION, PLAIN_MESSAGE);
205  } else {
206  StringBuilder msg = new StringBuilder(correlationAttributes.size());
207  int percentage;
208  try {
210  for (CorrelationAttributeInstance eamArtifact : correlationAttributes) {
211  try {
212  percentage = dbManager.getFrequencyPercentage(eamArtifact);
213  msg.append(Bundle.DataContentViewerOtherCases_correlatedArtifacts_byType(percentage,
214  eamArtifact.getCorrelationType().getDisplayName(),
215  eamArtifact.getCorrelationValue()));
217  LOGGER.log(Level.WARNING, String.format("Error getting commonality details for artifact with ID: %s.", eamArtifact.getID()), ex);
218  }
219  }
220  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
221  msg.toString(),
222  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
223  DEFAULT_OPTION, PLAIN_MESSAGE);
224  } catch (CentralRepoException ex) {
225  LOGGER.log(Level.SEVERE, "Error getting commonality details.", ex);
226  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
227  Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
228  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
229  DEFAULT_OPTION, ERROR_MESSAGE);
230  }
231  }
232  }
233 
234  @Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
235  "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
236  "DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.",
237  "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
238  "DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
239  private void showCaseDetails(int selectedRowViewIdx) {
240  String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
241  String details = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails();
242  try {
243  if (-1 != selectedRowViewIdx) {
245  int selectedRowModelIdx = filesTable.convertRowIndexToModel(selectedRowViewIdx);
246  List<OtherOccurrenceNodeData> rowList = filesTableModel.getListOfNodesForFile(selectedRowModelIdx);
247  if (!rowList.isEmpty()) {
248  if (rowList.get(0) instanceof OtherOccurrenceNodeInstanceData) {
249  CorrelationCase eamCasePartial = ((OtherOccurrenceNodeInstanceData) rowList.get(0)).getCorrelationAttributeInstance().getCorrelationCase();
250  caseDisplayName = eamCasePartial.getDisplayName();
251  // query case details
252  CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
253  if (eamCase != null) {
254  details = eamCase.getCaseDetailsOptionsPaneDialog();
255  } else {
256  details = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails();
257  }
258  } else {
259  details = Bundle.DataContentViewerOtherCases_caseDetailsDialog_notSelected();
260  }
261  } else {
262  details = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference();
263  }
264  }
265  } catch (CentralRepoException ex) {
266  LOGGER.log(Level.SEVERE, "Error loading case details", ex);
267  } finally {
268  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
269  details,
270  caseDisplayName,
271  DEFAULT_OPTION, PLAIN_MESSAGE);
272  }
273  }
274 
275  private void saveToCSV() throws NoCurrentCaseException {
276  if (casesTableModel.getRowCount() > 0) {
277  Calendar now = Calendar.getInstance();
278  String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
279  CSVFileChooser.setCurrentDirectory(new File(Case.getCurrentCaseThrows().getExportDirectory()));
280  CSVFileChooser.setSelectedFile(new File(fileName));
281  CSVFileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv"));
282 
283  int returnVal = CSVFileChooser.showSaveDialog(filesTable);
284  if (returnVal == JFileChooser.APPROVE_OPTION) {
285 
286  File selectedFile = CSVFileChooser.getSelectedFile();
287  if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS
288  selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS
289  }
290  writeOtherOccurrencesToFileAsCSV(selectedFile);
291  }
292  }
293  }
294 
295  @Messages({
296  "DataContentViewerOtherCasesModel.csvHeader.case=Case",
297  "DataContentViewerOtherCasesModel.csvHeader.device=Device",
298  "DataContentViewerOtherCasesModel.csvHeader.dataSource=Data Source",
299  "DataContentViewerOtherCasesModel.csvHeader.attribute=Matched Attribute",
300  "DataContentViewerOtherCasesModel.csvHeader.value=Attribute Value",
301  "DataContentViewerOtherCasesModel.csvHeader.known=Known",
302  "DataContentViewerOtherCasesModel.csvHeader.path=Path",
303  "DataContentViewerOtherCasesModel.csvHeader.comment=Comment"
304  })
308  private void writeOtherOccurrencesToFileAsCSV(File destFile) {
309  try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) {
310  //write headers
311  StringBuilder headers = new StringBuilder("\"");
312  headers.append(Bundle.DataContentViewerOtherCasesModel_csvHeader_case())
313  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_dataSource())
314  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_attribute())
315  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_value())
316  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_known())
317  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_path())
318  .append(OtherOccurrenceNodeInstanceData.getCsvItemSeparator()).append(Bundle.DataContentViewerOtherCasesModel_csvHeader_comment())
319  .append('"').append(System.getProperty("line.separator"));
320  writer.write(headers.toString());
321  //write content
322  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
323  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
324  // get correlation and reference set instances from DB
325  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
326  for (OtherOccurrenceNodeInstanceData nodeData : correlatedNodeDataMap.values()) {
327  writer.write(nodeData.toCsvString());
328  }
329  }
330  } catch (IOException ex) {
331  LOGGER.log(Level.SEVERE, "Error writing selected rows to CSV.", ex);
332  }
333  }
334 
338  private void reset() {
339  // start with empty table
340  casesTableModel.clearTable();
341  dataSourcesTableModel.clearTable();
342  filesTableModel.clearTable();
343  correlationAttributes.clear();
344  earliestCaseDate.setText(Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable());
345  foundInLabel.setText("");
346  //calling getPreferredSize has a side effect of ensuring it has a preferred size which reflects the contents which are visible
347  occurrencePanel = new OccurrencePanel();
348  occurrencePanel.getPreferredSize();
349  detailsPanelScrollPane.setViewportView(occurrencePanel);
350  }
351 
352  @Override
353  public String getTitle() {
354  return Bundle.DataContentViewerOtherCases_title();
355  }
356 
357  @Override
358  public String getToolTip() {
359  return Bundle.DataContentViewerOtherCases_toolTip();
360  }
361 
362  @Override
364  return new DataContentViewerOtherCases();
365  }
366 
367  @Override
368  public Component getComponent() {
369  return this;
370  }
371 
372  @Override
373  public void resetComponent() {
374  reset();
375  }
376 
377  @Override
378  public int isPreferred(Node node) {
379  return 1;
380 
381  }
382 
390  private BlackboardArtifact
392  BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class
393  );
394  BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class
395  );
396 
397  if (nodeBbArtifactTag != null) {
398  return nodeBbArtifactTag.getArtifact();
399  } else if (nodeBbArtifact != null) {
400  return nodeBbArtifact;
401  }
402 
403  return null;
404 
405  }
406 
414  private AbstractFile getAbstractFileFromNode(Node node) {
415  BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class
416  );
417  ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class
418  );
419  BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class
420  );
421  AbstractFile nodeAbstractFile = node.getLookup().lookup(AbstractFile.class
422  );
423 
424  if (nodeBbArtifactTag != null) {
425  Content content = nodeBbArtifactTag.getContent();
426  if (content instanceof AbstractFile) {
427  return (AbstractFile) content;
428  }
429  } else if (nodeContentTag != null) {
430  Content content = nodeContentTag.getContent();
431  if (content instanceof AbstractFile) {
432  return (AbstractFile) content;
433  }
434  } else if (nodeBbArtifact != null) {
435  Content content;
436  try {
437  content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
438  } catch (TskCoreException ex) {
439  LOGGER.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS
440  return null;
441  }
442 
443  if (content instanceof AbstractFile) {
444  return (AbstractFile) content;
445  }
446  } else if (nodeAbstractFile != null) {
447  return nodeAbstractFile;
448  }
449 
450  return null;
451  }
452 
461  private Collection<CorrelationAttributeInstance> getCorrelationAttributesFromNode(Node node) {
462  Collection<CorrelationAttributeInstance> ret = new ArrayList<>();
463 
464  // correlate on blackboard artifact attributes if they exist and supported
465  BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
466  if (bbArtifact != null && CentralRepository.isEnabled()) {
468  }
469 
470  // we can correlate based on the MD5 if it is enabled
471  if (this.file != null && CentralRepository.isEnabled() && this.file.getSize() > 0) {
472  try {
473 
475  String md5 = this.file.getMd5Hash();
476  if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) {
477  for (CorrelationAttributeInstance.Type aType : artifactTypes) {
478  if (aType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
480  try {
481  ret.add(new CorrelationAttributeInstance(
482  aType,
483  md5,
484  corCase,
485  CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
486  file.getParentPath() + file.getName(),
487  "",
488  file.getKnown(),
489  file.getId()));
491  LOGGER.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
492  }
493  break;
494  }
495  }
496  }
497  } catch (CentralRepoException | TskCoreException ex) {
498  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
499  }
500  // If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
501  } else if (this.file != null && this.file.getSize() > 0) {
502  String md5 = this.file.getMd5Hash();
503  if (md5 != null && !md5.isEmpty()) {
504  try {
505  final CorrelationAttributeInstance.Type fileAttributeType
507  .stream()
508  .filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
509  .findAny()
510  .get();
511  //The Central Repository is not enabled
512  ret.add(new CorrelationAttributeInstance(fileAttributeType, md5, null, null, "", "", TskData.FileKnown.UNKNOWN, this.file.getId()));
513  } catch (CentralRepoException ex) {
514  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
516  LOGGER.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
517  }
518  }
519  }
520 
521  return ret;
522  }
523 
524  @Messages({"DataContentViewerOtherCases.earliestCaseNotAvailable= Not Enabled."})
529  private void setEarliestCaseDate() {
530  String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable();
531 
533  LocalDateTime earliestDate = LocalDateTime.now(DateTimeZone.UTC);
534  DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
535  try {
537  List<CorrelationCase> cases = dbManager.getCases();
538  for (CorrelationCase aCase : cases) {
539  LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate()));
540 
541  if (caseDate.isBefore(earliestDate)) {
542  earliestDate = caseDate;
543  dateStringDisplay = aCase.getCreationDate();
544  }
545 
546  }
547 
548  } catch (CentralRepoException ex) {
549  LOGGER.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
550  } catch (ParseException ex) {
551  LOGGER.log(Level.SEVERE, "Error parsing date of cases from database.", ex); // NON-NLS
552  }
553 
554  }
555  earliestCaseDate.setText(dateStringDisplay);
556  }
557 
570  private Map<UniquePathKey, OtherOccurrenceNodeInstanceData> getCorrelatedInstances(CorrelationAttributeInstance corAttr, String dataSourceName, String deviceId) {
571  // @@@ Check exception
572  try {
573  final Case openCase = Case.getCurrentCaseThrows();
574  String caseUUID = openCase.getName();
575  HashMap<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap = new HashMap<>();
576 
578  List<CorrelationAttributeInstance> instances = CentralRepository.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
579 
580  for (CorrelationAttributeInstance artifactInstance : instances) {
581 
582  // Only add the attribute if it isn't the object the user selected.
583  // We consider it to be a different object if at least one of the following is true:
584  // - the case UUID is different
585  // - the data source name is different
586  // - the data source device ID is different
587  // - the file path is different
588  if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
589  || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
590  || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
591  || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
592 
593  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
594  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
595  nodeDataMap.put(uniquePathKey, newNode);
596  }
597  }
598  }
599  if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
600  List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
601 
602  for (AbstractFile caseDbFile : caseDbFiles) {
603  addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
604  }
605  }
606  return nodeDataMap;
607  } catch (CentralRepoException ex) {
608  LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
610  LOGGER.log(Level.INFO, "Error getting artifact instances from database.", ex); // NON-NLS
611  } catch (NoCurrentCaseException ex) {
612  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
613  } catch (TskCoreException ex) {
614  // do nothing.
615  // @@@ Review this behavior
616  LOGGER.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
617  }
618 
619  return new HashMap<>(0);
620  }
621 
635  private List<AbstractFile> getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, CentralRepoException {
636  String md5 = corAttr.getCorrelationValue();
637  SleuthkitCase tsk = openCase.getSleuthkitCase();
638  List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5}));
639 
640  List<AbstractFile> caseDbArtifactInstances = new ArrayList<>();
641  for (AbstractFile fileMatch : matches) {
642  if (this.file.equals(fileMatch)) {
643  continue; // If this is the file the user clicked on
644  }
645  caseDbArtifactInstances.add(fileMatch);
646  }
647  return caseDbArtifactInstances;
648 
649  }
650 
661  private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap, AbstractFile newFile) throws TskCoreException, CentralRepoException {
662 
663  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase);
664 
665  // If the caseDB object has a notable tag associated with it, update
666  // the known status to BAD
667  if (newNode.getKnown() != TskData.FileKnown.BAD) {
668  List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
669  for (ContentTag tag : fileMatchTags) {
670  TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
671  if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
672  newNode.updateKnown(TskData.FileKnown.BAD);
673  break;
674  }
675  }
676  }
677 
678  // Make a key to see if the file is already in the map
679  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
680 
681  // If this node is already in the list, the only thing we need to do is
682  // update the known status to BAD if the caseDB version had known status BAD.
683  // Otherwise this is a new node so add the new node to the map.
684  if (nodeDataMap.containsKey(uniquePathKey)) {
685  if (newNode.getKnown() == TskData.FileKnown.BAD) {
686  OtherOccurrenceNodeInstanceData prevInstance = nodeDataMap.get(uniquePathKey);
687  prevInstance.updateKnown(newNode.getKnown());
688  }
689  } else {
690  nodeDataMap.put(uniquePathKey, newNode);
691  }
692  }
693 
694  @Override
695  public boolean isSupported(Node node) {
696 
697  // Is supported if one of the following is true:
698  // - The central repo is enabled and the node has correlatable content
699  // (either through the MD5 hash of the associated file or through a BlackboardArtifact)
700  // - The central repo is disabled and the backing file has a valid MD5 hash
701  this.file = this.getAbstractFileFromNode(node);
703  return !getCorrelationAttributesFromNode(node).isEmpty();
704  } else {
705  return this.file != null
706  && this.file.getSize() > 0
707  && ((this.file.getMd5Hash() != null) && (!this.file.getMd5Hash().isEmpty()));
708  }
709  }
710 
711  @Override
712  public void setNode(Node node) {
713 
714  reset(); // reset the table to empty.
715  if (node == null) {
716  return;
717  }
718  //could be null
719  this.file = this.getAbstractFileFromNode(node);
720  populateTable(node);
721 
722  }
723 
730  @Messages({
731  "DataContentViewerOtherCases.dataSources.header.text=Data Source Name",
732  "DataContentViewerOtherCases.foundIn.text=Found %d instances in %d cases and %d data sources."
733  })
734  private void populateTable(Node node) {
735  try {
736  if (this.file != null) {
737  Content dataSource = this.file.getDataSource();
738  dataSourceName = dataSource.getName();
739  deviceId = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
740  }
741  } catch (TskException | NoCurrentCaseException ex) {
742  // do nothing.
743  // @@@ Review this behavior
744  }
745 
746  // get the attributes we can correlate on
747  correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
748  Map<String, CorrelationCase> caseNames = new HashMap<>();
749  int totalCount = 0;
750  Set<String> dataSources = new HashSet<>();
751  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
752  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
753 
754  // get correlation and reference set instances from DB
755  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
756  for (OtherOccurrenceNodeInstanceData nodeData : correlatedNodeDataMap.values()) {
757  if (nodeData.isCentralRepoNode()) {
758  try {
759  dataSources.add(makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
760  caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase());
761  } catch (CentralRepoException ex) {
762  LOGGER.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex);
763  }
764  } else {
765  try {
766  dataSources.add(makeDataSourceString(Case.getCurrentCaseThrows().getName(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
768  } catch (NoCurrentCaseException ex) {
769  LOGGER.log(Level.WARNING, "No current case open for other occurrences", ex);
770  }
771  }
772  totalCount++;
773  }
774  }
775  for (CorrelationCase corCase : caseNames.values()) {
776  casesTableModel.addCorrelationCase(new CorrelationCaseWrapper(corCase));
777  }
778  int caseCount = casesTableModel.getRowCount();
779  if (correlationAttributes.isEmpty()) {
780  casesTableModel.addCorrelationCase(NO_ARTIFACTS_CASE);
781  } else if (caseCount == 0) {
782  casesTableModel.addCorrelationCase(NO_RESULTS_CASE);
783  }
784  setEarliestCaseDate();
785  foundInLabel.setText(String.format(Bundle.DataContentViewerOtherCases_foundIn_text(), totalCount, caseCount, dataSources.size()));
786  if (caseCount > 0) {
787  casesTable.setRowSelectionInterval(0, 0);
788  }
789  }
790 
795  private String makeDataSourceString(String caseUUID, String deviceId, String dataSourceName) {
796  return caseUUID + deviceId + dataSourceName;
797  }
798 
802  private void updateOnCaseSelection() {
803  int[] selectedCaseIndexes = casesTable.getSelectedRows();
804  dataSourcesTableModel.clearTable();
805  filesTableModel.clearTable();
806 
807  if (selectedCaseIndexes.length == 0) {
808  //special case when no cases are selected
809  occurrencePanel = new OccurrencePanel();
810  occurrencePanel.getPreferredSize();
811  detailsPanelScrollPane.setViewportView(occurrencePanel);
812  } else {
813  String currentCaseName;
814  try {
815  currentCaseName = Case.getCurrentCaseThrows().getName();
816  } catch (NoCurrentCaseException ex) {
817  currentCaseName = null;
818  LOGGER.log(Level.WARNING, "Unable to get current case for other occurrences content viewer", ex);
819  }
820  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
821  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
822 
823  // get correlation and reference set instances from DB
824  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
825  for (OtherOccurrenceNodeInstanceData nodeData : correlatedNodeDataMap.values()) {
826  for (int selectedRow : selectedCaseIndexes) {
827  try {
828  if (nodeData.isCentralRepoNode()) {
829  if (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)) != null
830  && casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())) {
831  dataSourcesTableModel.addNodeData(nodeData);
832  }
833  } else if (currentCaseName != null && (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(currentCaseName))) {
834  dataSourcesTableModel.addNodeData(nodeData);
835  }
836  } catch (CentralRepoException ex) {
837  LOGGER.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
838  }
839  }
840  }
841  }
842  if (dataSourcesTable.getRowCount() > 0) {
843  dataSourcesTable.setRowSelectionInterval(0, 0);
844  }
845  }
846  }
847 
853  int[] selectedDataSources = dataSourcesTable.getSelectedRows();
854  filesTableModel.clearTable();
855  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
856  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
857 
858  // get correlation and reference set instances from DB
859  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
860  for (OtherOccurrenceNodeInstanceData nodeData : correlatedNodeDataMap.values()) {
861  for (int selectedDataSourceRow : selectedDataSources) {
862  try {
863  if (nodeData.isCentralRepoNode()) {
864  if (dataSourcesTableModel.getCaseUUIDForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())
865  && dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
866  filesTableModel.addNodeData(nodeData);
867  }
868  } else {
869  if (dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
870  filesTableModel.addNodeData(nodeData);
871  }
872  }
873  } catch (CentralRepoException ex) {
874  LOGGER.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
875  }
876  }
877  }
878  }
879  if (filesTable.getRowCount() > 0) {
880  filesTable.setRowSelectionInterval(0, 0);
881  }
882  }
883 
888  private void updateOnFileSelection() {
889  if (filesTable.getSelectedRowCount() == 1) {
890  //if there is one file selected update the deatils to show the data for that file
891  occurrencePanel = new OccurrencePanel(filesTableModel.getListOfNodesForFile(filesTable.convertRowIndexToModel(filesTable.getSelectedRow())));
892  } else if (dataSourcesTable.getSelectedRowCount() == 1) {
893  //if no files were selected and only one data source is selected update the information to reflect the data source
894  String caseName = dataSourcesTableModel.getCaseNameForRow(dataSourcesTable.convertRowIndexToModel(dataSourcesTable.getSelectedRow()));
895  String dsName = dataSourcesTableModel.getValueAt(dataSourcesTable.convertRowIndexToModel(dataSourcesTable.getSelectedRow()), 0).toString();
896  String caseCreatedDate = "";
897  for (int row : casesTable.getSelectedRows()) {
898  if (casesTableModel.getValueAt(casesTable.convertRowIndexToModel(row), 0).toString().equals(caseName)) {
899  caseCreatedDate = getCaseCreatedDate(row);
900  break;
901  }
902  }
903  occurrencePanel = new OccurrencePanel(caseName, caseCreatedDate, dsName);
904  } else if (casesTable.getSelectedRowCount() == 1) {
905  //if no files were selected and a number of data source other than 1 are selected
906  //update the information to reflect the case
907  String createdDate = "";
908  String caseName = "";
909  if (casesTable.getRowCount() > 0) {
910  caseName = casesTableModel.getValueAt(casesTable.convertRowIndexToModel(casesTable.getSelectedRow()), 0).toString();
911  }
912  if (caseName.isEmpty()) {
913  occurrencePanel = new OccurrencePanel();
914  } else {
915  createdDate = getCaseCreatedDate(casesTable.getSelectedRow());
916  occurrencePanel = new OccurrencePanel(caseName, createdDate);
917  }
918  } else {
919  //else display an empty details area
920  occurrencePanel = new OccurrencePanel();
921  }
922  //calling getPreferredSize has a side effect of ensuring it has a preferred size which reflects the contents which are visible
923  occurrencePanel.getPreferredSize();
924  detailsPanelScrollPane.setViewportView(occurrencePanel);
925  }
926 
935  private String getCaseCreatedDate(int caseTableRowIdx) {
936  try {
938  CorrelationCase partialCase;
939  partialCase = casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(caseTableRowIdx));
940  if (partialCase == null) {
941  return "";
942  }
943  return CentralRepository.getInstance().getCaseByUUID(partialCase.getCaseUUID()).getCreationDate();
944  } else {
946  }
947  } catch (CentralRepoException ex) {
948  LOGGER.log(Level.WARNING, "Error getting case created date for row: " + caseTableRowIdx, ex);
949  }
950  return "";
951  }
952 
958  @SuppressWarnings("unchecked")
959  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
960  private void initComponents() {
961 
962  rightClickPopupMenu = new javax.swing.JPopupMenu();
963  exportToCSVMenuItem = new javax.swing.JMenuItem();
964  showCaseDetailsMenuItem = new javax.swing.JMenuItem();
965  showCommonalityMenuItem = new javax.swing.JMenuItem();
966  CSVFileChooser = new javax.swing.JFileChooser();
967  tableContainerPanel = new javax.swing.JPanel();
968  earliestCaseLabel = new javax.swing.JLabel();
969  earliestCaseDate = new javax.swing.JLabel();
970  foundInLabel = new javax.swing.JLabel();
971  tablesViewerSplitPane = new javax.swing.JSplitPane();
972  caseDatasourceFileSplitPane = new javax.swing.JSplitPane();
973  caseDatasourceSplitPane = new javax.swing.JSplitPane();
974  caseScrollPane = new javax.swing.JScrollPane();
975  casesTable = new javax.swing.JTable();
976  dataSourceScrollPane = new javax.swing.JScrollPane();
977  dataSourcesTable = new javax.swing.JTable();
978  filesTableScrollPane = new javax.swing.JScrollPane();
979  filesTable = new javax.swing.JTable();
980  detailsPanelScrollPane = new javax.swing.JScrollPane();
981 
982  rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
983  public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
984  }
985  public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
986  }
987  public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
988  rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
989  }
990  });
991 
992  org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
993  rightClickPopupMenu.add(exportToCSVMenuItem);
994 
995  org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
996  rightClickPopupMenu.add(showCaseDetailsMenuItem);
997 
998  org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
999  rightClickPopupMenu.add(showCommonalityMenuItem);
1000 
1001  setMinimumSize(new java.awt.Dimension(1000, 10));
1002  setOpaque(false);
1003  setPreferredSize(new java.awt.Dimension(1000, 63));
1004 
1005  tableContainerPanel.setPreferredSize(new java.awt.Dimension(600, 63));
1006  tableContainerPanel.setRequestFocusEnabled(false);
1007 
1008  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.text")); // NOI18N
1009  earliestCaseLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.toolTipText")); // NOI18N
1010 
1011  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N
1012 
1013  org.openide.awt.Mnemonics.setLocalizedText(foundInLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.foundInLabel.text")); // NOI18N
1014 
1015  tablesViewerSplitPane.setDividerLocation(450);
1016  tablesViewerSplitPane.setResizeWeight(0.75);
1017 
1018  caseDatasourceFileSplitPane.setDividerLocation(300);
1019  caseDatasourceFileSplitPane.setResizeWeight(0.66);
1020  caseDatasourceFileSplitPane.setToolTipText("");
1021 
1022  caseDatasourceSplitPane.setDividerLocation(150);
1023  caseDatasourceSplitPane.setResizeWeight(0.5);
1024 
1025  caseScrollPane.setPreferredSize(new java.awt.Dimension(150, 30));
1026 
1027  casesTable.setAutoCreateRowSorter(true);
1028  casesTable.setModel(casesTableModel);
1029  caseScrollPane.setViewportView(casesTable);
1030 
1031  caseDatasourceSplitPane.setLeftComponent(caseScrollPane);
1032 
1033  dataSourceScrollPane.setPreferredSize(new java.awt.Dimension(150, 30));
1034 
1035  dataSourcesTable.setAutoCreateRowSorter(true);
1036  dataSourcesTable.setModel(dataSourcesTableModel);
1037  dataSourceScrollPane.setViewportView(dataSourcesTable);
1038 
1039  caseDatasourceSplitPane.setRightComponent(dataSourceScrollPane);
1040 
1041  caseDatasourceFileSplitPane.setLeftComponent(caseDatasourceSplitPane);
1042 
1043  filesTableScrollPane.setPreferredSize(new java.awt.Dimension(150, 30));
1044 
1045  filesTable.setAutoCreateRowSorter(true);
1046  filesTable.setModel(filesTableModel);
1047  filesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
1048  filesTable.setComponentPopupMenu(rightClickPopupMenu);
1049  filesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
1050  filesTableScrollPane.setViewportView(filesTable);
1051 
1052  caseDatasourceFileSplitPane.setRightComponent(filesTableScrollPane);
1053 
1054  tablesViewerSplitPane.setLeftComponent(caseDatasourceFileSplitPane);
1055 
1056  detailsPanelScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
1057  detailsPanelScrollPane.setPreferredSize(new java.awt.Dimension(300, 100));
1058  tablesViewerSplitPane.setRightComponent(detailsPanelScrollPane);
1059 
1060  javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
1061  tableContainerPanel.setLayout(tableContainerPanelLayout);
1062  tableContainerPanelLayout.setHorizontalGroup(
1063  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
1064  .addGroup(tableContainerPanelLayout.createSequentialGroup()
1065  .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
1066  .addGroup(tableContainerPanelLayout.createSequentialGroup()
1067  .addComponent(earliestCaseLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 161, javax.swing.GroupLayout.PREFERRED_SIZE)
1068  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
1069  .addComponent(earliestCaseDate, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
1070  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
1071  .addComponent(foundInLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
1072  .addComponent(tablesViewerSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 990, Short.MAX_VALUE))
1073  .addContainerGap())
1074  );
1075  tableContainerPanelLayout.setVerticalGroup(
1076  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
1077  .addGroup(tableContainerPanelLayout.createSequentialGroup()
1078  .addGap(0, 0, 0)
1079  .addComponent(tablesViewerSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 33, Short.MAX_VALUE)
1080  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
1081  .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
1082  .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
1083  .addComponent(earliestCaseLabel)
1084  .addComponent(earliestCaseDate))
1085  .addComponent(foundInLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
1086  .addContainerGap())
1087  );
1088 
1089  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
1090  this.setLayout(layout);
1091  layout.setHorizontalGroup(
1092  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
1093  .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1000, Short.MAX_VALUE)
1094  );
1095  layout.setVerticalGroup(
1096  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
1097  .addGroup(layout.createSequentialGroup()
1098  .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 64, Short.MAX_VALUE)
1099  .addGap(0, 0, 0))
1100  );
1101  }// </editor-fold>//GEN-END:initComponents
1102 
1103  private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
1104  boolean enableCentralRepoActions = false;
1105  if (CentralRepository.isEnabled() && filesTable.getSelectedRowCount() == 1) {
1106  int rowIndex = filesTable.getSelectedRow();
1107  List<OtherOccurrenceNodeData> selectedFile = filesTableModel.getListOfNodesForFile(rowIndex);
1108  if (!selectedFile.isEmpty() && selectedFile.get(0) instanceof OtherOccurrenceNodeInstanceData) {
1109  OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) selectedFile.get(0);
1110  enableCentralRepoActions = instanceData.isCentralRepoNode();
1111  }
1112  }
1113  showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
1114  showCommonalityMenuItem.setVisible(enableCentralRepoActions);
1115  }//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
1116 
1117  // Variables declaration - do not modify//GEN-BEGIN:variables
1118  private javax.swing.JFileChooser CSVFileChooser;
1119  private javax.swing.JSplitPane caseDatasourceFileSplitPane;
1120  private javax.swing.JSplitPane caseDatasourceSplitPane;
1121  private javax.swing.JScrollPane caseScrollPane;
1122  private javax.swing.JTable casesTable;
1123  private javax.swing.JScrollPane dataSourceScrollPane;
1124  private javax.swing.JTable dataSourcesTable;
1125  private javax.swing.JScrollPane detailsPanelScrollPane;
1126  private javax.swing.JLabel earliestCaseDate;
1127  private javax.swing.JLabel earliestCaseLabel;
1128  private javax.swing.JMenuItem exportToCSVMenuItem;
1129  private javax.swing.JTable filesTable;
1130  private javax.swing.JScrollPane filesTableScrollPane;
1131  private javax.swing.JLabel foundInLabel;
1132  private javax.swing.JPopupMenu rightClickPopupMenu;
1133  private javax.swing.JMenuItem showCaseDetailsMenuItem;
1134  private javax.swing.JMenuItem showCommonalityMenuItem;
1135  private javax.swing.JPanel tableContainerPanel;
1136  private javax.swing.JSplitPane tablesViewerSplitPane;
1137  // End of variables declaration//GEN-END:variables
1138 
1143  private static final class UniquePathKey {
1144 
1145  private final String dataSourceID;
1146  private final String filePath;
1147  private final String type;
1148  private final String caseUUID;
1149 
1150  UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) {
1151  super();
1152  dataSourceID = nodeData.getDeviceID();
1153  if (nodeData.getFilePath() != null) {
1154  filePath = nodeData.getFilePath().toLowerCase();
1155  } else {
1156  filePath = null;
1157  }
1158  type = nodeData.getType();
1159  String tempCaseUUID;
1160  try {
1161  tempCaseUUID = nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID();
1162  } catch (CentralRepoException ignored) {
1163  //non central repo nodeData won't have a correlation case
1164  try {
1165  tempCaseUUID = Case.getCurrentCaseThrows().getName();
1166  //place holder value will be used since correlation attribute was unavailble
1167  } catch (NoCurrentCaseException ex) {
1168  LOGGER.log(Level.WARNING, "Unable to get current case", ex);
1169  tempCaseUUID = UUID_PLACEHOLDER_STRING;
1170  }
1171  }
1172  caseUUID = tempCaseUUID;
1173  }
1174 
1175  @Override
1176  public boolean equals(Object other) {
1177  if (other instanceof UniquePathKey) {
1178  UniquePathKey otherKey = (UniquePathKey) (other);
1179  return (Objects.equals(otherKey.getDataSourceID(), this.getDataSourceID())
1180  && Objects.equals(otherKey.getFilePath(), this.getFilePath())
1181  && Objects.equals(otherKey.getType(), this.getType())
1182  && Objects.equals(otherKey.getCaseUUID(), this.getCaseUUID()));
1183  }
1184  return false;
1185  }
1186 
1187  @Override
1188  public int hashCode() {
1189  return Objects.hash(getDataSourceID(), getFilePath(), getType(), getCaseUUID());
1190  }
1191 
1197  String getType() {
1198  return type;
1199  }
1200 
1206  String getFilePath() {
1207  return filePath;
1208  }
1209 
1215  String getDataSourceID() {
1216  return dataSourceID;
1217  }
1218 
1224  String getCaseUUID() {
1225  return caseUUID;
1226  }
1227  }
1228 }
String makeDataSourceString(String caseUUID, String deviceId, String dataSourceName)
List< CorrelationAttributeInstance > getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
List< CorrelationAttributeInstance.Type > getDefinedCorrelationTypes()
static List< CorrelationAttributeInstance > makeCorrAttrsForCorrelation(BlackboardArtifact artifact)
void addOrUpdateNodeData(final Case autopsyCase, Map< UniquePathKey, OtherOccurrenceNodeInstanceData > nodeDataMap, AbstractFile newFile)
int getFrequencyPercentage(CorrelationAttributeInstance corAttr)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
List< AbstractFile > getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase)
Map< UniquePathKey, OtherOccurrenceNodeInstanceData > getCorrelatedInstances(CorrelationAttributeInstance corAttr, String dataSourceName, String deviceId)

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