diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 696eeb6721..e4fc1c7864 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -45,6 +45,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.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl; @@ -53,6 +54,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; import org.sleuthkit.datamodel.*; @@ -75,11 +77,6 @@ public class Case implements SleuthkitCase.ErrorObserver { */ public static final String propStartup = "LBL_StartupDialog"; //NON-NLS - // RJCTODO: Replace PropertyChangeSupport with AutopsyEventPublisher. - private static final PropertyChangeSupport pcs = new PropertyChangeSupport(Case.class); - private static final Set eventNames = Stream.of(Events.values()) - .map(Events::toString) - .collect(Collectors.toSet()); private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher(); /** @@ -90,12 +87,9 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Property name that indicates the name of the current case has - * changed. When a case is opened, "old name" is empty string and "new - * name" is the name. When a case is closed, "old name" is the case name - * and "new name" is empty string. When a case is renamed, "old name" - * has the original name and "new name" has the new name. + * changed. The old value is the old case name, the new value is the new + * case name. */ - // @@@ BC: I propose that this is no longer called for case open/close. NAME, /** * Property name that indicates the number of the current case has @@ -205,16 +199,6 @@ public class Case implements SleuthkitCase.ErrorObserver { this.caseType = type; this.db = db; this.services = new Services(db); - if (CaseType.MULTI_USER_CASE == this.caseType) { - try { - eventPublisher.openRemoteEventChannel(name); - } catch (AutopsyEventException ex) { - logger.log(Level.SEVERE, "Failed to start remote event publisher", ex); - MessageNotifyUtil.Message.error(NbBundle.getMessage(Case.class, - "Case.OpenEventChannel.ErrMsg", - name)); - } - } } /** @@ -261,58 +245,30 @@ public class Case implements SleuthkitCase.ErrorObserver { Case oldCase = Case.currentCase; Case.currentCase = null; if (oldCase != null) { - doCaseChange(null); //closes windows, etc - - try { - pcs.firePropertyChange(Events.CURRENT_CASE.toString(), oldCase, null); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(Case.class, "Case.moduleErr"), - NbBundle.getMessage(Case.class, - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - doCaseNameChange(""); - - try { - pcs.firePropertyChange(Events.NAME.toString(), oldCase.name, ""); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(Case.class, "Case.moduleErr"), - NbBundle.getMessage(Case.class, - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + doCaseChange(null); //closes windows, etc + eventPublisher.publishLocally(new AutopsyEvent(Events.CURRENT_CASE.toString(), oldCase, null)); + if (CaseType.MULTI_USER_CASE == oldCase.getCaseType()) { + eventPublisher.closeRemoteEventChannel(); + } } if (newCase != null) { currentCase = newCase; - Logger.setLogDirectory(currentCase.getLogDirectoryPath()); - - try { - pcs.firePropertyChange(Events.CURRENT_CASE.toString(), null, currentCase); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(Case.class, "Case.moduleErr"), - NbBundle.getMessage(Case.class, - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } doCaseChange(currentCase); - - try { - pcs.firePropertyChange(Events.NAME.toString(), "", currentCase.name); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(Case.class, "Case.moduleErr"), - NbBundle.getMessage(Case.class, - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - doCaseNameChange(currentCase.name); - + updateMainWindowTitle(currentCase.name); RecentCases.getInstance().addRecentCase(currentCase.name, currentCase.configFilePath); // update the recent cases + if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) { + try { + eventPublisher.openRemoteEventChannel(newCase.getName()); + } catch (AutopsyEventException ex) { + logger.log(Level.SEVERE, "Failed to start remote event publisher", ex); + MessageNotifyUtil.Message.error(NbBundle.getMessage(Case.class, + "Case.OpenEventChannel.ErrMsg", + newCase.getName())); + } + } + eventPublisher.publishLocally(new AutopsyEvent(Events.CURRENT_CASE.toString(), null, currentCase)); } else { Logger.setLogDirectory(PlatformUtil.getLogDirectory()); } @@ -525,25 +481,14 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param imgPaths the paths of the image that being added * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added + * @deprecated Use notifyNewDataSource() instead. */ @Deprecated public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException { - logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone}); //NON-NLS - try { - Image newImage = db.getImageById(imgId); - - try { - pcs.firePropertyChange(Events.DATA_SOURCE_ADDED.toString(), null, newImage); // the new value is the instance of the image - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - CoreComponentControl.openCoreWindows(); - return newImage; + Image newDataSource = db.getImageById(imgId); + notifyNewDataSource(newDataSource); + return newDataSource; } catch (Exception ex) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.addImg.exception.msg"), ex); } @@ -554,6 +499,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * reopens windows if needed. * * @param newDataSource new data source added + * @deprecated Use notifyNewDataSource() instead. */ @Deprecated void addLocalDataSource(Content newDataSource) { @@ -563,20 +509,10 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Notifies the UI that a new data source has been added. * - * * @param newDataSource new data source added */ void notifyNewDataSource(Content newDataSource) { - - try { - pcs.firePropertyChange(Events.DATA_SOURCE_ADDED.toString(), null, newDataSource); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + eventPublisher.publish(new DataSourceAddedEvent(newDataSource)); CoreComponentControl.openCoreWindows(); } @@ -603,9 +539,6 @@ public class Case implements SleuthkitCase.ErrorObserver { public void closeCase() throws CaseActionException { changeCase(null); try { - if (CaseType.MULTI_USER_CASE == this.caseType) { - eventPublisher.closeRemoteEventChannel(); - } services.close(); this.xmlcm.close(); // close the xmlcm this.db.close(); @@ -655,17 +588,8 @@ public class Case implements SleuthkitCase.ErrorObserver { xmlcm.setCaseName(newCaseName); // set the case name = newCaseName; // change the local value RecentCases.getInstance().updateRecentCase(oldCaseName, oldPath, newCaseName, newPath); // update the recent case - try { - pcs.firePropertyChange(Events.NAME.toString(), oldCaseName, newCaseName); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - doCaseNameChange(newCaseName); - + eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); + updateMainWindowTitle(newCaseName); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateCaseName.exception.msg"), e); } @@ -681,15 +605,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { xmlcm.setCaseExaminer(newExaminer); // set the examiner examiner = newExaminer; - try { - pcs.firePropertyChange(Events.EXAMINER.toString(), oldExaminer, newExaminer); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + eventPublisher.publish(new AutopsyEvent(Events.EXAMINER.toString(), oldExaminer, newExaminer)); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateExaminer.exception.msg"), e); } @@ -705,16 +621,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { xmlcm.setCaseNumber(newCaseNumber); // set the case number number = newCaseNumber; - - try { - pcs.firePropertyChange(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber)); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateCaseNum.exception.msg"), e); } @@ -917,12 +824,14 @@ public class Case implements SleuthkitCase.ErrorObserver { } /** - * get the PropertyChangeSupport of this class + * Gets a new PropertyChangeSupport object. * - * @return PropertyChangeSupport + * @return A new PropertyChangeSupport object with source set to null. + * @deprecated Do not use. */ + @Deprecated public static PropertyChangeSupport getPropertyChangeSupport() { - return pcs; + return new PropertyChangeSupport(null); } /** @@ -958,20 +867,35 @@ public class Case implements SleuthkitCase.ErrorObserver { return timezones; } - // RJCTODO: Deprecate in favor of addEventSubscriber() and remove use of PropertyChangeSupport + /** + * Adds a subscriber to all case events from this Autopsy node and other + * Autopsy nodes. To subscribe to only specific events, use one of the + * overloads of addEventSubscriber(). + * + * @param listener The subscriber to add. + */ public static synchronized void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); -// eventPublisher.addSubscriber(eventNames, listener); - } - - // RJCTODO: Deprecate in favor of removeEventSubscriber() and remove use of PropertyChangeSupport - public static synchronized void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); -// eventPublisher.removeSubscriber(eventNames, listener); + addEventSubscriber(Stream.of(Events.values()) + .map(Events::toString) + .collect(Collectors.toSet()), listener); } /** - * Adds a subscriber to events from this Autopsy node and other Autopsy nodes. + * Removes a subscriber from all case events from this Autopsy node and + * other Autopsy nodes. To remove a subscription to only specific events, + * use one of the overloads of removeEventSubscriber(). + * + * @param listener The subscriber to add. + */ + public static synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + removeEventSubscriber(Stream.of(Events.values()) + .map(Events::toString) + .collect(Collectors.toSet()), listener); + } + + /** + * Adds a subscriber to events from this Autopsy node and other Autopsy + * nodes. * * @param eventNames The events the subscriber is interested in. * @param subscriber The subscriber to add. @@ -981,7 +905,8 @@ public class Case implements SleuthkitCase.ErrorObserver { } /** - * Adds a subscriber to events from this Autopsy node and other Autopsy nodes. + * Adds a subscriber to events from this Autopsy node and other Autopsy + * nodes. * * @param eventNames The event the subscriber is interested in. * @param subscriber The subscriber to add. @@ -991,7 +916,8 @@ public class Case implements SleuthkitCase.ErrorObserver { } /** - * Adds a subscriber to events from this Autopsy node and other Autopsy nodes. + * Adds a subscriber to events from this Autopsy node and other Autopsy + * nodes. * * @param eventName The event the subscriber is no longer interested in. * @param subscriber The subscriber to add. @@ -1001,7 +927,8 @@ public class Case implements SleuthkitCase.ErrorObserver { } /** - * Removes a subscriber to events from this Autopsy node and other Autopsy nodes. + * Removes a subscriber to events from this Autopsy node and other Autopsy + * nodes. * * @param eventNames The event the subscriber is no longer interested in. * @param subscriber The subscriber to add. @@ -1301,7 +1228,7 @@ public class Case implements SleuthkitCase.ErrorObserver { } //case name change helper - private static void doCaseNameChange(String newCaseName) { + private static void updateMainWindowTitle(String newCaseName) { // update case name if (!newCaseName.equals("")) { Frame f = WindowManager.getDefault().getMainWindow(); @@ -1309,15 +1236,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } } - //delete image helper - private void doDeleteImage() { - // no more image left in this case - if (currentCase.hasData()) { - // close all top components - CoreComponentControl.closeCoreWindows(); - } - } - @Override public void receiveError(String context, String errorMessage) { MessageNotifyUtil.Notify.error(context, errorMessage); @@ -1336,12 +1254,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { Report report = this.db.addReport(localPath, srcModuleName, reportName); - try { - Case.pcs.firePropertyChange(Events.REPORT_ADDED.toString(), null, report); - } catch (Exception ex) { - String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORT_ADDED.toString()); //NON-NLS - logger.log(Level.SEVERE, errorMessage, ex); - } + eventPublisher.publish(new AutopsyEvent(Events.REPORT_ADDED.toString(), null, report)); } public List getAllReports() throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java new file mode 100644 index 0000000000..ebf379b43f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java @@ -0,0 +1,82 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit 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.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.AutopsyEvent; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Event published when a data source is added to a case. + */ +public final class DataSourceAddedEvent extends AutopsyEvent implements Serializable { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(DataSourceAddedEvent.class.getName()); + private transient Content dataSource; + + /** + * Constructs an event published when a data source is added to a case. + * + * @param dataSource The data source that was added. + */ + public DataSourceAddedEvent(Content dataSource) { + /** + * Putting the object id of the data source into newValue to allow for + * lazy loading of the Content object. This bypasses the issues related + * to the serialization and de-serialization of Content objects when the + * event is published over a network. + */ + super(Case.Events.DATA_SOURCE_ADDED.toString(), null, dataSource.getId()); + this.dataSource = dataSource; + } + + /** + * Gets the data source that was added. + * + * @return The data source. + */ + @Override + public Object getNewValue() { + /** + * 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.getOldValue(); + 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; + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 8161914bb9..d66cc06823 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -27,6 +27,7 @@ import java.beans.PropertyVetoException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; @@ -117,7 +118,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat subscribeToChangeEvents(); associateLookup(ExplorerUtils.createLookup(em, getActionMap())); - this.pcs = new PropertyChangeSupport(this); // set the back & forward list and also disable the back & forward button @@ -144,7 +144,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } }); - Case.addPropertyChangeListener(this); + Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this); this.em.addPropertyChangeListener(this); IngestManager.getInstance().addIngestJobEventListener(this); IngestManager.getInstance().addIngestModuleEventListener(this); @@ -245,9 +245,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat forwardList.addLast(currentNodePath); forwardButton.setEnabled(true); - /* We peek instead of poll because we use its existence - * in the list later on so that we do not reset the forward list - * after the selection occurs. */ + /* + * We peek instead of poll because we use its existence in the list + * later on so that we do not reset the forward list after the selection + * occurs. + */ String[] newCurrentNodePath = backList.peekLast(); // enable / disable the back and forward button @@ -388,7 +390,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat root = new DirectoryTreeFilterNode(root, true); - em.setRootContext(root); em.getRootContext().setName(currentCase.getName()); em.getRootContext().setDisplayName(currentCase.getName()); @@ -407,7 +408,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat tree.expandNode(resultsChilds.findChild(KeywordHits.NAME)); tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME)); - Node views = childNodes.findChild(ViewsNode.NAME); Children viewsChilds = views.getChildren(); for (Node n : viewsChilds.getNodes()) { @@ -421,7 +421,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat dataResult.open(); // open the data result top component as well when the directory tree is opened } - // select the first image node, if there is one // (this has to happen after dataResult is opened, because the event // of changing the selected node fires a handler that tries to make @@ -534,22 +533,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat String changed = evt.getPropertyName(); Object oldValue = evt.getOldValue(); Object newValue = evt.getNewValue(); - - // change in the case name - if (changed.equals(Case.Events.NAME.toString())) { - // set the main title of the window - String oldCaseName = oldValue.toString(); - String newCaseName = newValue.toString(); - - - // update the case name - if ((!oldCaseName.equals("")) && (!newCaseName.equals(""))) { - // change the root name and display name - em.getRootContext().setName(newCaseName); - em.getRootContext().setDisplayName(newCaseName); - } - } // changed current case - else if (changed.equals(Case.Events.CURRENT_CASE.toString())) { + if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case // When a case is closed, the old value of this property is the // closed Case object and the new value is null. When a case is // opened, the old value is null and the new value is the new Case @@ -563,7 +547,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Node emptyNode = new AbstractNode(Children.LEAF); em.setRootContext(emptyNode); } else if (newValue != null) { - // A new case has been opened. Reset the forward and back + // A new case has been opened. Reset the ExplorerManager. + Case newCase = (Case) newValue; + String newCaseName = newCase.getName(); + em.getRootContext().setName(newCaseName); + em.getRootContext().setDisplayName(newCaseName); + + // Reset the forward and back // buttons. Note that a call to CoreComponentControl.openCoreWindows() // by the new Case object will lead to a componentOpened() call // that will repopulate the tree. @@ -574,12 +564,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } // if the image is added to the case else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { componentOpened(); - } - // change in node selection + } // change in node selection else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) { respondSelection((Node[]) oldValue, (Node[]) newValue); - } - else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { // nothing to do here. // all nodes should be listening for these events and update accordingly. } else if (changed.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -615,7 +603,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return; } - // Some lock that prevents certain Node operations is set during the // ExplorerManager selection-change, so we must handle changes after the // selection-change event is processed. @@ -630,7 +617,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // make sure dataResult is open, redundant? //dataResult.open(); - Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode(); if (treeNode != null) { DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class); @@ -687,10 +673,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Node selectedNode = selectedNodes[0]; String selectedNodeName = selectedNode.getName(); - /* get the previous entry to make sure we don't duplicate it. - * Motivation for this is also that if we used the back button, - * then we already added the 'current' node to 'back' and we will - * detect that and not reset the forward list. + /* + * get the previous entry to make sure we don't duplicate it. Motivation + * for this is also that if we used the back button, then we already + * added the 'current' node to 'back' and we will detect that and not + * reset the forward list. */ String[] currentLast = backList.peekLast(); String lastNodeName = null; @@ -783,7 +770,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat //final TreeView tree = getTree(); //tree.expandNode(imagesNode); - setSelectedNode(selectedPath, DataSourcesNode.NAME); } @@ -838,7 +824,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // //@@@ setSelectedNode(selectedPath, ResultsNode.NAME); // // } - /** * Set the selected node using a path to a previously selected node. * @@ -975,11 +960,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } treeNode = extractedChilds.findChild(type.getLabel()); } - + if (treeNode == null) { return; } - + try { em.setExploredContextAndSelection(treeNode, new Node[]{treeNode}); } catch (PropertyVetoException ex) { @@ -1025,7 +1010,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat logger.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"), NbBundle.getMessage(this.getClass(), - "DirectoryTreeTopComponent.moduleErr.msg"), + "DirectoryTreeTopComponent.moduleErr.msg"), MessageNotifyUtil.MessageType.ERROR); } } diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java index 04821df349..d73d6835b0 100644 --- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java @@ -125,18 +125,28 @@ public final class AutopsyEventPublisher { } /** - * Publishes an event. + * Publishes an event to this Autopsy node and other Autopsy nodes. * * @param event The event to publish. - * @throws JMSException */ - synchronized public void publish(AutopsyEvent event) throws JMSException { - event.setSourceType(AutopsyEvent.SourceType.LOCAL); - localPublisher.publish(event); + synchronized public void publish(AutopsyEvent event) { + publishLocally(event); if (null != remotePublisher) { - event.setSourceType(AutopsyEvent.SourceType.REMOTE); - remotePublisher.send(event); + try { + remotePublisher.publish(event); + } catch (JMSException ex) { + logger.log(Level.SEVERE, String.format("Failed to publish %s event remotely", event.getPropertyName()), ex); //NON-NLS + } } } + + /** + * Publishes an event to this Autopsy node only. + * + * @param event The event to publish. + */ + synchronized public void publishLocally(AutopsyEvent event) { + localPublisher.publish(event); + } } diff --git a/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java index a4de5ba5ed..030d72c2f7 100644 --- a/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java +++ b/Core/src/org/sleuthkit/autopsy/events/RemoteEventPublisher.java @@ -74,7 +74,7 @@ final class RemoteEventPublisher { session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = session.createTopic(eventChannelName); producer = session.createProducer(topic); - MessageConsumer consumer = session.createConsumer(topic, "events = '" + ALL_MESSAGE_SELECTOR + "'", true); + MessageConsumer consumer = session.createConsumer(topic, "events = '" + ALL_MESSAGE_SELECTOR + "'", true); // RJCTODO: Can I use the empty string? receiver = new MessageReceiver(); consumer.setMessageListener(receiver); } catch (URISyntaxException | JMSException ex) { @@ -102,9 +102,9 @@ final class RemoteEventPublisher { /** * Sends an event message to the message service. * - * @param event The event to send. + * @param event The event to publish. */ - synchronized void send(AutopsyEvent event) throws JMSException { + synchronized void publish(AutopsyEvent event) throws JMSException { ObjectMessage message = session.createObjectMessage(); message.setStringProperty("events", ALL_MESSAGE_SELECTOR); message.setObject(event); @@ -131,6 +131,7 @@ final class RemoteEventPublisher { Object object = objectMessage.getObject(); if (object instanceof AutopsyEvent) { AutopsyEvent event = (AutopsyEvent) object; + event.setSourceType(AutopsyEvent.SourceType.REMOTE); localPublisher.publish(event); } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 6c9a14eec1..5fb2b14615 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -160,7 +160,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { private static List createTimeZoneList() { - List timeZones = new ArrayList(); + List timeZones = new ArrayList<>(); if (Case.existsCurrentCase()) { // get the latest case @@ -241,7 +241,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { Object oldValue = evt.getOldValue(); Object newValue = evt.getNewValue(); - if (changed.equals(Case.Events.CURRENT_CASE.toString().toString())) { + if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // create or open a case if (newValue != null) { DateSearchFilter.this.updateTimeZoneList(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 8a64c28a1e..225383628b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -38,7 +38,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.jms.JMSException; import javax.swing.JOptionPane; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -283,15 +282,13 @@ public class IngestManager { * Subscribes this ingest manager to local and remote case-related events. */ private void subscribeToCaseEvents() { - Case.addPropertyChangeListener(new PropertyChangeListener() { + Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { - if (event.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { - if (event.getNewValue() != null) { - handleCaseOpened(); - } else { - handleCaseClosed(); - } + if (event.getNewValue() != null) { + handleCaseOpened(); + } else { + handleCaseClosed(); } } }); @@ -309,16 +306,16 @@ public class IngestManager { } catch (AutopsyEventException ex) { logger.log(Level.SEVERE, "Failed to open remote job events channel", ex); //NON-NLS MessageNotifyUtil.Message.error(NbBundle.getMessage(IngestManager.class, - "IngestManager.OpenEventChannel.ErrMsg", - caseName)); + "IngestManager.OpenEventChannel.ErrMsg", + caseName)); } try { moduleEventPublisher.openRemoteEventChannel(String.format(MODULE_EVENT_CHANNEL_NAME, caseName)); } catch (AutopsyEventException ex) { logger.log(Level.SEVERE, "Failed to open remote module events channel", ex); //NON-NLS MessageNotifyUtil.Message.error(NbBundle.getMessage(IngestManager.class, - "IngestManager.OpenEventChannel.ErrMsg", - caseName)); + "IngestManager.OpenEventChannel.ErrMsg", + caseName)); } } } catch (IllegalStateException ex) { @@ -889,11 +886,7 @@ public class IngestManager { */ @Override public void run() { - try { - publisher.publish(event); - } catch (JMSException ex) { - logger.log(Level.SEVERE, String.format("Failed to publish %s event to remote subscribers", event.getPropertyName()), ex); - } + publisher.publish(event); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java index 486a30e84c..ca629bf261 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java @@ -52,6 +52,7 @@ public final class FileAnalyzedEvent extends AutopsyEvent implements Serializabl * event is published over a network. */ super(IngestManager.IngestModuleEvent.FILE_DONE.toString(), file.getId(), null); + this.file = file; } /**