diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED
index cde18d3900..468e6d9430 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED
@@ -72,9 +72,9 @@ DataContentViewerHex.totalPageLabel.text_1=100
DataContentViewerHex.pageLabel2.text=Page
# Product Information panel
-LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2}
-LBL_Copyright=Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
+LBL_Copyright=Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
SortChooser.dialogTitle=Choose Sort Criteria
ThumbnailViewChildren.progress.cancelling=(Cancelling)
# {0} - file name
@@ -97,7 +97,7 @@ DataContentViewerHex.goToPageTextField.text=
DataContentViewerHex.goToPageLabel.text=Go to Page:
DataResultViewerThumbnail.imagesLabel.text=Images:
DataResultViewerThumbnail.imagesRangeLabel.text=-
-DataResultViewerThumbnail.filePathLabel.text=\
+DataResultViewerThumbnail.filePathLabel.text=\ \ \
AdvancedConfigurationDialog.cancelButton.text=Cancel
DataArtifactContentViewer.waitText=Retrieving and preparing data, please wait...
DataArtifactContentViewer.errorText=Error retrieving result
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java
index 2a5e03e103..a9a0487401 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java
@@ -36,7 +36,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -51,6 +50,7 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEventUtils;
+import org.sleuthkit.autopsy.mainui.datamodel.events.KeywordHitEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeCounts;
import org.sleuthkit.autopsy.mainui.nodes.DAOFetcher;
@@ -333,18 +333,6 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
return keywordHitCache.get(searchParams, () -> fetchSetNameHitsForTable(searchParams));
}
- public void dropAnalysisResultCache() {
- analysisResultCache.invalidateAll();
- }
-
- public void dropHashHitCache() {
- setHitCache.invalidateAll();
- }
-
- public void dropKeywordHitCache() {
- keywordHitCache.invalidateAll();
- }
-
/**
* Returns a search results dto containing rows of counts data.
*
@@ -358,10 +346,22 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
*/
public TreeResultsDTO getAnalysisResultCounts(Long dataSourceId) throws ExecutionException {
try {
+
+ Set indeterminateTypes = this.treeCounts.getEnqueued().stream()
+ .filter(evt -> dataSourceId == null || Objects.equals(evt.getDataSourceId(), dataSourceId))
+ .map(evt -> evt.getArtifactType())
+ .collect(Collectors.toSet());
+
// get row dto's sorted by display name
Map typeCounts = getCounts(BlackboardArtifact.Category.ANALYSIS_RESULT, dataSourceId);
List> treeItemRows = typeCounts.entrySet().stream()
- .map(entry -> getTreeItem(entry.getKey(), dataSourceId, TreeDisplayCount.getDeterminate(entry.getValue())))
+ .map(entry -> {
+ TreeDisplayCount displayCount = indeterminateTypes.contains(entry.getKey())
+ ? TreeDisplayCount.INDETERMINATE
+ : TreeDisplayCount.getDeterminate(entry.getValue());
+
+ return getTreeItem(entry.getKey(), dataSourceId, displayCount);
+ })
.sorted(Comparator.comparing(countRow -> countRow.getDisplayName()))
.collect(Collectors.toList());
@@ -375,7 +375,7 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
private TreeItemDTO getTreeItem(BlackboardArtifact.Type type, Long dataSourceId, TreeDisplayCount displayCount) {
return new TreeItemDTO<>(
- BlackboardArtifact.Category.ANALYSIS_RESULT.name(),
+ AnalysisResultSearchParam.getTypeId(),
new AnalysisResultSearchParam(type, dataSourceId),
type.getTypeID(),
type.getDisplayName(),
@@ -458,16 +458,29 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
Long dataSourceId,
String nullSetName) throws IllegalArgumentException, ExecutionException {
+ Set indeterminateSetNames = new HashSet<>();
+ for (AnalysisResultEvent evt : this.treeCounts.getEnqueued()) {
+ if (evt instanceof AnalysisResultSetEvent
+ && (dataSourceId == null || Objects.equals(evt.getDataSourceId(), dataSourceId))
+ && evt.getArtifactType().equals(type)) {
+ indeterminateSetNames.add(((AnalysisResultSetEvent) evt).getSetName());
+ }
+ }
+
List> allSets
= getSetCountsMap(type, BlackboardAttribute.Type.TSK_SET_NAME, dataSourceId).entrySet().stream()
.filter(entry -> nullSetName != null || entry.getKey() != null)
.sorted((a, b) -> compareSetStrings(a.getKey(), b.getKey()))
.map(entry -> {
+ TreeDisplayCount displayCount = indeterminateSetNames.contains(entry.getKey())
+ ? TreeDisplayCount.INDETERMINATE
+ : TreeDisplayCount.getDeterminate(entry.getValue());
+
return getSetTreeItem(type,
dataSourceId,
entry.getKey(),
entry.getKey() == null ? nullSetName : entry.getKey(),
- TreeDisplayCount.getDeterminate(entry.getValue()));
+ displayCount);
})
.collect(Collectors.toList());
@@ -478,7 +491,7 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
Long dataSourceId, String setName, String displayName, TreeDisplayCount displayCount) {
return new TreeItemDTO<>(
- type.getTypeName(),
+ AnalysisResultSetSearchParam.getTypeId(),
new AnalysisResultSetSearchParam(type, dataSourceId, setName),
setName == null ? 0 : setName,
displayName,
@@ -528,6 +541,18 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
throw new IllegalArgumentException("Expected data source id to be > 0");
}
+ Set> indeterminateSearchTerms = new HashSet<>();
+ for (AnalysisResultEvent evt : this.treeCounts.getEnqueued()) {
+ if (evt instanceof KeywordHitEvent
+ && (dataSourceId == null || Objects.equals(evt.getDataSourceId(), dataSourceId))
+ && evt.getArtifactType().equals(BlackboardArtifact.Type.TSK_KEYWORD_HIT)
+ && Objects.equals(((KeywordHitEvent) evt).getSetName(), setName)) {
+
+ KeywordHitEvent keywordEvt = (KeywordHitEvent) evt;
+ indeterminateSearchTerms.add(Pair.of(keywordEvt.getSearchString(), keywordEvt.getSearchType()));
+ }
+ }
+
String dataSourceClause = dataSourceId == null
? ""
: "AND art.data_source_obj_id = ?\n";
@@ -599,29 +624,18 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
long count = resultSet.getLong("count");
boolean hasChildren = resultSet.getBoolean("has_children");
- String searchTermModified;
- switch (searchType) {
- case 0:
- searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_exactMatch(searchTerm == null ? "" : searchTerm);
- break;
- case 1:
- searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_substringMatch(searchTerm == null ? "" : searchTerm);
- break;
- case 2:
- searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_regexMatch(searchTerm == null ? "" : searchTerm);
- break;
- default:
- logger.log(Level.WARNING, MessageFormat.format("Non-standard search type value: {0}.", searchType));
- searchTermModified = searchTerm;
- break;
- }
+ String searchTermModified = getSearchTermDisplayName(searchTerm, searchType);
+
+ TreeDisplayCount displayCount = indeterminateSearchTerms.contains(Pair.of(searchTerm, searchType))
+ ? TreeDisplayCount.INDETERMINATE
+ : TreeDisplayCount.getDeterminate(count);
TreeItemDTO treeItem = new TreeItemDTO<>(
- "KEYWORD_SEARCH_TERMS",
+ KeywordSearchTermParams.getTypeId(),
new KeywordSearchTermParams(setName, searchTerm, searchType, hasChildren, dataSourceId),
searchTermModified,
searchTermModified,
- TreeDisplayCount.getDeterminate(count)
+ displayCount
);
items.add(treeItem);
@@ -638,6 +652,34 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
}
}
+ /**
+ * Returns the UI display name for a search term.
+ *
+ * @param searchTerm The search term.
+ * @param searchType The search type enum value.
+ *
+ * @return The display name.
+ */
+ public String getSearchTermDisplayName(String searchTerm, int searchType) {
+ String searchTermModified;
+ switch (searchType) {
+ case 0:
+ searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_exactMatch(searchTerm == null ? "" : searchTerm);
+ break;
+ case 1:
+ searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_substringMatch(searchTerm == null ? "" : searchTerm);
+ break;
+ case 2:
+ searchTermModified = Bundle.AnalysisResultDAO_getKeywordSearchTermCounts_regexMatch(searchTerm == null ? "" : searchTerm);
+ break;
+ default:
+ logger.log(Level.WARNING, MessageFormat.format("Non-standard search type value: {0}.", searchType));
+ searchTermModified = searchTerm;
+ break;
+ }
+ return searchTermModified;
+ }
+
/**
* Get counts for string matches of a particular regex/substring search
* term.
@@ -687,6 +729,23 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
+ "AND res.search_type = ?\n"
+ "GROUP BY keyword";
+ Set indeterminateMatches = new HashSet<>();
+ for (AnalysisResultEvent evt : this.treeCounts.getEnqueued()) {
+ if (evt instanceof KeywordHitEvent
+ && (dataSourceId == null || Objects.equals(evt.getDataSourceId(), dataSourceId))
+ && evt.getArtifactType().equals(BlackboardArtifact.Type.TSK_KEYWORD_HIT)) {
+
+ KeywordHitEvent keywordEvt = (KeywordHitEvent) evt;
+ if (Objects.equals(keywordEvt.getSetName(), setName)
+ && Objects.equals(keywordEvt.getSearchString(), regexStr)
+ && keywordEvt.getSearchType() == searchType) {
+
+ indeterminateMatches.add(keywordEvt.getMatch());
+ }
+
+ }
+ }
+
try (CaseDbPreparedStatement preparedStatement = getCase().getCaseDbAccessManager().prepareSelect(query)) {
// get artifact types and counts
int paramIdx = 0;
@@ -708,12 +767,17 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
String keyword = resultSet.getString("keyword");
long count = resultSet.getLong("count");
+ TreeDisplayCount displayCount = indeterminateMatches.contains(keyword)
+ ? TreeDisplayCount.INDETERMINATE
+ : TreeDisplayCount.getDeterminate(count);
+
items.add(new TreeItemDTO<>(
- "KEYWORD_MATCH",
+ KeywordMatchParams.getTypeId(),
new KeywordMatchParams(setName, regexStr, keyword, searchType, dataSourceId),
keyword,
keyword == null ? "" : keyword,
- TreeDisplayCount.getDeterminate(count)));
+ displayCount
+ ));
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "An error occurred while fetching results from result set.", ex);
@@ -735,7 +799,7 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
}
@Override
- Set processEvent(PropertyChangeEvent evt) {
+ Set extends DAOEvent> processEvent(PropertyChangeEvent evt) {
// get a grouping of artifacts mapping the artifact type id to data source id.
Map> analysisResultMap = new HashMap<>();
Map, Set> setMap = new HashMap<>();
@@ -768,16 +832,11 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
return Collections.emptySet();
}
- clearRelevantCacheEntries(analysisResultMap, setMap);
+ SubDAOUtils.invalidateKeys(this.analysisResultCache, ar -> Pair.of(ar.getArtifactType(), ar.getDataSourceId()), analysisResultMap);
+ SubDAOUtils.invalidateKeys(this.setHitCache, ar -> Pair.of(Pair.of(ar.getArtifactType(), ar.getSetName()), ar.getDataSourceId()), setMap);
- List daoEvents = getResultViewEvents(analysisResultMap, setMap);
- Collection treeEvents = this.treeCounts.enqueueAll(daoEvents).stream()
- .map(arEvt -> getTreeEvent(arEvt, false))
- .collect(Collectors.toList());
-
- return Stream.of(daoEvents, treeEvents)
- .flatMap(lst -> lst.stream())
- .collect(Collectors.toSet());
+ // GVDTODO handle keyword hits
+ return getResultViewEvents(analysisResultMap, setMap);
}
/**
@@ -793,7 +852,7 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
*
* @return The list of dao events.
*/
- private List getResultViewEvents(Map> analysisResultMap, Map, Set> resultsWithSetMap) {
+ private Set extends DAOEvent> getResultViewEvents(Map> analysisResultMap, Map, Set> resultsWithSetMap) {
Stream analysisResultEvts = analysisResultMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(dsId -> new AnalysisResultEvent(entry.getKey(), dsId)));
@@ -801,82 +860,50 @@ public class AnalysisResultDAO extends BlackboardArtifactDAO {
.flatMap(entry -> entry.getValue().stream().map(dsId -> new AnalysisResultSetEvent(entry.getKey().getRight(), entry.getKey().getLeft(), dsId)));
// GVDTODO handle keyword hits
- return Stream.of(analysisResultEvts, analysisResultSetEvts)
+
+ List daoEvents = Stream.of(analysisResultEvts, analysisResultSetEvts)
.flatMap(s -> s)
.collect(Collectors.toList());
+
+ Collection treeEvents = this.treeCounts.enqueueAll(daoEvents).stream()
+ .map(arEvt -> new TreeEvent(getTreeItem(arEvt, TreeDisplayCount.INDETERMINATE), false))
+ .collect(Collectors.toList());
+
+ return Stream.of(daoEvents, treeEvents)
+ .flatMap(lst -> lst.stream())
+ .collect(Collectors.toSet());
}
/**
- * Clears cache entries given the provided digests of autopsy events.
- *
- * @param analysisResultMap Contains the analysis results that do not use a
- * set name. A mapping of analysis result type ids
- * to data sources where the results were created.
- * @param resultsWithSetMap Contains the anlaysis results that do use a set
- * name. A mapping of (analysis result type id, set
- * name) to data sources where results were
- * created.
- */
- private void clearRelevantCacheEntries(Map> analysisResultMap, Map, Set> resultsWithSetMap) {
- ConcurrentMap, AnalysisResultTableSearchResultsDTO> arConcurrentMap = this.analysisResultCache.asMap();
- arConcurrentMap.forEach((k, v) -> {
- BlackboardArtifactSearchParam searchParam = k.getParamData();
- Set dsIds = analysisResultMap.get(searchParam.getArtifactType());
- if (dsIds != null && (searchParam.getDataSourceId() == null || dsIds.contains(searchParam.getDataSourceId()))) {
- arConcurrentMap.remove(k);
- }
- });
-
- ConcurrentMap, AnalysisResultTableSearchResultsDTO> setConcurrentMap = this.setHitCache.asMap();
- setConcurrentMap.forEach((k, v) -> {
- AnalysisResultSetSearchParam searchParam = k.getParamData();
- Set dsIds = resultsWithSetMap.get(Pair.of(searchParam.getArtifactType(), searchParam.getSetName()));
- if (dsIds != null && (searchParam.getDataSourceId() == null || dsIds.contains(searchParam.getDataSourceId()))) {
- arConcurrentMap.remove(k);
- }
- });
-
- // GVDTODO handle clearing cache for keyword search hits
- // private final Cache, AnalysisResultTableSearchResultsDTO> keywordHitCache = CacheBuilder.newBuilder().maximumSize(1000).build();
- }
-
- /**
- * Creates a TreeEvent instance based on the analysis result event and
+ * Creates a TreeItemDTO instance based on the analysis result event and
* whether or not this event should trigger a full refresh of counts.
*
- * @param arEvt The analysis result event.
- * @param shouldRefresh Whether or not this tree event should trigger a full
- * refresh of counts.
+ * @param arEvt The analysis result event.
+ * @param displayCount The count to display.
*
* @return The tree event.
*/
- private TreeEvent getTreeEvent(AnalysisResultEvent arEvt, boolean shouldRefresh) {
+ private TreeItemDTO> getTreeItem(AnalysisResultEvent arEvt, TreeDisplayCount displayCount) {
// GVDTODO handle keyword items when integrated
if (arEvt instanceof AnalysisResultSetEvent) {
AnalysisResultSetEvent setEvt = (AnalysisResultSetEvent) arEvt;
- return new TreeEvent(getSetTreeItem(setEvt.getArtifactType(), setEvt.getDataSourceId(),
+ return getSetTreeItem(setEvt.getArtifactType(), setEvt.getDataSourceId(),
setEvt.getSetName(), setEvt.getSetName() == null ? "" : setEvt.getSetName(),
- shouldRefresh ? TreeDisplayCount.UNSPECIFIED : TreeDisplayCount.INDETERMINATE),
- shouldRefresh);
+ displayCount);
} else {
- return new TreeEvent(getTreeItem(arEvt.getArtifactType(), arEvt.getDataSourceId(),
- shouldRefresh ? TreeDisplayCount.UNSPECIFIED : TreeDisplayCount.INDETERMINATE),
- shouldRefresh);
+ return getTreeItem(arEvt.getArtifactType(), arEvt.getDataSourceId(), displayCount);
}
}
@Override
- Set handleIngestComplete() {
- return this.treeCounts.flushEvents().stream()
- .map(arEvt -> getTreeEvent(arEvt, true))
- .collect(Collectors.toSet());
+ Set extends DAOEvent> handleIngestComplete() {
+ return SubDAOUtils.getIngestCompleteEvents(this.treeCounts, (arEvt, count) -> getTreeItem(arEvt, count));
}
@Override
Set shouldRefreshTree() {
- return this.treeCounts.getEventTimeouts().stream()
- .map(arEvt -> getTreeEvent(arEvt, true))
- .collect(Collectors.toSet());
+ return SubDAOUtils.getRefreshEvents(this.treeCounts, (arEvt, count) -> getTreeItem(arEvt, count));
+
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSearchParam.java
index 4f2805a650..c9ad697a82 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSearchParam.java
@@ -24,8 +24,17 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
* Key for analysis result in order to retrieve data from DAO.
*/
public class AnalysisResultSearchParam extends BlackboardArtifactSearchParam {
-
+
+ private static final String TYPE_ID = BlackboardArtifact.Category.ANALYSIS_RESULT.name();
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
public AnalysisResultSearchParam(BlackboardArtifact.Type artifactType, Long dataSourceId) {
super(artifactType, dataSourceId);
- }
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSetSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSetSearchParam.java
index 767491c3fe..ca4480d708 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSetSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultSetSearchParam.java
@@ -25,14 +25,23 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
* Base class for search params for analysis results that filter by set name.
*/
public class AnalysisResultSetSearchParam extends AnalysisResultSearchParam {
-
+
+ private static final String TYPE_ID = "ANALYSIS_RESULT_SET";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final String setName;
public AnalysisResultSetSearchParam(BlackboardArtifact.Type artifactType, Long dataSourceId, String setName) {
super(artifactType, dataSourceId);
this.setName = setName;
}
-
+
public String getSetName() {
return setName;
}
@@ -63,5 +72,4 @@ public class AnalysisResultSetSearchParam extends AnalysisResultSearchParam {
return super.equals(obj);
}
-
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/BlackboardArtifactSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/BlackboardArtifactSearchParam.java
index 2bfd9a3929..8fd1f38c1d 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/BlackboardArtifactSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/BlackboardArtifactSearchParam.java
@@ -25,6 +25,16 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
* Key for data artifact in order to retrieve data from DAO.
*/
public class BlackboardArtifactSearchParam {
+
+ private static final String TYPE_ID = "BLACKBOARD_ARTIFACT";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final BlackboardArtifact.Type artifactType;
private final Long dataSourceId;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsDAO.java
index 186817ab24..c9a039153d 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsDAO.java
@@ -160,7 +160,7 @@ public class CommAccountsDAO extends AbstractDAO {
private static TreeResultsDTO.TreeItemDTO createAccountTreeItem(Account.Type accountType, Long dataSourceId, TreeResultsDTO.TreeDisplayCount count) {
return new TreeResultsDTO.TreeItemDTO<>(
- "ACCOUNTS",
+ CommAccountsSearchParams.getTypeId(),
new CommAccountsSearchParams(accountType, dataSourceId),
accountType.getTypeName(),
accountType.getDisplayName(),
@@ -236,7 +236,7 @@ public class CommAccountsDAO extends AbstractDAO {
Set extends DAOEvent> handleIngestComplete() {
return SubDAOUtils.getIngestCompleteEvents(
this.accountCounts,
- (daoEvt) -> createAccountTreeItem(daoEvt.getAccountType(), daoEvt.getDataSourceId(), TreeResultsDTO.TreeDisplayCount.UNSPECIFIED)
+ (daoEvt, count) -> createAccountTreeItem(daoEvt.getAccountType(), daoEvt.getDataSourceId(), count)
);
}
@@ -244,7 +244,7 @@ public class CommAccountsDAO extends AbstractDAO {
Set shouldRefreshTree() {
return SubDAOUtils.getRefreshEvents(
this.accountCounts,
- (daoEvt) -> createAccountTreeItem(daoEvt.getAccountType(), daoEvt.getDataSourceId(), TreeResultsDTO.TreeDisplayCount.UNSPECIFIED)
+ (daoEvt, count) -> createAccountTreeItem(daoEvt.getAccountType(), daoEvt.getDataSourceId(), count)
);
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsSearchParams.java
index 8b187b15a7..d20b427168 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsSearchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/CommAccountsSearchParams.java
@@ -27,9 +27,18 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
*/
public class CommAccountsSearchParams extends DataArtifactSearchParam {
+ private static final String TYPE_ID = "DATA_ARTIFACT_ACCOUNT";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final Account.Type type;
private final Long dataSourceId;
-
+
public CommAccountsSearchParams(Account.Type type, Long dataSourceId) {
super(BlackboardArtifact.Type.TSK_ACCOUNT, dataSourceId);
this.type = type;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactDAO.java
index 4728c27010..3c152fc152 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactDAO.java
@@ -245,7 +245,7 @@ public class DataArtifactDAO extends BlackboardArtifactDAO {
private TreeItemDTO createDataArtifactTreeItem(BlackboardArtifact.Type artifactType, Long dataSourceId, TreeDisplayCount displayCount) {
return new TreeResultsDTO.TreeItemDTO<>(
- BlackboardArtifact.Category.DATA_ARTIFACT.name(),
+ DataArtifactSearchParam.getTypeId(),
new DataArtifactSearchParam(artifactType, dataSourceId),
artifactType.getTypeID(),
getDisplayName(artifactType),
@@ -255,13 +255,13 @@ public class DataArtifactDAO extends BlackboardArtifactDAO {
@Override
Set extends DAOEvent> handleIngestComplete() {
return SubDAOUtils.getIngestCompleteEvents(this.treeCounts,
- (daoEvt) -> createDataArtifactTreeItem(daoEvt.getArtifactType(), daoEvt.getDataSourceId(), TreeDisplayCount.UNSPECIFIED));
+ (daoEvt, count) -> createDataArtifactTreeItem(daoEvt.getArtifactType(), daoEvt.getDataSourceId(), count));
}
@Override
Set shouldRefreshTree() {
return SubDAOUtils.getRefreshEvents(this.treeCounts,
- (daoEvt) -> createDataArtifactTreeItem(daoEvt.getArtifactType(), daoEvt.getDataSourceId(), TreeDisplayCount.UNSPECIFIED));
+ (daoEvt, count) -> createDataArtifactTreeItem(daoEvt.getArtifactType(), daoEvt.getDataSourceId(), count));
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactSearchParam.java
index 0956cf4b5c..9fff59cd28 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/DataArtifactSearchParam.java
@@ -25,7 +25,16 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
*/
public class DataArtifactSearchParam extends BlackboardArtifactSearchParam {
+ private static final String TYPE_ID = BlackboardArtifact.Category.DATA_ARTIFACT.name();
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
public DataArtifactSearchParam(BlackboardArtifact.Type artifactType, Long dataSourceId) {
- super (artifactType, dataSourceId);
- }
+ super(artifactType, dataSourceId);
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java
index ff74c0ab85..32c5798f7a 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java
@@ -24,6 +24,16 @@ import java.util.Objects;
* Key for content object in order to retrieve data from DAO.
*/
public class FileSystemContentSearchParam {
+
+ private static final String TYPE_ID = "FILE_SYSTEM_CONTENT";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final Long contentObjectId;
public FileSystemContentSearchParam(Long contentObjectId) {
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemDAO.java
index de174d3477..a1b0b48f24 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemDAO.java
@@ -23,11 +23,10 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@@ -58,11 +57,14 @@ import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.LayoutFileRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.SlackFileRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.ContentRowDTO.PoolRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
+import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
import org.sleuthkit.autopsy.mainui.datamodel.events.FileSystemContentEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.FileSystemHostEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.FileSystemPersonEvent;
+import org.sleuthkit.autopsy.mainui.datamodel.events.TreeCounts;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
import org.sleuthkit.autopsy.mainui.nodes.DAOFetcher;
+import org.sleuthkit.datamodel.AbstractContent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource;
@@ -110,8 +112,11 @@ public class FileSystemDAO extends AbstractDAO {
Case.Events.HOSTS_REMOVED_FROM_PERSON.toString()
);
- private final Cache, BaseSearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
-
+ private final Cache, BaseSearchResultsDTO> searchParamsCache
+ = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
+
+ private final TreeCounts treeCounts = new TreeCounts<>();
+
private static final String FILE_SYSTEM_TYPE_ID = "FILE_SYSTEM";
private static FileSystemDAO instance = null;
@@ -130,7 +135,7 @@ public class FileSystemDAO extends AbstractDAO {
FileSystemContentEvent contentEvt = (FileSystemContentEvent) daoEvent;
- return contentEvt.getContentObjectId() == null || key.getContentObjectId().equals(contentEvt.getContentObjectId());
+ return contentEvt.getContentObjectId() == null || Objects.equals(key.getContentObjectId(), contentEvt.getContentObjectId());
}
private boolean isSystemHostInvalidating(FileSystemHostSearchParam key, DAOEvent daoEvent) {
@@ -315,19 +320,13 @@ public class FileSystemDAO extends AbstractDAO {
return searchParamsCache.get(searchParams, () -> fetchHostsForTable(searchParams));
}
- @Override
- void clearCaches() {
- this.searchParamsCache.invalidateAll();
- }
-
- private Long getHostFromDs(Content dataSource) {
+ private Host getHostFromDs(Content dataSource) {
if (!(dataSource instanceof DataSource)) {
return null;
}
try {
- Host host = ((DataSource) dataSource).getHost();
- return host == null ? null : host.getHostId();
+ return ((DataSource) dataSource).getHost();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "There was an error getting the host for data source with id: " + dataSource.getId(), ex);
return null;
@@ -358,24 +357,16 @@ public class FileSystemDAO extends AbstractDAO {
return false;
}
- @Override
- Set handleIngestComplete() {
- // GVDTODO
- return Collections.emptySet();
- }
-
- @Override
- Set shouldRefreshTree() {
- // GVDTODO
- return Collections.emptySet();
- }
-
@Override
Set processEvent(PropertyChangeEvent evt) {
- // GVDTODO these can probably be rewritten now that it isn't handling a collection of autopsy events
- Set affectedPersons = new HashSet<>();
- Set affectedHosts = new HashSet<>();
- Set affectedParentContent = new HashSet<>();
+ Content affectedContent = null;
+ Content affectedParentContent = null;
+ Host affectedParentHost = null;
+
+ // GVDTODO person parents and parent of persons not handled yet
+ // optional present but null indicates no person parent
+ Optional affectedParentPerson = Optional.empty();
+
boolean refreshAllContent = false;
Content content = DAOEventUtils.getDerivedFileContentFromFileEvent(evt);
@@ -388,132 +379,158 @@ public class FileSystemDAO extends AbstractDAO {
return Collections.emptySet();
}
- if (parentContent == null) {
- return Collections.emptySet();
- }
-
if (invalidatesAllFileSystem(parentContent)) {
refreshAllContent = true;
} else {
- affectedParentContent.add(parentContent.getId());
+ affectedContent = content;
+ affectedParentContent = parentContent;
}
} else if (evt instanceof DataSourceAddedEvent) {
- Long hostId = getHostFromDs(((DataSourceAddedEvent) evt).getDataSource());
- if (hostId != null) {
- affectedHosts.add(hostId);
- }
+ Host host = getHostFromDs(((DataSourceAddedEvent) evt).getDataSource());
+ affectedParentHost = host;
+
} else if (evt instanceof DataSourceNameChangedEvent) {
- Long hostId = getHostFromDs(((DataSourceNameChangedEvent) evt).getDataSource());
- if (hostId != null) {
- affectedHosts.add(hostId);
- }
+ Host host = getHostFromDs(((DataSourceNameChangedEvent) evt).getDataSource());
+ affectedParentHost = host;
+
} else if (evt instanceof HostsAddedEvent) {
// GVDTODO how best to handle host added?
} else if (evt instanceof HostsUpdatedEvent) {
// GVDTODO how best to handle host updated?
} else if (evt instanceof HostsAddedToPersonEvent) {
Person person = ((HostsAddedToPersonEvent) evt).getPerson();
- affectedPersons.add(person == null ? null : person.getPersonId());
+ affectedParentPerson = Optional.of(person);
} else if (evt instanceof HostsRemovedFromPersonEvent) {
Person person = ((HostsRemovedFromPersonEvent) evt).getPerson();
- affectedPersons.add(person == null ? null : person.getPersonId());
+ affectedParentPerson = Optional.of(person);
}
- final boolean triggerFullRefresh = refreshAllContent;
+ // if nothing affected, return no events
+ if (!refreshAllContent && affectedContent == null && affectedParentHost == null && !affectedParentPerson.isPresent()) {
+ return Collections.emptySet();
+ }
- // GVDTODO handling null ids versus the 'No Persons' option
- ConcurrentMap, BaseSearchResultsDTO> concurrentMap = this.searchParamsCache.asMap();
- concurrentMap.forEach((k, v) -> {
- Object searchParams = k.getParamData();
- if (searchParams instanceof FileSystemPersonSearchParam) {
- FileSystemPersonSearchParam personParam = (FileSystemPersonSearchParam) searchParams;
- if (affectedPersons.contains(personParam.getPersonObjectId())) {
- concurrentMap.remove(k);
- }
- } else if (searchParams instanceof FileSystemHostSearchParam) {
- FileSystemHostSearchParam hostParams = (FileSystemHostSearchParam) searchParams;
- if (affectedHosts.contains(hostParams.getHostObjectId())) {
- concurrentMap.remove(k);
- }
- } else if (searchParams instanceof FileSystemContentSearchParam) {
- FileSystemContentSearchParam contentParams = (FileSystemContentSearchParam) searchParams;
- if (triggerFullRefresh
- || contentParams.getContentObjectId() == null
- || affectedParentContent.contains(contentParams.getContentObjectId())) {
- concurrentMap.remove(k);
- }
+ invalidateKeys(affectedParentPerson, affectedParentHost, affectedContent, refreshAllContent);
+
+ return getDAOEvents(affectedParentPerson, affectedParentHost, affectedContent, affectedParentContent, refreshAllContent);
+ }
+
+ private Set getDAOEvents(Optional affectedPerson, Host affectedHost, Content affectedContent, Content affectedParentContent, boolean triggerFullRefresh) {
+ List daoEvents = new ArrayList<>();
+
+ if (triggerFullRefresh) {
+ daoEvents.add(new FileSystemContentEvent(null, null, null));
+ } else if (affectedContent != null) {
+ Host parentHost = null;
+
+ try {
+ parentHost = (affectedContent instanceof DataSource)
+ ? ((DataSource) affectedContent).getHost()
+ : null;
+ } catch (TskCoreException ex) {
+ logger.log(Level.WARNING, "An error occurred while fetching content id and host id for content with id of: " + affectedContent.getId(), ex);
}
+
+ daoEvents.add(new FileSystemContentEvent(affectedContent, affectedParentContent == null ? null : affectedParentContent.getId(), parentHost));
+ }
+
+ if (affectedHost != null) {
+ daoEvents.add(new FileSystemHostEvent(affectedHost.getHostId()));
+ }
+
+ affectedPerson.ifPresent((person) -> {
+ daoEvents.add(new FileSystemPersonEvent(person == null ? null : person.getPersonId()));
});
- Stream fileEvts = triggerFullRefresh
- ? Stream.of(new FileSystemContentEvent(null))
- : affectedParentContent.stream().map(id -> new FileSystemContentEvent(id));
+ List treeEvents = this.treeCounts.enqueueAll(daoEvents).stream()
+ .map(daoEvt -> createTreeEvent(daoEvt, TreeDisplayCount.INDETERMINATE, false))
+ .filter(evt -> evt != null)
+ .collect(Collectors.toList());
- return Stream.of(
- affectedPersons.stream().map(id -> new FileSystemPersonEvent(id)),
- affectedHosts.stream().map(id -> new FileSystemHostEvent(id)),
- fileEvts
- )
- .flatMap(s -> s)
+ return Stream.of(daoEvents, treeEvents)
+ .flatMap(lst -> lst.stream())
.collect(Collectors.toSet());
}
-
+
+ private void invalidateKeys(Optional affectedPerson, Host affectedHost, Content affectedContent, boolean triggerFullRefresh) {
+ ConcurrentMap, ?> concurrentMap = this.searchParamsCache.asMap();
+ concurrentMap.forEach((k, v) -> {
+ Object searchParams = k.getParamData();
+ boolean shouldInvalidate = false;
+ if (searchParams instanceof FileSystemPersonSearchParam && affectedPerson.isPresent()) {
+ shouldInvalidate = Objects.equals(
+ ((FileSystemPersonSearchParam) searchParams).getPersonObjectId(),
+ // to allow for null parent person
+ affectedPerson.flatMap(p -> Optional.ofNullable(p.getPersonId())).orElse(null)
+ );
+
+ } else if (searchParams instanceof FileSystemHostSearchParam && affectedHost != null) {
+ shouldInvalidate = Objects.equals(
+ ((FileSystemHostSearchParam) searchParams).getHostObjectId(),
+ affectedHost.getHostId()
+ );
+
+ } else if (searchParams instanceof FileSystemContentSearchParam) {
+ if (triggerFullRefresh) {
+ shouldInvalidate = true;
+ } else if (affectedContent != null) {
+ shouldInvalidate = Objects.equals(
+ ((FileSystemContentSearchParam) searchParams).getContentObjectId(),
+ affectedContent.getId()
+ );
+ }
+ }
+
+ if (shouldInvalidate) {
+ concurrentMap.remove(k);
+ }
+ });
+ }
+
/**
* Get all data sources belonging to a given host.
- *
+ *
* @param host The host.
- *
+ *
* @return Results containing all data sources for the given host.
- *
- * @throws ExecutionException
+ *
+ * @throws ExecutionException
*/
public TreeResultsDTO getDataSourcesForHost(Host host) throws ExecutionException {
try {
List> treeItemRows = new ArrayList<>();
for (DataSource ds : Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getDataSourcesForHost(host)) {
- treeItemRows.add(new TreeResultsDTO.TreeItemDTO<>(
- ds.getClass().getSimpleName(),
- new FileSystemContentSearchParam(ds.getId()),
- ds,
- ds.getName(),
- null
- ));
+ treeItemRows.add(createDisplayableContentTreeItem(ds, TreeDisplayCount.NOT_SHOWN));
}
return new TreeResultsDTO<>(treeItemRows);
} catch (NoCurrentCaseException | TskCoreException ex) {
throw new ExecutionException("An error occurred while fetching images for host with ID " + host.getHostId(), ex);
}
}
-
+
/**
* Create results for a single given data source ID (not its children).
- *
+ *
* @param dataSourceObjId The data source object ID.
- *
+ *
* @return Results containing just this data source.
- *
- * @throws ExecutionException
+ *
+ * @throws ExecutionException
*/
public TreeResultsDTO getSingleDataSource(long dataSourceObjId) throws ExecutionException {
try {
List> treeItemRows = new ArrayList<>();
DataSource ds = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(dataSourceObjId);
- treeItemRows.add(new TreeResultsDTO.TreeItemDTO<>(
- ds.getClass().getSimpleName(),
- new FileSystemContentSearchParam(ds.getId()),
- ds,
- ds.getName(),
- null
- ));
-
+ treeItemRows.add(createDisplayableContentTreeItem(ds, TreeDisplayCount.NOT_SHOWN));
return new TreeResultsDTO<>(treeItemRows);
} catch (NoCurrentCaseException | TskCoreException | TskDataException ex) {
throw new ExecutionException("An error occurred while fetching data source with ID " + dataSourceObjId, ex);
}
}
-
+
/**
- * Get the children that will be displayed in the tree for a given content ID.
+ * Get the children that will be displayed in the tree for a given content
+ * ID.
*
* @param contentId Object ID of parent content.
*
@@ -523,23 +540,18 @@ public class FileSystemDAO extends AbstractDAO {
*/
public TreeResultsDTO getDisplayableContentChildren(Long contentId) throws ExecutionException {
try {
-
+
List treeChildren = FileSystemColumnUtils.getVisibleTreeNodeChildren(contentId);
-
+
List> treeItemRows = new ArrayList<>();
for (Content child : treeChildren) {
Long countForNode = null;
if ((child instanceof AbstractFile)
- && ! (child instanceof LocalFilesDataSource)) {
+ && !(child instanceof LocalFilesDataSource)) {
countForNode = getContentForTable(new FileSystemContentSearchParam(child.getId()), 0, null).getTotalResultsCount();
}
- treeItemRows.add(new TreeResultsDTO.TreeItemDTO<>(
- child.getClass().getSimpleName(),
- new FileSystemContentSearchParam(child.getId()),
- child,
- getNameForContent(child),
- countForNode == null ? TreeDisplayCount.NOT_SHOWN : TreeDisplayCount.getDeterminate(countForNode)
- ));
+ TreeDisplayCount displayCount = countForNode == null ? TreeDisplayCount.NOT_SHOWN : TreeDisplayCount.getDeterminate(countForNode);
+ treeItemRows.add(createDisplayableContentTreeItem(child, displayCount));
}
return new TreeResultsDTO<>(treeItemRows);
@@ -547,23 +559,160 @@ public class FileSystemDAO extends AbstractDAO {
throw new ExecutionException("An error occurred while fetching data artifact counts.", ex);
}
}
-
+
+ private FileSystemTreeItem createDisplayableContentTreeItem(Content child, TreeDisplayCount displayCount) {
+ return new FileSystemTreeItem(
+ FileSystemContentSearchParam.getTypeId(),
+ new FileSystemContentSearchParam(child == null ? null : child.getId()),
+ child,
+ child == null ? null : getNameForContent(child),
+ child instanceof AbstractFile ? ((AbstractFile) child).getMetaType() : null,
+ displayCount
+ );
+ }
+
/**
* Get display name for the given content.
- *
+ *
* @param content The content.
- *
+ *
* @return Display name for the content.
*/
private String getNameForContent(Content content) {
if (content instanceof Volume) {
- return FileSystemColumnUtils.getVolumeDisplayName((Volume)content);
+ return FileSystemColumnUtils.getVolumeDisplayName((Volume) content);
} else if (content instanceof AbstractFile) {
return FileSystemColumnUtils.convertDotDirName((AbstractFile) content);
}
return content.getName();
}
+ private TreeEvent createTreeEvent(DAOEvent daoEvent, TreeDisplayCount count, boolean fullRefresh) {
+
+ if (daoEvent instanceof FileSystemContentEvent) {
+ FileSystemContentEvent contentEvt = (FileSystemContentEvent) daoEvent;
+
+ return new FileSystemTreeEvent(
+ contentEvt.getParentObjId(),
+ contentEvt.getParentHost(),
+ createDisplayableContentTreeItem(contentEvt.getContent(), count),
+ fullRefresh);
+
+ } else if (daoEvent instanceof FileSystemHostEvent) {
+ // GVDTODO not currently integrated into tree
+ } else if (daoEvent instanceof FileSystemPersonEvent) {
+ // GVDTODO not currently integrated into tree
+ }
+
+ return null;
+ }
+
+ @Override
+ void clearCaches() {
+ this.searchParamsCache.invalidateAll();
+ handleIngestComplete();
+ }
+
+ @Override
+ Set extends DAOEvent> handleIngestComplete() {
+ return treeCounts.flushEvents().stream()
+ .map(daoEvt -> createTreeEvent(daoEvt, TreeDisplayCount.UNSPECIFIED, true))
+ .filter(evt -> evt != null)
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ Set shouldRefreshTree() {
+ return treeCounts.getEventTimeouts().stream()
+ .map(daoEvt -> createTreeEvent(daoEvt, TreeDisplayCount.UNSPECIFIED, true))
+ .filter(evt -> evt != null)
+ .collect(Collectors.toSet());
+ }
+
+ public static class DataSourceRefreshTreeEvent extends TreeEvent {
+
+ public DataSourceRefreshTreeEvent(boolean refresh) {
+ super(null, refresh);
+ }
+
+ }
+
+ public static class FileSystemTreeItem extends TreeItemDTO {
+
+ private final TskData.TSK_FS_META_TYPE_ENUM metaType;
+
+ FileSystemTreeItem(
+ String typeId,
+ FileSystemContentSearchParam searchParams,
+ Object id,
+ String displayName,
+ TskData.TSK_FS_META_TYPE_ENUM metaType,
+ TreeDisplayCount count) {
+
+ super(typeId, searchParams, id, displayName, count);
+ this.metaType = metaType;
+ }
+
+ public TskData.TSK_FS_META_TYPE_ENUM getMetaType() {
+ return metaType;
+ }
+
+ }
+
+ public static class FileSystemTreeEvent extends TreeEvent {
+
+ private final Long parentContentId;
+ private final Host parentHost;
+ private final FileSystemTreeItem itemRecord;
+
+ FileSystemTreeEvent(Long parentContentId, Host parentHost, FileSystemTreeItem itemRecord, boolean refreshRequired) {
+ super(itemRecord, refreshRequired);
+ this.parentContentId = parentContentId;
+ this.parentHost = parentHost;
+ this.itemRecord = itemRecord;
+ }
+
+ public Long getParentContentId() {
+ return parentContentId;
+ }
+
+ public Host getParentHost() {
+ return parentHost;
+ }
+
+ @Override
+ public FileSystemTreeItem getItemRecord() {
+ // override to be typed and contain extra information
+ return itemRecord;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 31 * hash + Objects.hashCode(this.itemRecord);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final FileSystemTreeEvent other = (FileSystemTreeEvent) obj;
+ if (!Objects.equals(this.itemRecord, other.itemRecord)) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
/**
* Handles fetching and paging of data for file types by mime type.
*/
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemHostSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemHostSearchParam.java
index 2f78e597a8..a258b2320d 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemHostSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemHostSearchParam.java
@@ -24,6 +24,16 @@ import java.util.Objects;
* Key for content object in order to retrieve data from DAO.
*/
public class FileSystemHostSearchParam {
+
+ private static final String TYPE_ID = "FILE_SYSTEM_HOST";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final Long hostObjectId;
public FileSystemHostSearchParam(Long hostObjectId) {
@@ -59,4 +69,3 @@ public class FileSystemHostSearchParam {
return true;
}
}
-
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemPersonSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemPersonSearchParam.java
index 99f75b1764..ae198a89dd 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemPersonSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemPersonSearchParam.java
@@ -24,12 +24,23 @@ import java.util.Objects;
* Key for person object in order to retrieve data from DAO.
*/
public class FileSystemPersonSearchParam {
+
+ private static final String TYPE_ID = "FILE_SYSTEM_PERSON";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final Long personObjectId;
/**
* Create search param.
- *
- * @param personObjectId May be null to fetch hosts not associated with a Person
+ *
+ * @param personObjectId May be null to fetch hosts not associated with a
+ * Person
*/
public FileSystemPersonSearchParam(Long personObjectId) {
this.personObjectId = personObjectId;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeExtensionsSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeExtensionsSearchParams.java
index fe875e1463..be0bf45de2 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeExtensionsSearchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeExtensionsSearchParams.java
@@ -25,6 +25,15 @@ import java.util.Objects;
*/
public class FileTypeExtensionsSearchParams {
+ private static final String TYPE_ID = "FILE_VIEWS_EXTENSION";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final FileExtSearchFilter filter;
private final Long dataSourceId;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeMimeSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeMimeSearchParams.java
index 8e95b18beb..0b89294e95 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeMimeSearchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeMimeSearchParams.java
@@ -25,9 +25,18 @@ import java.util.Objects;
*/
public class FileTypeMimeSearchParams {
+ private static final String TYPE_ID = "FILE_VIEWS_MIME";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final String mimeType;
private final Long dataSourceId;
-
+
public FileTypeMimeSearchParams(String mimeType, Long dataSourceId) {
this.mimeType = mimeType;
this.dataSourceId = dataSourceId;
@@ -70,5 +79,4 @@ public class FileTypeMimeSearchParams {
return true;
}
-
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java
index 1a1eb91917..898f1fca83 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java
@@ -25,6 +25,14 @@ import java.util.Objects;
*/
public class FileTypeSizeSearchParams {
+ private static final String TYPE_ID = "FILE_VIEWS_SIZE";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
private final FileSizeFilter sizeFilter;
private final Long dataSourceId;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java
index dc8495bffd..96299f9804 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java
@@ -24,7 +24,16 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
* Key for keyword hits in order to retrieve data from DAO.
*/
public class HashHitSearchParam extends AnalysisResultSetSearchParam {
-
+
+ private static final String TYPE_ID = "HASH_HIT";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
public HashHitSearchParam(Long dataSourceId, String setName) {
super(BlackboardArtifact.Type.TSK_HASHSET_HIT, dataSourceId, setName);
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java
index fc59d36bd2..fe9a53f012 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java
@@ -26,19 +26,28 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
*/
public class KeywordHitSearchParam extends AnalysisResultSetSearchParam {
+ private static final String TYPE_ID = "KEYWORD_HIT";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final String keyword;
private final String regex;
-
+
public KeywordHitSearchParam(Long dataSourceId, String setName, String keyword, String regex) {
super(BlackboardArtifact.Type.TSK_KEYWORD_HIT, dataSourceId, setName);
this.keyword = keyword;
this.regex = regex;
}
-
+
public String getRegex() {
return regex;
}
-
+
public String getKeyword() {
return keyword;
}
@@ -72,6 +81,5 @@ public class KeywordHitSearchParam extends AnalysisResultSetSearchParam {
}
return super.equals(obj);
}
-
-
+
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordMatchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordMatchParams.java
index 1351939423..597c55e7c4 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordMatchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordMatchParams.java
@@ -23,6 +23,15 @@ package org.sleuthkit.autopsy.mainui.datamodel;
*/
public class KeywordMatchParams {
+ private static final String TYPE_ID = "KEYWORD_MATCH";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final String setName;
private final String searchTerm;
private final String keywordMatch;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordSearchTermParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordSearchTermParams.java
index c22a6c97b9..d2acd4a74d 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordSearchTermParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordSearchTermParams.java
@@ -23,6 +23,15 @@ package org.sleuthkit.autopsy.mainui.datamodel;
*/
public class KeywordSearchTermParams {
+ private static final String TYPE_ID = "KEYWORD_SEARCH_TERM";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final String setName;
private final String searchTerm;
private final boolean hasChildren;
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java
index 44de97b935..817a3e212c 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java
@@ -259,6 +259,7 @@ public class MainDAO extends AbstractDAO {
return allDAOs.stream()
.map(subDAO -> subDAO.processEvent(evt))
.flatMap(evts -> evts == null ? Stream.empty() : evts.stream())
+ .filter(e -> e != null)
.collect(Collectors.toSet());
}
@@ -267,6 +268,7 @@ public class MainDAO extends AbstractDAO {
return allDAOs.stream()
.map((subDAO) -> subDAO.shouldRefreshTree())
.flatMap(evts -> evts == null ? Stream.empty() : evts.stream())
+ .filter(e -> e != null)
.collect(Collectors.toSet());
}
@@ -280,6 +282,7 @@ public class MainDAO extends AbstractDAO {
return daoStreamEvts.stream()
.flatMap(evts -> evts == null ? Stream.empty() : evts.stream())
+ .filter(evt -> evt != null)
.collect(Collectors.toSet());
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsDAO.java
index 78020b4dbf..ceace7b7f1 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsDAO.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsDAO.java
@@ -24,7 +24,6 @@ import com.google.common.cache.CacheBuilder;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -187,13 +186,11 @@ public class OsAccountsDAO extends AbstractDAO {
@Override
Set handleIngestComplete() {
- // GVDTODO
return Collections.emptySet();
}
@Override
Set shouldRefreshTree() {
- // GVDTODO
return Collections.emptySet();
}
@@ -202,9 +199,9 @@ public class OsAccountsDAO extends AbstractDAO {
if (!OS_EVENTS.contains(evt.getPropertyName())) {
return Collections.emptySet();
}
-
- this.searchParamsCache.invalidateAll();
-
+
+ this.searchParamsCache.invalidateAll();
+
return Collections.singleton(new OsAccountEvent());
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsSearchParams.java
index e21db61826..61801fbb3d 100755
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsSearchParams.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/OsAccountsSearchParams.java
@@ -25,8 +25,17 @@ import java.util.Objects;
*/
public class OsAccountsSearchParams {
+ private static final String TYPE_ID = "OS_ACCOUNTS";
+
+ /**
+ * @return The type id for this search parameter.
+ */
+ public static String getTypeId() {
+ return TYPE_ID;
+ }
+
private final Long dataSourceId;
-
+
public OsAccountsSearchParams(Long dataSourceId) {
this.dataSourceId = dataSourceId;
}
diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/SubDAOUtils.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/SubDAOUtils.java
index 53e2f7cfb3..2d0aff456a 100644
--- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/SubDAOUtils.java
+++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/SubDAOUtils.java
@@ -19,14 +19,16 @@
package org.sleuthkit.autopsy.mainui.datamodel;
import com.google.common.cache.Cache;
-import java.util.Collections;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiFunction;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
+import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
+import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeCounts;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
@@ -46,32 +48,28 @@ public class SubDAOUtils {
* no data source filtering).
* @param itemDataSourceMapping The event digest.
*/
- static void invalidateKeys(Cache, ?> cache, Function> getKeys, Map> itemDataSourceMapping) {
- invalidateKeys(cache, getKeys, Collections.singletonList(itemDataSourceMapping));
+ static void invalidateKeys(Cache, ?> cache, Function> getKeys, Map> itemDsMapping) {
+ invalidateKeys(cache, (keyParams) -> {
+ Pair pairItems = getKeys.apply(keyParams);
+ T searchParamsKey = pairItems.getLeft();
+ Long searchParamsDsId = pairItems.getRight();
+ Set dsIds = itemDsMapping.get(searchParamsKey);
+ return (dsIds != null && (searchParamsDsId == null || dsIds.contains(searchParamsDsId)));
+ });
}
/**
- * Using a digest of event information, clears keys in a cache that may be
- * effected by events.
+ * Determines what keys should be kept in the cache while iterating through
+ * all the keys.
*
- * @param cache The cache.
- * @param getKeys Using a key from a cache, provides a tuple
- * of the relevant key in the data source
- * mapping and the data source id (or null if
- * no data source filtering).
- * @param itemDataSourceMapping The list of event digests.
+ * @param cache The cache.
+ * @param shouldInvalidate If the key should be removed from the cache.
*/
- static void invalidateKeys(Cache, ?> cache, Function> getKeys, List