19package org.sleuthkit.autopsy.timeline;
21import com.google.common.cache.CacheBuilder;
22import com.google.common.cache.LoadingCache;
23import com.google.common.collect.ImmutableList;
24import com.google.common.eventbus.EventBus;
25import java.util.Collection;
26import java.util.Collections;
27import java.util.HashSet;
31import java.util.concurrent.ExecutionException;
32import java.util.concurrent.TimeUnit;
33import java.util.logging.Level;
34import javafx.beans.InvalidationListener;
35import javafx.beans.property.ReadOnlyObjectProperty;
36import javafx.beans.property.ReadOnlyObjectWrapper;
37import javafx.collections.FXCollections;
38import javafx.collections.ObservableMap;
39import static org.apache.commons.collections4.CollectionUtils.emptyIfNull;
40import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
41import org.joda.time.DateTimeZone;
42import org.joda.time.Interval;
43import org.openide.util.NbBundle;
44import org.sleuthkit.autopsy.casemodule.Case;
45import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
46import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
47import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent.DeletedBlackboardArtifactTagInfo;
48import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
49import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
50import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo;
51import org.sleuthkit.autopsy.coreutils.Logger;
52import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
53import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
54import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent;
55import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent;
56import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState;
57import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState;
58import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.SqlFilterState;
59import org.sleuthkit.autopsy.timeline.utils.CacheLoaderImpl;
60import org.sleuthkit.autopsy.timeline.utils.FilterUtils;
61import org.sleuthkit.autopsy.timeline.zooming.EventsModelParams;
62import org.sleuthkit.datamodel.AbstractFile;
63import org.sleuthkit.datamodel.BlackboardArtifact;
64import org.sleuthkit.datamodel.BlackboardArtifactTag;
65import org.sleuthkit.datamodel.Content;
66import org.sleuthkit.datamodel.ContentTag;
67import org.sleuthkit.datamodel.DataSource;
68import org.sleuthkit.datamodel.SleuthkitCase;
69import org.sleuthkit.datamodel.TimelineManager;
70import org.sleuthkit.datamodel.TskCoreException;
71import org.sleuthkit.datamodel.TimelineEvent;
72import org.sleuthkit.datamodel.TimelineEventType;
73import org.sleuthkit.datamodel.TimelineFilter;
74import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter;
75import org.sleuthkit.datamodel.TimelineFilter.DataSourcesFilter;
76import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
77import org.sleuthkit.datamodel.TimelineFilter.FileTypesFilter;
78import org.sleuthkit.datamodel.TimelineFilter.HashHitsFilter;
79import org.sleuthkit.datamodel.TimelineFilter.HideKnownFilter;
80import org.sleuthkit.datamodel.TimelineFilter.RootFilter;
81import org.sleuthkit.datamodel.TimelineFilter.TagsFilter;
82import org.sleuthkit.datamodel.TimelineFilter.TextFilter;
83import org.sleuthkit.datamodel.TimelineLevelOfDetail;
99 private final EventBus
eventbus =
new EventBus(
"EventsModel_EventBus");
111 private final ReadOnlyObjectWrapper<EventsModelParams>
modelParamsProperty =
new ReadOnlyObjectWrapper<>();
113 private final ReadOnlyObjectWrapper<Interval>
timeRangeProperty =
new ReadOnlyObjectWrapper<>();
114 private final ReadOnlyObjectWrapper<TimelineEventType.HierarchyLevel>
eventTypesHierarchyLevelProperty =
new ReadOnlyObjectWrapper<>(TimelineEventType.HierarchyLevel.CATEGORY);
115 private final ReadOnlyObjectWrapper<TimelineLevelOfDetail>
timelineLODProperty =
new ReadOnlyObjectWrapper<>(TimelineLevelOfDetail.LOW);
124 private final LoadingCache<EventsModelParams, Map<TimelineEventType, Long>>
eventCountsCache;
135 return new DataSourceFilter(dataSourceEntry.getValue(), dataSourceEntry.getKey());
149 this.caseDbEventManager =
currentCase.getSleuthkitCase().getTimelineManager();
159 .expireAfterAccess(10, TimeUnit.MINUTES)
163 .expireAfterAccess(10, TimeUnit.MINUTES)
175 InvalidationListener dataSourcesMapListener = observable -> {
177 addDataSourceFilters(rootFilter);
195 if (params !=
null) {
213 SleuthkitCase skCase =
currentCase.getSleuthkitCase();
214 for (DataSource ds : skCase.getDataSources()) {
225 synchronized void addDataSourceFilters(
RootFilterState rootFilterState) {
243 if (modelParams.getTimeRange() ==
null) {
244 return Collections.emptyMap();
246 return caseDbEventManager.countEventsByType(modelParams.getTimeRange().getStartMillis() / 1000,
247 modelParams.getTimeRange().getEndMillis() / 1000,
248 modelParams.getEventFilterState().getActiveFilter(),
249 modelParams.getEventTypesHierarchyLevel());
287 "FilteredEventsModel.timeRangeProperty.errorTitle=Timeline",
288 "FilteredEventsModel.timeRangeProperty.errorMessage=Error getting spanning interval."})
293 }
catch (TskCoreException timelineCacheException) {
295 Bundle.FilteredEventsModel_timeRangeProperty_errorMessage());
296 logger.log(Level.SEVERE,
"Error getting spanning interval.", timelineCacheException);
389 DataSourcesFilter dataSourcesFilter =
new DataSourcesFilter();
398 new HideKnownFilter(),
400 new HashHitsFilter(),
402 new EventTypeFilter(TimelineEventType.ROOT_EVENT_TYPE),
405 Collections.emptySet()));
407 return rootFilterState;
420 public TimelineEvent
getEventById(Long eventID)
throws TskCoreException {
423 }
catch (ExecutionException ex) {
424 throw new TskCoreException(
"Error getting cached event from ID", ex);
438 public Set<TimelineEvent>
getEventsById(Collection<Long> eventIDs)
throws TskCoreException {
439 Set<TimelineEvent>
events =
new HashSet<>();
440 for (Long
id : eventIDs) {
459 final Interval overlap;
460 RootFilter intersection;
461 synchronized (
this) {
462 overlap =
EventsModel.this.getSpanningInterval().overlap(timeRange);
481 public Set<Long>
getEventIDsForFile(AbstractFile file,
boolean includeDerivedArtifacts)
throws TskCoreException {
509 public Map<TimelineEventType, Long>
getEventCounts(Interval timeRange)
throws TskCoreException {
511 final TimelineEventType.HierarchyLevel typeZoom;
512 synchronized (
this) {
518 }
catch (ExecutionException executionException) {
519 throw new TskCoreException(
"Error getting cached event counts.`1", executionException);
576 }
catch (ExecutionException ex) {
577 throw new TskCoreException(
"Error getting cached min time.", ex);
593 }
catch (ExecutionException ex) {
594 throw new TskCoreException(
"Error getting cached max time.", ex);
610 ContentTag contentTag = evt.getAddedTag();
611 Content content = contentTag.getContent();
612 Set<Long> updatedEventIDs =
caseDbEventManager.updateEventsForContentTagAdded(content);
613 if (isNotEmpty(updatedEventIDs)) {
631 BlackboardArtifactTag artifactTag = evt.getAddedTag();
632 BlackboardArtifact artifact = artifactTag.getArtifact();
633 Set<Long> updatedEventIDs =
caseDbEventManager.updateEventsForArtifactTagAdded(artifact);
634 if (isNotEmpty(updatedEventIDs)) {
654 Set<Long> updatedEventIDs =
caseDbEventManager.updateEventsForContentTagDeleted(content);
655 if (isNotEmpty(updatedEventIDs)) {
667 synchronized void handleDataSourceAdded() throws TskCoreException {
686 Set<Long> updatedEventIDs =
caseDbEventManager.updateEventsForArtifactTagDeleted(artifact);
687 if (isNotEmpty(updatedEventIDs)) {
703 boolean tagsUpdated = !updatedEventIDs.isEmpty();
720 boolean tagsUpdated = !updatedEventIDs.isEmpty();
774 Set<Long> updatedEventIDs =
new HashSet<>();
775 for (BlackboardArtifact artifact : hashSetHitArtifacts) {
776 Content content =
currentCase.getSleuthkitCase().getContentById(artifact.getObjectID());
779 if (isNotEmpty(updatedEventIDs)) {
782 return updatedEventIDs;
795 public synchronized void invalidateCaches(Collection<Long> updatedEventIDs)
throws TskCoreException {
synchronized static Logger getLogger(String name)
static void error(String title, String message)
synchronized void registerForEvents(Object subscriber)
Interval getSpanningInterval(DateTimeZone timeZone)
synchronized void populateDataSourcesCache()
Interval getSpanningInterval()
ImmutableList< TimelineEventType > getEventTypes()
synchronized ReadOnlyObjectProperty< RootFilterState > eventFilterProperty()
synchronized TimelineEventType.HierarchyLevel getEventTypeZoom()
Interval getSpanningInterval(Collection< Long > eventIDs)
void postRefreshRequest()
boolean postTagsDeleted(Set< Long > updatedEventIDs)
SleuthkitCase getSleuthkitCase()
static final Logger logger
final ReadOnlyObjectWrapper< TimelineEventType.HierarchyLevel > eventTypesHierarchyLevelProperty
synchronized boolean handleArtifactTagDeleted(BlackBoardArtifactTagDeletedEvent evt)
synchronized boolean handleContentTagAdded(ContentTagAddedEvent evt)
Map< TimelineEventType, Long > getEventCounts(Interval timeRange)
synchronized ReadOnlyObjectProperty< TimelineEventType.HierarchyLevel > eventTypesHierarchyLevelProperty()
boolean postTagsAdded(Set< Long > updatedEventIDs)
final ReadOnlyObjectWrapper< Interval > timeRangeProperty
final ReadOnlyObjectWrapper< TimelineLevelOfDetail > timelineLODProperty
EventsModel(Case currentCase, ReadOnlyObjectProperty< EventsModelParams > modelParams)
synchronized ReadOnlyObjectProperty< TimelineLevelOfDetail > descriptionLODProperty()
synchronized RootFilterState getDefaultEventFilterState()
synchronized TimelineLevelOfDetail getDescriptionLOD()
TimelineEvent getEventById(Long eventID)
TimelineManager getEventManager()
final TimelineManager caseDbEventManager
synchronized void invalidateCaches(Collection< Long > updatedEventIDs)
synchronized Interval getTimeRange()
static DataSourceFilter newDataSourceFilter(Map.Entry< Long, String > dataSourceEntry)
synchronized EventsModelParams getModelParams()
synchronized boolean handleContentTagDeleted(ContentTagDeletedEvent evt)
final LoadingCache< EventsModelParams, Map< TimelineEventType, Long > > eventCountsCache
final ObservableMap< Long, String > datasourceIDsToNamesMap
synchronized boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt)
synchronized ReadOnlyObjectProperty< Interval > timeRangeProperty()
final LoadingCache< Object, Long > maxEventTimeCache
synchronized void unRegisterForEvents(Object subscriber)
synchronized RootFilterState getEventFilterState()
Map< TimelineEventType, Long > countEventsByType(EventsModelParams modelParams)
final ReadOnlyObjectWrapper< RootFilterState > filterStateProperty
synchronized Set< Long > updateEventsForHashSetHits(Collection< BlackboardArtifact > hashSetHitArtifacts)
final LoadingCache< Object, Long > minEventTimeCache
Set< Long > getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts)
synchronized ReadOnlyObjectProperty< EventsModelParams > modelParamsProperty()
final LoadingCache< Long, TimelineEvent > idsToEventsCache
Set< TimelineEvent > getEventsById(Collection< Long > eventIDs)
List< Long > getEventIDs(Interval timeRange, FilterState<? extends TimelineFilter > filterState)
List< Long > getEventIDsForArtifact(BlackboardArtifact artifact)
final ReadOnlyObjectWrapper< EventsModelParams > modelParamsProperty
void addSubFilterState(FilterState< ? extends SubFilterType > newSubFilterState)
RootFilter getActiveFilter()
CompoundFilterState< DataSourceFilter, DataSourcesFilter > getDataSourcesFilterState()
RootFilterState intersect(FilterState< ? extends TimelineFilter > other)
static FileTypesFilter createDefaultFileTypesFilter()
RootFilterState getEventFilterState()
TimelineLevelOfDetail getTimelineLOD()
TimelineEventType.HierarchyLevel getEventTypesHierarchyLevel()