From 40520cf312b7d1b747af9b656109c7d2d51a3af8 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 5 Jun 2015 13:49:34 -0400 Subject: [PATCH] Revise CollaborationMonitor --- .../casemodule/CollaborationMonitor.java | 222 +++++++++--------- .../autopsy/events/AutopsyEventPublisher.java | 23 +- .../sleuthkit/autopsy/ingest/IngestJob.java | 37 +-- .../autopsy/ingest/IngestManager.java | 38 +++ 4 files changed, 192 insertions(+), 128 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java index 430a5058ad..e863779294 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java @@ -47,96 +47,82 @@ import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent; /** - * Listens to local events and tracks them as collaboration tasks that can be - * broadcast to collaborating nodes, receives event messages from collaborating - * nodes and translates them into case activity indicators for the user, and - * monitors the health of the services needed for collaboration so that users - * can be informed if those service become unavailable. + * 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. */ -// TODO: This class probably has too many responsibilities! final class CollaborationMonitor { private static final String EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events"; private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT"; private static final Set CASE_EVENTS_OF_INTEREST = new HashSet<>(Arrays.asList(new String[]{Case.Events.ADDING_DATA_SOURCE.toString(), Case.Events.DATA_SOURCE_ADDED.toString()})); - private static final String HEARTBEAT_THREAD_NAME = "collab-monitor-heartbeat-%d"; - private static final long MINUTES_BETWEEN_HEARTBEATS = 1; - private static final String STALE_TASKS_DETECTION_THREAD_NAME = "collab-monitor-stale-remote-tasks-detector-%d"; - private static final long STALE_TASKS_DETECTION_INTERVAL_SECS = 60; - private static final String CRASH_DETECTION_THREAD_NAME = "collab-monitor-crash-detector-%d"; - private static final long CRASH_DETECTION_INTERVAL_SECS = 60; + private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1; + private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; + private static final long HEARTBEAT_INTERVAL_MINUTES = 1; + private static final long MAX_MISSED_HEARTBEATS = 5; + private static final long STALE_TASKS_DETECTION_INTERVAL_MINUTES = 2; + private static final long CRASH_DETECTION_INTERVAL_MINUTES = 5; private static final long EXECUTOR_TERMINATION_WAIT_SECS = 30; private static final Logger logger = Logger.getLogger(CollaborationMonitor.class.getName()); private final String hostName; private final LocalTasksManager localTasksManager; private final RemoteTasksManager remoteTasksManager; private final AutopsyEventPublisher eventPublisher; - private final ScheduledThreadPoolExecutor heartbeatExecutor; - private final ScheduledThreadPoolExecutor staleTasksCheckExecutor; - private final ScheduledThreadPoolExecutor crashDetectionExecutor; + private final ScheduledThreadPoolExecutor periodicTasksExecutor; /** - * Constructs an object that listens to local events and tracks them as - * collaboration tasks that can be broadcast to collaborating nodes, - * receives event messages from collaborating nodes and translates them into - * case activity indicators for the user, and monitors the health of the - * services needed for collaboration so that users can be informed if those - * service become unavailable. + * 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 + * collaboration services. */ CollaborationMonitor() throws CollaborationMonitorException { + /** + * Get the local host name so it can be used to identify the source of + * collaboration tasks broadcast by this node. + */ hostName = getHostName(); /** - * Create an Autopsy event publisher for the current case. This will be - * used to communicate with collaboration monitors on other Autopsy - * nodes working on the case. + * Create an event publisher that will be used to communicate with + * collaboration monitors on other nodes working on the case. */ eventPublisher = new AutopsyEventPublisher(); try { - eventPublisher.openRemoteEventChannel(String.format(EVENT_CHANNEL_NAME, Case.getCurrentCase().getName())); + Case openedCase = Case.getCurrentCase(); + String channelPrefix = openedCase.getTextIndexName(); + eventPublisher.openRemoteEventChannel(String.format(EVENT_CHANNEL_NAME, channelPrefix)); } catch (AutopsyEventException ex) { throw new CollaborationMonitorException("Failed to initialize", ex); } /** * Create a remote tasks manager to track and display the progress of - * tasks other Autopsy nodes as reported by their collaboration - * monitors. + * remote tasks. */ remoteTasksManager = new RemoteTasksManager(); eventPublisher.addSubscriber(COLLABORATION_MONITOR_EVENT, remoteTasksManager); /** - * Create a local tasks manager to keep track of and broadcast the - * events happening on this Autopsy node to the collaboration monitors - * on other nodes. + * Create a local tasks manager to track and broadcast local tasks. */ localTasksManager = new LocalTasksManager(); IngestManager.getInstance().addIngestJobEventListener(localTasksManager); Case.addEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager); - // RJCTODO: Do we really need three ScheduledThreadPoolExecutors? - // Perhaps one is enough.... /** - * Start a periodic task on its own thread that will send heartbeat - * messages to the collaboration monitors on other nodes. + * Start periodic tasks that: + * + * 1. Send heartbeats to collaboration monitors on other nodes.
+ * 2. Check for stale remote tasks.
+ * 3. Check the availability of key collaboration services.
*/ - heartbeatExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat(HEARTBEAT_THREAD_NAME).build()); - heartbeatExecutor.scheduleAtFixedRate(new HeartbeatTask(), MINUTES_BETWEEN_HEARTBEATS, MINUTES_BETWEEN_HEARTBEATS, TimeUnit.MINUTES); - - /** - * Start a periodic task on its own thread that will check for stale - * remote tasks. - */ - staleTasksCheckExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat(STALE_TASKS_DETECTION_THREAD_NAME).build()); - staleTasksCheckExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECTION_INTERVAL_SECS, STALE_TASKS_DETECTION_INTERVAL_SECS, TimeUnit.SECONDS); - - /** - * Start a periodic task on its own thread that will report on the - * availability of key collaboration services. - */ - crashDetectionExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat(CRASH_DETECTION_THREAD_NAME).build()); - crashDetectionExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_SECS, CRASH_DETECTION_INTERVAL_SECS, TimeUnit.SECONDS); + periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); + periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES); + periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECTION_INTERVAL_MINUTES, STALE_TASKS_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); + periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); } /** @@ -148,8 +134,7 @@ final class CollaborationMonitor { String name; try { name = java.net.InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException ex) { - // RJCTODO: Log info message + } catch (UnknownHostException notUsed) { name = System.getenv("COMPUTERNAME"); } return name; @@ -159,28 +144,23 @@ final class CollaborationMonitor { * Shuts down this collaboration monitor. */ void stop() { - stopExecutor(crashDetectionExecutor, CRASH_DETECTION_THREAD_NAME); - stopExecutor(heartbeatExecutor, HEARTBEAT_THREAD_NAME); - // RJCTODO: Shut down other stuff - eventPublisher.removeSubscriber(COLLABORATION_MONITOR_EVENT, remoteTasksManager); - eventPublisher.closeRemoteEventChannel(); - } - - /** - * Gracefully shuts down a scheduled thread pool executor. - */ - private static void stopExecutor(ScheduledThreadPoolExecutor executor, String name) { - if (null != executor) { - executor.shutdownNow(); + if (null != periodicTasksExecutor) { + periodicTasksExecutor.shutdownNow(); try { - while (!executor.awaitTermination(EXECUTOR_TERMINATION_WAIT_SECS, TimeUnit.SECONDS)) { - logger.log(Level.WARNING, "Waited at least {0} seconds for {1} executor to shut down, continuing to wait", new Object[]{EXECUTOR_TERMINATION_WAIT_SECS, name}); //NON-NLS + while (!periodicTasksExecutor.awaitTermination(EXECUTOR_TERMINATION_WAIT_SECS, TimeUnit.SECONDS)) { + logger.log(Level.WARNING, "Waited at least {0} seconds for periodic tasks executor to shut down, continuing to wait", EXECUTOR_TERMINATION_WAIT_SECS); //NON-NLS } } catch (InterruptedException ex) { - logger.log(Level.SEVERE, "Unexpected interrupt while stopping thread executor", ex); //NON-NLS - // RJCTODO: Reset? + logger.log(Level.SEVERE, "Unexpected interrupt while stopping periodic tasks executor", ex); //NON-NLS } } + + if (null != eventPublisher) { + eventPublisher.removeSubscriber(COLLABORATION_MONITOR_EVENT, remoteTasksManager); + eventPublisher.closeRemoteEventChannel(); + } + + // RJCTODO: Shut down other stuff? } /** @@ -207,8 +187,8 @@ final class CollaborationMonitor { } /** - * Updates the collection of tasks this node is performing in response - * to receiving an event in the form of a property change. + * Translates events into updates of the collection of local tasks this + * node is broadcasting to other nodes. * * @param event A PropertyChangeEvent. */ @@ -227,53 +207,56 @@ final class CollaborationMonitor { } /** - * Adds a task for tracking adding the data source and publishes the - * updated local tasks list to any collaborating nodes. + * Adds an adding data source task to the collection of local tasks and + * publishes the updated collection to any collaborating nodes. * - * @param evt An adding data source event. + * @param event An adding data source event. */ synchronized void addDataSourceAddTask(AddingDataSourceEvent event) { String status = String.format("%s adding data source", hostName); // RJCTODO: Bundle uuidsToAddDataSourceTasks.put(event.getDataSourceId().hashCode(), new Task(++nextTaskId, status)); - eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks())); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); } /** - * Removes the task for adding the data source and publishes the updated - * local tasks list to any collaborating nodes. + * Removes an adding data source task from the collection of local tasks + * and publishes the updated collection to any collaborating nodes. * - * @param evt A data source added event + * @param event A data source added event */ synchronized void removeDataSourceAddTask(DataSourceAddedEvent event) { uuidsToAddDataSourceTasks.remove(event.getDataSourceId().hashCode()); - eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks())); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); } /** - * RJCTODO + * Adds a data source analysis task to the collection of local tasks and + * publishes the updated collection to any collaborating nodes. * - * @param evt + * @param event A data source analysis started event. */ synchronized void addDataSourceAnalysisTask(DataSourceAnalysisStartedEvent event) { String status = String.format("%s analyzing %s", hostName, event.getDataSource().getName()); // RJCTODO: Bundle jobIdsTodataSourceAnalysisTasks.put(event.getDataSourceIngestJobId(), new Task(++nextTaskId, status)); - eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks())); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); } /** - * RJCTODO + * Removes a data source analysis task from the collection of local + * tasks and publishes the updated collection to any collaborating + * nodes. * - * @param evt + * @param event A data source analysis completed event. */ synchronized void removeDataSourceAnalysisTask(DataSourceAnalysisCompletedEvent event) { jobIdsTodataSourceAnalysisTasks.remove(event.getDataSourceIngestJobId()); - eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks())); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); } /** * Gets the current local tasks. * - * @return A mapping of task IDs to tasks + * @return A mapping of task IDs to tasks, may be empty. */ synchronized Map getCurrentTasks() { Map currentTasks = new HashMap<>(); @@ -288,18 +271,31 @@ final class CollaborationMonitor { } /** - * The remote tasks manager listens to events broadcast by collaboration + * Listens for collaboration event messages broadcast by collaboration * monitors on other nodes and translates them into remote tasks represented - * using progress bars. + * locally using progress bars. Note that all access to the remote tasks is + * synchronized since it may be accessed by a JMS thread running code in the + * Autopsy event publisher and by a thread running periodic checks for + * "stale" tasks. */ private final class RemoteTasksManager implements PropertyChangeListener { - private Map hostToTasks; + private final Map hostsToTasks; /** - * RJCTODO + * 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. + */ + RemoteTasksManager() { + hostsToTasks = new HashMap<>(); + } + + /** + * Update the remote tasks based to reflect a collaboration event + * received from another node. * - * @param event + * @param event A collaboration event. */ @Override public void propertyChange(PropertyChangeEvent event) { @@ -315,19 +311,19 @@ final class CollaborationMonitor { */ synchronized void updateTasks(CollaborationEvent event) { // RJCTODO: This is a little hard to understand, consider some renaming - RemoteTasks tasks = hostToTasks.get(event.getHostName()); + RemoteTasks tasks = hostsToTasks.get(event.getHostName()); if (null != tasks) { tasks.update(event); } else { - hostToTasks.put(event.getHostName(), new RemoteTasks(event)); + hostsToTasks.put(event.getHostName(), new RemoteTasks(event)); } } /** * RJCTODO */ - synchronized void finshStaleTasks() { - for (Iterator> it = hostToTasks.entrySet().iterator(); it.hasNext();) { + synchronized void finishStaleTasks() { + for (Iterator> it = hostsToTasks.entrySet().iterator(); it.hasNext();) { Map.Entry entry = it.next(); RemoteTasks tasks = entry.getValue(); if (tasks.isStale()) { @@ -338,22 +334,24 @@ final class CollaborationMonitor { } /** - * A collection of progress bars for tasks on a collaborating node, - * obtained from a collaboration event and bundled with the time of the - * last update. + * A collection of progress bars for tasks on a collaborating node. */ class RemoteTasks { - private final Duration MAX_MINUTES_WITHOUT_UPDATE = Duration.ofSeconds(MINUTES_BETWEEN_HEARTBEATS * 5); + private final Duration MAX_MINUTES_WITHOUT_UPDATE = Duration.ofSeconds(HEARTBEAT_INTERVAL_MINUTES * MAX_MISSED_HEARTBEATS); private Instant lastUpdateTime; private Map taskIdsToProgressBars; /** - * RJCTODO + * Construct a set of progress bars to represent remote tasks for a + * particular host. * - * @param event + * @param event A collaboration event. */ RemoteTasks(CollaborationEvent event) { + /** + * Set the initial value of the last update time stamp. + */ lastUpdateTime = Instant.now(); event.getCurrentTasks().values().stream().forEach((task) -> { ProgressHandle progress = ProgressHandleFactory.createHandle(event.getHostName()); @@ -371,21 +369,27 @@ final class CollaborationMonitor { */ void update(CollaborationEvent event) { /** - * Update the timestamp. + * Update the last update timestamp. */ lastUpdateTime = Instant.now(); - Map currentTasks = event.getCurrentTasks(); /** * Create or update the progress bars for the current tasks of * the node that published the event. */ - currentTasks.values().stream().forEach((task) -> { + Map remoteTasks = event.getCurrentTasks(); + remoteTasks.values().stream().forEach((task) -> { ProgressHandle progress = taskIdsToProgressBars.get(task.getId()); if (null != progress) { + /** + * Update the existing progress bar. + */ progress.progress(task.getStatus()); } else { + /** + * A new task, create a progress bar. + */ progress = ProgressHandleFactory.createHandle(event.getHostName()); progress.start(); progress.progress(task.getStatus()); @@ -398,13 +402,17 @@ final class CollaborationMonitor { * it is finished. Remove the progress bars for finished tasks. */ for (Long id : taskIdsToProgressBars.keySet()) { - if (!currentTasks.containsKey(id)) { + if (!remoteTasks.containsKey(id)) { ProgressHandle progress = taskIdsToProgressBars.remove(id); progress.finish(); } } } + /** + * Unconditionally finishes the entire set or remote tasks. To be + * used when a host drops off unexpectedly. + */ void finishAllTasks() { taskIdsToProgressBars.values().stream().forEach((progress) -> { progress.finish(); @@ -440,7 +448,7 @@ final class CollaborationMonitor { */ @Override public void run() { - eventPublisher.publish(new CollaborationEvent(hostName, localTasksManager.getCurrentTasks())); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, localTasksManager.getCurrentTasks())); } } @@ -454,7 +462,7 @@ final class CollaborationMonitor { */ @Override public void run() { - remoteTasksManager.finshStaleTasks(); + remoteTasksManager.finishStaleTasks(); } } diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java index f6011621c4..df2b21674a 100644 --- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java @@ -134,13 +134,7 @@ public final class AutopsyEventPublisher { */ public void publish(AutopsyEvent event) { publishLocally(event); - if (null != remotePublisher) { - try { - remotePublisher.publish(event); - } catch (JMSException ex) { - logger.log(Level.SEVERE, String.format("Failed to publish %s event remotely", event.getPropertyName()), ex); //NON-NLS - } - } + publishRemotely(event); } /** @@ -152,4 +146,19 @@ public final class AutopsyEventPublisher { localPublisher.publish(event); } + /** + * Publishes an event to other Autopsy nodes only. + * + * @param event The event to publish. + */ + public void publishRemotely(AutopsyEvent event) { + if (null != remotePublisher) { + try { + remotePublisher.publish(event); + } catch (JMSException ex) { + logger.log(Level.SEVERE, String.format("Failed to publish %s event remotely", event.getPropertyName()), ex); //NON-NLS + } + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java index a4106cb1cc..718b8a88c7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java @@ -94,13 +94,13 @@ public final class IngestJob { * @return A collection of ingest module start up errors, empty on success. */ synchronized List start() { - List errors = new ArrayList<>(); + List errors = new ArrayList<>(); if (started) { errors.add(new IngestModuleError("IngestJob", new IllegalStateException("Job already started"))); return errors; } started = true; - + for (DataSourceIngestJob dataSourceJob : this.dataSourceJobs.values()) { errors.addAll(dataSourceJob.start()); if (!errors.isEmpty()) { @@ -116,15 +116,20 @@ public final class IngestJob { * startup is going to fail, it will likely fail for the first child * data source ingest job. */ - if (!errors.isEmpty()) { - for (DataSourceIngestJob dataSourceJob : this.dataSourceJobs.values()) { + if (errors.isEmpty()) { + IngestManager ingestManager = IngestManager.getInstance(); + this.dataSourceJobs.values().stream().forEach((dataSourceJob) -> { + ingestManager.fireDataSourceAnalysisStarted(id, dataSourceJob.getId(), dataSourceJob.getDataSource()); + }); + } else { + this.dataSourceJobs.values().stream().forEach((dataSourceJob) -> { dataSourceJob.cancel(); - } + }); } return errors; } - + /** * Gets a snapshot of the progress of this ingest job. * @@ -142,7 +147,7 @@ public final class IngestJob { public ProgressSnapshot getSnapshot(boolean getIngestTasksSnapshot) { return new ProgressSnapshot(getIngestTasksSnapshot); } - + /** * Gets snapshots of the progress of each of this ingest job's child data * source ingest jobs. @@ -151,9 +156,9 @@ public final class IngestJob { */ List getDataSourceIngestJobSnapshots() { List snapshots = new ArrayList<>(); - for (DataSourceIngestJob dataSourceJob : this.dataSourceJobs.values()) { + this.dataSourceJobs.values().stream().forEach((dataSourceJob) -> { snapshots.add(dataSourceJob.getSnapshot(true)); - } + }); return snapshots; } @@ -164,9 +169,11 @@ public final class IngestJob { * pipelines respond by stopping processing. */ public void cancel() { - for (DataSourceIngestJob job : this.dataSourceJobs.values()) { + IngestManager ingestManager = IngestManager.getInstance(); + this.dataSourceJobs.values().stream().forEach((job) -> { job.cancel(); - } + ingestManager.fireDataSourceAnalysisCancelled(id, job.getId(), job.getDataSource()); + }); this.cancelled = true; } @@ -184,11 +191,13 @@ public final class IngestJob { * Provides a callback for completed data source ingest jobs, allowing this * ingest job to notify the ingest manager when it is complete. * - * @param dataSourceIngestJob A completed data source ingest job. + * @param job A completed data source ingest job. */ - void dataSourceJobFinished(DataSourceIngestJob dataSourceIngestJob) { + void dataSourceJobFinished(DataSourceIngestJob job) { + IngestManager ingestManager = IngestManager.getInstance(); + ingestManager.fireDataSourceAnalysisCompleted(id, job.getId(), job.getDataSource()); if (incompleteJobsCount.decrementAndGet() == 0) { - IngestManager.getInstance().finishIngestJob(this); + ingestManager.finishIngestJob(this); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 0028369cf7..c5a2081fc5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -51,6 +51,8 @@ import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; import org.sleuthkit.autopsy.ingest.events.BlackboardPostEvent; import org.sleuthkit.autopsy.ingest.events.ContentChangedEvent; +import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; +import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent; import org.sleuthkit.autopsy.ingest.events.FileAnalyzedEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -643,6 +645,42 @@ public class IngestManager { eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher)); } + /** + * Fire an ingest event signifying analysis of a data source started. + * + * @param ingestJobId The ingest job id. + * @param dataSourceIngestJobId The data source ingest job id. + * @param dataSource The data source. + */ + void fireDataSourceAnalysisStarted(long ingestJobId, long dataSourceIngestJobId, Content dataSource) { + AutopsyEvent event = new DataSourceAnalysisStartedEvent(ingestJobId, dataSourceIngestJobId, dataSource); + eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher)); + } + + /** + * Fire an ingest event signifying analysis of a data source finished. + * + * @param ingestJobId The ingest job id. + * @param dataSourceIngestJobId The data source ingest job id. + * @param dataSource The data source. + */ + void fireDataSourceAnalysisCompleted(long ingestJobId, long dataSourceIngestJobId, Content dataSource) { + AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.COMPLETED); + eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher)); + } + + /** + * Fire an ingest event signifying analysis of a data source was canceled. + * + * @param ingestJobId The ingest job id. + * @param dataSourceIngestJobId The data source ingest job id. + * @param dataSource The data source. + */ + void fireDataSourceAnalysisCancelled(long ingestJobId, long dataSourceIngestJobId, Content dataSource) { + AutopsyEvent event = new DataSourceAnalysisCompletedEvent(ingestJobId, dataSourceIngestJobId, dataSource, DataSourceAnalysisCompletedEvent.Reason.CANCELLED); + eventPublishingExecutor.submit(new PublishEventTask(event, jobEventPublisher)); + } + /** * Fire an ingest event signifying the ingest of a file is completed. *