generic search result table node; needs work in ThreePanelDAO and DataArtifactNodev2

This commit is contained in:
Greg DiCristofaro 2021-10-06 20:17:03 -04:00
parent 3d634568b8
commit 3a43a3915f
6 changed files with 229 additions and 205 deletions

View File

@ -40,10 +40,13 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DataArtifactTypeNodev2; import org.sleuthkit.autopsy.datamodel.DataArtifactNodev2;
import org.sleuthkit.autopsy.datamodel.SearchResultChildFactory.NodeCreator;
import org.sleuthkit.autopsy.datamodel.SearchResultTableNode;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO; import org.sleuthkit.autopsy.datamodel.ThreePanelDAO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableSearchResultsDTO; import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableSearchResultsDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.RowResultDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.SearchResultsDTO;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -372,8 +375,7 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
public void displayDataArtifact(BlackboardArtifact.Type artifactType, Long dataSourceId) { public void displayDataArtifact(BlackboardArtifact.Type artifactType, Long dataSourceId) {
try { try {
DataArtifactTableSearchResultsDTO table = threePanelDAO.getDataArtifactsForTable(artifactType, dataSourceId); DataArtifactTableSearchResultsDTO table = threePanelDAO.getDataArtifactsForTable(artifactType, dataSourceId);
dataResultPanel.setNode(new DataArtifactTypeNodev2(table)); displaySearchResults(table, DataArtifactNodev2::new);
dataResultPanel.setNumberOfChildNodes(table.getTotalResultsCount());
} catch (ExecutionException | IllegalArgumentException ex) { } catch (ExecutionException | IllegalArgumentException ex) {
logger.log(Level.WARNING, MessageFormat.format( logger.log(Level.WARNING, MessageFormat.format(
"There was an error fetching data for artifact type: {0} and data source id: {1}.", "There was an error fetching data for artifact type: {0} and data source id: {1}.",
@ -382,6 +384,12 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
ex); ex);
} }
} }
public <T extends SearchResultsDTO<S>, S extends RowResultDTO> void displaySearchResults(T searchResults, NodeCreator<T, S> nodeCreator) {
dataResultPanel.setNode(new SearchResultTableNode(nodeCreator, searchResults));
dataResultPanel.setNumberOfChildNodes(
searchResults.getTotalResultsCount() > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) searchResults.getTotalResultsCount());
}
@Override @Override
public void setTitle(String title) { public void setTitle(String title) {

View File

@ -1,29 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableSearchResultsDTO;
/**
*
* @author gregd
*/
public class DataArtifactFactoryv2 extends SearchResultChildFactory<DataArtifactTableSearchResultsDTO, DataArtifactTableDTO> {
public DataArtifactFactoryv2() {
}
public DataArtifactFactoryv2(DataArtifactTableSearchResultsDTO initialResults) {
super(initialResults);
}
@Override
protected Node createNodeForKey(DataArtifactTableSearchResultsDTO searchResults, DataArtifactTableDTO itemData) {
return new DataArtifactNodev2(searchResults, itemData);
}
}

View File

@ -1,56 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.DataArtifactTableSearchResultsDTO;
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
/**
*
* @author gregd
*/
public class DataArtifactTypeNodev2 extends AbstractNode {
private final SearchResultChildFactory<?,?> factory;
public DataArtifactTypeNodev2(DataArtifactTableSearchResultsDTO initialResults) {
this(initialResults, new DataArtifactFactoryv2(initialResults));
}
private DataArtifactTypeNodev2(DataArtifactTableSearchResultsDTO initialResults, DataArtifactFactoryv2 factory) {
super(Children.create(factory, true));
this.factory = factory;
setName(initialResults.getArtifactType().getTypeName());
setDisplayName(initialResults.getArtifactType().getDisplayName());
String iconPath = IconsUtil.getIconFilePath(initialResults.getArtifactType().getTypeID());
setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
getDisplayName()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
this.factory.getResultCount()));
return sheet;
}
}

View File

@ -11,30 +11,29 @@ import java.util.stream.Collectors;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.SearchResultChildFactory.ChildKey; import org.sleuthkit.autopsy.datamodel.SearchResultChildFactory.ChildKey;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.RowResultDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.SearchResultsDTO; import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.SearchResultsDTO;
/** /**
* *
* @author gregd * @author gregd
*/ */
public abstract class SearchResultChildFactory<T extends SearchResultsDTO<S>, S> extends ChildFactory<ChildKey<S, T>> { public class SearchResultChildFactory<T extends SearchResultsDTO<S>, S extends RowResultDTO> extends ChildFactory<ChildKey<T, S>> {
private final NodeCreator<T,S> nodeCreator;
private T results; private T results;
public SearchResultChildFactory() {
this(null);
}
public SearchResultChildFactory(T initialResults) { public SearchResultChildFactory(NodeCreator<T,S> nodeCreator, T initialResults) {
this.nodeCreator = nodeCreator;
this.results = initialResults; this.results = initialResults;
} }
@Override @Override
protected boolean createKeys(List<ChildKey<S, T>> toPopulate) { protected boolean createKeys(List<ChildKey<T, S>> toPopulate) {
T results = this.results; T results = this.results;
if (results != null) { if (results != null) {
List<ChildKey<S, T>> childKeys = results.getItems().stream() List<ChildKey<T, S>> childKeys = results.getItems().stream()
.map((item) -> new ChildKey<>(results, item)) .map((item) -> new ChildKey<>(results, item))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -45,23 +44,27 @@ public abstract class SearchResultChildFactory<T extends SearchResultsDTO<S>, S>
} }
@Override @Override
protected Node createNodeForKey(ChildKey<S, T> key) { protected Node createNodeForKey(ChildKey<T, S> key) {
return createNodeForKey(key.getSearchResults(), key.getChild()); return this.nodeCreator.create(key.getSearchResults(), key.getChild());
} }
protected abstract Node createNodeForKey(T searchResults, S itemData);
public void update(T newResults) { public void update(T newResults) {
this.results = newResults; this.results = newResults;
this.refresh(false); this.refresh(false);
} }
public int getResultCount() { public long getResultCount() {
return results == null ? 0 : results.getTotalResultsCount(); return results == null ? 0 : results.getTotalResultsCount();
} }
public static interface NodeCreator<T extends SearchResultsDTO<S>, S extends RowResultDTO> {
Node create(T searchResults, S itemData);
}
static class ChildKey<S, T extends SearchResultsDTO<S>> { static class ChildKey<T, S> {
private final T searchResults; private final T searchResults;
private final S child; private final S child;

View File

@ -0,0 +1,60 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.SearchResultChildFactory.NodeCreator;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.RowResultDTO;
import org.sleuthkit.autopsy.datamodel.ThreePanelDAO.SearchResultsDTO;
/**
*
* @author gregd
*/
public class SearchResultTableNode<T extends SearchResultsDTO<S>, S extends RowResultDTO> extends AbstractNode {
private final SearchResultChildFactory<T, S> factory;
public SearchResultTableNode(NodeCreator<T,S> nodeCreator, SearchResultsDTO<S> initialResults) {
this(initialResults, new SearchResultChildFactory(nodeCreator, initialResults));
}
private SearchResultTableNode(SearchResultsDTO<S> initialResults, SearchResultChildFactory<T, S> factory) {
super(Children.create(factory, true));
this.factory = factory;
setName(initialResults.getTypeId());
setDisplayName(initialResults.getDisplayName());
// String iconPath = IconsUtil.getIconFilePath(initialResults.getArtifactType().getTypeID());
// setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
getDisplayName()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
this.factory.getResultCount()));
return sheet;
}
}

View File

@ -18,7 +18,6 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -54,7 +53,7 @@ public class ThreePanelDAO {
} }
private final Cache<DataArtifactCacheKey, DataArtifactTableSearchResultsDTO> dataArtifactCache = CacheBuilder.newBuilder().maximumSize(1000).build(); private final Cache<DataArtifactCacheKey, DataArtifactTableSearchResultsDTO> dataArtifactCache = CacheBuilder.newBuilder().maximumSize(1000).build();
private final Cache<Long, List<FilesContentTableDTO>> filesCache = CacheBuilder.newBuilder().maximumSize(1000).build(); // private final Cache<Long, List<FilesContentTableDTO>> filesCache = CacheBuilder.newBuilder().maximumSize(1000).build();
private SleuthkitCase getCase() throws NoCurrentCaseException { private SleuthkitCase getCase() throws NoCurrentCaseException {
return Case.getCurrentCaseThrows().getSleuthkitCase(); return Case.getCurrentCaseThrows().getSleuthkitCase();
@ -247,14 +246,13 @@ public class ThreePanelDAO {
// } // }
// return filesCache.get(parentId, () -> fetchChildFiles(parentId)); // return filesCache.get(parentId, () -> fetchChildFiles(parentId));
// } // }
// public void dropFilesCache() {
public void dropFilesCache() { // filesCache.invalidateAll();
filesCache.invalidateAll(); // }
} //
// public void dropFilesCache(long parentId) {
public void dropFilesCache(long parentId) { // filesCache.invalidate(parentId);
filesCache.invalidate(parentId); // }
}
private static class DataArtifactCacheKey { private static class DataArtifactCacheKey {
@ -305,32 +303,22 @@ public class ThreePanelDAO {
} }
public static class DataArtifactTableDTO { public static class DataArtifactTableDTO extends BaseRowResultDTO {
private final long id;
private final Map<Integer, Object> attributeValues;
//private final Map<Integer, Object> attributeValues;
//private final String dataSourceName;
private final DataArtifact dataArtifact; private final DataArtifact dataArtifact;
private final Content srcContent; private final Content srcContent;
private final Content linkedFile; private final Content linkedFile;
private String dataSourceName; private final boolean isTimelineSupported;
public DataArtifactTableDTO(long id, Map<Integer, Object> attributeValues, DataArtifact dataArtifact, Content srcContent, Content linkedFile, String dataSourceName) { public DataArtifactTableDTO(DataArtifact dataArtifact, Content srcContent, Content linkedFile, boolean isTimelineSupported, List<Object> cellValues, long id) {
this.id = id; super(cellValues, id);
this.attributeValues = attributeValues;
this.dataArtifact = dataArtifact; this.dataArtifact = dataArtifact;
this.srcContent = srcContent; this.srcContent = srcContent;
this.linkedFile = linkedFile; this.linkedFile = linkedFile;
this.dataSourceName = dataSourceName; this.isTimelineSupported = isTimelineSupported;
}
public long getId() {
return id;
}
public Map<Integer, Object> getAttributeValues() {
return attributeValues;
} }
public DataArtifact getDataArtifact() { public DataArtifact getDataArtifact() {
@ -345,14 +333,70 @@ public class ThreePanelDAO {
return linkedFile; return linkedFile;
} }
public String getDataSourceName() { public boolean isIsTimelineSupported() {
return dataSourceName; return isTimelineSupported;
}
}
public class ColumnKey {
private final String fieldName;
private final String displayName;
private final String description;
public ColumnKey(String fieldName, String displayName, String description) {
this.fieldName = fieldName;
this.displayName = displayName;
this.description = description;
}
public String getFieldName() {
return fieldName;
}
public String getDisplayName() {
return displayName;
}
public String getDescription() {
return description;
}
}
public interface RowResultDTO {
List<Object> getCellValues();
long getId();
}
public class BaseRowResultDTO implements RowResultDTO {
private final List<Object> cellValues;
private final long id;
public BaseRowResultDTO(List<Object> cellValues, long id) {
this.cellValues = cellValues;
this.id = id;
}
@Override
public List<Object> getCellValues() {
return cellValues;
}
@Override
public long getId() {
return id;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int hash = 7; int hash = 3;
hash = 67 * hash + (int) (this.id ^ (this.id >>> 32)); hash = 23 * hash + (int) (this.id ^ (this.id >>> 32));
return hash; return hash;
} }
@ -367,95 +411,89 @@ public class ThreePanelDAO {
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
final DataArtifactTableDTO other = (DataArtifactTableDTO) obj; final BaseRowResultDTO other = (BaseRowResultDTO) obj;
if (this.id != other.id) { if (this.id != other.id) {
return false; return false;
} }
return true; return true;
} }
} }
public interface SearchResultsDTO<T> { public interface SearchResultsDTO<R extends RowResultDTO> {
int getTotalResultsCount();
List<T> getItems(); String getTypeId();
String getDisplayName();
List<ColumnKey> getColumns();
List<R> getItems();
long getTotalResultsCount();
} }
public static class DataArtifactTableSearchResultsDTO implements SearchResultsDTO<DataArtifactTableDTO> { public class BaseSearchResultsDTO<R extends RowResultDTO> implements SearchResultsDTO<R> {
private final BlackboardArtifact.Type artifactType; private final String typeId;
private final List<BlackboardAttribute.Type> attributeTypes; private final String displayName;
private final List<DataArtifactTableDTO> items; private final List<ColumnKey> columns;
private final int totalResultsCount; private final List<R> items;
private final long totalResultsCount;
public DataArtifactTableSearchResultsDTO(BlackboardArtifact.Type artifactType, List<BlackboardAttribute.Type> attributeKeys, List<DataArtifactTableDTO> items) { public BaseSearchResultsDTO(String typeId, String displayName, List<ColumnKey> columns, List<R> items) {
this(artifactType, attributeKeys, items, items.size()); this(typeId, displayName, columns, items, items == null ? 0 : items.size());
} }
public BaseSearchResultsDTO(String typeId, String displayName, List<ColumnKey> columns, List<R> items, long totalResultsCount) {
public DataArtifactTableSearchResultsDTO(BlackboardArtifact.Type artifactType, List<BlackboardAttribute.Type> attributeKeys, List<DataArtifactTableDTO> items, int totalResultsCount) { this.typeId = typeId;
this.artifactType = artifactType; this.displayName = displayName;
this.attributeTypes = attributeKeys; this.columns = columns;
this.items = items; this.items = items;
this.totalResultsCount = totalResultsCount; this.totalResultsCount = totalResultsCount;
} }
@Override
public String getTypeId() {
return typeId;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public List<ColumnKey> getColumns() {
return columns;
}
@Override
public List<R> getItems() {
return items;
}
@Override
public long getTotalResultsCount() {
return totalResultsCount;
}
}
public static class DataArtifactTableSearchResultsDTO extends BaseSearchResultsDTO<DataArtifactTableDTO> {
private static final String TYPE_ID = "DATA_ARTIFACT";
private final BlackboardArtifact.Type artifactType;
public DataArtifactTableSearchResultsDTO(BlackboardArtifact.Type artifactType, List<ColumnKey> columns, List<DataArtifactTableDTO> items) {
super(TYPE_ID, artifactType.getDisplayName(), columns, items);
this.artifactType = artifactType;
}
public BlackboardArtifact.Type getArtifactType() { public BlackboardArtifact.Type getArtifactType() {
return artifactType; return artifactType;
} }
public List<BlackboardAttribute.Type> getAttributeTypes() {
return attributeTypes;
}
@Override
public List<DataArtifactTableDTO> getItems() {
return items;
}
@Override
public int getTotalResultsCount() {
return totalResultsCount;
}
}
public enum FilesType {
DIR,
FILE
}
public static class FilesContentTableDTO {
private final Content content;
private final String displayName;
private final String extension;
private final long id;
public FilesContentTableDTO(Content content, String displayName, String extension, long id) {
this.content = content;
this.displayName = displayName;
this.extension = extension;
this.id = id;
}
public Content getContent() {
return content;
}
public String getDisplayName() {
return displayName;
}
public String getExtension() {
return extension;
}
public long getId() {
return id;
}
} }
} }