Complete first implementation of CollaboratinoMonitor

This commit is contained in:
Richard Cordovano
2015-06-08 13:52:41 -04:00
parent b6c8c28d49
commit 2d030aef8e
13 changed files with 303 additions and 134 deletions
-1
View File
@@ -7,7 +7,6 @@ file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.solr-solrj-4.9.1.jar=release/modules/ext/solr-solrj-4.9.1.jar
file.reference.sqlite-jdbc-3.7.15-M1.jar=release/modules/ext/sqlite-jdbc-3.7.15-M1.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.tika-core-1.5.jar=release/modules/ext/tika-core-1.5.jar
-4
View File
@@ -258,10 +258,6 @@
<runtime-relative-path>ext/Tsk_DataModel.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Tsk_DataModel.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/solr-solrj-4.9.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/solr-solrj-4.9.1.jar</binary-origin>
</class-path-extension>
</data>
</configuration>
</project>
@@ -310,7 +310,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyNewDataSource(newContents.get(0), dataSourceId);
} else {
Case.getCurrentCase().notifyNewDataSource(null, dataSourceId); // RJCTODO: Update for null scenario
Case.getCurrentCase().notifyFailedAddingNewDataSource(dataSourceId);
}
@@ -241,3 +241,7 @@ LocalFilesPanel.errorLabel.text=Error Label
NewCaseVisualPanel1.errorLabel.text=Error Label
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
CollaborationMonitor.failedService.notify.title=Collaboration Failure
CollaborationMonitor.failedDbService.notify.msg=Lost connection to database server
CollaborationMonitor.failedSolrService.notify.msg=Lost connection to keyword search server
CollaborationMonitor.failedMessageService.notify.msg=Lost connection to messaging server
@@ -50,6 +50,7 @@ import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.SystemAction;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
import org.sleuthkit.autopsy.casemodule.services.Services;
@@ -119,23 +120,33 @@ public class Case {
/**
* Property name used for a property change event that indicates a new
* data source (image, local/logical file or local disk) is being added
* to the current case. The new value field of the property change event
* is the path of the data source.
* to the current case. The old and new values of the
* PropertyChangeEvent are null - cast the PropertyChangeEvent to
* org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent to
* access event data.
*/
ADDING_DATA_SOURCE,
/**
* Property name used for a property change event that indicates a
* failure adding a new data source (image, local/logical file or local
* disk) to the current case. The old and new values of the
* PropertyChangeEvent are null - cast the PropertyChangeEvent to
* org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent
* to access event data.
*/
ADDING_DATA_SOURCE_FAILED,
/**
* Property name that indicates a new data source (image, disk or local
* file) has been added to the current case. The old and new values of
* the PropertyChangeEvent are null - cast the PropertyChangeEvent to
* org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent to
* access event data.
* file) has been added to the current case. The new value is the
* newly-added instance of the new data source, and the old value is
* always null.
*/
DATA_SOURCE_ADDED,
/**
* Property name that indicates a data source has been removed from the
* current case. The "old value" is the (int) content ID of the data
* source that was removed, the new value is the instance of the data
* source. RJCTODO: Improve this doc
* source.
*/
DATA_SOURCE_DELETED,
/**
@@ -215,7 +226,7 @@ public class Case {
private boolean hasData = false;
private CollaborationMonitor collaborationMonitor;
/**
* Constructor for the Case class
*/
@@ -295,12 +306,13 @@ public class Case {
eventPublisher.openRemoteEventChannel(String.format(EVENT_CHANNEL_NAME, newCase.getTextIndexName()));
currentCase.collaborationMonitor = new CollaborationMonitor();
} catch (AutopsyEventException | CollaborationMonitor.CollaborationMonitorException ex) {
currentCase.collaborationMonitor.stop();
logger.log(Level.SEVERE, "Failed to setup for collaboration", ex);
MessageNotifyUtil.Notify.error(NbBundle.getMessage(Case.class, "Case.CollaborationSetup.FailNotify.Title"), NbBundle.getMessage(Case.class, "Case.CollaborationSetup.FailNotify.ErrMsg"));
}
}
eventPublisher.publishLocally(new AutopsyEvent(Events.CURRENT_CASE.toString(), null, currentCase));
} else {
Logger.setLogDirectory(PlatformUtil.getLogDirectory());
}
@@ -546,6 +558,16 @@ public class Case {
eventPublisher.publish(new AddingDataSourceEvent(dataSourceId));
}
/**
* Notifies case event subscribers (property change listeners) that a data
* source failed to be added to the case database.
*
* @param dataSourceId A unique identifier for the data source.
*/
public void notifyFailedAddingNewDataSource(UUID dataSourceId) {
eventPublisher.publish(new AddingDataSourceFailedEvent(dataSourceId));
}
/**
* Notifies case event subscribers (property change listeners) that a data
* source is being added to the case database.
@@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.casemodule;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
@@ -35,19 +34,18 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import javax.jms.Connection;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -62,10 +60,10 @@ import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
/**
* A collaboration monitor listens to local events and represents them as
* collaboration tasks that are broadcast to collaborating nodes, informs the
* user of collaboration tasks on other nodes using progress bars, and monitors
* the health of the key collaboration services.
* A collaboration monitor listens to local events and translates them into
* collaboration tasksForHost that are broadcast to collaborating nodes, informs
* the user of collaboration tasksForHost on other nodes using progress bars,
* and monitors the health of key collaboration services.
*/
final class CollaborationMonitor {
@@ -88,9 +86,9 @@ final class CollaborationMonitor {
/**
* Constructs a collaboration monitor that listens to local events and
* represents them as collaboration tasks that are broadcast to
* collaborating nodes, informs the user of collaboration tasks on other
* nodes using progress bars, and monitors the health of the key
* translates them into collaboration tasksForHost that are broadcast to
* collaborating nodes, informs the user of collaboration tasksForHost on
* other nodes using progress bars, and monitors the health of key
* collaboration services.
*/
CollaborationMonitor() throws CollaborationMonitorException {
@@ -141,7 +139,8 @@ final class CollaborationMonitor {
}
/**
* Determines the name of the local host for use in describing local tasks.
* Determines the name of the local host for use in describing local
* tasksForHost.
*
* @return The host name of this Autopsy node.
*/
@@ -183,11 +182,11 @@ final class CollaborationMonitor {
}
/**
* The local tasks manager listens to local events and translates them into
* tasks it broadcasts to collaborating nodes. Note that all access to the
* task collections is synchronized since they may be accessed by both the
* threads publishing property change events and by the heartbeat task
* thread.
* The local tasksForHost manager listens to local events and translates
* them into tasksForHost it broadcasts to collaborating nodes. Note that
* all access to the task collections is synchronized since they may be
* accessed by both the threads publishing property change events and by the
* heartbeat task thread.
*/
private final class LocalTasksManager implements PropertyChangeListener {
@@ -196,9 +195,9 @@ final class CollaborationMonitor {
private final Map<Long, Task> jobIdsTodataSourceAnalysisTasks;
/**
* Constructs a local tasks manager that listens to local events and
* translates them into tasks that can be broadcast to collaborating
* nodes.
* Constructs a local tasksForHost manager that listens to local events
* and translates them into tasksForHost that can be broadcast to
* collaborating nodes.
*/
LocalTasksManager() {
nextTaskId = 0;
@@ -207,8 +206,8 @@ final class CollaborationMonitor {
}
/**
* Translates events into updates of the collection of local tasks this
* node is broadcasting to other nodes.
* Translates events into updates of the collection of local
* tasksForHost this node is broadcasting to other nodes.
*
* @param event A PropertyChangeEvent.
*/
@@ -217,8 +216,10 @@ final class CollaborationMonitor {
String eventName = event.getPropertyName();
if (eventName.equals(Case.Events.ADDING_DATA_SOURCE.toString())) {
addDataSourceAddTask((AddingDataSourceEvent) event);
} else if (eventName.equals(Case.Events.ADDING_DATA_SOURCE_FAILED.toString())) {
removeDataSourceAddTask(((AddingDataSourceFailedEvent) event).getDataSourceId());
} else if (eventName.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
removeDataSourceAddTask((DataSourceAddedEvent) event);
removeDataSourceAddTask(((DataSourceAddedEvent) event).getDataSourceId());
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED.toString())) {
addDataSourceAnalysisTask((DataSourceAnalysisStartedEvent) event);
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED.toString())) {
@@ -227,8 +228,9 @@ final class CollaborationMonitor {
}
/**
* Adds an adding data source task to the collection of local tasks and
* publishes the updated collection to any collaborating nodes.
* Adds an adding data source task to the collection of local
* tasksForHost and publishes the updated collection to any
* collaborating nodes.
*
* @param event An adding data source event.
*/
@@ -239,19 +241,22 @@ final class CollaborationMonitor {
}
/**
* Removes an adding data source task from the collection of local tasks
* and publishes the updated collection to any collaborating nodes.
* Removes an adding data source task from the collection of local
* tasksForHost and publishes the updated collection to any
* collaborating nodes.
*
* @param event A data source added event
* @param dataSourceId A data source id to pair a data source added or
* adding data source failed event with an adding data source event.
*/
synchronized void removeDataSourceAddTask(DataSourceAddedEvent event) {
uuidsToAddDataSourceTasks.remove(event.getDataSourceId().hashCode());
synchronized void removeDataSourceAddTask(UUID dataSourceId) {
uuidsToAddDataSourceTasks.remove(dataSourceId.hashCode());
eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Adds a data source analysis task to the collection of local tasks and
* publishes the updated collection to any collaborating nodes.
* Adds a data source analysis task to the collection of local
* tasksForHost and publishes the updated collection to any
* collaborating nodes.
*
* @param event A data source analysis started event.
*/
@@ -263,8 +268,8 @@ final class CollaborationMonitor {
/**
* Removes a data source analysis task from the collection of local
* tasks and publishes the updated collection to any collaborating
* nodes.
* tasksForHost and publishes the updated collection to any
* collaborating nodes.
*
* @param event A data source analysis completed event.
*/
@@ -274,9 +279,9 @@ final class CollaborationMonitor {
}
/**
* Gets the current local tasks.
* Gets the current local tasksForHost.
*
* @return A mapping of task IDs to tasks, may be empty.
* @return A mapping of task IDs to tasksForHost, may be empty.
*/
synchronized Map<Long, Task> getCurrentTasks() {
Map<Long, Task> currentTasks = new HashMap<>();
@@ -292,11 +297,11 @@ final class CollaborationMonitor {
/**
* Listens for collaboration event messages broadcast by collaboration
* monitors on other nodes and translates them into remote tasks represented
* locally using progress bars. Note that all access to the remote tasks is
* synchronized since it may be accessed by both the threads publishing
* property change events and by the thread running periodic checks for
* "stale" tasks.
* monitors on other nodes and translates them into remote tasksForHost
* represented locally using progress bars. Note that all access to the
* remote tasksForHost is synchronized since it may be accessed by both the
* threads publishing property change events and by the thread running
* periodic checks for "stale" tasksForHost.
*/
private final class RemoteTasksManager implements PropertyChangeListener {
@@ -305,15 +310,16 @@ final class CollaborationMonitor {
/**
* Constructs an object that listens for collaboration event messages
* broadcast by collaboration monitors on other nodes and translates
* them into remote tasks represented locally using progress bars.
* them into remote tasksForHost represented locally using progress
* bars.
*/
RemoteTasksManager() {
hostsToTasks = new HashMap<>();
}
/**
* Updates the remote tasks based to reflect a collaboration event
* received from another node.
* Updates the remote tasksForHost based to reflect a collaboration
* event received from another node.
*
* @param event A collaboration event.
*/
@@ -325,39 +331,39 @@ final class CollaborationMonitor {
}
/**
* Updates the remote tasks based to reflect a collaboration event
* received from another node.
* Updates the remote tasksForHost based to reflect a collaboration
* event received from another node.
*
* @param event A collaboration event.
*/
synchronized void updateTasks(CollaborationEvent event) {
// RJCTODO: This is a little hard to understand, consider some renaming
RemoteTasks tasks = hostsToTasks.get(event.getHostName());
if (null != tasks) {
tasks.update(event);
RemoteTasks tasksForHost = hostsToTasks.get(event.getHostName());
if (null != tasksForHost) {
tasksForHost.update(event);
} else {
hostsToTasks.put(event.getHostName(), new RemoteTasks(event));
}
}
/**
* Finishes any remote tasks that have gone stale, i.e., tasks for which
* updates have ceased, presumably because the collaborating node has
* gone down or there is a network issue.
* Finishes any remote tasksForHost that have gone stale, i.e.,
* tasksForHost for which updates have ceased, presumably because the
* collaborating node has gone down or there is a network issue.
*/
synchronized void finishStaleTasks() {
for (Iterator<Map.Entry<String, RemoteTasks>> it = hostsToTasks.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, RemoteTasks> entry = it.next();
RemoteTasks tasks = entry.getValue();
if (tasks.isStale()) {
tasks.finishAllTasks();
RemoteTasks tasksForHost = entry.getValue();
if (tasksForHost.isStale()) {
tasksForHost.finishAllTasks();
it.remove();
}
}
}
/**
* A collection of progress bars for tasks on a collaborating node.
* A collection of progress bars for tasksForHost on a collaborating
* node.
*/
class RemoteTasks {
@@ -366,8 +372,8 @@ final class CollaborationMonitor {
private Map<Long, ProgressHandle> taskIdsToProgressBars;
/**
* Construct a set of progress bars to represent remote tasks for a
* particular host.
* Construct a set of progress bars to represent remote tasksForHost
* for a particular host.
*
* @param event A collaboration event.
*/
@@ -387,10 +393,10 @@ final class CollaborationMonitor {
}
/**
* Updates this remote tasks collection.
* Updates this remote tasksForHost collection.
*
* @param event A collaboration event from the collaborating node
* associated with these tasks.
* associated with these tasksForHost.
*/
void update(CollaborationEvent event) {
/**
@@ -434,8 +440,8 @@ final class CollaborationMonitor {
}
/**
* Unconditionally finishes the entire set or remote tasks. To be
* used when a host drops off unexpectedly.
* Unconditionally finishes the entire set or remote tasksForHost.
* To be used when a host drops off unexpectedly.
*/
void finishAllTasks() {
taskIdsToProgressBars.values().stream().forEach((progress) -> {
@@ -446,8 +452,8 @@ final class CollaborationMonitor {
/**
* Determines whether or not the time since the last update of this
* remote tasks collection is greater than the maximum acceptable
* interval between updates.
* remote tasksForHost collection is greater than the maximum
* acceptable interval between updates.
*
* @return True or false.
*/
@@ -459,11 +465,12 @@ final class CollaborationMonitor {
}
/**
* A Runnable task that periodically publishes the local tasks in progress
* on this node, providing a heartbeat message for collaboration monitors on
* other nodes. The current local tasks are included in the heartbeat
* message so that nodes that have just joined the event channel know what
* this node is doing, even if they join after the current tasks are begun.
* A Runnable task that periodically publishes the local tasksForHost in
* progress on this node, providing a heartbeat message for collaboration
* monitors on other nodes. The current local tasksForHost are included in
* the heartbeat message so that nodes that have just joined the event
* channel know what this node is doing, even if they join after the current
* tasksForHost are begun.
*/
private final class HeartbeatTask implements Runnable {
@@ -477,14 +484,15 @@ final class CollaborationMonitor {
}
/**
* A Runnable task that periodically deals with any remote tasks that have
* gone stale, i.e., tasks for which updates have ceased, presumably because
* the collaborating node has gone down or there is a network issue.
* A Runnable task that periodically deals with any remote tasksForHost that
* have gone stale, i.e., tasksForHost for which updates have ceased,
* presumably because the collaborating node has gone down or there is a
* network issue.
*/
private final class StaleTaskDetectionTask implements Runnable {
/**
* Check for stale remote tasks and clean them up, if found.
* Check for stale remote tasksForHost and clean them up, if found.
*/
@Override
public void run() {
@@ -509,19 +517,26 @@ final class CollaborationMonitor {
try {
DriverManager.getConnection("jdbc:postgresql://" + dbInfo.getHost() + ":" + dbInfo.getPort() + "/" + "postgres", dbInfo.getUserName(), dbInfo.getUserName()); // NON-NLS
} catch (SQLException ex) {
MessageNotifyUtil.Notify.error("Collaboration Failure", "Lost connection to database server"); // RJCTODO: Bundle
logger.log(Level.SEVERE, "Failed to connect to PostgreSQL", ex);
MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedDbService.notify.msg"));
}
// RJCTODO: Can this be made to work...seems to wander off on line 519 and never comes back...
/**
* TODO: Figure out what is wrong with this code. The call to
* construct the HttpSolrServer object never returns. Perhaps this
* is the result of a dependency of the solr-solrj-4.91.jar that is
* not satisfied. Removing the jar from wrapped jars for now.
*/
// try {
// String host = UserPreferences.getIndexingServerHost();
// String port = UserPreferences.getIndexingServerPort();
// HttpSolrServer solr = new HttpSolrServer("http://" + host + ":" + port + "/solr/" + Case.getCurrentCase().getTextIndexName());
// HttpSolrServer solr = new HttpSolrServer("http://" + host + ":" + port + "/solr");
// CoreAdminRequest.getStatus(Case.getCurrentCase().getTextIndexName(), solr);
// } catch (SolrServerException | IOException ex) {
// MessageNotifyUtil.Notify.error("Collaboration Failure", "Lost connection to keyword search server"); // RJCTODO: Bundle
// logger.log(Level.SEVERE, "Failed to connect to Solr", ex);
// MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedSolrService.notify.msg"));
// }
MessageServiceConnectionInfo msgInfo = UserPreferences.getMessageServiceConnectionInfo();
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(msgInfo.getUserName(), msgInfo.getPassword(), msgInfo.getURI());
@@ -529,7 +544,8 @@ final class CollaborationMonitor {
connection.start();
connection.close();
} catch (URISyntaxException | JMSException ex) {
MessageNotifyUtil.Notify.error("Collaboration Failure", "Lost connection to messaging server"); // RJCTODO: Bundle
logger.log(Level.SEVERE, "Failed to connect to ActiveMQ", ex);
MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedMessageService.notify.msg"));
}
}
@@ -550,7 +566,8 @@ final class CollaborationMonitor {
* collaboration monitors on other Autopsy nodes.
*
* @param hostName The name of the host sending the event.
* @param currentTasks The tasks in progress for this Autopsy node.
* @param currentTasks The tasksForHost in progress for this Autopsy
* node.
*/
CollaborationEvent(String hostName, Map<Long, Task> currentTasks) {
super(COLLABORATION_MONITOR_EVENT, null, null);
@@ -568,10 +585,10 @@ final class CollaborationMonitor {
}
/**
* Gets the current tasks for the Autopsy node that published this
* event.
* Gets the current tasksForHost for the Autopsy node that published
* this event.
*
* @return A mapping of task IDs to current tasks
* @return A mapping of task IDs to current tasksForHost
*/
Map<Long, Task> getCurrentTasks() {
return currentTasks;
@@ -38,7 +38,8 @@ public final class AddingDataSourceEvent extends AutopsyEvent implements Seriali
* case.
*
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this AddindDataSourceEvent with a DataSoruceAddedEvent.
* Used to pair this AddingDataSourceEvent with a DataSourceAddedEvent or a
* AddingDataSourceFailedEvent.
*/
public AddingDataSourceEvent(UUID dataSourceId) {
super(Case.Events.ADDING_DATA_SOURCE.toString(), null, null);
@@ -47,7 +48,8 @@ public final class AddingDataSourceEvent extends AutopsyEvent implements Seriali
/**
* Gets the unique id for the data source used to pair this
* AddindDataSourceEvent with a DataSoruceAddedEvent.
* AddindDataSourceEvent with a a DataSourceAddedEvent or a
* AddingDataSourceFailedEvent.
*
* @return The unique id.
*/
@@ -0,0 +1,58 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.casemodule.events;
import java.io.Serializable;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
* Event published when an attempt to add a data source to a case fails.
*/
@Immutable
public final class AddingDataSourceFailedEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final UUID dataSourceId;
/**
* Constructs an event published when an attempt to add a data source to a
* case fails.
*
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this AddingDataSourceFailedEvent with a AddingDataSourceEvent.
*/
public AddingDataSourceFailedEvent(UUID dataSourceId) {
super(Case.Events.ADDING_DATA_SOURCE_FAILED.toString(), null, null);
this.dataSourceId = dataSourceId;
}
/**
* Gets the unique id for the data source used to pair this
* AddingDataSourceFailedEvent with a AddingDataSourceEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}
@@ -42,7 +42,7 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
*
* @param dataSource The data source that was added.
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this DataSoruceAddedEvent with a AddindDataSourceEvent.
* Used to pair this DataSourceAddedEvent with a AddindDataSourceEvent.
*/
public DataSourceAddedEvent(Content dataSource, UUID dataSourceId) {
/**
@@ -59,7 +59,8 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
/**
* Gets the data source that was added.
*
* @return The data source.
* @return The data source or null if there is an error retrieving the data
* source.
*/
@Override
public Object getNewValue() {
@@ -92,15 +93,15 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
public Content getDataSource() {
return (Content) getNewValue();
}
/**
* Gets the unique id for the data source used to pair this
* DataSoruceAddedEvent with a AddindDataSourceEvent.
* DataSourceAddedEvent with a AddingDataSourceEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}
@@ -174,11 +174,21 @@ public class IngestManager {
*/
CANCELLED,
/**
* RJCTODO
* Property change event fired when analysis (ingest) of a data source
* included in an ingest job is started. Both the old and new values of
* the ProerptyChangeEvent are set to null - cast the
* PropertyChangeEvent to
* org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent to
* access event data.
*/
DATA_SOURCE_ANALYSIS_STARTED,
/**
* RJCTODO
* Property change event fired when analysis (ingest) of a data source
* included in an ingest job is completed. Both the old and new values
* of the ProerptyChangeEvent are set to null - cast the
* PropertyChangeEvent to
* org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent
* to access event data.
*/
DATA_SOURCE_ANALYSIS_COMPLETED,
};
@@ -355,7 +365,7 @@ public class IngestManager {
synchronized boolean isRunningInteractively() {
return this.runInteractively;
}
/**
* Called by the custom installer for this package once the window system is
* initialized, allowing the ingest manager to get the top component used to
@@ -664,7 +674,7 @@ public class IngestManager {
* @param dataSource The data source.
*/
void fireDataSourceAnalysisCompleted(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.COMPLETED);
AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.ANALYSIS_COMPLETED);
eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher));
}
@@ -676,7 +686,7 @@ public class IngestManager {
* @param dataSource The data source.
*/
void fireDataSourceAnalysisCancelled(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.CANCELLED);
AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.ANALYSIS_CANCELLED);
eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher));
}
@@ -23,25 +23,44 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
* Event published when analysis (ingest) of a data source included in an ingest
* job is completed.
*/
public class DataSourceAnalysisCompletedEvent extends DataSourceAnalysisEvent implements Serializable {
/**
* The reason why the analysis of the data source completed.
*/
public enum Reason {
COMPLETED,
CANCELLED
ANALYSIS_COMPLETED,
ANALYSIS_CANCELLED
}
private static final long serialVersionUID = 1L;
private final Reason reason;
/**
* Constructs an event published when analysis (ingest) of a data source
* included in an ingest job is completed.
*
* @param ingestJobId The identifier of the ingest job, specific to this
* node.
* @param dataSourceIngestJobId The identifier of the data source ingest
* job,specific to this node.
* @param dataSource The data source.
* @param reason The reason analysis completed.
*/
public DataSourceAnalysisCompletedEvent(long ingestJobId, long dataSourceIngestJobId, Content dataSource, Reason reason) {
super(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED, ingestJobId, dataSourceIngestJobId, dataSource);
this.reason = reason;
}
/**
* Gets the reason why the analysis of the data source completed.
*/
public Reason getResult() {
return reason;
}
}
@@ -19,27 +19,36 @@
package org.sleuthkit.autopsy.ingest.events;
import java.io.Serializable;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* RJCTODO
* A base class for events published in connection with the analysis (ingest) of
* a data source.
*/
public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(DataSourceAnalysisEvent.class.getName());
private final long ingestJobId;
private final long dataSourceIngestJobId;
private transient Content dataSource; // RJCTODO: Make able to be published remotely
private transient Content dataSource;
/**
* RJCTOD
* Constructs an instance of the base class for events published in
* connection with the analysis (ingest) of a data source.
*
* @param eventType
* @param ingestJobId
* @param dataSourceIngestJobId
* @param dataSource
* @param eventType The event string for the subtype.
* @param ingestJobId The identifier of the ingest job, specific to this
* node.
* @param dataSourceIngestJobId The identifier of the data source ingest
* job,specific to this node.
* @param dataSource The data source.
*/
public DataSourceAnalysisEvent(IngestManager.IngestJobEvent eventType, long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(eventType.toString(), null, null);
@@ -49,29 +58,50 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se
}
/**
* RJCTODO
* Gets the id of the ingest job of which the analysis of this data source
* is a part.
*
* @return
* @return The id.
*/
public long getIngestJobId() {
return ingestJobId;
}
/**
* RJCTODO
* Gets the id of the data source ingest job of which the analysis of this
* data source is a part.
*
* @return
* @return The id.
*/
public long getDataSourceIngestJobId() {
return dataSourceIngestJobId;
}
/**
* RJCTODO
* Gets the data source associated with this event.
*
* @return
* @return The data source.
*/
public Content getDataSource() {
return dataSource;
/**
* The dataSource field is set in the constructor, but it is transient
* so it will become null when the event is serialized for publication
* over a network. Doing a lazy load of the Content object bypasses the
* issues related to the serialization and de-serialization of Content
* objects and may also save database round trips from other nodes since
* subscribers to this event are often not interested in the event data.
*/
if (null != dataSource) {
return dataSource;
}
try {
long id = (Long) super.getNewValue();
dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id);
return dataSource;
} catch (IllegalStateException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex);
return null;
}
}
}
@@ -23,14 +23,25 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
* Event published when analysis (ingest) of a data source included in an ingest
* job is started.
*/
public class DataSourceAnalysisStartedEvent extends DataSourceAnalysisEvent implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Constructs an event published when analysis (ingest) of a data source
* included in an ingest job is started.
*
* @param ingestJobId The identifier of the ingest job, specific to this
* node.
* @param dataSourceIngestJobId The identifier of the data source ingest
* job,specific to this node.
* @param dataSource The data source.
*/
public DataSourceAnalysisStartedEvent(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED, ingestJobId, dataSourceIngestJobId, dataSource);
}
}