diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form
index 60667bae46..7b9e47c236 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form
@@ -80,7 +80,7 @@
-
+
@@ -106,7 +106,7 @@
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
index 8ead475d95..c3558a106b 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
@@ -126,7 +126,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
showCommonalityDetails();
} else if (jmi.equals(addCommentMenuItem)) {
try {
- OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow());
+ OtherOccurrenceNodeInstanceData selectedNode = (OtherOccurrenceNodeInstanceData) tableModel.getRow(otherCasesTable.getSelectedRow());
AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute());
String currentComment = action.addEditCentralRepoComment();
selectedNode.updateComment(currentComment);
@@ -205,7 +205,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
if (-1 != selectedRowViewIdx) {
EamDb dbManager = EamDb.getInstance();
int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
- OtherOccurrenceNodeData nodeData = (OtherOccurrenceNodeData) tableModel.getRow(selectedRowModelIdx);
+ OtherOccurrenceNodeInstanceData nodeData = (OtherOccurrenceNodeInstanceData) tableModel.getRow(selectedRowModelIdx);
CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase();
if (eamCasePartial == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
@@ -504,13 +504,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
*
* @return A collection of correlated artifact instances
*/
- private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
+ private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception
try {
final Case openCase = Case.getCurrentCase();
String caseUUID = openCase.getName();
- HashMap nodeDataMap = new HashMap<>();
+ HashMap nodeDataMap = new HashMap<>();
if (EamDb.isEnabled()) {
List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
@@ -528,7 +528,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
|| !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
- OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
+ OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
UniquePathKey uniquePathKey = new UniquePathKey(newNode);
nodeDataMap.put(uniquePathKey, newNode);
}
@@ -592,9 +592,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* @throws TskCoreException
* @throws EamDbException
*/
- private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
+ private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
- OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase);
+ OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase);
// If the caseDB object has a notable tag associated with it, update
// the known status to BAD
@@ -617,7 +617,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// Otherwise this is a new node so add the new node to the map.
if (nodeDataMap.containsKey(uniquePathKey)) {
if (newNode.getKnown() == TskData.FileKnown.BAD) {
- OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey);
+ OtherOccurrenceNodeInstanceData prevInstance = nodeDataMap.get(uniquePathKey);
prevInstance.updateKnown(newNode.getKnown());
}
} else {
@@ -663,8 +663,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
*
* @param node The node being viewed.
*/
- @Messages({"DataContentViewerOtherCases.table.isempty=There are no associated artifacts or files from other occurrences to display.",
- "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."})
+ @Messages({
+ "DataContentViewerOtherCases.table.noResultsFound=No results found.",
+ "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."
+ })
private void populateTable(Node node) {
String dataSourceName = "";
String deviceId = "";
@@ -682,7 +684,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// get the attributes we can correlate on
correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
for (CorrelationAttribute corAttr : correlationAttributes) {
- Map correlatedNodeDataMap = new HashMap<>(0);
+ Map correlatedNodeDataMap = new HashMap<>(0);
// get correlation and reference set instances from DB
correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
@@ -697,7 +699,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// @@@ BC: We should have a more descriptive message than this. Mention that the file didn't have a MD5, etc.
displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts());
} else if (0 == tableModel.getRowCount()) {
- displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty());
+ tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound()));
} else {
clearMessageOnTableStatusPanel();
setColumnWidths();
@@ -877,8 +879,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
int rowIndex = otherCasesTable.getSelectedRow();
OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
- if (selectedNode.isCentralRepoNode()) {
- enableCentralRepoActions = true;
+ if (selectedNode instanceof OtherOccurrenceNodeInstanceData) {
+ OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) selectedNode;
+ enableCentralRepoActions = instanceData.isCentralRepoNode();
}
}
@@ -915,7 +918,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private final String filePath;
private final String type;
- UniquePathKey(OtherOccurrenceNodeData nodeData) {
+ UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) {
super();
dataSourceID = nodeData.getDeviceID();
if (nodeData.getFilePath() != null) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java
index 5febf88dc3..0d7018885c 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java
@@ -1,7 +1,7 @@
/*
* Central Repository
*
- * Copyright 2015-2017 Basis Technology Corp.
+ * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,8 +22,6 @@ import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
/**
* Model for cells in data content viewer table
@@ -34,7 +32,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
"DataContentViewerOtherCasesTableModel.device=Device",
"DataContentViewerOtherCasesTableModel.dataSource=Data Source",
"DataContentViewerOtherCasesTableModel.path=Path",
- "DataContentViewerOtherCasesTableModel.type=Correlation Type",
+ "DataContentViewerOtherCasesTableModel.property=Correlation Property",
"DataContentViewerOtherCasesTableModel.value=Correlation Value",
"DataContentViewerOtherCasesTableModel.known=Known",
"DataContentViewerOtherCasesTableModel.comment=Comment",
@@ -44,7 +42,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.DataContentViewerOtherCasesTableModel_case(), 100),
DATA_SOURCE(Bundle.DataContentViewerOtherCasesTableModel_dataSource(), 100),
- TYPE(Bundle.DataContentViewerOtherCasesTableModel_type(), 100),
+ PROPERTY(Bundle.DataContentViewerOtherCasesTableModel_property(), 125),
VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 200),
KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 50),
FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 450),
@@ -126,38 +124,49 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
*/
private Object mapValueById(int rowIdx, TableColumns colId) {
OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx);
+
+ if (nodeData instanceof OtherOccurrenceNodeMessageData) {
+ if (colId == TableColumns.CASE_NAME) {
+ OtherOccurrenceNodeMessageData messageData = (OtherOccurrenceNodeMessageData) nodeData;
+ return messageData.getDisplayMessage();
+ } else {
+ return "";
+ }
+ }
+
+ OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) nodeData;
String value = Bundle.DataContentViewerOtherCasesTableModel_noData();
switch (colId) {
case CASE_NAME:
- if (null != nodeData.getCaseName()) {
- value = nodeData.getCaseName();
+ if (null != instanceData.getCaseName()) {
+ value = instanceData.getCaseName();
}
break;
case DEVICE:
- if (null != nodeData.getDeviceID()) {
- value = nodeData.getDeviceID();
+ if (null != instanceData.getDeviceID()) {
+ value = instanceData.getDeviceID();
}
break;
case DATA_SOURCE:
- if (null != nodeData.getDataSourceName()) {
- value = nodeData.getDataSourceName();
+ if (null != instanceData.getDataSourceName()) {
+ value = instanceData.getDataSourceName();
}
break;
case FILE_PATH:
- value = nodeData.getFilePath();
+ value = instanceData.getFilePath();
break;
- case TYPE:
- value = nodeData.getType();
+ case PROPERTY:
+ value = instanceData.getType();
break;
case VALUE:
- value = nodeData.getValue();
+ value = instanceData.getValue();
break;
case KNOWN:
- value = nodeData.getKnown().getName();
+ value = instanceData.getKnown().getName();
break;
case COMMENT:
- value = nodeData.getComment();
+ value = instanceData.getComment();
break;
}
return value;
@@ -178,6 +187,9 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
fireTableDataChanged();
}
+ /**
+ * Clear the node data table.
+ */
void clearTable() {
nodeDataList.clear();
fireTableDataChanged();
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java
old mode 100644
new mode 100755
index 958068fb14..c10f078313
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java
@@ -1,5 +1,5 @@
/*
- * Central Repository
+ * Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier sleuthkit org
@@ -18,216 +18,9 @@
*/
package org.sleuthkit.autopsy.centralrepository.contentviewer;
-import org.sleuthkit.autopsy.casemodule.Case;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
-import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
-import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.DataSource;
-import org.sleuthkit.datamodel.TskCoreException;
-import org.sleuthkit.datamodel.TskData;
-import org.sleuthkit.datamodel.TskDataException;
-
/**
- * Class for populating the Other Occurrences tab
+ * Marker interface for Other Occurrences nodes.
*/
-class OtherOccurrenceNodeData {
+interface OtherOccurrenceNodeData {
- // For now hard code the string for the central repo files type, since
- // getting it dynamically can fail.
- private static final String FILE_TYPE_STR = "Files";
-
- private final String caseName;
- private String deviceID;
- private String dataSourceName;
- private final String filePath;
- private final String typeStr;
- private final CorrelationAttribute.Type type;
- private final String value;
- private TskData.FileKnown known;
- private String comment;
-
- private AbstractFile originalAbstractFile = null;
- private CorrelationAttributeInstance originalCorrelationInstance = null;
-
- /**
- * Create a node from a central repo instance.
- * @param instance The central repo instance
- * @param type The type of the instance
- * @param value The value of the instance
- */
- OtherOccurrenceNodeData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) {
- caseName = instance.getCorrelationCase().getDisplayName();
- deviceID = instance.getCorrelationDataSource().getDeviceID();
- dataSourceName = instance.getCorrelationDataSource().getName();
- filePath = instance.getFilePath();
- this.typeStr = type.getDisplayName();
- this.type = type;
- this.value = value;
- known = instance.getKnownStatus();
- comment = instance.getComment();
-
- originalCorrelationInstance = instance;
- }
-
- /**
- * Create a node from an abstract file.
- * @param newFile The abstract file
- * @param autopsyCase The current case
- * @throws EamDbException
- */
- OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException {
- caseName = autopsyCase.getDisplayName();
- try {
- DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId());
- deviceID = dataSource.getDeviceId();
- dataSourceName = dataSource.getName();
- } catch (TskDataException | TskCoreException ex) {
- throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex);
- }
-
- filePath = newFile.getParentPath() + newFile.getName();
- typeStr = FILE_TYPE_STR;
- this.type = null;
- value = newFile.getMd5Hash();
- known = newFile.getKnown();
- comment = "";
-
- originalAbstractFile = newFile;
- }
-
- /**
- * Check if this node is a "file" type
- * @return true if it is a file type
- */
- boolean isFileType() {
- return FILE_TYPE_STR.equals(typeStr);
- }
-
- /**
- * Update the known status for this node
- * @param newKnownStatus The new known status
- */
- void updateKnown(TskData.FileKnown newKnownStatus) {
- known = newKnownStatus;
- }
-
- /**
- * Update the comment for this node
- * @param newComment The new comment
- */
- void updateComment(String newComment) {
- comment = newComment;
- }
-
- /**
- * Check if this is a central repo node.
- * @return true if this node was created from a central repo instance, false otherwise
- */
- boolean isCentralRepoNode() {
- return (originalCorrelationInstance != null);
- }
-
- /**
- * Uses the saved instance plus type and value to make a new CorrelationAttribute.
- * Should only be called if isCentralRepoNode() is true.
- * @return the newly created CorrelationAttribute
- */
- CorrelationAttribute createCorrelationAttribute() throws EamDbException {
- if (! isCentralRepoNode() ) {
- throw new EamDbException("Can not create CorrelationAttribute for non central repo node");
- }
- CorrelationAttribute attr = new CorrelationAttribute(type, value);
- attr.addInstance(originalCorrelationInstance);
- return attr;
- }
-
- /**
- * Get the case name
- * @return the case name
- */
- String getCaseName() {
- return caseName;
- }
-
- /**
- * Get the device ID
- * @return the device ID
- */
- String getDeviceID() {
- return deviceID;
- }
-
- /**
- * Get the data source name
- * @return the data source name
- */
- String getDataSourceName() {
- return dataSourceName;
- }
-
- /**
- * Get the file path
- * @return the file path
- */
- String getFilePath() {
- return filePath;
- }
-
- /**
- * Get the type (as a string)
- * @return the type
- */
- String getType() {
- return typeStr;
- }
-
- /**
- * Get the value (MD5 hash for files)
- * @return the value
- */
- String getValue() {
- return value;
- }
-
- /**
- * Get the known status
- * @return the known status
- */
- TskData.FileKnown getKnown() {
- return known;
- }
-
- /**
- * Get the comment
- * @return the comment
- */
- String getComment() {
- return comment;
- }
-
- /**
- * Get the backing abstract file.
- * Should only be called if isCentralRepoNode() is false
- * @return the original abstract file
- */
- AbstractFile getAbstractFile() throws EamDbException {
- if (originalCorrelationInstance == null) {
- throw new EamDbException("AbstractFile is null");
- }
- return originalAbstractFile;
- }
-
- /**
- * Get the backing CorrelationAttributeInstance.
- * Should only be called if isCentralRepoNode() is true
- * @return the original CorrelationAttributeInstance
- * @throws EamDbException
- */
- CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException {
- if (originalCorrelationInstance == null) {
- throw new EamDbException("CorrelationAttributeInstance is null");
- }
- return originalCorrelationInstance;
- }
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java
new file mode 100644
index 0000000000..7eb907aba8
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java
@@ -0,0 +1,233 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 Basis Technology Corp.
+ * Contact: carrier sleuthkit org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.centralrepository.contentviewer;
+
+import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
+import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.DataSource;
+import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
+import org.sleuthkit.datamodel.TskDataException;
+
+/**
+ * Class for populating the Other Occurrences tab
+ */
+class OtherOccurrenceNodeInstanceData implements OtherOccurrenceNodeData {
+
+ // For now hard code the string for the central repo files type, since
+ // getting it dynamically can fail.
+ private static final String FILE_TYPE_STR = "Files";
+
+ private final String caseName;
+ private String deviceID;
+ private String dataSourceName;
+ private final String filePath;
+ private final String typeStr;
+ private final CorrelationAttribute.Type type;
+ private final String value;
+ private TskData.FileKnown known;
+ private String comment;
+
+ private AbstractFile originalAbstractFile = null;
+ private CorrelationAttributeInstance originalCorrelationInstance = null;
+
+ /**
+ * Create a node from a central repo instance.
+ * @param instance The central repo instance
+ * @param type The type of the instance
+ * @param value The value of the instance
+ */
+ OtherOccurrenceNodeInstanceData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) {
+ caseName = instance.getCorrelationCase().getDisplayName();
+ deviceID = instance.getCorrelationDataSource().getDeviceID();
+ dataSourceName = instance.getCorrelationDataSource().getName();
+ filePath = instance.getFilePath();
+ this.typeStr = type.getDisplayName();
+ this.type = type;
+ this.value = value;
+ known = instance.getKnownStatus();
+ comment = instance.getComment();
+
+ originalCorrelationInstance = instance;
+ }
+
+ /**
+ * Create a node from an abstract file.
+ * @param newFile The abstract file
+ * @param autopsyCase The current case
+ * @throws EamDbException
+ */
+ OtherOccurrenceNodeInstanceData(AbstractFile newFile, Case autopsyCase) throws EamDbException {
+ caseName = autopsyCase.getDisplayName();
+ try {
+ DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId());
+ deviceID = dataSource.getDeviceId();
+ dataSourceName = dataSource.getName();
+ } catch (TskDataException | TskCoreException ex) {
+ throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex);
+ }
+
+ filePath = newFile.getParentPath() + newFile.getName();
+ typeStr = FILE_TYPE_STR;
+ this.type = null;
+ value = newFile.getMd5Hash();
+ known = newFile.getKnown();
+ comment = "";
+
+ originalAbstractFile = newFile;
+ }
+
+ /**
+ * Check if this node is a "file" type
+ * @return true if it is a file type
+ */
+ boolean isFileType() {
+ return FILE_TYPE_STR.equals(typeStr);
+ }
+
+ /**
+ * Update the known status for this node
+ * @param newKnownStatus The new known status
+ */
+ void updateKnown(TskData.FileKnown newKnownStatus) {
+ known = newKnownStatus;
+ }
+
+ /**
+ * Update the comment for this node
+ * @param newComment The new comment
+ */
+ void updateComment(String newComment) {
+ comment = newComment;
+ }
+
+ /**
+ * Check if this is a central repo node.
+ * @return true if this node was created from a central repo instance, false otherwise
+ */
+ boolean isCentralRepoNode() {
+ return (originalCorrelationInstance != null);
+ }
+
+ /**
+ * Uses the saved instance plus type and value to make a new CorrelationAttribute.
+ * Should only be called if isCentralRepoNode() is true.
+ * @return the newly created CorrelationAttribute
+ */
+ CorrelationAttribute createCorrelationAttribute() throws EamDbException {
+ if (! isCentralRepoNode() ) {
+ throw new EamDbException("Can not create CorrelationAttribute for non central repo node");
+ }
+ CorrelationAttribute attr = new CorrelationAttribute(type, value);
+ attr.addInstance(originalCorrelationInstance);
+ return attr;
+ }
+
+ /**
+ * Get the case name
+ * @return the case name
+ */
+ String getCaseName() {
+ return caseName;
+ }
+
+ /**
+ * Get the device ID
+ * @return the device ID
+ */
+ String getDeviceID() {
+ return deviceID;
+ }
+
+ /**
+ * Get the data source name
+ * @return the data source name
+ */
+ String getDataSourceName() {
+ return dataSourceName;
+ }
+
+ /**
+ * Get the file path
+ * @return the file path
+ */
+ String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * Get the type (as a string)
+ * @return the type
+ */
+ String getType() {
+ return typeStr;
+ }
+
+ /**
+ * Get the value (MD5 hash for files)
+ * @return the value
+ */
+ String getValue() {
+ return value;
+ }
+
+ /**
+ * Get the known status
+ * @return the known status
+ */
+ TskData.FileKnown getKnown() {
+ return known;
+ }
+
+ /**
+ * Get the comment
+ * @return the comment
+ */
+ String getComment() {
+ return comment;
+ }
+
+ /**
+ * Get the backing abstract file.
+ * Should only be called if isCentralRepoNode() is false
+ * @return the original abstract file
+ */
+ AbstractFile getAbstractFile() throws EamDbException {
+ if (originalCorrelationInstance == null) {
+ throw new EamDbException("AbstractFile is null");
+ }
+ return originalAbstractFile;
+ }
+
+ /**
+ * Get the backing CorrelationAttributeInstance.
+ * Should only be called if isCentralRepoNode() is true
+ * @return the original CorrelationAttributeInstance
+ * @throws EamDbException
+ */
+ CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException {
+ if (originalCorrelationInstance == null) {
+ throw new EamDbException("CorrelationAttributeInstance is null");
+ }
+ return originalCorrelationInstance;
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java
new file mode 100755
index 0000000000..99e530349a
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java
@@ -0,0 +1,34 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2018 Basis Technology Corp.
+ * Contact: carrier sleuthkit org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.centralrepository.contentviewer;
+
+/**
+ * Class for populating the Other Occurrences tab with a single message.
+ */
+final class OtherOccurrenceNodeMessageData implements OtherOccurrenceNodeData {
+ private final String displayMessage;
+
+ OtherOccurrenceNodeMessageData(String displayMessage) {
+ this.displayMessage = displayMessage;
+ }
+
+ String getDisplayMessage() {
+ return displayMessage;
+ }
+}