diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index fecf47d7cd..35af75738b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -72,6 +72,7 @@ public class EmailExtracted implements AutopsyVisitableItem { private final class EmailResults extends Observable { + // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized private final Map>> accounts = new LinkedHashMap<>(); EmailResults() { @@ -79,20 +80,28 @@ public class EmailExtracted implements AutopsyVisitableItem { } public Set getAccounts() { - return accounts.keySet(); + synchronized (accounts) { + return accounts.keySet(); + } } public Set getFolders(String account) { - return accounts.get(account).keySet(); + synchronized (accounts) { + return accounts.get(account).keySet(); + } } public List getArtifactIds(String account, String folder) { - return accounts.get(account).get(folder); + synchronized (accounts) { + return accounts.get(account).get(folder); + } } @SuppressWarnings("deprecation") public void update() { - accounts.clear(); + synchronized (accounts) { + accounts.clear(); + } if (skCase == null) { return; } @@ -107,24 +116,26 @@ public class EmailExtracted implements AutopsyVisitableItem { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); - while (resultSet.next()) { - final String path = resultSet.getString("value_text"); //NON-NLS - final long artifactId = resultSet.getLong("artifact_id"); //NON-NLS - final Map parsedPath = parsePath(path); - final String account = parsedPath.get(MAIL_ACCOUNT); - final String folder = parsedPath.get(MAIL_FOLDER); + synchronized (accounts) { + while (resultSet.next()) { + final String path = resultSet.getString("value_text"); //NON-NLS + final long artifactId = resultSet.getLong("artifact_id"); //NON-NLS + final Map parsedPath = parsePath(path); + final String account = parsedPath.get(MAIL_ACCOUNT); + final String folder = parsedPath.get(MAIL_FOLDER); - Map> folders = accounts.get(account); - if (folders == null) { - folders = new LinkedHashMap<>(); - accounts.put(account, folders); + Map> folders = accounts.get(account); + if (folders == null) { + folders = new LinkedHashMap<>(); + accounts.put(account, folders); + } + List messages = folders.get(folder); + if (messages == null) { + messages = new ArrayList<>(); + folders.put(folder, messages); + } + messages.add(artifactId); } - List messages = folders.get(folder); - if (messages == null) { - messages = new ArrayList<>(); - folders.put(folder, messages); - } - messages.add(artifactId); } } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 6ecaec6258..2264b95ac6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -78,7 +78,7 @@ public class HashsetHits implements AutopsyVisitableItem { private class HashsetResults extends Observable { // maps hashset name to list of artifacts for that set - + // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized private final Map> hashSetHitsMap = new LinkedHashMap<>(); HashsetResults() { @@ -86,18 +86,25 @@ public class HashsetHits implements AutopsyVisitableItem { } List getSetNames() { - List names = new ArrayList<>(hashSetHitsMap.keySet()); + List names; + synchronized (hashSetHitsMap) { + names = new ArrayList<>(hashSetHitsMap.keySet()); + } Collections.sort(names); return names; } Set getArtifactIds(String hashSetName) { - return hashSetHitsMap.get(hashSetName); + synchronized (hashSetHitsMap) { + return hashSetHitsMap.get(hashSetName); + } } @SuppressWarnings("deprecation") final void update() { - hashSetHitsMap.clear(); + synchronized (hashSetHitsMap) { + hashSetHitsMap.clear(); + } if (skCase == null) { return; @@ -113,13 +120,15 @@ public class HashsetHits implements AutopsyVisitableItem { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); - while (resultSet.next()) { - String setName = resultSet.getString("value_text"); //NON-NLS - long artifactId = resultSet.getLong("artifact_id"); //NON-NLS - if (!hashSetHitsMap.containsKey(setName)) { - hashSetHitsMap.put(setName, new HashSet()); + synchronized (hashSetHitsMap) { + while (resultSet.next()) { + String setName = resultSet.getString("value_text"); //NON-NLS + long artifactId = resultSet.getLong("artifact_id"); //NON-NLS + if (!hashSetHitsMap.containsKey(setName)) { + hashSetHitsMap.put(setName, new HashSet()); + } + hashSetHitsMap.get(setName).add(artifactId); } - hashSetHitsMap.get(setName).add(artifactId); } } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 8faec30ab7..b07f5568c0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -64,20 +64,28 @@ public class InterestingHits implements AutopsyVisitableItem { private class InterestingResults extends Observable { + // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized private final Map> interestingItemsMap = new LinkedHashMap<>(); public List getSetNames() { - List setNames = new ArrayList<>(interestingItemsMap.keySet()); + List setNames; + synchronized (interestingItemsMap) { + setNames = new ArrayList<>(interestingItemsMap.keySet()); + } Collections.sort(setNames); return setNames; } public Set getArtifactIds(String setName) { - return interestingItemsMap.get(setName); + synchronized (interestingItemsMap) { + return interestingItemsMap.get(setName); + } } public void update() { - interestingItemsMap.clear(); + synchronized (interestingItemsMap) { + interestingItemsMap.clear(); + } loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); setChanged(); @@ -103,14 +111,16 @@ public class InterestingHits implements AutopsyVisitableItem { + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { - ResultSet resultSet = dbQuery.getResultSet(); - while (resultSet.next()) { - String value = resultSet.getString("value_text"); //NON-NLS - long artifactId = resultSet.getLong("artifact_id"); //NON-NLS - if (!interestingItemsMap.containsKey(value)) { - interestingItemsMap.put(value, new HashSet<>()); + synchronized (interestingItemsMap) { + ResultSet resultSet = dbQuery.getResultSet(); + while (resultSet.next()) { + String value = resultSet.getString("value_text"); //NON-NLS + long artifactId = resultSet.getLong("artifact_id"); //NON-NLS + if (!interestingItemsMap.containsKey(value)) { + interestingItemsMap.put(value, new HashSet<>()); + } + interestingItemsMap.get(value).add(artifactId); } - interestingItemsMap.get(value).add(artifactId); } } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 987cf72caa..319d9ecf9f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -73,85 +73,94 @@ public class KeywordHits implements AutopsyVisitableItem { private final class KeywordResults extends Observable { // Map from listName/Type to Map of keyword to set of artifact Ids - private final Map>> topLevelMap; + // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized + private final Map>> topLevelMap = new LinkedHashMap<>(); KeywordResults() { - topLevelMap = new LinkedHashMap<>(); update(); } List getListNames() { - List names = new ArrayList<>(topLevelMap.keySet()); - // this causes the "Single ..." terms to be in the middle of the results, - // which is wierd. Make a custom comparator or do something else to maek them on top - //Collections.sort(names); - return names; + synchronized (topLevelMap) { + List names = new ArrayList<>(topLevelMap.keySet()); + // this causes the "Single ..." terms to be in the middle of the results, + // which is wierd. Make a custom comparator or do something else to maek them on top + //Collections.sort(names); + return names; + } } List getKeywords(String listName) { - List keywords = new ArrayList<>(topLevelMap.get(listName).keySet()); + List keywords; + synchronized (topLevelMap) { + keywords = new ArrayList<>(topLevelMap.get(listName).keySet()); + } Collections.sort(keywords); return keywords; } Set getArtifactIds(String listName, String keyword) { - return topLevelMap.get(listName).get(keyword); + synchronized (topLevelMap) { + return topLevelMap.get(listName).get(keyword); + } } // populate maps based on artifactIds void populateMaps(Map> artifactIds) { - topLevelMap.clear(); + synchronized (topLevelMap) { + topLevelMap.clear(); - // map of list name to keword to artifact IDs - Map>> listsMap = new LinkedHashMap<>(); + // map of list name to keword to artifact IDs + Map>> listsMap = new LinkedHashMap<>(); - // Map from from literal keyword to artifact IDs - Map> literalMap = new LinkedHashMap<>(); + // Map from from literal keyword to artifact IDs + Map> literalMap = new LinkedHashMap<>(); - // Map from regex keyword artifact IDs - Map> regexMap = new LinkedHashMap<>(); + // Map from regex keyword artifact IDs + Map> regexMap = new LinkedHashMap<>(); - // top-level nodes - topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap); - topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap); + // top-level nodes + topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap); + topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap); - for (Map.Entry> art : artifactIds.entrySet()) { - long id = art.getKey(); - Map attributes = art.getValue(); + for (Map.Entry> art : artifactIds.entrySet()) { + long id = art.getKey(); + Map attributes = art.getValue(); - // I think we can use attributes.remove(...) here? - String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID())); - String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID())); - String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID())); + // I think we can use attributes.remove(...) here? + String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID())); + String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID())); + String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID())); - // part of a list - if (listName != null) { - if (listsMap.containsKey(listName) == false) { - listsMap.put(listName, new LinkedHashMap>()); + // part of a list + if (listName != null) { + if (listsMap.containsKey(listName) == false) { + listsMap.put(listName, new LinkedHashMap>()); + } + + Map> listMap = listsMap.get(listName); + if (listMap.containsKey(word) == false) { + listMap.put(word, new HashSet()); + } + + listMap.get(word).add(id); + } // regular expression, single term + else if (reg != null) { + if (regexMap.containsKey(reg) == false) { + regexMap.put(reg, new HashSet()); + } + regexMap.get(reg).add(id); + } // literal, single term + else { + if (literalMap.containsKey(word) == false) { + literalMap.put(word, new HashSet()); + } + literalMap.get(word).add(id); } - - Map> listMap = listsMap.get(listName); - if (listMap.containsKey(word) == false) { - listMap.put(word, new HashSet()); - } - - listMap.get(word).add(id); - } // regular expression, single term - else if (reg != null) { - if (regexMap.containsKey(reg) == false) { - regexMap.put(reg, new HashSet()); - } - regexMap.get(reg).add(id); - } // literal, single term - else { - if (literalMap.containsKey(word) == false) { - literalMap.put(word, new HashSet()); - } - literalMap.get(word).add(id); + topLevelMap.putAll(listsMap); } - topLevelMap.putAll(listsMap); } - + setChanged(); notifyObservers(); }