Merge pull request #1384 from rcordovano/closed-case-checks

Closed case checks
This commit is contained in:
Richard Cordovano 2015-06-19 14:32:53 -04:00
commit e1599e13a1
18 changed files with 674 additions and 285 deletions

View File

@ -1392,29 +1392,33 @@ public class Case {
Case.clearTempFolder(); Case.clearTempFolder();
checkSubFolders(toChangeTo); checkSubFolders(toChangeTo);
// enable these menus if (IngestManager.getInstance().isRunningInteractively()) {
CallableSystemAction.get(AddImageAction.class).setEnabled(true); // enable these menus
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(AddImageAction.class).setEnabled(true);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu
if (toChangeTo.hasData()) { if (toChangeTo.hasData()) {
// open all top components // open all top components
CoreComponentControl.openCoreWindows(); CoreComponentControl.openCoreWindows();
} else { } else {
// close all top components // close all top components
CoreComponentControl.closeCoreWindows(); CoreComponentControl.closeCoreWindows();
}
} }
} else { // case is closed } else { // case is closed
// close all top components first if (IngestManager.getInstance().isRunningInteractively()) {
CoreComponentControl.closeCoreWindows(); // close all top components first
CoreComponentControl.closeCoreWindows();
// disable these menus
CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu
// disable these menus
CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu
}
//clear pending notifications //clear pending notifications
MessageNotifyUtil.Notify.clear(); MessageNotifyUtil.Notify.clear();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2014 Basis Technology Corp. * Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -180,16 +180,40 @@ public class DeletedContent implements AutopsyVisitableItem {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
// new file was added
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
// @@@ COULD CHECK If the new file is deleted before notifying... /**
update(); * Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
*/
try {
Case.getCurrentCase();
// new file was added
// @@@ COULD CHECK If the new file is deleted before notifying...
update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
update(); || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
} else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { /**
update(); * Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
*/
try {
Case.getCurrentCase();
update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { } 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {

View File

@ -204,17 +204,47 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG) { /**
emailResults.update(); * Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
/**
* Even with the check above, it is still possible that the
* case will be closed in a different thread before this
* code executes. If that happens, it is possible for the
* event to have a null oldValue.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG) {
emailResults.update();
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { /**
emailResults.update(); * Checking for a current case is a stop gap measure until a
} * different way of handling the closing of cases is worked
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
emailResults.update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
removeNotify(); removeNotify();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -126,7 +126,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
* more specific form elsewhere in the tree. * more specific form elsewhere in the tree.
*/ */
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.ARTIFACT_TYPE> { private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.ARTIFACT_TYPE> {
private final ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotShow; private final ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotShow = new ArrayList<>();
// maps the artifact type to its child node // maps the artifact type to its child node
private final HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>(); private final HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>();
@ -134,7 +134,6 @@ public class ExtractedContent implements AutopsyVisitableItem {
super(); super();
// these are shown in other parts of the UI tree // these are shown in other parts of the UI tree
doNotShow = new ArrayList<>();
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO); doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT);
@ -143,26 +142,53 @@ public class ExtractedContent implements AutopsyVisitableItem {
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
} }
private final PropertyChangeListener pcl = new PropertyChangeListener() { private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
@Override String eventType = evt.getPropertyName();
public void propertyChange(PropertyChangeEvent evt) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
String eventType = evt.getPropertyName(); /**
* This is a stop gap measure until a different way of
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { * handling the closing of cases is worked out. Currently,
* remote events may be received for a case that is already
* closed.
*/
try {
Case.getCurrentCase();
/**
* Due to some unresolved issues with how cases are
* closed, it is possible for the event to have a null
* oldValue if the event is a remote event.
*/
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (doNotShow.contains(event.getArtifactType()) == false) { if (null != event && doNotShow.contains(event.getArtifactType()) == false) {
refresh(true); refresh(true);
} }
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) } catch (IllegalStateException notUsed) {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { /**
refresh(true); * Case is closed, do nothing.
*/
} }
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
// case was closed. Remove listeners so that we don't get called with a stale case handle || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
if (evt.getNewValue() == null) { /**
removeNotify(); * This is a stop gap measure until a different way of
skCase = null; * handling the closing of cases is worked out. Currently,
} * remote events may be received for a case that is already
* closed.
*/
try {
Case.getCurrentCase();
refresh(true);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
}
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;
} }
} }
}; };
@ -362,15 +388,46 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); /**
if (event.getArtifactType() == type) { * Checking for a current case is a stop gap measure until a
refresh(true); * different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
/**
* Even with the check above, it is still possible that
* the case will be closed in a different thread before
* this code executes. If that happens, it is possible
* for the event to have a null oldValue.
*/
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (null != event && event.getArtifactType() == type) {
refresh(true);
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
refresh(true); /**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
refresh(true);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} }
} }
}; };

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2014 Basis Technology Corp. * Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -178,15 +178,40 @@ public class FileSize implements AutopsyVisitableItem {
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
// new file was added
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
// @@@ could check the size here and only fire off updates if we know the file meets the min size criteria /**
update(); * Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
*/
try {
// new file was added
// @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
Case.getCurrentCase();
update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
update(); || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
} else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { /**
update(); * Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
*/
try {
Case.getCurrentCase();
update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { } 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -152,15 +152,24 @@ public class FileTypesNode extends DisplayableItemNode {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
// new file was added || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
update(); || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) /**
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { * Checking for a current case is a stop gap measure
update(); * until a different way of handling the closing of
} else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { * cases is worked out. Currently, remote events may be
update(); * received for a case that is already closed.
*/
try {
Case.getCurrentCase();
update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { } 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -181,17 +181,46 @@ public class HashsetHits implements AutopsyVisitableItem {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == ARTIFACT_TYPE.TSK_HASHSET_HIT) { /**
hashsetResults.update(); * Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
/**
* Due to some unresolved issues with how cases are
* closed, it is possible for the event to have a null
* oldValue if the event is a remote event.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getArtifactType() == ARTIFACT_TYPE.TSK_HASHSET_HIT) {
hashsetResults.update();
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { /**
hashsetResults.update(); * Checking for a current case is a stop gap measure until a
} * different way of handling the closing of cases is worked
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
hashsetResults.update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
removeNotify(); removeNotify();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -50,34 +49,34 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
public class InterestingHits implements AutopsyVisitableItem { public class InterestingHits implements AutopsyVisitableItem {
private static final String INTERESTING_ITEMS = NbBundle private static final String INTERESTING_ITEMS = NbBundle
.getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"); .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text");
private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text"); private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text");
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final InterestingResults interestingResults = new InterestingResults(); private final InterestingResults interestingResults = new InterestingResults();
public InterestingHits(SleuthkitCase skCase) { public InterestingHits(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
interestingResults.update(); interestingResults.update();
} }
private class InterestingResults extends Observable { private class InterestingResults extends Observable {
private final Map<String, Set<Long>> interestingItemsMap = new LinkedHashMap<>(); private final Map<String, Set<Long>> interestingItemsMap = new LinkedHashMap<>();
public List<String> getSetNames() { public List<String> getSetNames() {
List<String> setNames = new ArrayList<>(interestingItemsMap.keySet()); List<String> setNames = new ArrayList<>(interestingItemsMap.keySet());
Collections.sort(setNames); Collections.sort(setNames);
return setNames; return setNames;
} }
public Set<Long> getArtifactIds(String setName) { public Set<Long> getArtifactIds(String setName) {
return interestingItemsMap.get(setName); return interestingItemsMap.get(setName);
} }
public void update() { public void update() {
interestingItemsMap.clear(); interestingItemsMap.clear();
loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
@ -85,16 +84,17 @@ public class InterestingHits implements AutopsyVisitableItem {
setChanged(); setChanged();
notifyObservers(); notifyObservers();
} }
/* /*
* Reads the artifacts of specified type, grouped by Set, and loads into the interestingItemsMap * Reads the artifacts of specified type, grouped by Set, and loads into
* the interestingItemsMap
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) { private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) {
if (skCase == null) { if (skCase == null) {
return; return;
} }
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = artType.getTypeID(); int artId = artType.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
@ -118,13 +118,13 @@ public class InterestingHits implements AutopsyVisitableItem {
} }
} }
} }
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> v) { public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
/** /**
* Node for the interesting items * Node for the interesting items
*/ */
public class RootNode extends DisplayableItemNode { public class RootNode extends DisplayableItemNode {
@ -140,7 +140,7 @@ public class InterestingHits implements AutopsyVisitableItem {
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return false; return false;
} }
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -156,36 +156,67 @@ public class InterestingHits implements AutopsyVisitableItem {
} }
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"),
getName())); getName()));
return s; return s;
} }
} }
private class SetNameFactory extends ChildFactory.Detachable<String> implements Observer {
/* This should probably be in the top-level class, but the factory has nice methods private class SetNameFactory extends ChildFactory.Detachable<String> implements Observer {
* for its startup and shutdown, so it seemed like a cleaner place to register the
* property change listener. /*
* This should probably be in the top-level class, but the factory has
* nice methods for its startup and shutdown, so it seemed like a
* cleaner place to register the property change listener.
*/ */
private final PropertyChangeListener pcl = new PropertyChangeListener() { private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT) || /**
(((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)) { * Checking for a current case is a stop gap measure until a
interestingResults.update(); * different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
/**
* Even with the check above, it is still possible that
* the case will be closed in a different thread before
* this code executes. If that happens, it is possible
* for the event to have a null oldValue.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && (eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT
|| eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)) {
interestingResults.update();
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { /**
interestingResults.update(); * Checking for a current case is a stop gap measure until a
} * different way of handling the closing of cases is worked
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
interestingResults.update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
removeNotify(); removeNotify();
@ -211,7 +242,7 @@ public class InterestingHits implements AutopsyVisitableItem {
Case.removePropertyChangeListener(pcl); Case.removePropertyChangeListener(pcl);
interestingResults.deleteObserver(this); interestingResults.deleteObserver(this);
} }
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
list.addAll(interestingResults.getSetNames()); list.addAll(interestingResults.getSetNames());
@ -228,9 +259,11 @@ public class InterestingHits implements AutopsyVisitableItem {
refresh(true); refresh(true);
} }
} }
public class SetNameNode extends DisplayableItemNode implements Observer { public class SetNameNode extends DisplayableItemNode implements Observer {
private final String setName; private final String setName;
public SetNameNode(String setName) {//, Set<Long> children) { public SetNameNode(String setName) {//, Set<Long> children) {
super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName)); super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName));
this.setName = setName; this.setName = setName;
@ -239,7 +272,7 @@ public class InterestingHits implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
interestingResults.addObserver(this); interestingResults.addObserver(this);
} }
private void updateDisplayName() { private void updateDisplayName() {
super.setDisplayName(setName + " (" + interestingResults.getArtifactIds(setName).size() + ")"); super.setDisplayName(setName + " (" + interestingResults.getArtifactIds(setName).size() + ")");
} }
@ -259,9 +292,9 @@ public class InterestingHits implements AutopsyVisitableItem {
} }
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"),
getName())); getName()));
return s; return s;
} }
@ -276,8 +309,9 @@ public class InterestingHits implements AutopsyVisitableItem {
updateDisplayName(); updateDisplayName();
} }
} }
private class HitFactory extends ChildFactory<Long> implements Observer { private class HitFactory extends ChildFactory<Long> implements Observer {
private final String setName; private final String setName;
private HitFactory(String setName) { private HitFactory(String setName) {
@ -297,7 +331,7 @@ public class InterestingHits implements AutopsyVisitableItem {
@Override @Override
protected Node createNodeForKey(Long l) { protected Node createNodeForKey(Long l) {
if (skCase == null) { if (skCase == null) {
return null; return null;
} }
try { try {
return new BlackboardArtifactNode(skCase.getBlackboardArtifact(l)); return new BlackboardArtifactNode(skCase.getBlackboardArtifact(l));

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -246,17 +246,47 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT) { /**
keywordResults.update(); * Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
/**
* Even with the check above, it is still possible that
* the case will be closed in a different thread before
* this code executes. If that happens, it is possible
* for the event to have a null oldValue.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT) {
keywordResults.update();
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { /**
keywordResults.update(); * Checking for a current case is a stop gap measure until a
} * different way of handling the closing of cases is worked
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
keywordResults.update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} 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 // case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
removeNotify(); removeNotify();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2014 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -98,7 +98,20 @@ public final class Reports implements AutopsyVisitableItem {
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.REPORT_ADDED.toString())) { if (eventType.equals(Case.Events.REPORT_ADDED.toString())) {
ReportNodeFactory.this.refresh(true); /**
* Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
*/
try {
Case.getCurrentCase();
ReportNodeFactory.this.refresh(true);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} }
} }
}); });

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013 Basis Technology Corp. * Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -51,26 +51,23 @@ public class Tags implements AutopsyVisitableItem {
// Creation of a RootNode object corresponding to a Tags object is done // Creation of a RootNode object corresponding to a Tags object is done
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
// override of Children.Keys<T>.createNodes(). // override of Children.Keys<T>.createNodes().
private final 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 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 private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> v) { public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
/** /**
* This class largely does nothing except act as a top-level object that * This class largely does nothing except act as a top-level object that the
* the other nodes can listen to. This mimics what other nodes have (keword search, etc.), * other nodes can listen to. This mimics what other nodes have (keword
* but theirs stores data. * search, etc.), but theirs stores data.
*/ */
private class TagResults extends Observable { private class TagResults extends Observable {
public void update() { public void update() {
setChanged(); setChanged();
notifyObservers(); notifyObservers();
@ -123,20 +120,56 @@ public class Tags implements AutopsyVisitableItem {
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
/* Note: this is a hack. In an ideal world, TagsManager /**
* would fire events so that the directory tree would * Checking for a current case is a stop gap measure until a
* refresh. But, we haven't had a chance to add that so, we * different way of handling the closing of cases is worked
* fire these events and the tree refreshes based on them. */ * out. Currently, remote events may be received for a case
if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) * that is already closed.
|| ((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { */
refresh(true); try {
tagResults.update(); Case.getCurrentCase();
/**
* There are two things to note here. * First, even with
* the check above, it is still possible that the case
* will be closed in a different thread before this code
* executes. If that happens, it is possible for the
* event to have a null oldValue. Second, the use of
* deprecated artifact types here is explained by the
* fact that in an ideal world, the TagsManager would
* fire tag-related events so that the tags tree would
* refresh. But, we haven't had a chance to add that, so
* we fire these events with bogus artifacts to indicate
* a tree refresh is required.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData
&& (eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
|| eventData.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
refresh(true);
tagResults.update();
}
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
} }
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
refresh(true); /**
tagResults.update(); * Checking for a current case is a stop gap measure until a
} * different way of handling the closing of cases is worked
else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
refresh(true);
tagResults.update();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that this can be garbage collected // case was closed. Remove listeners so that this can be garbage collected
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
removeNotify(); removeNotify();
@ -187,15 +220,15 @@ public class Tags implements AutopsyVisitableItem {
/** /**
* Instances of this class are elements of Node hierarchies consisting of * Instances of this class are elements of Node hierarchies consisting of
* content and blackboard artifact tags, grouped first by tag type, then by tag * content and blackboard artifact tags, grouped first by tag type, then by
* name. * tag name.
*/ */
public class TagNameNode extends DisplayableItemNode implements Observer { public class TagNameNode extends DisplayableItemNode implements Observer {
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; //NON-NLS private final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; //NON-NLS
private final TagName tagName; private final TagName tagName;
public TagNameNode(TagName tagName) { public TagNameNode(TagName tagName) {
super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName()))); super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName())));
this.tagName = tagName; this.tagName = tagName;
@ -250,12 +283,13 @@ public class Tags implements AutopsyVisitableItem {
updateDisplayName(); updateDisplayName();
} }
} }
/** /**
* Creates nodes for the two types of tags: file and artifact. * Creates nodes for the two types of tags: file and artifact. Does not need
* Does not need observer / messages since it always has the same children * observer / messages since it always has the same children
*/ */
private class TagTypeNodeFactory extends ChildFactory<String> { private class TagTypeNodeFactory extends ChildFactory<String> {
private final TagName tagName; private final TagName tagName;
private final String CONTENT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.contentTagTypeNodeKey.text"); private final String CONTENT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.contentTagTypeNodeKey.text");
private final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.bbArtTagTypeNodeKey.text"); private final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = NbBundle.getMessage(TagNameNode.class, "TagNameNode.bbArtTagTypeNodeKey.text");
@ -284,19 +318,20 @@ public class Tags implements AutopsyVisitableItem {
} }
} }
} }
private final String CONTENT_DISPLAY_NAME = NbBundle.getMessage(ContentTagTypeNode.class, "ContentTagTypeNode.displayName.text"); private final String CONTENT_DISPLAY_NAME = NbBundle.getMessage(ContentTagTypeNode.class, "ContentTagTypeNode.displayName.text");
/** /**
* Node for the content tags. Children are specific tags. * Node for the content tags. Children are specific tags. Instances of this
* Instances of this class are are elements of a directory tree sub-tree * class are are elements of a directory tree sub-tree consisting of content
* consisting of content and blackboard artifact tags, grouped first by tag * and blackboard artifact tags, grouped first by tag type, then by tag
* type, then by tag name. * name.
*/ */
public class ContentTagTypeNode extends DisplayableItemNode implements Observer { public class ContentTagTypeNode extends DisplayableItemNode implements Observer {
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private TagName tagName; private TagName tagName;
public ContentTagTypeNode(TagName tagName) { public ContentTagTypeNode(TagName tagName) {
super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + CONTENT_DISPLAY_NAME)); super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + CONTENT_DISPLAY_NAME));
this.tagName = tagName; this.tagName = tagName;
@ -305,7 +340,7 @@ public class Tags implements AutopsyVisitableItem {
this.setIconBaseWithExtension(ICON_PATH); this.setIconBaseWithExtension(ICON_PATH);
tagResults.addObserver(this); tagResults.addObserver(this);
} }
private void updateDisplayName() { private void updateDisplayName() {
long tagsCount = 0; long tagsCount = 0;
try { try {
@ -341,10 +376,11 @@ public class Tags implements AutopsyVisitableItem {
@Override @Override
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
updateDisplayName(); updateDisplayName();
} }
} }
private class ContentTagNodeFactory extends ChildFactory<ContentTag> implements Observer { private class ContentTagNodeFactory extends ChildFactory<ContentTag> implements Observer {
private final TagName tagName; private final TagName tagName;
ContentTagNodeFactory(TagName tagName) { ContentTagNodeFactory(TagName tagName) {
@ -377,13 +413,15 @@ public class Tags implements AutopsyVisitableItem {
} }
private final String ARTIFACT_DISPLAY_NAME = NbBundle.getMessage(BlackboardArtifactTagTypeNode.class, "BlackboardArtifactTagTypeNode.displayName.text"); private final String ARTIFACT_DISPLAY_NAME = NbBundle.getMessage(BlackboardArtifactTagTypeNode.class, "BlackboardArtifactTagTypeNode.displayName.text");
/** /**
* Instances of this class are elements in a sub-tree of the Autopsy * Instances of this class are elements in a sub-tree of the Autopsy
* presentation of the SleuthKit data model. The sub-tree consists of content * presentation of the SleuthKit data model. The sub-tree consists of
* and blackboard artifact tags, grouped first by tag type, then by tag name. * content and blackboard artifact tags, grouped first by tag type, then by
* tag name.
*/ */
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode implements Observer { public class BlackboardArtifactTagTypeNode extends DisplayableItemNode implements Observer {
private TagName tagName; private TagName tagName;
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
@ -395,7 +433,7 @@ public class Tags implements AutopsyVisitableItem {
updateDisplayName(); updateDisplayName();
tagResults.addObserver(this); tagResults.addObserver(this);
} }
private void updateDisplayName() { private void updateDisplayName() {
long tagsCount = 0; long tagsCount = 0;
try { try {
@ -435,28 +473,29 @@ public class Tags implements AutopsyVisitableItem {
} }
private class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> { private class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> {
private final TagName tagName;
BlackboardArtifactTagNodeFactory(TagName tagName) { private final TagName tagName;
super();
this.tagName = tagName;
}
@Override BlackboardArtifactTagNodeFactory(TagName tagName) {
protected boolean createKeys(List<BlackboardArtifactTag> keys) { super();
try { this.tagName = tagName;
// Use the blackboard artifact tags bearing the specified tag name as the keys. }
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
} catch (TskCoreException ex) {
Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
return true;
}
@Override @Override
protected Node createNodeForKey(BlackboardArtifactTag key) { protected boolean createKeys(List<BlackboardArtifactTag> keys) {
// The blackboard artifact tags to be wrapped are used as the keys. try {
return new BlackboardArtifactTagNode(key); // Use the blackboard artifact tags bearing the specified tag name as the keys.
} keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
} } catch (TskCoreException ex) {
Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifactTag key) {
// The blackboard artifact tags to be wrapped are used as the keys.
return new BlackboardArtifactTagNode(key);
}
}
} }

View File

@ -34,7 +34,6 @@ import java.util.logging.Level;
import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener; import java.util.prefs.PreferenceChangeListener;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.tree.TreeSelectionModel; import javax.swing.tree.TreeSelectionModel;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
@ -524,60 +523,83 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
*/ */
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName(); if (IngestManager.getInstance().isRunningInteractively()) {
Object oldValue = evt.getOldValue(); String changed = evt.getPropertyName();
Object newValue = evt.getNewValue(); if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case
if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case // When a case is closed, the old value of this property is the
// When a case is closed, the old value of this property is the // closed Case object and the new value is null. When a case is
// closed Case object and the new value is null. When a case is // opened, the old value is null and the new value is the new Case
// opened, the old value is null and the new value is the new Case // object.
// object. // @@@ This needs to be revisited. Perhaps case closed and case
// @@@ This needs to be revisited. Perhaps case closed and case // opened events instead of property change events would be a better
// opened events instead of property change events would be a better // solution. Either way, more probably needs to be done to clean up
// solution. Either way, more probably needs to be done to clean up // data model objects when a case is closed.
// data model objects when a case is closed. if (evt.getOldValue() != null && evt.getNewValue() == null) {
if (oldValue != null && newValue == null) { // The current case has been closed. Reset the ExplorerManager.
// The current case has been closed. Reset the ExplorerManager. SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() -> { Node emptyNode = new AbstractNode(Children.LEAF);
Node emptyNode = new AbstractNode(Children.LEAF); em.setRootContext(emptyNode);
em.setRootContext(emptyNode); });
}); } else if (evt.getNewValue() != null) {
} else if (newValue != null) { // A new case has been opened. Reset the ExplorerManager.
// A new case has been opened. Reset the ExplorerManager. Case newCase = (Case) evt.getNewValue();
Case newCase = (Case) newValue; final String newCaseName = newCase.getName();
final String newCaseName = newCase.getName(); SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() -> { em.getRootContext().setName(newCaseName);
em.getRootContext().setName(newCaseName); em.getRootContext().setDisplayName(newCaseName);
em.getRootContext().setDisplayName(newCaseName);
// Reset the forward and back // Reset the forward and back
// buttons. Note that a call to CoreComponentControl.openCoreWindows() // buttons. Note that a call to CoreComponentControl.openCoreWindows()
// by the new Case object will lead to a componentOpened() call // by the new Case object will lead to a componentOpened() call
// that will repopulate the tree. // that will repopulate the tree.
// @@@ The repopulation of the tree in this fashion also merits // @@@ The repopulation of the tree in this fashion also merits
// reconsideration. // reconsideration.
resetHistory(); resetHistory();
});
}
} // if the image is added to the case
else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked out.
* Currently, remote events may be received for a case that is
* already closed.
*/
try {
Case.getCurrentCase();
CoreComponentControl.openCoreWindows();
SwingUtilities.invokeLater(this::componentOpened);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} // change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
SwingUtilities.invokeLater(() -> {
respondSelection((Node[]) evt.getOldValue(), (Node[]) evt.getNewValue());
}); });
} } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
} // if the image is added to the case
else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
if (IngestManager.getInstance().isRunningInteractively()) {
CoreComponentControl.openCoreWindows();
}
SwingUtilities.invokeLater(this::componentOpened);
} // change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
SwingUtilities.invokeLater(() -> {
respondSelection((Node[]) oldValue, (Node[]) newValue);
});
} else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
// nothing to do here. // nothing to do here.
// all nodes should be listening for these events and update accordingly. // all nodes should be listening for these events and update accordingly.
} else if (changed.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) } else if (changed.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| changed.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { || changed.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
SwingUtilities.invokeLater(this::refreshDataSourceTree); || changed.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
} else if (changed.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { /**
SwingUtilities.invokeLater(this::refreshDataSourceTree); * Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked out.
* Currently, remote events may be received for a case that is
* already closed.
*/
try {
Case.getCurrentCase();
SwingUtilities.invokeLater(this::refreshDataSourceTree);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
}
} }
} }

View File

@ -32,7 +32,9 @@ import javax.jms.ObjectMessage;
import javax.jms.Session; import javax.jms.Session;
import javax.jms.Topic; import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
/** /**
* Provides thread-safe support for publishing events to registered subscribers * Provides thread-safe support for publishing events to registered subscribers
@ -99,7 +101,7 @@ final class RemoteEventPublisher {
} }
if (null != consumer) { if (null != consumer) {
consumer.close(); consumer.close();
} }
if (null != session) { if (null != session) {
session.close(); session.close();
} }
@ -134,21 +136,40 @@ final class RemoteEventPublisher {
*/ */
@Override @Override
public void onMessage(Message message) { public void onMessage(Message message) {
try { if (IngestManager.getInstance().isRunningInteractively()) {
if (message instanceof ObjectMessage) { /**
ObjectMessage objectMessage = (ObjectMessage) message; * This is a stop gap measure until a different way of handling
Object object = objectMessage.getObject(); * the closing of cases is worked out. Currently,
if (object instanceof AutopsyEvent) { * Case.currentCase is set to null before
AutopsyEvent event = (AutopsyEvent) object; * Case.Event.CURRENT_CASE is published. That means that clients
event.setSourceType(AutopsyEvent.SourceType.REMOTE); * of this class have not had the chance to close their remote
localPublisher.publish(event); * event channels and remote events may be received for a case
} * that is already closed.
*/
try {
Case.getCurrentCase();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do not publish the event.
*/
return;
}
try {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
Object object = objectMessage.getObject();
if (object instanceof AutopsyEvent) {
AutopsyEvent event = (AutopsyEvent) object;
event.setSourceType(AutopsyEvent.SourceType.REMOTE);
localPublisher.publish(event);
}
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error receiving message", ex);
} }
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error receiving message", ex);
} }
} }
} }
} }

View File

@ -74,7 +74,7 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
public String getPredicate() throws FilterValidationException { public String getPredicate() throws FilterValidationException {
String query = "NULL"; String query = "NULL";
DateSearchPanel panel = this.getComponent(); DateSearchPanel panel = this.getComponent();
// first, get the selected timeZone from the dropdown list // first, get the selected timeZone from the dropdown list
String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString(); String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString();
String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID
@ -126,7 +126,7 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
toDate = fromDate; toDate = fromDate;
fromDate = temp; fromDate = temp;
} }
final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected(); final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected();
final boolean changedChecked = panel.getChangedCheckBox().isSelected(); final boolean changedChecked = panel.getChangedCheckBox().isSelected();
final boolean accessedChecked = panel.getAccessedCheckBox().isSelected(); final boolean accessedChecked = panel.getAccessedCheckBox().isSelected();
@ -253,7 +253,20 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
break; break;
case DATA_SOURCE_ADDED: case DATA_SOURCE_ADDED:
case DATA_SOURCE_DELETED: case DATA_SOURCE_DELETED:
SwingUtilities.invokeLater(DateSearchFilter.this::updateTimeZoneList); /**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
SwingUtilities.invokeLater(DateSearchFilter.this::updateTimeZoneList);
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
break; break;
} }
} }

View File

@ -53,7 +53,7 @@ public final class BlackboardPostEvent extends AutopsyEvent implements Serializa
*/ */
public BlackboardPostEvent(ModuleDataEvent eventData) { public BlackboardPostEvent(ModuleDataEvent eventData) {
/** /**
* Putting a serializable data holding object into newValue to allow for * Putting a serializable data holding object into oldValue to allow for
* lazy loading of the ModuleDataEvent object for remote events. This * lazy loading of the ModuleDataEvent object for remote events. This
* bypasses the issues related to the serialization and de-serialization * bypasses the issues related to the serialization and de-serialization
* of BlackboardArtifact objects when the event is published over a * of BlackboardArtifact objects when the event is published over a

View File

@ -680,10 +680,23 @@ public class TimeLineController {
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) { switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
case FILE_DONE: case FILE_DONE:
Platform.runLater(() -> { /**
newEventsFlag.set(true); * Checking for a current case is a stop gap measure until a
}); * different way of handling the closing of cases is worked
break; * out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
Platform.runLater(() -> {
newEventsFlag.set(true);
});
break;
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} }
} }
} }
@ -696,9 +709,22 @@ public class TimeLineController {
switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) { switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) {
case CANCELLED: case CANCELLED:
case COMPLETED: case COMPLETED:
SwingUtilities.invokeLater(() -> { /**
outOfDatePromptAndRebuild(); * Checking for a current case is a stop gap measure until a
}); * different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
SwingUtilities.invokeLater(() -> {
outOfDatePromptAndRebuild();
});
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
break; break;
} }
} }
@ -711,9 +737,22 @@ public class TimeLineController {
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
switch (Case.Events.valueOf(evt.getPropertyName())) { switch (Case.Events.valueOf(evt.getPropertyName())) {
case DATA_SOURCE_ADDED: case DATA_SOURCE_ADDED:
SwingUtilities.invokeLater(() -> { /**
outOfDatePromptAndRebuild(); * Checking for a current case is a stop gap measure until a
}); * different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCase();
SwingUtilities.invokeLater(() -> {
outOfDatePromptAndRebuild();
});
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
break; break;
case CURRENT_CASE: case CURRENT_CASE:
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Mon, 08 Jun 2015 11:37:44 -0400 #Fri, 19 Jun 2015 13:59:39 -0400
LBL_splash_window_title=Starting Autopsy LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314 SPLASH_HEIGHT=314
SPLASH_WIDTH=538 SPLASH_WIDTH=538

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Mon, 08 Jun 2015 11:37:44 -0400 #Fri, 19 Jun 2015 13:59:39 -0400
CTL_MainWindow_Title=Autopsy 3.1.2 CTL_MainWindow_Title=Autopsy 3.1.2
CTL_MainWindow_Title_No_Project=Autopsy 3.1.2 CTL_MainWindow_Title_No_Project=Autopsy 3.1.2