From b9872c8f61780f90fbbdec4db45d2d9b0c351001 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 18 Apr 2018 17:12:09 +0200 Subject: [PATCH] introduce TimelineCacheException and throw it instead of ExecutionException --- .../timeline/datamodel/EventsRepository.java | 72 +++++++++++-------- .../datamodel/FilteredEventsModel.java | 45 ++++++------ .../datamodel/TimelineCacheException.java | 33 +++++++++ 3 files changed, 98 insertions(+), 52 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/datamodel/TimelineCacheException.java diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/EventsRepository.java index 62ee3ef55e..25604458c2 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/EventsRepository.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import static java.util.Objects.isNull; @@ -37,7 +38,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.logging.Level; -import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; @@ -194,41 +194,55 @@ public class EventsRepository { /** * @return min time (in seconds from unix epoch) */ - public Long getMaxTime() { - return maxCache.getUnchecked("max"); // NON-NLS - + public Long getMaxTime() throws TimelineCacheException { + try { + return maxCache.get("max"); // NON-NLS + } catch (ExecutionException ex) { + throw new TimelineCacheException("Error getting cached max time", ex); // NON-NLS + } } /** * @return max tie (in seconds from unix epoch) */ - public Long getMinTime() { - return minCache.getUnchecked("min"); // NON-NLS - - } - - public SingleEvent getEventById(Long eventID) { - return idToEventCache.getUnchecked(eventID); - } - - synchronized public Set getEventsById(Collection eventIDs) { - return eventIDs.stream() - .map(idToEventCache::getUnchecked) - .collect(Collectors.toSet()); - - } - - synchronized public List getEventStripes(ZoomParams params) { + public Long getMinTime() throws TimelineCacheException { try { - return eventStripeCache.get(params); + return minCache.get("min"); // NON-NLS } catch (ExecutionException ex) { - logger.log(Level.SEVERE, "Failed to load Event Stripes from cache for " + params.toString(), ex); //NON-NLS - return Collections.emptyList(); + throw new TimelineCacheException("Error getting cached min time", ex); // NON-NLS } } - synchronized public Map countEvents(ZoomParams params) throws ExecutionException { - return eventCountsCache.get(params); + public SingleEvent getEventById(Long eventID) throws TimelineCacheException { + try { + return idToEventCache.get(eventID); + } catch (ExecutionException ex) { + throw new TimelineCacheException("Error getting cached event from id " + eventID, ex); // NON-NLS + } + } + + synchronized public Set getEventsById(Collection eventIDs) throws TimelineCacheException { + HashSet events = new HashSet<>(); + for (Long eventID : eventIDs) { + events.add(getEventById(eventID)); + } + return events; + } + + synchronized public List getEventStripes(ZoomParams params) throws TimelineCacheException { + try { + return eventStripeCache.get(params); + } catch (ExecutionException ex) { + throw new TimelineCacheException("Failed to load Event Stripes from cache for " + params.toString(), ex); //NON-NLS + } + } + + synchronized public Map countEvents(ZoomParams params) throws TimelineCacheException { + try { + return eventCountsCache.get(params); + } catch (ExecutionException ex) { + throw new TimelineCacheException("Failed to load event counts from cache for " + params.toString(), ex); //NON-NLS + } } synchronized public int countAllEvents() throws TskCoreException { @@ -678,9 +692,9 @@ public class EventsRepository { for (Map.Entry timeEntry : timeMap.entrySet()) { if (timeEntry.getValue() > 0) { // if the time is legitimate ( greater than zero ) insert it - eventManager.insertEvent(timeEntry.getValue(), timeEntry.getKey(), + eventManager.addEvent(timeEntry.getValue(), timeEntry.getKey(), datasourceID, f.getId(), null, uniquePath, medDesc, - shortDesc, known, hashSets, tags); + shortDesc, known, hashSets.isEmpty() == false, tags.isEmpty() == false); } } } @@ -743,7 +757,7 @@ public class EventsRepository { String fullDescription = eventDescription.getFullDescription(); String medDescription = eventDescription.getMedDescription(); String shortDescription = eventDescription.getShortDescription(); - eventManager.insertEvent(eventDescription.getTime(), type, datasourceID, objectID, artifactID, fullDescription, medDescription, shortDescription, null, hashSets, tags); + eventManager.addEvent(eventDescription.getTime(), type, datasourceID, objectID, artifactID, fullDescription, medDescription, shortDescription, null, hashSets.isEmpty() == false, tags.isEmpty() == false); } } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index eef76f0b65..bea10b34ac 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javafx.beans.Observable; import javafx.beans.property.ReadOnlyObjectProperty; @@ -48,6 +47,21 @@ import org.sleuthkit.autopsy.timeline.events.DBUpdatedEvent; import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent; import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.timeline.CombinedEvent; +import org.sleuthkit.datamodel.timeline.DescriptionLoD; +import org.sleuthkit.datamodel.timeline.EventStripe; +import org.sleuthkit.datamodel.timeline.EventType; +import org.sleuthkit.datamodel.timeline.EventTypeZoomLevel; +import org.sleuthkit.datamodel.timeline.RootEventType; +import org.sleuthkit.datamodel.timeline.SingleEvent; +import org.sleuthkit.datamodel.timeline.ZoomParams; import org.sleuthkit.datamodel.timeline.filters.DataSourceFilter; import org.sleuthkit.datamodel.timeline.filters.DataSourcesFilter; import org.sleuthkit.datamodel.timeline.filters.Filter; @@ -59,21 +73,6 @@ import org.sleuthkit.datamodel.timeline.filters.TagNameFilter; import org.sleuthkit.datamodel.timeline.filters.TagsFilter; import org.sleuthkit.datamodel.timeline.filters.TextFilter; import org.sleuthkit.datamodel.timeline.filters.TypeFilter; -import org.sleuthkit.datamodel.timeline.DescriptionLoD; -import org.sleuthkit.datamodel.timeline.ZoomParams; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifactTag; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.timeline.CombinedEvent; -import org.sleuthkit.datamodel.timeline.EventStripe; -import org.sleuthkit.datamodel.timeline.EventType; -import org.sleuthkit.datamodel.timeline.EventTypeZoomLevel; -import org.sleuthkit.datamodel.timeline.RootEventType; -import org.sleuthkit.datamodel.timeline.SingleEvent; /** * This class acts as the model for a TimelineView @@ -83,8 +82,8 @@ import org.sleuthkit.datamodel.timeline.SingleEvent; * This class is implemented as a filtered view into an underlying * EventsRepository. * - * Maintainers, NOTE: as many methods as possible should cache their results - * so as to avoid unnecessary db calls through the EventsRepository -jm + * Maintainers, NOTE: as many methods as possible should cache their results so + * as to avoid unnecessary db calls through the EventsRepository -jm * * Concurrency Policy: repo is internally synchronized, so methods that only * access the repo atomically do not need further synchronization @@ -318,7 +317,7 @@ public final class FilteredEventsModel { * * @return */ - public Map getEventCounts(Interval timeRange) throws ExecutionException { + public Map getEventCounts(Interval timeRange) throws TimelineCacheException { final RootFilter filter; final EventTypeZoomLevel typeZoom; @@ -349,7 +348,7 @@ public final class FilteredEventsModel { * event available from the repository, ignoring any filters or * requested ranges */ - public Long getMinTime() { + public Long getMinTime() throws TimelineCacheException { return repo.getMinTime(); } @@ -358,7 +357,7 @@ public final class FilteredEventsModel { * event available from the repository, ignoring any filters or * requested ranges */ - public Long getMaxTime() { + public Long getMaxTime() throws TimelineCacheException { return repo.getMaxTime(); } @@ -367,7 +366,7 @@ public final class FilteredEventsModel { * @return a list of event clusters at the requested zoom levels that are * within the requested time range and pass the requested filter */ - public List getEventStripes() { + public List getEventStripes() throws TimelineCacheException { final Interval range; final RootFilter filter; final EventTypeZoomLevel zoom; @@ -388,7 +387,7 @@ public final class FilteredEventsModel { * range and pass the requested filter, using the given aggregation * to control the grouping of events */ - public List getEventStripes(ZoomParams params) { + public List getEventStripes(ZoomParams params) throws TimelineCacheException { return repo.getEventStripes(params); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/TimelineCacheException.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/TimelineCacheException.java new file mode 100644 index 0000000000..9bde9497d4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/TimelineCacheException.java @@ -0,0 +1,33 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.timeline.datamodel; + +/** + * Exception thown when there is an error loading a cached value. + * + * NOTE: This should probably not be a RuntimeException. But the ripple effect + * of introducing this as a checked exception was spreading extremely far. + * + */ +public class TimelineCacheException extends RuntimeException { + + public TimelineCacheException(String message, Throwable cause) { + super(message, cause); + } +}