active listeners for tag and other events

This commit is contained in:
Brian Carrier
2018-09-19 20:17:53 -04:00
parent df3f0f4890
commit 6400a72f3a
7 changed files with 198 additions and 56 deletions
@@ -644,8 +644,11 @@ public final class FilteredEventsModel {
return updatedEventIDs;
}
synchronized Set<Long> setFileStatus(AbstractFile file) throws TskCoreException {
Set<Long> updatedEventIDs = eventManager.setFileStatus(file);
synchronized public Set<Long> setHashHit(Collection<BlackboardArtifact> artifacts, boolean hasHashHit) throws TskCoreException {
Set<Long> updatedEventIDs = new HashSet<>();
for (BlackboardArtifact artifact : artifacts) {
updatedEventIDs.addAll(eventManager.setEventsHashed(artifact.getObjectID(), hasHashHit));
}
if (!updatedEventIDs.isEmpty()) {
invalidateCaches(updatedEventIDs);
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.timeline;
/**
* The org.openide.modules.OnStart annotation tells NetBeans to invoke this
* class's run method.
*/
@org.openide.modules.OnStart
public class OnStart implements Runnable {
/**
* This method is invoked by virtue of the OnStart annotation on the this
* class
*/
@Override
public void run() {
TimeLineModule.onStart();
}
}
@@ -60,19 +60,10 @@ public final class OpenTimelineAction extends CallableSystemAction {
private static final Logger logger = Logger.getLogger(OpenTimelineAction.class.getName());
private static final int FILE_LIMIT = 6_000_000;
private static TimeLineController timeLineController;
private final JMenuItem menuItem;
private final JButton toolbarButton = new JButton(getName(),
new ImageIcon(getClass().getResource("images/btn_icon_timeline_colorized_26.png"))); //NON-NLS
/**
* Invalidate the reference to the controller so that a new one will be
* instantiated the next time this action is invoked
*/
synchronized static void invalidateController() {
timeLineController = null;
}
public OpenTimelineAction() {
toolbarButton.addActionListener(actionEvent -> performAction());
@@ -95,11 +86,6 @@ public final class OpenTimelineAction extends CallableSystemAction {
public void performAction() {
if (tooManyFiles()) {
Platform.runLater(PromptDialogManager::showTooManyFiles);
synchronized (OpenTimelineAction.this) {
if (timeLineController != null) {
timeLineController.shutDownTimeLine();
}
}
setEnabled(false);
} else if ("false".equals(ModuleSettings.getConfigSetting("timeline", "enable_timeline"))) {
Platform.runLater(PromptDialogManager::showTimeLineDisabledMessage);
@@ -125,13 +111,8 @@ public final class OpenTimelineAction extends CallableSystemAction {
logger.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
return;
}
if (timeLineController == null) {
timeLineController = new TimeLineController(currentCase);
} else if (timeLineController.getAutopsyCase() != currentCase) {
timeLineController.shutDownTimeLine();
timeLineController = new TimeLineController(currentCase);
}
timeLineController.showTimeLine(file, artifact);
TimeLineController controller = TimeLineModule.getController();
controller.showTimeLine(file, artifact);
} catch (NoCurrentCaseException e) {
//there is no case... Do nothing.
}
@@ -73,6 +73,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.timeline.events.ViewInTimelineRequestedEvent;
import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState;
@@ -86,6 +87,7 @@ import org.sleuthkit.datamodel.timeline.EventType;
import org.sleuthkit.datamodel.timeline.EventTypeZoomLevel;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState;
import org.sleuthkit.autopsy.timeline.zooming.TimeUnits;
import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.timeline.TimelineFilter.DescriptionFilter;
import org.sleuthkit.datamodel.timeline.TimelineFilter.TypeFilter;
@@ -194,9 +196,6 @@ public class TimeLineController {
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private boolean listeningToAutopsy = false;
private final PropertyChangeListener caseListener = new AutopsyCaseListener();
private final PropertyChangeListener ingestModuleListener = new AutopsyIngestModuleListener();
@GuardedBy("this")
private final ReadOnlyObjectWrapper<ViewMode> viewMode = new ReadOnlyObjectWrapper<>(ViewMode.COUNTS);
@@ -280,7 +279,7 @@ public class TimeLineController {
return viewMode.get();
}
public TimeLineController(Case autoCase) throws TskCoreException {
TimeLineController(Case autoCase) throws TskCoreException {
this.autoCase = autoCase;
filteredEvents = new FilteredEventsModel(autoCase, currentParams.getReadOnlyProperty());
/*
@@ -383,14 +382,10 @@ public class TimeLineController {
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public void shutDownTimeLine() {
listeningToAutopsy = false;
IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener);
Case.removePropertyChangeListener(caseListener);
if (topComponent != null) {
topComponent.close();
topComponent = null;
}
OpenTimelineAction.invalidateController();
}
/**
@@ -403,12 +398,6 @@ public class TimeLineController {
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void showTimeLine(AbstractFile file, BlackboardArtifact artifact) {
// listen for case changes (specifically images being added, and case changes).
if (Case.isCaseOpen() && !listeningToAutopsy) {
IngestManager.getInstance().addIngestModuleEventListener(ingestModuleListener);
Case.addPropertyChangeListener(caseListener);
listeningToAutopsy = true;
}
Platform.runLater(() -> {
//if there is an existing prompt or progressdialog,...
if (promptDialogManager.bringCurrentDialogToFront()) {
@@ -726,14 +715,8 @@ public class TimeLineController {
}
/**
* Listener for IngestManager.IngestModuleEvents.
*/
@Immutable
private class AutopsyIngestModuleListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
void handleIngestModuleEvent(PropertyChangeEvent evt) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked out.
@@ -746,30 +729,39 @@ public class TimeLineController {
// Case is closed, do nothing.
return;
}
// ignore remote events. The node running the ingest should update the Case DB
// @@@ We should signal though that there is more data and flush caches...
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) {
return;
}
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
case CONTENT_CHANGED:
// new files were already added to the events table from SleuthkitCase.
break;
case DATA_ADDED:
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
executor.submit(() -> filteredEvents.setHashHit(eventData.getArtifacts(), true));
}
break;
case FILE_DONE:
/*
* Since the known state or hash hit state may have changed
* invalidate caches.
*/
executor.submit(filteredEvents::invalidateAllCaches);
//@@@ This causes HUGE slow downs during ingest when TL is open.
// executor.submit(filteredEvents::invalidateAllCaches);
// known state should have been udpated automatically via SleuthkitCase.setKnown();
// hashes should have been updated from event
}
}
}
/**
* Listener for Case.Events
*/
@Immutable
private class AutopsyCaseListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
switch (Case.Events.valueOf(evt.getPropertyName())) {
void handleCaseEvent(PropertyChangeEvent evt) {
switch (Case.Events.valueOf(evt.getPropertyName())) {
case BLACKBOARD_ARTIFACT_TAG_ADDED:
executor.submit(() -> filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt));
break;
@@ -793,6 +785,6 @@ public class TimeLineController {
executor.submit(filteredEvents::invalidateAllCaches);
break;
}
}
}
}
+127
View File
@@ -0,0 +1,127 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.timeline;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javafx.application.Platform;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Manages listeners and the controller.
*
*/
public class TimeLineModule {
private static final Logger logger = Logger.getLogger(TimeLineModule.class.getName());
private static final Object controllerLock = new Object();
private static TimeLineController controller;
/**
* provides static utilities, can not be instantiated
*/
private TimeLineModule() {
}
/**
* Get instance of the controller for the current case
* @return
* @throws NoCurrentCaseException
*/
public static TimeLineController getController() throws NoCurrentCaseException {
synchronized (controllerLock) {
if (controller == null) {
try {
controller = new TimeLineController(Case.getCurrentCaseThrows());
} catch (NoCurrentCaseException | TskCoreException ex) {
throw new NoCurrentCaseException("Error getting TimeLineController for the current case.", ex);
}
}
return controller;
}
}
/**
* This method is invoked by virtue of the OnStart annotation on the OnStart
* class class
*/
static void onStart() {
Platform.setImplicitExit(false);
logger.info("Setting up TimeLine listeners"); //NON-NLS
IngestManager.getInstance().addIngestModuleEventListener(new IngestModuleEventListener());
Case.addPropertyChangeListener(new CaseEventListener());
}
/**
* Listener for case events.
*/
static private class CaseEventListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
try {
TimeLineController tlController = getController();
tlController.handleCaseEvent(evt);
} catch (NoCurrentCaseException ex) {
// ignore
return;
}
switch (Case.Events.valueOf(evt.getPropertyName())) {
case CURRENT_CASE:
// we care only about case closing here
if (evt.getNewValue() != null) {
break;
}
synchronized (controllerLock) {
if (controller != null) {
controller.shutDownTimeLine();
}
controller = null;
}
break;
}
}
}
/**
* Listener for IngestModuleEvents
*/
static private class IngestModuleEventListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
try {
TimeLineController tlController = getController();
tlController.handleIngestModuleEvent(evt);
} catch (NoCurrentCaseException ex) {
// ignore
return;
}
}
}
}
@@ -22,6 +22,7 @@ import java.util.Set;
/**
* A TagsUpdatedEvent for tags that have been added to events.
* NOTE: This event is internal to timeline components
*/
public class TagsAddedEvent extends TagsUpdatedEvent {
@@ -22,6 +22,7 @@ import java.util.Set;
/**
* A TagsUpdatedEvent for tags that have been removed from events.
* NOTE: This event is internal to timeline components
*/
public class TagsDeletedEvent extends TagsUpdatedEvent {