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.ObservableList;
39 import javafx.collections.ObservableMap;
40 import javafx.collections.ObservableSet;
41 import static org.apache.commons.collections4.CollectionUtils.emptyIfNull;
42 import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
43 import org.joda.time.DateTimeZone;
44 import org.joda.time.Interval;
45 import org.openide.util.NbBundle;
79 import org.
sleuthkit.datamodel.TimelineFilter.DataSourceFilter;
80 import org.
sleuthkit.datamodel.TimelineFilter.DataSourcesFilter;
81 import org.
sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
82 import org.
sleuthkit.datamodel.TimelineFilter.FileTypesFilter;
83 import org.
sleuthkit.datamodel.TimelineFilter.HashHitsFilter;
84 import org.
sleuthkit.datamodel.TimelineFilter.HashSetFilter;
85 import org.
sleuthkit.datamodel.TimelineFilter.HideKnownFilter;
86 import org.
sleuthkit.datamodel.TimelineFilter.RootFilter;
87 import org.
sleuthkit.datamodel.TimelineFilter.TagNameFilter;
88 import org.
sleuthkit.datamodel.TimelineFilter.TagsFilter;
89 import org.
sleuthkit.datamodel.TimelineFilter.TextFilter;
115 private final EventBus
eventbus =
new EventBus(
"FilteredEventsModel_EventBus");
118 private final ReadOnlyObjectWrapper<RootFilterState>
requestedFilter =
new ReadOnlyObjectWrapper<>();
121 private final ReadOnlyObjectWrapper< TimelineEventType.TypeLevel>
requestedTypeZoom =
new ReadOnlyObjectWrapper<>(TimelineEventType.TypeLevel.BASE_TYPE);
122 private final ReadOnlyObjectWrapper< TimelineEvent.DescriptionLevel>
requestedLOD =
new ReadOnlyObjectWrapper<>(TimelineEvent.DescriptionLevel.SHORT);
131 private final ObservableMap<Long, String>
datasourcesMap = FXCollections.observableHashMap();
132 private final ObservableSet< String>
hashSets = FXCollections.observableSet();
133 private final ObservableList<TagName>
tagNames = FXCollections.observableArrayList();
144 return new DataSourceFilter(dataSourceEntry.getValue(), dataSourceEntry.getKey());
153 idToEventCache = CacheBuilder.newBuilder()
155 .expireAfterAccess(10, TimeUnit.MINUTES)
157 eventCountsCache = CacheBuilder.newBuilder()
159 .expireAfterAccess(10, TimeUnit.MINUTES)
162 maxCache = CacheBuilder.newBuilder()
164 minCache = CacheBuilder.newBuilder()
167 InvalidationListener filterSyncListener = observable -> {
170 requestedFilter.set(rootFilter.
copyOf());
173 datasourcesMap.addListener(filterSyncListener);
174 hashSets.addListener(filterSyncListener);
175 tagNames.addListener(filterSyncListener);
179 requestedZoomState.addListener(observable -> {
180 final ZoomState zoomState = requestedZoomState.get();
182 if (zoomState != null) {
192 requestedZoomState.bind(currentStateProperty);
207 if (zoomState.getTimeRange() == null) {
208 return Collections.emptyMap();
210 return eventManager.countEventsByType(zoomState.getTimeRange().getStartMillis() / 1000,
211 zoomState.getTimeRange().getEndMillis() / 1000,
212 zoomState.getFilterState().getActiveFilter(), zoomState.getTypeZoomLevel());
225 return eventManager.getSpanningInterval(timeRange, filter, timeZone);
234 return requestedZoomState.getReadOnlyProperty();
243 return requestedZoomState.get();
251 hashSets.addAll(eventManager.getHashSetNames());
254 for (DataSource ds : skCase.getDataSources()) {
255 datasourcesMap.putIfAbsent(ds.getId(), ds.getName());
259 tagNames.setAll(skCase.getTagNamesInUse());
273 for (TagName tagName : tagNames) {
274 tagsFilterState.getFilter().addSubFilter(
new TagNameFilter(tagName));
278 tagFilterState.setDisabled(tagNames.contains(tagFilterState.getFilter().getTagName()) ==
false);
285 for (String hashSet : hashSets) {
286 hashSetsFilter.addSubFilter(
new HashSetFilter(hashSet));
296 "FilteredEventsModel.timeRangeProperty.errorTitle=Timeline",
297 "FilteredEventsModel.timeRangeProperty.errorMessage=Error getting spanning interval."})
299 if (requestedTimeRange.get() == null) {
302 }
catch (TskCoreException timelineCacheException) {
304 Bundle.FilteredEventsModel_timeRangeProperty_errorMessage());
305 logger.log(Level.SEVERE,
"Error getting spanning interval.", timelineCacheException);
308 return requestedTimeRange.getReadOnlyProperty();
316 return requestedFilter.getReadOnlyProperty();
349 DataSourcesFilter dataSourcesFilter =
new DataSourcesFilter();
350 datasourcesMap.entrySet().forEach(dataSourceEntry
353 HashHitsFilter hashHitsFilter =
new HashHitsFilter();
354 hashSets.stream().map(HashSetFilter::new).forEach(hashHitsFilter::addSubFilter);
356 TagsFilter tagsFilter =
new TagsFilter();
357 tagNames.stream().map(TagNameFilter::new).forEach(tagsFilter::addSubFilter);
365 new EventTypeFilter(TimelineEventType.ROOT_EVENT_TYPE),
368 Collections.emptySet()));
375 public TimelineEvent
getEventById(Long eventID)
throws TskCoreException {
377 return idToEventCache.get(eventID);
378 }
catch (ExecutionException ex) {
379 throw new TskCoreException(
"Error getting cached event from ID", ex);
383 public Set<TimelineEvent>
getEventsById(Collection<Long> eventIDs)
throws TskCoreException {
384 Set<TimelineEvent> events =
new HashSet<>();
385 for (Long
id : eventIDs) {
402 return eventManager.getTagCountsByTagName(eventIDsWithTags);
407 final Interval overlap;
408 RootFilter intersection;
409 synchronized (
this) {
414 return eventManager.getEventIDs(overlap, intersection);
429 public Map<TimelineEventType, Long>
getEventCounts(Interval timeRange)
throws TskCoreException {
432 final TimelineEventType.TypeLevel typeZoom;
433 synchronized (
this) {
438 return eventCountsCache.get(
new ZoomState(timeRange, typeZoom, filter, null));
439 }
catch (ExecutionException executionException) {
440 throw new TskCoreException(
"Error getting cached event counts.`1", executionException);
464 return eventManager.getSpanningInterval(eventIDs);
476 return minCache.get(
"min");
477 }
catch (ExecutionException ex) {
478 throw new TskCoreException(
"Error getting cached min time.", ex);
491 return maxCache.get(
"max");
492 }
catch (ExecutionException ex) {
493 throw new TskCoreException(
"Error getting cached max time.", ex);
498 ContentTag contentTag = evt.getAddedTag();
499 Content content = contentTag.getContent();
500 Set<Long> updatedEventIDs =
addTag(content.getId(), null, contentTag);
505 BlackboardArtifactTag artifactTag = evt.getAddedTag();
506 BlackboardArtifact artifact = artifactTag.getArtifact();
507 Set<Long> updatedEventIDs =
addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag);
516 Set<Long> updatedEventIDs =
deleteTag(content.getId(), null, deletedTagInfo.getTagID(), tagged);
525 Set<Long> updatedEventIDs =
deleteTag(artifact.getObjectID(), artifact.getArtifactID(), deletedTagInfo.getTagID(), tagged);
546 public Set<Long>
getEventIDsForFile(AbstractFile file,
boolean includeDerivedArtifacts)
throws TskCoreException {
547 return eventManager.getEventIDsForFile(file, includeDerivedArtifacts);
562 return eventManager.getEventIDsForArtifact(artifact);
575 boolean tagsUpdated = !updatedEventIDs.isEmpty();
592 boolean tagsUpdated = !updatedEventIDs.isEmpty();
606 eventbus.register(subscriber);
615 eventbus.unregister(subscriber);
632 eventbus.post(event);
636 return eventManager.getEventTypes();
639 synchronized public Set<Long>
addTag(
long objID, Long artifactID, Tag tag)
throws TskCoreException {
640 Set<Long> updatedEventIDs = eventManager.setEventsTagged(objID, artifactID,
true);
641 if (isNotEmpty(updatedEventIDs)) {
644 return updatedEventIDs;
647 synchronized public Set<Long>
deleteTag(
long objID, Long artifactID,
long tagID,
boolean tagged)
throws TskCoreException {
648 Set<Long> updatedEventIDs = eventManager.setEventsTagged(objID, artifactID, tagged);
649 if (isNotEmpty(updatedEventIDs)) {
652 return updatedEventIDs;
655 synchronized public Set<Long>
setHashHit(Collection<BlackboardArtifact> artifacts,
boolean hasHashHit)
throws TskCoreException {
656 Set<Long> updatedEventIDs =
new HashSet<>();
657 for (BlackboardArtifact artifact : artifacts) {
658 updatedEventIDs.addAll(eventManager.setEventsHashed(artifact.getObjectID(), hasHashHit));
660 if (isNotEmpty(updatedEventIDs)) {
663 return updatedEventIDs;
678 public synchronized void invalidateCaches(Collection<Long> updatedEventIDs)
throws TskCoreException {
679 minCache.invalidateAll();
680 maxCache.invalidateAll();
681 idToEventCache.invalidateAll(emptyIfNull(updatedEventIDs));
682 eventCountsCache.invalidateAll();
final ReadOnlyObjectWrapper< TimelineEvent.DescriptionLevel > requestedLOD
final LoadingCache< Long, TimelineEvent > idToEventCache
final TimelineManager eventManager
Map< TimelineEventType, Long > getEventCounts(Interval timeRange)
SleuthkitCase getSleuthkitCase()
synchronized boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt)
CompoundFilterState< HashSetFilter, HashHitsFilter > getHashHitsFilterState()
static DataSourceFilter newDataSourceFromMapEntry(Map.Entry< Long, String > dataSourceEntry)
synchronized Set< Long > deleteTag(long objID, Long artifactID, long tagID, boolean tagged)
Map< String, Long > getTagCountsByTagName(Set< Long > eventIDsWithTags)
Set< Long > getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts)
Set< TimelineEvent > getEventsById(Collection< Long > eventIDs)
synchronized ZoomState getZoomState()
void syncFilters(RootFilterState rootFilterState)
synchronized RootFilterState getDefaultFilter()
synchronized ReadOnlyObjectProperty< TimelineEventType.TypeLevel > eventTypeZoomProperty()
final ReadOnlyObjectWrapper< ZoomState > requestedZoomState
synchronized boolean handleContentTagAdded(ContentTagAddedEvent evt)
synchronized TimelineEventType.TypeLevel getEventTypeZoom()
TimelineEventType.TypeLevel getTypeZoomLevel()
synchronized void populateFilterData()
final ReadOnlyObjectWrapper< TimelineEventType.TypeLevel > requestedTypeZoom
List< Long > getEventIDs(Interval timeRange, FilterState<?extends TimelineFilter > filter)
RootFilter getActiveFilter()
FilteredEventsModel(Case autoCase, ReadOnlyObjectProperty< ZoomState > currentStateProperty)
static final Logger logger
final LoadingCache< ZoomState, Map< TimelineEventType, Long > > eventCountsCache
RootFilterState getFilterState()
TimelineManager getEventManager()
synchronized TimelineEvent.DescriptionLevel getDescriptionLOD()
synchronized ReadOnlyObjectProperty< TimelineEvent.DescriptionLevel > descriptionLODProperty()
boolean postTagsAdded(Set< Long > updatedEventIDs)
ImmutableList< TimelineEventType > getEventTypes()
Map< TimelineEventType, Long > countEventsByType(ZoomState zoomState)
Interval getBoundingEventsInterval(DateTimeZone timeZone)
Interval getBoundingEventsInterval(Interval timeRange, RootFilter filter, DateTimeZone timeZone)
TagsManager getTagsManager()
final ReadOnlyObjectWrapper< RootFilterState > requestedFilter
TagsFilterState getTagsFilterState()
final LoadingCache< Object, Long > minCache
List< Long > getEventIDsForArtifact(BlackboardArtifact artifact)
TimelineEvent.DescriptionLevel getDescriptionLOD()
synchronized boolean handleContentTagDeleted(ContentTagDeletedEvent evt)
synchronized Set< Long > addTag(long objID, Long artifactID, Tag tag)
final LoadingCache< Object, Long > maxCache
synchronized RootFilterState getFilterState()
void postAutopsyEventLocally(AutopsyEvent event)
final ReadOnlyObjectWrapper< Interval > requestedTimeRange
Interval getSpanningInterval(Collection< Long > eventIDs)
SleuthkitCase getSleuthkitCase()
synchronized void invalidateCaches(Collection< Long > updatedEventIDs)
synchronized ReadOnlyObjectProperty< Interval > timeRangeProperty()
static FileTypesFilter createDefaultFileTypesFilter()
final ObservableSet< String > hashSets
synchronized Interval getTimeRange()
static void error(String title, String message)
synchronized static Logger getLogger(String name)
TimelineEvent getEventById(Long eventID)
ObservableList< FilterState< ?extends SubFilterType > > getSubFilterStates()
synchronized void unRegisterForEvents(Object subscriber)
CompoundFilterState< DataSourceFilter, DataSourcesFilter > getDataSourcesFilterState()
synchronized ReadOnlyObjectProperty< RootFilterState > filterProperty()
synchronized boolean handleArtifactTagDeleted(BlackBoardArtifactTagDeletedEvent evt)
RootFilterState intersect(FilterState< ?extends TimelineFilter > otherFilter)
boolean postTagsDeleted(Set< Long > updatedEventIDs)
final ObservableMap< Long, String > datasourcesMap
synchronized Set< Long > setHashHit(Collection< BlackboardArtifact > artifacts, boolean hasHashHit)
Interval getSpanningInterval()
synchronized ReadOnlyObjectProperty< ZoomState > zoomStateProperty()
synchronized void registerForEvents(Object subscriber)
void postRefreshRequest()
final ObservableList< TagName > tagNames