Tree nodes listen for case closing and stop listening and dereference case. Avoids null pointer exceptions

This commit is contained in:
Brian Carrier 2014-05-19 18:06:50 -04:00
parent 35a2ffa896
commit a117f15cbf
6 changed files with 120 additions and 26 deletions

View File

@ -39,6 +39,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -62,7 +63,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
private static final String MAIL_PATH_SEPARATOR = "/";
private SleuthkitCase skCase;
private EmailResults emailResults;
private final EmailResults emailResults;
public EmailExtracted(SleuthkitCase skCase) {
@ -71,7 +72,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
}
private final class EmailResults extends Observable {
private Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
private final Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
EmailResults() {
update();
@ -91,6 +92,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
public void update() {
accounts.clear();
if (skCase == null) {
return;
}
try {
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
@ -291,6 +296,13 @@ public class EmailExtracted implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
emailResults.update();
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
@ -298,6 +310,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
emailResults.update();
emailResults.addObserver(this);
}
@ -306,6 +319,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
emailResults.deleteObserver(this);
}
@ -484,6 +498,9 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(Long artifactId) {
if (skCase == null) {
return null;
}
try {
BlackboardArtifact artifact = skCase.getBlackboardArtifact(artifactId);
return new BlackboardArtifactNode(artifact);

View File

@ -32,6 +32,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -67,7 +68,7 @@ import org.sleuthkit.datamodel.TskException;
*/
public class ExtractedContent implements AutopsyVisitableItem {
private SleuthkitCase skCase;
private SleuthkitCase skCase; // set to null after case has been closed
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
public ExtractedContent(SleuthkitCase skCase) {
@ -86,7 +87,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
public class RootNode extends DisplayableItemNode {
public RootNode(SleuthkitCase skCase) {
super(Children.create(new TypeFactory(skCase), true), Lookups.singleton(NAME));
super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME));
super.setName(NAME);
super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS
@ -125,15 +126,12 @@ public class ExtractedContent implements AutopsyVisitableItem {
* more specific form elsewhere in the tree.
*/
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.ARTIFACT_TYPE> {
private SleuthkitCase skCase;
private final ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotShow;
// maps the artifact type to its child node
private HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>();
private final HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>();
public TypeFactory(SleuthkitCase skCase) {
public TypeFactory() {
super();
this.skCase = skCase;
// these are shown in other parts of the UI tree
doNotShow = new ArrayList<>();
@ -161,6 +159,13 @@ public class ExtractedContent implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
refresh(true);
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
@ -168,17 +173,23 @@ public class ExtractedContent implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
typeNodeList.clear();
}
@Override
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
if (skCase == null) {
return false;
}
try {
List<BlackboardArtifact.ARTIFACT_TYPE> inUse = skCase.getBlackboardArtifactTypesInUse();
inUse.removeAll(doNotShow);
@ -208,7 +219,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
TypeNode node = new TypeNode(key, skCase);
TypeNode node = new TypeNode(key);
typeNodeList.put(key, node);
return node;
}
@ -224,18 +235,20 @@ public class ExtractedContent implements AutopsyVisitableItem {
private BlackboardArtifact.ARTIFACT_TYPE type;
private long childCount = 0;
private SleuthkitCase skCase;
TypeNode(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
super(Children.create(new ArtifactFactory(type, skCase), true), Lookups.singleton(type.getDisplayName()));
TypeNode(BlackboardArtifact.ARTIFACT_TYPE type) {
super(Children.create(new ArtifactFactory(type), true), Lookups.singleton(type.getDisplayName()));
super.setName(type.getLabel());
this.skCase = skCase;
this.type = type;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/" + getIcon(type)); //NON-NLS
updateDisplayName();
}
final void updateDisplayName() {
if (skCase == null) {
return;
}
// NOTE: This completely destroys our lazy-loading ideal
// a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase
@ -333,14 +346,12 @@ public class ExtractedContent implements AutopsyVisitableItem {
/**
* Creates children for a given artifact type
*/
private static class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
private class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
private SleuthkitCase skCase;
private BlackboardArtifact.ARTIFACT_TYPE type;
public ArtifactFactory(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
public ArtifactFactory(BlackboardArtifact.ARTIFACT_TYPE type) {
super();
this.skCase = skCase;
this.type = type;
}
@ -375,6 +386,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
if (skCase == null) {
return false;
}
try {
List<BlackboardArtifact> arts = skCase.getBlackboardArtifacts(type.getTypeID());
list.addAll(arts);

View File

@ -40,6 +40,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -56,7 +57,7 @@ public class HashsetHits implements AutopsyVisitableItem {
private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel();
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
private final SleuthkitCase skCase;
private SleuthkitCase skCase;
private final HashsetResults hashsetResults;
public HashsetHits(SleuthkitCase skCase) {
@ -76,7 +77,7 @@ public class HashsetHits implements AutopsyVisitableItem {
*/
private class HashsetResults extends Observable {
// maps hashset name to list of artifacts for that set
private Map<String, Set<Long>> hashSetHitsMap = new LinkedHashMap<>();
private final Map<String, Set<Long>> hashSetHitsMap = new LinkedHashMap<>();
HashsetResults() {
update();
@ -94,6 +95,11 @@ public class HashsetHits implements AutopsyVisitableItem {
final void update() {
hashSetHitsMap.clear();
if (skCase == null) {
return;
}
ResultSet rs = null;
try {
int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
@ -191,6 +197,13 @@ public class HashsetHits implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
hashsetResults.update();
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
@ -198,6 +211,7 @@ public class HashsetHits implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
hashsetResults.update();
hashsetResults.addObserver(this);
}
@ -206,6 +220,7 @@ public class HashsetHits implements AutopsyVisitableItem {
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
hashsetResults.deleteObserver(this);
}
@ -309,6 +324,10 @@ public class HashsetHits implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(Long id) {
if (skCase == null) {
return null;
}
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
return new BlackboardArtifactNode(art);

View File

@ -42,6 +42,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Exceptions;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -57,7 +58,7 @@ public class InterestingHits implements AutopsyVisitableItem {
private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text");
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
private SleuthkitCase skCase;
private InterestingResults interestingResults = new InterestingResults();
private final InterestingResults interestingResults = new InterestingResults();
public InterestingHits(SleuthkitCase skCase) {
this.skCase = skCase;
@ -65,7 +66,7 @@ public class InterestingHits implements AutopsyVisitableItem {
}
private class InterestingResults extends Observable {
private Map<String, Set<Long>> interestingItemsMap = new LinkedHashMap<>();
private final Map<String, Set<Long>> interestingItemsMap = new LinkedHashMap<>();
public List<String> getSetNames() {
List<String> setNames = new ArrayList<>(interestingItemsMap.keySet());
@ -89,6 +90,10 @@ public class InterestingHits implements AutopsyVisitableItem {
* Reads the artifacts of specified type, grouped by Set, and loads into the interestingItemsMap
*/
private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) {
if (skCase == null) {
return;
}
ResultSet rs = null;
try {
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
@ -188,6 +193,13 @@ public class InterestingHits implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
interestingResults.update();
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
@ -195,6 +207,7 @@ public class InterestingHits implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
interestingResults.update();
interestingResults.addObserver(this);
}
@ -203,6 +216,7 @@ public class InterestingHits implements AutopsyVisitableItem {
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
interestingResults.deleteObserver(this);
}
@ -290,6 +304,9 @@ public class InterestingHits implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(Long l) {
if (skCase == null) {
return null;
}
try {
return new BlackboardArtifactNode(skCase.getBlackboardArtifact(l));
} catch (TskCoreException ex) {

View File

@ -39,6 +39,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -61,7 +62,7 @@ public class KeywordHits implements AutopsyVisitableItem {
.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
public static final String SIMPLE_REGEX_SEARCH = NbBundle
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
private KeywordResults keywordResults;
private final KeywordResults keywordResults;
public KeywordHits(SleuthkitCase skCase) {
this.skCase = skCase;
@ -70,7 +71,7 @@ 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 Map<String, Map<String, Set<Long>>> topLevelMap;
private final Map<String, Map<String, Set<Long>>> topLevelMap;
KeywordResults() {
topLevelMap = new LinkedHashMap<>();
@ -146,6 +147,10 @@ public class KeywordHits implements AutopsyVisitableItem {
public void update() {
Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
if (skCase == null) {
return;
}
ResultSet rs = null;
try {
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
@ -245,6 +250,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
keywordResults.update();
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
@ -252,6 +264,7 @@ public class KeywordHits implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
keywordResults.update();
keywordResults.addObserver(this);
}
@ -260,6 +273,7 @@ public class KeywordHits implements AutopsyVisitableItem {
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
keywordResults.deleteObserver(this);
}
@ -462,12 +476,16 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(Long artifactId) {
if (skCase == null) {
return null;
}
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = art.getSleuthkitCase().getAbstractFileById(art.getObjectID());
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;

View File

@ -52,7 +52,7 @@ public class Tags implements AutopsyVisitableItem {
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
// override of Children.Keys<T>.createNodes().
private TagResults tagResults = new TagResults();
private final TagResults tagResults = new TagResults();
private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text");
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
@ -130,6 +130,12 @@ public class Tags implements AutopsyVisitableItem {
refresh(true);
tagResults.update();
}
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that this can be garbage collected
if (evt.getNewValue() == null) {
removeNotify();
}
}
}
};
@ -137,6 +143,7 @@ public class Tags implements AutopsyVisitableItem {
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
tagResults.update();
tagResults.addObserver(this);
}
@ -145,6 +152,7 @@ public class Tags implements AutopsyVisitableItem {
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
tagResults.deleteObserver(this);
}