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;
 
   74 import org.
sleuthkit.datamodel.TimelineFilter.DataSourceFilter;
 
   75 import org.
sleuthkit.datamodel.TimelineFilter.DataSourcesFilter;
 
   76 import org.
sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
 
   77 import org.
sleuthkit.datamodel.TimelineFilter.FileTypesFilter;
 
   78 import org.
sleuthkit.datamodel.TimelineFilter.HashHitsFilter;
 
   79 import org.
sleuthkit.datamodel.TimelineFilter.HideKnownFilter;
 
   80 import org.
sleuthkit.datamodel.TimelineFilter.RootFilter;
 
   81 import org.
sleuthkit.datamodel.TimelineFilter.TagsFilter;
 
   82 import org.
sleuthkit.datamodel.TimelineFilter.TextFilter;
 
   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());
 
  147     public EventsModel(
Case currentCase, ReadOnlyObjectProperty<EventsModelParams> modelParams) 
throws TskCoreException {
 
  149         this.caseDbEventManager = currentCase.
getSleuthkitCase().getTimelineManager();
 
  157         idsToEventsCache = CacheBuilder.newBuilder()
 
  159                 .expireAfterAccess(10, TimeUnit.MINUTES)
 
  161         eventCountsCache = CacheBuilder.newBuilder()
 
  163                 .expireAfterAccess(10, TimeUnit.MINUTES)
 
  165         maxEventTimeCache = CacheBuilder.newBuilder()
 
  167         minEventTimeCache = CacheBuilder.newBuilder()
 
  175         InvalidationListener dataSourcesMapListener = observable -> {
 
  176             RootFilterState rootFilter = filterStateProperty.getReadOnlyProperty().get();
 
  177             addDataSourceFilters(rootFilter);
 
  178             filterStateProperty.set(rootFilter.
copyOf());
 
  180         datasourceIDsToNamesMap.addListener(dataSourcesMapListener);
 
  193         modelParamsProperty.addListener(observable -> {
 
  195             if (params != null) {
 
  205         modelParamsProperty.bind(modelParams);
 
  214         for (DataSource ds : skCase.getDataSources()) {
 
  215             datasourceIDsToNamesMap.putIfAbsent(ds.getId(), ds.getName());
 
  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());
 
  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)) {
 
  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();
 
  734         eventbus.register(subscriber);
 
  743         eventbus.unregister(subscriber);
 
  759         return caseDbEventManager.getEventTypes();
 
  774         Set<Long> updatedEventIDs = 
new HashSet<>();
 
  775         for (BlackboardArtifact artifact : hashSetHitArtifacts) {
 
  776             Content content = currentCase.
getSleuthkitCase().getContentById(artifact.getObjectID());
 
  777             updatedEventIDs.addAll(caseDbEventManager.updateEventsForHashSetHit(content));
 
  779         if (isNotEmpty(updatedEventIDs)) {
 
  782         return updatedEventIDs;
 
  795     public synchronized void invalidateCaches(Collection<Long> updatedEventIDs) 
throws TskCoreException {
 
  796         minEventTimeCache.invalidateAll();
 
  797         maxEventTimeCache.invalidateAll();
 
  798         idsToEventsCache.invalidateAll(emptyIfNull(updatedEventIDs));
 
  799         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()
 
void addSubFilterState(FilterState< ?extends SubFilterType > newSubFilterState)
 
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