Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
TimeLineController.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2014-2020 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.timeline;
20
21import com.google.common.eventbus.EventBus;
22import com.google.common.util.concurrent.Futures;
23import com.google.common.util.concurrent.ListenableFuture;
24import com.google.common.util.concurrent.ListeningExecutorService;
25import com.google.common.util.concurrent.MoreExecutors;
26import com.google.common.util.concurrent.ThreadFactoryBuilder;
27import java.beans.PropertyChangeEvent;
28import java.time.ZoneId;
29import java.util.Collection;
30import java.util.Collections;
31import static java.util.Collections.singleton;
32import java.util.Optional;
33import java.util.TimeZone;
34import java.util.concurrent.ExecutionException;
35import java.util.concurrent.Executors;
36import java.util.logging.Level;
37import javafx.application.Platform;
38import javafx.beans.Observable;
39import javafx.beans.property.ReadOnlyBooleanProperty;
40import javafx.beans.property.ReadOnlyDoubleProperty;
41import javafx.beans.property.ReadOnlyDoubleWrapper;
42import javafx.beans.property.ReadOnlyListProperty;
43import javafx.beans.property.ReadOnlyListWrapper;
44import javafx.beans.property.ReadOnlyObjectProperty;
45import javafx.beans.property.ReadOnlyObjectWrapper;
46import javafx.beans.property.ReadOnlyStringProperty;
47import javafx.beans.property.ReadOnlyStringWrapper;
48import javafx.collections.FXCollections;
49import javafx.collections.ObservableList;
50import javafx.collections.ObservableSet;
51import javafx.concurrent.Task;
52import static javafx.concurrent.Worker.State.FAILED;
53import static javafx.concurrent.Worker.State.SUCCEEDED;
54import javafx.scene.control.Alert;
55import javax.annotation.concurrent.GuardedBy;
56import javax.swing.SwingUtilities;
57import org.joda.time.DateTime;
58import org.joda.time.DateTimeZone;
59import org.joda.time.Interval;
60import org.joda.time.ReadablePeriod;
61import org.joda.time.format.DateTimeFormat;
62import org.joda.time.format.DateTimeFormatter;
63import org.openide.util.NbBundle;
64import org.sleuthkit.autopsy.casemodule.Case;
65import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED;
66import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
67import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
68import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
69import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
70import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
71import org.sleuthkit.autopsy.coreutils.History;
72import org.sleuthkit.autopsy.coreutils.LoggedTask;
73import org.sleuthkit.autopsy.coreutils.Logger;
74import org.sleuthkit.autopsy.coreutils.ThreadConfined;
75import org.sleuthkit.autopsy.coreutils.ThreadUtils;
76import org.sleuthkit.autopsy.events.AutopsyEvent;
77import org.sleuthkit.autopsy.ingest.IngestManager;
78import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
79import org.sleuthkit.autopsy.timeline.events.TimelineEventAddedEvent;
80import org.sleuthkit.autopsy.timeline.events.ViewInTimelineRequestedEvent;
81import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent;
82import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.SqlFilterState;
83import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilterState;
84import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState;
85import org.sleuthkit.autopsy.timeline.utils.IntervalUtils;
86import org.sleuthkit.autopsy.timeline.zooming.TimeUnits;
87import org.sleuthkit.autopsy.timeline.zooming.EventsModelParams;
88import org.sleuthkit.datamodel.AbstractFile;
89import org.sleuthkit.datamodel.BlackboardArtifact;
90import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT;
91import org.sleuthkit.datamodel.TskCoreException;
92import org.sleuthkit.datamodel.TimelineEventType;
93import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
94import org.sleuthkit.datamodel.TimelineLevelOfDetail;
95
111@NbBundle.Messages({"Timeline.dialogs.title= Timeline",
112 "TimeLinecontroller.updateNowQuestion=Do you want to update the events database now?"})
113public class TimeLineController {
114
115 private static final Logger logger = Logger.getLogger(TimeLineController.class.getName());
116
117 private static final ReadOnlyObjectWrapper<TimeZone> timeZone = new ReadOnlyObjectWrapper<>(TimeZone.getDefault());
118
119 private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
120 new ThreadFactoryBuilder().setNameFormat("Timeline Controller BG thread").build()));
121 private final ReadOnlyListWrapper<Task<?>> tasks = new ReadOnlyListWrapper<>(FXCollections.observableArrayList());
122 private final ReadOnlyDoubleWrapper taskProgress = new ReadOnlyDoubleWrapper(-1);
123 private final ReadOnlyStringWrapper taskMessage = new ReadOnlyStringWrapper();
124 private final ReadOnlyStringWrapper taskTitle = new ReadOnlyStringWrapper();
125 private final ReadOnlyStringWrapper statusMessage = new ReadOnlyStringWrapper();
126
127 private final EventBus eventbus = new EventBus("TimeLineController_EventBus");
128
129 public static ZoneId getTimeZoneID() {
130 return timeZone.get().toZoneId();
131 }
132
133 public static DateTimeFormatter getZonedFormatter() {
134 return DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss").withZone(getJodaTimeZone()); //NON-NLS
135 }
136
137 public static DateTimeZone getJodaTimeZone() {
138 return DateTimeZone.forTimeZone(timeZoneProperty().get());
139 }
140
141 public static ReadOnlyObjectProperty<TimeZone> timeZoneProperty() {
142 return timeZone.getReadOnlyProperty();
143 }
144
145 public static TimeZone getTimeZone() {
146 return timeZone.get();
147 }
148
155 public ReadOnlyStringProperty statusMessageProperty() {
156 return statusMessage.getReadOnlyProperty();
157 }
158
159 public void setStatusMessage(String string) {
160 statusMessage.set(string);
161 }
162 private final Case autoCase;
163
165 private final ObservableList<DescriptionFilterState> quickHideFilters = FXCollections.observableArrayList();
166
168 return quickHideFilters;
169 }
170
175 return autoCase;
176 }
177
178 synchronized public ReadOnlyListProperty<Task<?>> getTasks() {
179 return tasks.getReadOnlyProperty();
180 }
181
182 synchronized public ReadOnlyDoubleProperty taskProgressProperty() {
183 return taskProgress.getReadOnlyProperty();
184 }
185
186 synchronized public ReadOnlyStringProperty taskMessageProperty() {
187 return taskMessage.getReadOnlyProperty();
188 }
189
190 synchronized public ReadOnlyStringProperty taskTitleProperty() {
191 return taskTitle.getReadOnlyProperty();
192 }
193
196
197 @GuardedBy("this")
198 private final ReadOnlyObjectWrapper<ViewMode> viewMode = new ReadOnlyObjectWrapper<>(ViewMode.COUNTS);
199
200 @GuardedBy("filteredEvents")
202
203 @GuardedBy("this")
205
206 @GuardedBy("this")
208
209 @GuardedBy("this")
210 private final ReadOnlyObjectWrapper<EventsModelParams> currentParams = new ReadOnlyObjectWrapper<>();
211
212 //selected events (ie shown in the result viewer)
213 @GuardedBy("this")
214 private final ObservableList<Long> selectedEventIDs = FXCollections.<Long>observableArrayList();
215
216 @GuardedBy("this")
217 private final ReadOnlyObjectWrapper<Interval> selectedTimeRange = new ReadOnlyObjectWrapper<>();
218
220
226 synchronized public ObservableList<Long> getSelectedEventIDs() {
227 return selectedEventIDs;
228 }
229
235 synchronized public ReadOnlyObjectProperty<Interval> selectedTimeRangeProperty() {
236 return selectedTimeRange.getReadOnlyProperty();
237 }
238
244 synchronized public Interval getSelectedTimeRange() {
245 return selectedTimeRange.get();
246 }
247
248 synchronized public ReadOnlyBooleanProperty canAdvanceProperty() {
249 return historyManager.getCanAdvance();
250 }
251
252 synchronized public ReadOnlyBooleanProperty canRetreatProperty() {
253 return historyManager.getCanRetreat();
254 }
255
256 synchronized public ReadOnlyObjectProperty<ViewMode> viewModeProperty() {
257 return viewMode.getReadOnlyProperty();
258 }
259
265 synchronized public void setViewMode(ViewMode viewMode) {
266 if (this.viewMode.get() != viewMode) {
267 this.viewMode.set(viewMode);
268 }
269 }
270
276 synchronized public ViewMode getViewMode() {
277 return viewMode.get();
278 }
279
280 TimeLineController(Case autoCase) throws TskCoreException {
281 this.autoCase = autoCase;
282 filteredEvents = new EventsModel(autoCase, currentParams.getReadOnlyProperty());
283 /*
284 * as the history manager's current state changes, modify the tags
285 * filter to be in sync, and expose that as propery from
286 * TimeLineController. Do we need to do this with datasource or hash hit
287 * filters?
288 */
289 historyManager.currentState().addListener((observable, oldState, newState) -> {
290 EventsModelParams historyManagerState = newState;
291 filteredEvents.addDataSourceFilters(historyManagerState.getEventFilterState());
292 currentParams.set(historyManagerState);
293
294 });
295
296 try {
297 InitialZoomState = new EventsModelParams(filteredEvents.getSpanningInterval(),
298 TimelineEventType.HierarchyLevel.CATEGORY,
299 filteredEvents.eventFilterProperty().get(),
300 TimelineLevelOfDetail.LOW);
301 } catch (TskCoreException ex) {
302 throw new TskCoreException("Error getting spanning interval.", ex);
303 }
304 historyManager.advance(InitialZoomState);
305
306 //clear the selected events when the view mode changes
307 viewMode.addListener(observable -> {
308 try {
309 selectEventIDs(Collections.emptySet());
310 } catch (TskCoreException ex) {
311 logger.log(Level.SEVERE, "Error clearing the timeline selection.", ex);
312 }
313 });
314 }
315
320 return filteredEvents;
321 }
322
323 public void applyDefaultFilters() {
324 pushFilters(filteredEvents.getDefaultEventFilterState());
325 }
326
327 public void zoomOutToActivity() throws TskCoreException {
328 Interval boundingEventsInterval = filteredEvents.getSpanningInterval(getJodaTimeZone());
329 advance(filteredEvents.modelParamsProperty().get().withTimeRange(boundingEventsInterval));
330 }
331
332 private final ObservableSet<DetailViewEvent> pinnedEvents = FXCollections.observableSet();
333 private final ObservableSet<DetailViewEvent> pinnedEventsUnmodifiable = FXCollections.unmodifiableObservableSet(pinnedEvents);
334
335 public void pinEvent(DetailViewEvent event) {
336 pinnedEvents.add(event);
337 }
338
339 public void unPinEvent(DetailViewEvent event) {
340 pinnedEvents.removeIf(event::equals);
341 }
342
343 public ObservableSet<DetailViewEvent> getPinnedEvents() {
345 }
346
350 boolean showFullRange() throws TskCoreException {
351 synchronized (filteredEvents) {
352 return pushTimeRange(filteredEvents.getSpanningInterval());
353 }
354 }
355
363 @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
364 private void showInListView(ViewInTimelineRequestedEvent requestEvent) throws TskCoreException {
365 synchronized (filteredEvents) {
367 selectEventIDs(requestEvent.getEventIDs());
368 try {
369 if (pushTimeRange(requestEvent.getInterval()) == false) {
370 eventbus.post(requestEvent);
371 }
372 } catch (TskCoreException ex) {
373 throw new TskCoreException("Error pushing requested timerange.", ex);
374 }
375 }
376 }
377
381 void shutDownTimeLineListeners() {
383 }
384
388 @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
389 public void shutDownTimeLineGui() {
390 if (topComponent != null) {
391 topComponent.close();
392 topComponent = null;
393 }
394 }
395
405 void showTimeLine(AbstractFile file, BlackboardArtifact artifact) {
406 Platform.runLater(() -> {
407 //if there is an existing prompt or progressdialog,...
408 if (promptDialogManager.bringCurrentDialogToFront()) {
409 //... just show that
410 } else {
411
412 if ( //confirm timeline during ingest
413 IngestManager.getInstance().isIngestRunning()
414 && promptDialogManager.confirmDuringIngest() == false) {
415 return; //if they cancel, do nothing.
416 }
417 try {
418 if (file == null && artifact == null) {
419 SwingUtilities.invokeLater(TimeLineController.this::showWindow);
420 } else {
421 //prompt user to pick specific event and time range
422 ShowInTimelineDialog showInTimelineDilaog = (file == null)
423 ? new ShowInTimelineDialog(this, artifact)
424 : new ShowInTimelineDialog(this, file);
425 Optional<ViewInTimelineRequestedEvent> dialogResult = showInTimelineDilaog.showAndWait();
426 dialogResult.ifPresent(viewInTimelineRequestedEvent -> {
427 SwingUtilities.invokeLater(this::showWindow);
428 try {
429 showInListView(viewInTimelineRequestedEvent); //show requested event in list view
430 } catch (TskCoreException ex) {
431 logger.log(Level.SEVERE, "Error showing requested events in listview: " + viewInTimelineRequestedEvent, ex);
432 new Alert(Alert.AlertType.ERROR, "There was an error opening Timeline.").showAndWait();
433 }
434 });
435
436 }
437 } catch (TskCoreException tskCoreException) {
438 logger.log(Level.SEVERE, "Error showing Timeline ", tskCoreException);
439 new Alert(Alert.AlertType.ERROR, "There was an error opening Timeline.").showAndWait();
440 }
441 }
442 });
443 }
444
452 synchronized public void pushPeriod(ReadablePeriod period) throws TskCoreException {
453 synchronized (filteredEvents) {
455 }
456 }
457
458 synchronized public void pushZoomOutTime() throws TskCoreException {
459 final Interval timeRange = filteredEvents.getTimeRange();
460 long toDurationMillis = timeRange.toDurationMillis() / 4;
461 DateTime start = timeRange.getStart().minus(toDurationMillis);
462 DateTime end = timeRange.getEnd().plus(toDurationMillis);
463 pushTimeRange(new Interval(start, end));
464 }
465
466 synchronized public void pushZoomInTime() throws TskCoreException {
467 final Interval timeRange = filteredEvents.getTimeRange();
468 long toDurationMillis = timeRange.toDurationMillis() / 4;
469 DateTime start = timeRange.getStart().plus(toDurationMillis);
470 DateTime end = timeRange.getEnd().minus(toDurationMillis);
471 pushTimeRange(new Interval(start, end));
472 }
473
479 synchronized private void showWindow() {
480 if (topComponent == null) {
482 }
483 if (topComponent.isOpened() == false) {
484 topComponent.open();
485 }
486 topComponent.toFront();
487 /*
488 * Make this top component active so its ExplorerManager's lookup gets
489 * proxied in Utilities.actionsGlobalContext()
490 */
491 topComponent.requestActive();
492 }
493
494 synchronized public TimeLineTopComponent getTopComponent() {
495 return topComponent;
496 }
497
498 synchronized public void pushEventTypeZoom(TimelineEventType.HierarchyLevel typeZoomeLevel) {
499 EventsModelParams currentZoom = filteredEvents.modelParamsProperty().get();
500 if (currentZoom == null) {
501 advance(InitialZoomState.withTypeZoomLevel(typeZoomeLevel));
502 } else if (currentZoom.hasTypeZoomLevel(typeZoomeLevel) == false) {
503 advance(currentZoom.withTypeZoomLevel(typeZoomeLevel));
504 }
505 }
506
516 synchronized public boolean pushTimeRange(Interval timeRange) throws TskCoreException {
517 //clamp timerange to case
518 Interval clampedTimeRange;
519 if (timeRange == null) {
520 clampedTimeRange = this.filteredEvents.getSpanningInterval();
521 } else {
522 Interval spanningInterval = this.filteredEvents.getSpanningInterval();
523 if (spanningInterval.overlaps(timeRange)) {
524 clampedTimeRange = spanningInterval.overlap(timeRange);
525 } else {
526 clampedTimeRange = spanningInterval;
527 }
528 }
529
530 EventsModelParams currentZoom = filteredEvents.modelParamsProperty().get();
531 if (currentZoom == null) {
532 advance(InitialZoomState.withTimeRange(clampedTimeRange));
533 return true;
534 } else if (currentZoom.hasTimeRange(clampedTimeRange) == false) {
535 advance(currentZoom.withTimeRange(clampedTimeRange));
536 return true;
537 } else {
538 return false;
539 }
540 }
541
552 synchronized public boolean pushTimeUnit(TimeUnits timeUnit) throws TskCoreException {
553 if (timeUnit == TimeUnits.FOREVER) {
554 return showFullRange();
555 } else {
556 return pushTimeRange(IntervalUtils.getIntervalAroundMiddle(filteredEvents.getTimeRange(), timeUnit.toUnitPeriod()));
557 }
558 }
559
560 synchronized public void pushDescrLOD(TimelineLevelOfDetail newLOD) {
561 EventsModelParams currentZoom = filteredEvents.modelParamsProperty().get();
562 if (currentZoom == null) {
563 advance(InitialZoomState.withDescrLOD(newLOD));
564 } else if (currentZoom.hasDescrLOD(newLOD) == false) {
565 advance(currentZoom.withDescrLOD(newLOD));
566 }
567 }
568
569 @SuppressWarnings("AssignmentToMethodParameter") //clamp timerange to case
570 synchronized public void pushTimeAndType(Interval timeRange, TimelineEventType.HierarchyLevel typeZoom) throws TskCoreException {
571 Interval overlappingTimeRange = this.filteredEvents.getSpanningInterval().overlap(timeRange);
572 EventsModelParams currentZoom = filteredEvents.modelParamsProperty().get();
573 if (currentZoom == null) {
574 advance(InitialZoomState.withTimeAndType(overlappingTimeRange, typeZoom));
575 } else if (currentZoom.hasTimeRange(overlappingTimeRange) == false && currentZoom.hasTypeZoomLevel(typeZoom) == false) {
576 advance(currentZoom.withTimeAndType(overlappingTimeRange, typeZoom));
577 } else if (currentZoom.hasTimeRange(overlappingTimeRange) == false) {
578 advance(currentZoom.withTimeRange(overlappingTimeRange));
579 } else if (currentZoom.hasTypeZoomLevel(typeZoom) == false) {
580 advance(currentZoom.withTypeZoomLevel(typeZoom));
581 }
582 }
583
584 synchronized public void pushFilters(RootFilterState filter) {
585 EventsModelParams currentZoom = filteredEvents.modelParamsProperty().get();
586 if (currentZoom == null) {
587 advance(InitialZoomState.withFilterState(filter));
588 } else if (currentZoom.hasFilterState(filter) == false) {
589 advance(currentZoom.withFilterState(filter));
590 }
591 }
592
593 synchronized public void advance() {
594 historyManager.advance();
595 }
596
597 synchronized public void retreat() {
598 historyManager.retreat();
599 }
600
601 synchronized private void advance(EventsModelParams newState) {
602 historyManager.advance(newState);
603 }
604
611 final synchronized public void selectEventIDs(Collection<Long> eventIDs) throws TskCoreException {
612 selectedTimeRange.set(filteredEvents.getSpanningInterval(eventIDs));
613 selectedEventIDs.setAll(eventIDs);
614 }
615
616 public void selectTimeAndType(Interval interval, TimelineEventType type) throws TskCoreException {
617 final Interval timeRange = filteredEvents.getSpanningInterval().overlap(interval);
618
619 final LoggedTask<Collection<Long>> selectTimeAndTypeTask = new LoggedTask<Collection<Long>>("Select Time and Type", true) { //NON-NLS
620 @Override
621 protected Collection< Long> call() throws Exception {
622 synchronized (TimeLineController.this) {
623 return filteredEvents.getEventIDs(timeRange, new SqlFilterState<>(new EventTypeFilter(type), true));
624 }
625 }
626
627 @Override
628 protected void succeeded() {
629 super.succeeded();
630 try {
631 synchronized (TimeLineController.this) {
632 selectedTimeRange.set(timeRange);
633 selectedEventIDs.setAll(get());
634
635 }
636 } catch (InterruptedException | ExecutionException ex) {
637 logger.log(Level.SEVERE, getTitle() + " Unexpected error", ex); //NON-NLS
638 }
639 }
640 };
641
642 monitorTask(selectTimeAndTypeTask);
643 }
644
651 synchronized public void monitorTask(final Task<?> task) {
652 //TODO: refactor this to use JavaFX Service? -jm
653 if (task != null) {
654 Platform.runLater(() -> {
655
656 //is this actually threadsafe, could we get a finished task stuck in the list?
657 task.stateProperty().addListener((Observable observable) -> {
658 switch (task.getState()) {
659 case READY:
660 case RUNNING:
661 case SCHEDULED:
662 break;
663 case SUCCEEDED:
664 case CANCELLED:
665 case FAILED:
666 tasks.remove(task);
667 if (tasks.isEmpty() == false) {
668 taskProgress.bind(tasks.get(0).progressProperty());
669 taskMessage.bind(tasks.get(0).messageProperty());
670 taskTitle.bind(tasks.get(0).titleProperty());
671 }
672 break;
673 }
674 });
675 tasks.add(task);
676 taskProgress.bind(task.progressProperty());
677 taskMessage.bind(task.messageProperty());
678 taskTitle.bind(task.titleProperty());
679 switch (task.getState()) {
680 case READY:
681 //TODO: Check future result for errors....
682 executor.submit(task);
683 break;
684 case SCHEDULED:
685 case RUNNING:
686
687 case SUCCEEDED:
688 case CANCELLED:
689 case FAILED:
690 tasks.remove(task);
691 if (tasks.isEmpty() == false) {
692 taskProgress.bind(tasks.get(0).progressProperty());
693 taskMessage.bind(tasks.get(0).messageProperty());
694 taskTitle.bind(tasks.get(0).titleProperty());
695 }
696 break;
697 }
698 });
699 }
700 }
701
708 synchronized public void registerForEvents(Object listener) {
709 eventbus.register(listener);
710 }
711
717 synchronized public void unRegisterForEvents(Object listener) {
718 eventbus.unregister(listener);
719 }
720
721 static synchronized public void setTimeZone(TimeZone timeZone) {
722 TimeLineController.timeZone.set(timeZone);
723
724 }
725
726 void handleIngestModuleEvent(PropertyChangeEvent evt) {
732 try {
734 } catch (NoCurrentCaseException notUsed) {
735 // Case is closed, do nothing.
736 return;
737 }
738 // ignore remote events. The node running the ingest should update the Case DB
739 // @@@ We should signal though that there is more data and flush caches...
740 if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) {
741 return;
742 }
743
744 switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
745 case CONTENT_CHANGED:
746 // new files were already added to the events table from SleuthkitCase.
747 break;
748 case DATA_ADDED:
749 ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
750 if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) {
751 logFutureException(executor.submit(() -> filteredEvents.updateEventsForHashSetHits(eventData.getArtifacts())),
752 "Error executing task in response to DATA_ADDED event.",
753 "Error executing response to new data.");
754 }
755 break;
756 case FILE_DONE:
757 /*
758 * Since the known state or hash hit state may have changed
759 * invalidate caches.
760 */
761 //@@@ This causes HUGE slow downs during ingest when TL is open.
762 // executor.submit(filteredEvents::invalidateAllCaches);
763
764 // known state should have been udpated automatically via SleuthkitCase.setKnown();
765 // hashes should have been updated from event
766 }
767 }
768
769 void handleCaseEvent(PropertyChangeEvent evt) {
770 ListenableFuture<?> future = Futures.immediateFuture(null);
771 switch (Case.Events.valueOf(evt.getPropertyName())) {
772 case BLACKBOARD_ARTIFACT_TAG_ADDED:
773 future = executor.submit(() -> filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt));
774 break;
775 case BLACKBOARD_ARTIFACT_TAG_DELETED:
776 future = executor.submit(() -> filteredEvents.handleArtifactTagDeleted((BlackBoardArtifactTagDeletedEvent) evt));
777 break;
778 case CONTENT_TAG_ADDED:
779 future = executor.submit(() -> filteredEvents.handleContentTagAdded((ContentTagAddedEvent) evt));
780 break;
781 case CONTENT_TAG_DELETED:
782 future = executor.submit(() -> filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt));
783 break;
784 case DATA_SOURCE_ADDED:
785 future = executor.submit(() -> {
786 filteredEvents.handleDataSourceAdded();
787 return null;
788 });
789 break;
790 case TIMELINE_EVENT_ADDED:
791 future = executor.submit(() -> {
792 filteredEvents.invalidateCaches(singleton(((TimelineEventAddedEvent) evt).getAddedEventID()));
793 return null;
794 });
795 break;
796 }
797 logFutureException(future,
798 "Error executing task in response to " + evt.getPropertyName() + " event.",
799 "Error executing task in response to case event.");
800 }
801
802 private void logFutureException(ListenableFuture<?> future, String errorLogMessage, String errorUserMessage) {
803 future.addListener(() -> {
804 try {
805 future.get();
806 } catch (InterruptedException | ExecutionException ex) {
807 logger.log(Level.SEVERE, errorLogMessage, ex);
808 }
809 }, MoreExecutors.directExecutor());
810 }
811}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static void shutDownTaskExecutor(ExecutorService executor)
final ReadOnlyObjectWrapper< Interval > selectedTimeRange
synchronized ReadOnlyBooleanProperty canAdvanceProperty()
synchronized void pushPeriod(ReadablePeriod period)
synchronized void unRegisterForEvents(Object listener)
synchronized TimeLineTopComponent getTopComponent()
synchronized void pushEventTypeZoom(TimelineEventType.HierarchyLevel typeZoomeLevel)
final synchronized void selectEventIDs(Collection< Long > eventIDs)
synchronized ReadOnlyStringProperty taskMessageProperty()
ObservableList< DescriptionFilterState > getQuickHideFilters()
static final ReadOnlyObjectWrapper< TimeZone > timeZone
synchronized ReadOnlyStringProperty taskTitleProperty()
void showInListView(ViewInTimelineRequestedEvent requestEvent)
synchronized boolean pushTimeUnit(TimeUnits timeUnit)
void selectTimeAndType(Interval interval, TimelineEventType type)
final ObservableList< DescriptionFilterState > quickHideFilters
final ReadOnlyObjectWrapper< ViewMode > viewMode
final ObservableSet< DetailViewEvent > pinnedEvents
synchronized ReadOnlyObjectProperty< ViewMode > viewModeProperty()
void logFutureException(ListenableFuture<?> future, String errorLogMessage, String errorUserMessage)
synchronized void pushFilters(RootFilterState filter)
synchronized boolean pushTimeRange(Interval timeRange)
synchronized void advance(EventsModelParams newState)
synchronized void registerForEvents(Object listener)
synchronized void monitorTask(final Task<?> task)
synchronized ReadOnlyObjectProperty< Interval > selectedTimeRangeProperty()
synchronized ObservableList< Long > getSelectedEventIDs()
static ReadOnlyObjectProperty< TimeZone > timeZoneProperty()
synchronized void setViewMode(ViewMode viewMode)
final ReadOnlyObjectWrapper< EventsModelParams > currentParams
synchronized void pushTimeAndType(Interval timeRange, TimelineEventType.HierarchyLevel typeZoom)
synchronized ReadOnlyListProperty< Task<?> > getTasks()
synchronized ReadOnlyDoubleProperty taskProgressProperty()
static synchronized void setTimeZone(TimeZone timeZone)
synchronized void pushDescrLOD(TimelineLevelOfDetail newLOD)
final ObservableSet< DetailViewEvent > pinnedEventsUnmodifiable
synchronized ReadOnlyBooleanProperty canRetreatProperty()
static Interval getIntervalAroundMiddle(Interval interval, ReadablePeriod period)
EventsModelParams withTypeZoomLevel(TimelineEventType.HierarchyLevel zoomLevel)
EventsModelParams withDescrLOD(TimelineLevelOfDetail descrLOD)
boolean hasTypeZoomLevel(TimelineEventType.HierarchyLevel typeZoom)
EventsModelParams withFilterState(RootFilterState filter)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.