Evolve CollaborationManager implementation

This commit is contained in:
Richard Cordovano 2015-06-03 18:03:36 -04:00
parent 5dd3849f15
commit a7b83af5bb
10 changed files with 267 additions and 66 deletions

View File

@ -25,6 +25,7 @@ import java.awt.Window;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
@ -237,10 +238,12 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
// get the selected DSProcessor
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
final UUID dataSourceId = UUID.randomUUID();
Case.getCurrentCase().notifyAddingNewDataSource(dataSourceId);
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback () {
@Override
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
dataSourceProcessorDone(result, errList, contents );
dataSourceProcessorDone(dataSourceId, result, errList, contents );
}
};
@ -263,7 +266,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
* Callback for the data source processor.
* Invoked by the DSP on the EDT thread, when it finishes processing the data source.
*/
private void dataSourceProcessorDone(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
// disable the cleanup task
cleanupTask.disable();
@ -305,8 +308,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
//notify the UI of the new content added to the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyNewDataSource(newContents.get(0));
Case.getCurrentCase().notifyNewDataSource(newContents.get(0), dataSourceId);
} else {
Case.getCurrentCase().notifyNewDataSource(null, dataSourceId); // RJCTODO: Update for null scenario
}

View File

@ -38,6 +38,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -48,6 +49,7 @@ import org.openide.util.NbBundle;
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.DataSourceAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
import org.sleuthkit.autopsy.casemodule.services.Services;
@ -516,7 +518,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException {
try {
Image newDataSource = db.getImageById(imgId);
notifyNewDataSource(newDataSource);
notifyNewDataSource(newDataSource, UUID.randomUUID());
return newDataSource;
} catch (Exception ex) {
throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.addImg.exception.msg"), ex);
@ -532,16 +534,32 @@ public class Case implements SleuthkitCase.ErrorObserver {
*/
@Deprecated
void addLocalDataSource(Content newDataSource) {
notifyNewDataSource(newDataSource);
notifyNewDataSource(newDataSource, UUID.randomUUID());
}
/**
* Notifies the UI that a new data source has been added.
* Notifies case event subscribers (property change listeners) that a data
* source is being added to the case database.
*
* @param newDataSource new data source added
* @param dataSourceId A unique identifier for the data source. This UUID
* should be used to call notifyNewDataSource() after the data source is
* added.
*/
public void notifyNewDataSource(Content newDataSource) {
eventPublisher.publish(new DataSourceAddedEvent(newDataSource));
public void notifyAddingNewDataSource(UUID dataSourceId) {
eventPublisher.publish(new AddingDataSourceEvent(dataSourceId));
}
/**
* Notifies case event subscribers (property change listeners) that a data
* source is being added to the case database.
*
* @param newDataSource New data source added.
* @param dataSourceId A unique identifier for the data source. Should be
* the same UUID used to call notifyAddingNewDataSource() when the process
* of adding the data source began.
*/
public void notifyNewDataSource(Content newDataSource, UUID dataSourceId) {
eventPublisher.publish(new DataSourceAddedEvent(newDataSource, dataSourceId));
CoreComponentControl.openCoreWindows();
}

View File

@ -25,20 +25,15 @@ import java.io.Serializable;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent;
@ -175,7 +170,7 @@ final class CollaborationMonitor {
executor.shutdownNow();
try {
while (!executor.awaitTermination(EXECUTOR_TERMINATION_WAIT_SECS, TimeUnit.SECONDS)) {
logger.log(Level.WARNING, "Waited at least thirty seconds for {0} executor to shut down, continuing to wait", name); //NON-NLS
logger.log(Level.WARNING, "Waited at least thirty seconds for {0} executor to shut down, continuing to wait", name); //NON-NLS RJCTODO
}
} catch (InterruptedException ex) {
// RJCTODO:
@ -190,7 +185,7 @@ final class CollaborationMonitor {
private final class LocalTasksManager implements PropertyChangeListener {
private final AtomicLong nextTaskId;
private final Map<String, Task> pathsToAddDataSourceTasks;
private final Map<Integer, Task> uuidsToAddDataSourceTasks;
private final Map<Long, Task> jobIdsTodataSourceAnalysisTasks;
/**
@ -200,7 +195,7 @@ final class CollaborationMonitor {
*/
LocalTasksManager() {
nextTaskId = new AtomicLong(0L);
pathsToAddDataSourceTasks = new HashMap<>();
uuidsToAddDataSourceTasks = new HashMap<>();
jobIdsTodataSourceAnalysisTasks = new HashMap<>();
}
@ -217,49 +212,54 @@ final class CollaborationMonitor {
addDataSourceAddTask(evt);
} else if (eventName.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
addDataSourceAddTask(evt);
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED.toString())) {
addDataSourceAnalysisTask(evt);
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED.toString())) {
removeDataSourceAnalysisTask(evt);
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_CANCELLED.toString())) {
removeDataSourceAnalysisTask(evt);
}
/**
* RJCTODO: When local ADDING_DATA_SOURCE (new) event is received,
* create a new task. When local DATA_SOURCE_ADDED event is
* received, delete the task. The new ADDING_DATA_SOURCE events can
* have full image paths to match up with the Content objects on the
* DATA_SOURCE_ADDED events.
*/
/**
* RJCTODO: When local DATA_SOURCE_INGEST_STARTED event (new) is
* received, create new data source analysis tasks. When local
* DATA_SOURCE_INGEST_COMPLETED (new) or
* DATA_SOURCE_INGEST_CANCELLED (new) is received, delete the task.
* These new events can have data source ingest job ids and data
* source names.
*/
}
/**
* Add a task for adding the data source and publishes the updated local
* tasks list to any collaborating nodes.
*
* @param evt RJCTODO
*/
synchronized void addDataSourceAddTask(PropertyChangeEvent evt) {
String dataSourcePath = (String) evt.getNewValue();
String taskStatus = String.format("Adding data source %s", dataSourcePath); // RJCTODO: Bundle
// RJCTODO: This probably will not work, path needs to be sanitized
pathsToAddDataSourceTasks.put(dataSourcePath, new Task(nextTaskId.getAndIncrement(), taskStatus));
AddingDataSourceEvent event = (AddingDataSourceEvent) evt;
String status = String.format("%s adding data source", hostName); // RJCTODO: Bundle
uuidsToAddDataSourceTasks.put(event.getDataSourceId().hashCode(), new Task(nextTaskId.getAndIncrement(), status));
eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Removes the task for adding the data source and publishes the updated
* local tasks list to any collaborating nodes.
*
* @param evt RJCTODO
*/
synchronized void removeDataSourceAddTask(PropertyChangeEvent evt) {
DataSourceAddedEvent event = (DataSourceAddedEvent) evt;
Content dataSource = event.getDataSource();
try {
pathsToAddDataSourceTasks.remove(dataSource.getUniquePath());
} catch (TskCoreException ex) {
// RJCTODO
}
uuidsToAddDataSourceTasks.remove(event.getDataSourceId().hashCode());
eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* RJCTODO
*
* @param evt
*/
synchronized void addDataSourceAnalysisTask(PropertyChangeEvent evt) {
eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* RJCTODO
*
* @param evt
*/
synchronized void removeDataSourceAnalysisTask(PropertyChangeEvent evt) {
eventPublisher.publish(new CollaborationEvent(hostName, getCurrentTasks()));
}
@ -271,7 +271,7 @@ final class CollaborationMonitor {
*/
synchronized Map<Long, Task> getCurrentTasks() {
Map<Long, Task> currentTasks = new HashMap<>();
pathsToAddDataSourceTasks.values().stream().forEach((task) -> {
uuidsToAddDataSourceTasks.values().stream().forEach((task) -> {
currentTasks.put(task.getId(), task);
});
jobIdsTodataSourceAnalysisTasks.values().stream().forEach((task) -> {

View File

@ -19,8 +19,6 @@
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
@ -33,26 +31,28 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
public final class AddingDataSourceEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final UUID uuid;
private List<String> dataSourceFileNames;
private final UUID dataSourceId;
/**
* Constructs an event published when a data source is being added to a
* case.
*
* @param dataSourceFileNames
* @param uuid
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this AddindDataSourceEvent with a DataSoruceAddedEvent.
*/
public AddingDataSourceEvent(List<String> dataSourceFileNames, UUID uuid) {
public AddingDataSourceEvent(UUID dataSourceId) {
super(Case.Events.ADDING_DATA_SOURCE.toString(), null, null);
this.uuid = uuid;
this.dataSourceId = dataSourceId;
}
public UUID getUUID() {
return uuid;
/**
* Gets the unique id for the data source used to pair this
* AddindDataSourceEvent with a DataSoruceAddedEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
public List<String> getDataSourceFileNames() {
return new ArrayList<>(dataSourceFileNames);
}
}

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.UUID;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -34,13 +35,16 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(DataSourceAddedEvent.class.getName());
private transient Content dataSource;
private final UUID dataSourceId;
/**
* Constructs an event published when a data source is added to a case.
*
* @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.
*/
public DataSourceAddedEvent(Content dataSource) {
public DataSourceAddedEvent(Content dataSource, UUID dataSourceId) {
/**
* Putting the object id of the data source into newValue to allow for
* lazy loading of the Content object. This bypasses the issues related
@ -49,6 +53,7 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
*/
super(Case.Events.DATA_SOURCE_ADDED.toString(), null, dataSource.getId());
this.dataSource = dataSource;
this.dataSourceId = dataSourceId;
}
/**
@ -85,6 +90,17 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
* @return The data source.
*/
public Content getDataSource() {
return (Content)getNewValue();
return (Content) getNewValue();
}
/**
* Gets the unique id for the data source used to pair this
* DataSoruceAddedEvent with a AddindDataSourceEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}

View File

@ -171,6 +171,18 @@ public class IngestManager {
* and the new value is set to null.
*/
CANCELLED,
/**
* RJCTODO
*/
DATA_SOURCE_ANALYSIS_STARTED,
/**
* RJCTODO
*/
DATA_SOURCE_ANALYSIS_COMPLETED,
/**
* RJCTODO
*/
DATA_SOURCE_ANALYSIS_CANCELLED
};
/**

View File

@ -0,0 +1,36 @@
/*
* 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.ingest.events;
import java.io.Serializable;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
*/
public class DataSourceAnalysisCancelledEvent extends DataSourceAnalysisEvent implements Serializable {
private static final long serialVersionUID = 1L;
public DataSourceAnalysisCancelledEvent(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_CANCELLED, ingestJobId, dataSourceIngestJobId, dataSource);
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.ingest.events;
import java.io.Serializable;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
*/
public class DataSourceAnalysisCompletedEvent extends DataSourceAnalysisEvent implements Serializable {
private static final long serialVersionUID = 1L;
public DataSourceAnalysisCompletedEvent(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED, ingestJobId, dataSourceIngestJobId, dataSource);
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.ingest.events;
import java.io.Serializable;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
*/
public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final long ingestJobId;
private final long dataSourceIngestJobId;
private transient Content dataSource;
public DataSourceAnalysisEvent(IngestManager.IngestJobEvent eventType, long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(eventType.toString(), null, null);
this.ingestJobId = ingestJobId;
this.dataSourceIngestJobId = dataSourceIngestJobId;
this.dataSource = dataSource;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.ingest.events;
import java.io.Serializable;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Content;
/**
* RJCTODO
*/
public class DataSourceAnalysisStartedEvent extends DataSourceAnalysisEvent implements Serializable {
private static final long serialVersionUID = 1L;
public DataSourceAnalysisStartedEvent(long ingestJobId, long dataSourceIngestJobId, Content dataSource) {
super(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED, ingestJobId, dataSourceIngestJobId, dataSource);
}
}