3080 Moved all actions as a result of CaseEventLister to background thread pool

This commit is contained in:
William Schaefer 2017-10-18 14:36:44 -04:00
parent 32af6d3b49
commit 2fb71f2ff0
5 changed files with 359 additions and 336 deletions

View File

@ -85,6 +85,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.core.UserPreferencesException; import org.sleuthkit.autopsy.core.UserPreferencesException;
import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl; import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl;
import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.DriveUtils;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ -1645,7 +1646,7 @@ public class Case {
} else { } else {
future.cancel(true); future.cancel(true);
} }
Case.shutDownTaskExecutor(caseLockingExecutor); ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
} catch (CancellationException discarded) { } catch (CancellationException discarded) {
/* /*
* The create/open task has been cancelled. Wait for it to finish, * The create/open task has been cancelled. Wait for it to finish,
@ -1654,7 +1655,7 @@ public class Case {
* will have been closed and the case directory lock released will * will have been closed and the case directory lock released will
* have been released. * have been released.
*/ */
Case.shutDownTaskExecutor(caseLockingExecutor); ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
throw new CaseActionCancelledException(Bundle.Case_exceptionMessage_cancelledByUser()); throw new CaseActionCancelledException(Bundle.Case_exceptionMessage_cancelledByUser());
} catch (ExecutionException ex) { } catch (ExecutionException ex) {
/* /*
@ -1664,7 +1665,7 @@ public class Case {
* case will have been closed and the case directory lock released * case will have been closed and the case directory lock released
* will have been released. * will have been released.
*/ */
Case.shutDownTaskExecutor(caseLockingExecutor); ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex); throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
} finally { } finally {
progressIndicator.finish(); progressIndicator.finish();
@ -1992,7 +1993,7 @@ public class Case {
* would be possible to start the next task before the current * would be possible to start the next task before the current
* task responded to a cancellation request. * task responded to a cancellation request.
*/ */
shutDownTaskExecutor(executor); ExecUtil.shutDownTaskExecutor(executor);
progressIndicator.finish(); progressIndicator.finish();
} }
@ -2063,7 +2064,7 @@ public class Case {
} catch (ExecutionException ex) { } catch (ExecutionException ex) {
throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex); throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
} finally { } finally {
shutDownTaskExecutor(caseLockingExecutor); ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
progressIndicator.finish(); progressIndicator.finish();
} }
} }
@ -2174,7 +2175,7 @@ public class Case {
Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage()))); Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
} }
} finally { } finally {
shutDownTaskExecutor(executor); ExecUtil.shutDownTaskExecutor(executor);
progressIndicator.finish(); progressIndicator.finish();
} }
} }
@ -2231,41 +2232,6 @@ public class Case {
} }
/**
* Shuts down a task executor service, waiting until all tasks are
* terminated. The current policy is to wait for the tasks to finish so that
* the case for which the executor is running can be left in a consistent
* state.
*
* @param executor The executor.
*/
private static void shutDownTaskExecutor(ExecutorService executor) {
executor.shutdown();
boolean taskCompleted = false;
while (!taskCompleted) {
try {
taskCompleted = executor.awaitTermination(EXECUTOR_AWAIT_TIMEOUT_SECS, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
/*
* The current policy is to wait for the task to finish so that
* the case can be left in a consistent state.
*
* For a specific example of the motivation for this policy,
* note that a application service (Solr search service)
* experienced an error condition when opening case resources
* that left the service blocked uninterruptibly on a socket
* read. This eventually led to a mysterious "freeze" as the
* user-cancelled service task continued to run holdiong a lock
* that a UI thread soon tried to acquire. Thus it has been
* deemed better to make the "freeze" happen in a more
* informative way, i.e., with the progress indicator for the
* unfinished task on the screen, if a similar error condition
* arises again.
*/
}
}
}
/** /**
* A case operation Cancel button listener for use with a * A case operation Cancel button listener for use with a
* ModalDialogProgressIndicator when running with a GUI. * ModalDialogProgressIndicator when running with a GUI.

View File

@ -18,9 +18,12 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.eventlisteners; package org.sleuthkit.autopsy.centralrepository.eventlisteners;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -39,6 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
@ -53,9 +57,19 @@ import org.sleuthkit.datamodel.TskDataException;
* accordingly * accordingly
*/ */
@Messages({"caseeventlistener.evidencetag=Evidence"}) @Messages({"caseeventlistener.evidencetag=Evidence"})
public class CaseEventListener implements PropertyChangeListener { final class CaseEventListener implements PropertyChangeListener {
private static final Logger LOGGER = Logger.getLogger(CaseEventListener.class.getName()); private static final Logger LOGGER = Logger.getLogger(CaseEventListener.class.getName());
private final ExecutorService jobProcessingExecutor;
private static final String CASE_EVENT_THREAD_NAME = "Case-Event-Listener-%d";
CaseEventListener() {
jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build());
}
void shutdown() {
ExecUtil.shutDownTaskExecutor(jobProcessingExecutor);
}
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
@ -69,250 +83,24 @@ public class CaseEventListener implements PropertyChangeListener {
switch (Case.Events.valueOf(evt.getPropertyName())) { switch (Case.Events.valueOf(evt.getPropertyName())) {
case CONTENT_TAG_ADDED: case CONTENT_TAG_ADDED:
case CONTENT_TAG_DELETED: { case CONTENT_TAG_DELETED: {
if (!EamDb.isEnabled()) { jobProcessingExecutor.submit(new ContentTagTask(dbManager, evt));
return; }
}
AbstractFile af;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(evt.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt;
final ContentTag tagAdded = tagAddedEvent.getAddedTag();
if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) {
if (tagAdded.getContent() instanceof AbstractFile) {
af = (AbstractFile) tagAdded.getContent();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { // CONTENT_TAG_DELETED
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!dbManager.getBadTags().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the content object
Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(dbManager.getBadTags()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
if (content instanceof AbstractFile) {
af = (AbstractFile) content;
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
}
final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af,
knownStatus, comment);
if (eamArtifact != null) {
// send update to Central Repository db
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
// TODO: send r into a thread pool instead
Thread t = new Thread(r);
t.start();
}
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
break; break;
case BLACKBOARD_ARTIFACT_TAG_DELETED: case BLACKBOARD_ARTIFACT_TAG_DELETED:
case BLACKBOARD_ARTIFACT_TAG_ADDED: { case BLACKBOARD_ARTIFACT_TAG_ADDED: {
if (!EamDb.isEnabled()) { jobProcessingExecutor.submit(new BlackboardTagTask(dbManager, evt));
return; }
}
Content content;
BlackboardArtifact bbArtifact;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(evt.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) evt;
final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) {
content = tagAdded.getContent();
bbArtifact = tagAdded.getArtifact();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { //BLACKBOARD_ARTIFACT_TAG_DELETED
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final BlackBoardArtifactTagDeletedEvent tagDeletedEvent = (BlackBoardArtifactTagDeletedEvent) evt;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!dbManager.getBadTags().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the artifact
content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(dbManager.getBadTags()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
}
if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
return;
}
List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true);
for (CorrelationAttribute eamArtifact : convertedArtifacts) {
eamArtifact.getInstances().get(0).setComment(comment);
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
// TODO: send r into a thread pool instead
Thread t = new Thread(r);
t.start();
}
} // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
break; break;
case DATA_SOURCE_ADDED: { case DATA_SOURCE_ADDED: {
if (!EamDb.isEnabled()) { jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt));
break; }
}
final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) evt;
Content newDataSource = dataSourceAddedEvent.getDataSource();
try {
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
if (null == correlationCase) {
dbManager.newCase(Case.getCurrentCase());
correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
}
if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) {
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
} catch (TskCoreException | TskDataException ex) {
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
}
} // DATA_SOURCE_ADDED
break; break;
case CURRENT_CASE: { case CURRENT_CASE: {
/* jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt));
* A case has been opened if evt.getOldValue() is null and }
* evt.getNewValue() is a valid Case.
*/
if ((null == evt.getOldValue()) && (evt.getNewValue() instanceof Case)) {
Case curCase = (Case) evt.getNewValue();
IngestEventsListener.resetCeModuleInstanceCount();
try {
// only add default evidence tag if case is open and it doesn't already exist in the tags list.
if (Case.isCaseOpen()
&& Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream()
.map(tag -> tag.getDisplayName())
.filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName))
.collect(Collectors.toList())
.isEmpty()) {
curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag());
}
} catch (TagsManager.TagNameAlreadyExistsException ex) {
LOGGER.info("Evidence tag already exists"); // NON-NLS
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS
}
CorrelationCase curCeCase = new CorrelationCase(
-1,
curCase.getName(), // unique case ID
EamOrganization.getDefault(),
curCase.getDisplayName(),
curCase.getCreatedDate(),
curCase.getNumber(),
curCase.getExaminer(),
null,
null,
null);
if (!EamDb.isEnabled()) {
break;
}
try {
// NOTE: Cannot determine if the opened case is a new case or a reopened case,
// so check for existing name in DB and insert if missing.
CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID());
if (null == existingCase) {
dbManager.newCase(curCeCase);
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
}
}
} // CURRENT_CASE
break; break;
case NAME: { case NAME: {
@ -340,4 +128,296 @@ public class CaseEventListener implements PropertyChangeListener {
break; break;
} }
} }
private final class ContentTagTask implements Runnable {
private final EamDb dbManager;
private final PropertyChangeEvent event;
private ContentTagTask(EamDb db, PropertyChangeEvent evt) {
dbManager = db;
event = evt;
}
@Override
public void run() {
if (!EamDb.isEnabled()) {
return;
}
AbstractFile af;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event;
final ContentTag tagAdded = tagAddedEvent.getAddedTag();
if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) {
if (tagAdded.getContent() instanceof AbstractFile) {
af = (AbstractFile) tagAdded.getContent();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { // CONTENT_TAG_DELETED
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!dbManager.getBadTags().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the content object
Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(dbManager.getBadTags()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
if (content instanceof AbstractFile) {
af = (AbstractFile) content;
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
}
final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af,
knownStatus, comment);
if (eamArtifact != null) {
// send update to Central Repository db
try {
dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
}
private final class BlackboardTagTask implements Runnable {
private final EamDb dbManager;
private final PropertyChangeEvent event;
private BlackboardTagTask(EamDb db, PropertyChangeEvent evt) {
dbManager = db;
event = evt;
}
@Override
public void run() {
if (!EamDb.isEnabled()) {
return;
}
Content content;
BlackboardArtifact bbArtifact;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) event;
final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) {
content = tagAdded.getContent();
bbArtifact = tagAdded.getArtifact();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { //BLACKBOARD_ARTIFACT_TAG_DELETED
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final BlackBoardArtifactTagDeletedEvent tagDeletedEvent = (BlackBoardArtifactTagDeletedEvent) event;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!dbManager.getBadTags().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the artifact
content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(dbManager.getBadTags()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
}
if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
return;
}
List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true);
for (CorrelationAttribute eamArtifact : convertedArtifacts) {
eamArtifact.getInstances().get(0).setComment(comment);
try {
dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
} // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
}
private final class DataSourceAddedTask implements Runnable {
private final EamDb dbManager;
private final PropertyChangeEvent event;
private DataSourceAddedTask(EamDb db, PropertyChangeEvent evt) {
dbManager = db;
event = evt;
}
@Override
public void run() {
if (!EamDb.isEnabled()) {
return;
}
final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
Content newDataSource = dataSourceAddedEvent.getDataSource();
try {
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
if (null == correlationCase) {
dbManager.newCase(Case.getCurrentCase());
correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
}
if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) {
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
} catch (TskCoreException | TskDataException ex) {
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
}
} // DATA_SOURCE_ADDED
}
private final class CurrentCaseTask implements Runnable {
private final EamDb dbManager;
private final PropertyChangeEvent event;
private CurrentCaseTask(EamDb db, PropertyChangeEvent evt) {
dbManager = db;
event = evt;
}
@Override
public void run() {
/*
* A case has been opened if evt.getOldValue() is null and
* evt.getNewValue() is a valid Case.
*/
if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
Case curCase = (Case) event.getNewValue();
IngestEventsListener.resetCeModuleInstanceCount();
try {
// only add default evidence tag if case is open and it doesn't already exist in the tags list.
if (Case.isCaseOpen()
&& Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream()
.map(tag -> tag.getDisplayName())
.filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName))
.collect(Collectors.toList())
.isEmpty()) {
curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag());
}
} catch (TagsManager.TagNameAlreadyExistsException ex) {
LOGGER.info("Evidence tag already exists"); // NON-NLS
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS
}
CorrelationCase curCeCase = new CorrelationCase(
-1,
curCase.getName(), // unique case ID
EamOrganization.getDefault(),
curCase.getDisplayName(),
curCase.getCreatedDate(),
curCase.getNumber(),
curCase.getExaminer(),
null,
null,
null);
if (!EamDb.isEnabled()) {
return;
}
try {
// NOTE: Cannot determine if the opened case is a new case or a reopened case,
// so check for existing name in DB and insert if missing.
CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID());
if (null == existingCase) {
dbManager.newCase(curCeCase);
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
}
}
} // CURRENT_CASE
}
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.eventlisteners; package org.sleuthkit.autopsy.centralrepository.eventlisteners;
import java.beans.PropertyChangeListener;
import org.openide.modules.ModuleInstall; import org.openide.modules.ModuleInstall;
import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
@ -32,7 +31,7 @@ public class Installer extends ModuleInstall {
private static final Logger LOGGER = Logger.getLogger(Installer.class.getName()); private static final Logger LOGGER = Logger.getLogger(Installer.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final PropertyChangeListener pcl = new CaseEventListener(); private final CaseEventListener pcl = new CaseEventListener();
private final IngestEventsListener ieListener = new IngestEventsListener(); private final IngestEventsListener ieListener = new IngestEventsListener();
private static Installer instance; private static Installer instance;
@ -71,6 +70,7 @@ public class Installer extends ModuleInstall {
//module is being unloaded //module is being unloaded
Case.removePropertyChangeListener(pcl); Case.removePropertyChangeListener(pcl);
pcl.shutdown();
ieListener.uninstallListeners(); ieListener.uninstallListeners();
// TODO: remove thread pool // TODO: remove thread pool

View File

@ -1,58 +0,0 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.eventlisteners;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.datamodel.TskData.FileKnown;
/**
* Thread to send info to remote DB that tags a file as known, unknown, or notable.
*/
public class KnownStatusChangeRunner implements Runnable {
private static final Logger LOGGER = Logger.getLogger(KnownStatusChangeRunner.class.getName());
private static final long serialVersionUID = 1L;
private final CorrelationAttribute artifact;
private final FileKnown knownStatus;
public KnownStatusChangeRunner(CorrelationAttribute artifact, FileKnown knownStatus) {
this.artifact = artifact;
this.knownStatus = knownStatus;
}
@Override
public void run() {
if (!EamDb.isEnabled()) {
LOGGER.log(Level.WARNING, "Central Repository database not configured"); // NON-NLS
return;
}
try {
EamDb dbManager = EamDb.getInstance();
dbManager.setArtifactInstanceKnownStatus(this.artifact, this.knownStatus);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
}
}
}

View File

@ -26,6 +26,7 @@ import java.io.InputStreamReader;
import java.io.Writer; import java.io.Writer;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
@ -212,6 +213,40 @@ public final class ExecUtil {
} }
} }
/**
* Shuts down a task executor service, waiting until all tasks are
* terminated. The current policy is to wait for the tasks to finish so that
* the case for which the executor is running can be left in a consistent
* state.
*
* @param executor The executor.
*/
public static void shutDownTaskExecutor(ExecutorService executor) {
executor.shutdown();
boolean taskCompleted = false;
while (!taskCompleted) {
try {
taskCompleted = executor.awaitTermination(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNITS);
} catch (InterruptedException ignored) {
/*
* The current policy is to wait for the task to finish so that
* the case can be left in a consistent state.
*
* For a specific example of the motivation for this policy,
* note that a application service (Solr search service)
* experienced an error condition when opening case resources
* that left the service blocked uninterruptibly on a socket
* read. This eventually led to a mysterious "freeze" as the
* user-cancelled service task continued to run holdiong a lock
* that a UI thread soon tried to acquire. Thus it has been
* deemed better to make the "freeze" happen in a more
* informative way, i.e., with the progress indicator for the
* unfinished task on the screen, if a similar error condition
* arises again.
*/
}
}
}
/** /**
* EVERYTHING FOLLOWING THIS LINE IS DEPRECATED AND SLATED FOR REMOVAL * EVERYTHING FOLLOWING THIS LINE IS DEPRECATED AND SLATED FOR REMOVAL
*/ */