19 package org.sleuthkit.autopsy.timeline;
21 import com.google.common.cache.CacheBuilder;
22 import com.google.common.cache.LoadingCache;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.eventbus.EventBus;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.TimeUnit;
33 import java.util.logging.Level;
34 import javafx.beans.InvalidationListener;
35 import javafx.beans.property.ReadOnlyObjectProperty;
36 import javafx.beans.property.ReadOnlyObjectWrapper;
37 import javafx.collections.FXCollections;
38 import javafx.collections.ObservableMap;
39 import static org.apache.commons.collections4.CollectionUtils.emptyIfNull;
40 import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
41 import org.joda.time.DateTimeZone;
42 import org.joda.time.Interval;
43 import org.openide.util.NbBundle;
73 import org.
sleuthkit.datamodel.TimelineFilter.DataSourceFilter;
74 import org.
sleuthkit.datamodel.TimelineFilter.DataSourcesFilter;
75 import org.
sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
76 import org.
sleuthkit.datamodel.TimelineFilter.FileTypesFilter;
77 import org.
sleuthkit.datamodel.TimelineFilter.HashHitsFilter;
78 import org.
sleuthkit.datamodel.TimelineFilter.HideKnownFilter;
79 import org.
sleuthkit.datamodel.TimelineFilter.RootFilter;
80 import org.
sleuthkit.datamodel.TimelineFilter.TagsFilter;
81 import org.
sleuthkit.datamodel.TimelineFilter.TextFilter;
98 private final EventBus
eventbus =
new EventBus(
"EventsModel_EventBus");
110 private final ReadOnlyObjectWrapper<EventsModelParams>
modelParamsProperty =
new ReadOnlyObjectWrapper<>();
112 private final ReadOnlyObjectWrapper<Interval>
timeRangeProperty =
new ReadOnlyObjectWrapper<>();
113 private final ReadOnlyObjectWrapper<TimelineEventType.HierarchyLevel>
eventTypesHierarchyLevelProperty =
new ReadOnlyObjectWrapper<>(TimelineEventType.HierarchyLevel.CATEGORY);
114 private final ReadOnlyObjectWrapper<TimelineLevelOfDetail>
timelineLODProperty =
new ReadOnlyObjectWrapper<>(TimelineLevelOfDetail.LOW);
123 private final LoadingCache<EventsModelParams, Map<TimelineEventType, Long>>
eventCountsCache;
134 return new DataSourceFilter(dataSourceEntry.getValue(), dataSourceEntry.getKey());
146 public EventsModel(
Case currentCase, ReadOnlyObjectProperty<EventsModelParams> modelParams)
throws TskCoreException {
148 this.caseDbEventManager = currentCase.
getSleuthkitCase().getTimelineManager();
156 idsToEventsCache = CacheBuilder.newBuilder()
158 .expireAfterAccess(10, TimeUnit.MINUTES)
160 eventCountsCache = CacheBuilder.newBuilder()
162 .expireAfterAccess(10, TimeUnit.MINUTES)
164 maxEventTimeCache = CacheBuilder.newBuilder()
166 minEventTimeCache = CacheBuilder.newBuilder()
174 InvalidationListener dataSourcesMapListener = observable -> {
175 RootFilterState rootFilter = filterStateProperty.getReadOnlyProperty().get();
176 addDataSourceFilters(rootFilter);
177 filterStateProperty.set(rootFilter.
copyOf());
179 datasourceIDsToNamesMap.addListener(dataSourcesMapListener);
192 modelParamsProperty.addListener(observable -> {
194 if (params != null) {
204 modelParamsProperty.bind(modelParams);
213 for (DataSource ds : skCase.getDataSources()) {
214 datasourceIDsToNamesMap.putIfAbsent(ds.getId(), ds.getName());
224 synchronized void addDataSourceFilters(
RootFilterState rootFilterState) {
226 datasourceIDsToNamesMap.entrySet().forEach(entry -> dataSourcesFilter.addSubFilter(
newDataSourceFilter(entry)));
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());
278 return modelParamsProperty.getReadOnlyProperty();
287 "FilteredEventsModel.timeRangeProperty.errorTitle=Timeline",
288 "FilteredEventsModel.timeRangeProperty.errorMessage=Error getting spanning interval."})
290 if (timeRangeProperty.get() == null) {
293 }
catch (TskCoreException timelineCacheException) {
295 Bundle.FilteredEventsModel_timeRangeProperty_errorMessage());
296 logger.log(Level.SEVERE,
"Error getting spanning interval.", timelineCacheException);
299 return timeRangeProperty.getReadOnlyProperty();
309 return timelineLODProperty.getReadOnlyProperty();
319 return filterStateProperty.getReadOnlyProperty();
338 return modelParamsProperty.get();
389 DataSourcesFilter dataSourcesFilter =
new DataSourcesFilter();
390 datasourceIDsToNamesMap.entrySet().forEach(dataSourceEntry
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 {
422 return idsToEventsCache.get(eventID);
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) {
465 return caseDbEventManager.getEventIDs(overlap, intersection);
481 public Set<Long>
getEventIDsForFile(AbstractFile file,
boolean includeDerivedArtifacts)
throws TskCoreException {
482 return caseDbEventManager.getEventIDsForContent(file, includeDerivedArtifacts);
496 return caseDbEventManager.getEventIDsForArtifact(artifact);
509 public Map<TimelineEventType, Long>
getEventCounts(Interval timeRange)
throws TskCoreException {
511 final TimelineEventType.HierarchyLevel typeZoom;
512 synchronized (
this) {
517 return eventCountsCache.get(
new EventsModelParams(timeRange, typeZoom, filter, null));
518 }
catch (ExecutionException executionException) {
519 throw new TskCoreException(
"Error getting cached event counts.`1", executionException);
561 return caseDbEventManager.getSpanningInterval(eventIDs);
575 return minEventTimeCache.get(
"min");
576 }
catch (ExecutionException ex) {
577 throw new TskCoreException(
"Error getting cached min time.", ex);
592 return maxEventTimeCache.get(
"max");
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)) {
675 Set<Long> updatedEventIDs = caseDbEventManager.updateEventsForArtifactTagDeleted(artifact);
676 if (isNotEmpty(updatedEventIDs)) {
692 boolean tagsUpdated = !updatedEventIDs.isEmpty();
709 boolean tagsUpdated = !updatedEventIDs.isEmpty();
723 eventbus.register(subscriber);
732 eventbus.unregister(subscriber);
748 return caseDbEventManager.getEventTypes();
763 Set<Long> updatedEventIDs =
new HashSet<>();
764 for (BlackboardArtifact artifact : hashSetHitArtifacts) {
765 Content content = currentCase.
getSleuthkitCase().getContentById(artifact.getObjectID());
766 updatedEventIDs.addAll(caseDbEventManager.updateEventsForHashSetHit(content));
768 if (isNotEmpty(updatedEventIDs)) {
771 return updatedEventIDs;
784 public synchronized void invalidateCaches(Collection<Long> updatedEventIDs)
throws TskCoreException {
786 minEventTimeCache.invalidateAll();
787 maxEventTimeCache.invalidateAll();
788 idsToEventsCache.invalidateAll(emptyIfNull(updatedEventIDs));
789 eventCountsCache.invalidateAll();
TimelineLevelOfDetail getTimelineLOD()
synchronized boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt)
Set< Long > getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts)
synchronized Set< Long > updateEventsForHashSetHits(Collection< BlackboardArtifact > hashSetHitArtifacts)
ImmutableList< TimelineEventType > getEventTypes()
Set< TimelineEvent > getEventsById(Collection< Long > eventIDs)
synchronized void unRegisterForEvents(Object subscriber)
synchronized void invalidateCaches(Collection< Long > updatedEventIDs)
synchronized RootFilterState getEventFilterState()
final TimelineManager caseDbEventManager
Interval getSpanningInterval(Collection< Long > eventIDs)
final LoadingCache< Long, TimelineEvent > idsToEventsCache
RootFilter getActiveFilter()
static DataSourceFilter newDataSourceFilter(Map.Entry< Long, String > dataSourceEntry)
Interval getSpanningInterval()
TimelineManager getEventManager()
SleuthkitCase getSleuthkitCase()
synchronized boolean handleArtifactTagDeleted(BlackBoardArtifactTagDeletedEvent evt)
synchronized EventsModelParams getModelParams()
List< Long > getEventIDs(Interval timeRange, FilterState<?extends TimelineFilter > filterState)
RootFilterState getEventFilterState()
static final Logger logger
Interval getSpanningInterval(DateTimeZone timeZone)
synchronized ReadOnlyObjectProperty< EventsModelParams > modelParamsProperty()
final LoadingCache< EventsModelParams, Map< TimelineEventType, Long > > eventCountsCache
final LoadingCache< Object, Long > maxEventTimeCache
EventsModel(Case currentCase, ReadOnlyObjectProperty< EventsModelParams > modelParams)
boolean postTagsAdded(Set< Long > updatedEventIDs)
TimelineEventType.HierarchyLevel getEventTypesHierarchyLevel()
final ReadOnlyObjectWrapper< TimelineLevelOfDetail > timelineLODProperty
final ReadOnlyObjectWrapper< RootFilterState > filterStateProperty
synchronized TimelineEventType.HierarchyLevel getEventTypeZoom()
synchronized RootFilterState getDefaultEventFilterState()
SleuthkitCase getSleuthkitCase()
boolean postTagsDeleted(Set< Long > updatedEventIDs)
synchronized void populateDataSourcesCache()
final ObservableMap< Long, String > datasourceIDsToNamesMap
synchronized ReadOnlyObjectProperty< Interval > timeRangeProperty()
static FileTypesFilter createDefaultFileTypesFilter()
synchronized void registerForEvents(Object subscriber)
synchronized ReadOnlyObjectProperty< TimelineEventType.HierarchyLevel > eventTypesHierarchyLevelProperty()
RootFilterState intersect(FilterState< ?extends TimelineFilter > other)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Map< TimelineEventType, Long > countEventsByType(EventsModelParams modelParams)
synchronized boolean handleContentTagDeleted(ContentTagDeletedEvent evt)
synchronized TimelineLevelOfDetail getDescriptionLOD()
void postRefreshRequest()
synchronized boolean handleContentTagAdded(ContentTagAddedEvent evt)
synchronized ReadOnlyObjectProperty< TimelineLevelOfDetail > descriptionLODProperty()
CompoundFilterState< DataSourceFilter, DataSourcesFilter > getDataSourcesFilterState()
synchronized Interval getTimeRange()
TimelineEvent getEventById(Long eventID)
List< Long > getEventIDsForArtifact(BlackboardArtifact artifact)
Map< TimelineEventType, Long > getEventCounts(Interval timeRange)
synchronized ReadOnlyObjectProperty< RootFilterState > eventFilterProperty()
final LoadingCache< Object, Long > minEventTimeCache