Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
EventCluster.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2018-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.timeline.ui.detailview.datamodel;
20 
21 import static java.util.Collections.emptySet;
22 import static java.util.Collections.singleton;
23 import java.util.Comparator;
24 import java.util.HashSet;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.SortedSet;
29 import org.joda.time.Interval;
31 import org.sleuthkit.datamodel.TimelineEventType;
32 import org.sleuthkit.datamodel.TimelineEvent;
33 import org.sleuthkit.datamodel.TimelineLevelOfDetail;
34 
40 public class EventCluster implements MultiEvent<EventStripe> {
41 
42  final private EventStripe parent;
43 
47  final private Interval span;
48 
52  final private TimelineEventType type;
53 
57  final private String description;
58 
62  private final TimelineLevelOfDetail lod;
63 
67  final private Set<Long> eventIDs;
68 
73  private final Set<Long> tagged;
74 
79  private final Set<Long> hashHits;
80 
90  public static EventCluster merge(EventCluster cluster1, EventCluster cluster2) {
91 
92  if (cluster1.getEventType() != cluster2.getEventType()) {
93  throw new IllegalArgumentException("event clusters are not compatible: they have different types");
94  }
95 
96  if (!cluster1.getDescription().equals(cluster2.getDescription())) {
97  throw new IllegalArgumentException("event clusters are not compatible: they have different descriptions");
98  }
99 
100  Interval spanningInterval = IntervalUtils.span(cluster1.span, cluster2.span);
101 
102  Set<Long> idsUnion = cluster1.getEventIDs();
103  if(!idsUnion.isEmpty()) {
104  idsUnion.addAll(cluster2.getEventIDs());
105  } else {
106  idsUnion = cluster2.getEventIDs();
107  }
108 
109  Set<Long> hashHitsUnion = cluster1.getEventIDsWithHashHits();
110  if(!hashHitsUnion.isEmpty()) {
111  hashHitsUnion.addAll(cluster2.getEventIDsWithHashHits());
112  } else {
113  hashHitsUnion = cluster2.getEventIDsWithHashHits();
114  }
115 
116  Set<Long> taggedUnion = cluster1.getEventIDsWithTags();
117  if(!taggedUnion.isEmpty()) {
118  taggedUnion.addAll(cluster2.getEventIDsWithTags());
119  } else {
120  taggedUnion = cluster2.getEventIDsWithTags();
121  }
122 
123  return new EventCluster(spanningInterval,
124  cluster1.getEventType(), idsUnion, hashHitsUnion, taggedUnion,
125  cluster1.getDescription(), cluster1.lod);
126  }
127 
128  private EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs,
129  Set<Long> hashHits, Set<Long> tagged, String description, TimelineLevelOfDetail lod,
130  EventStripe parent) {
131 
132  this.span = spanningInterval;
133 
134  this.type = type;
135  this.hashHits = hashHits;
136  this.tagged = tagged;
137  this.description = description;
138  this.eventIDs = eventIDs;
139  this.lod = lod;
140  this.parent = parent;
141  }
142 
143  public EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs,
144  Set<Long> hashHits, Set<Long> tagged, String description, TimelineLevelOfDetail lod) {
145  this(spanningInterval, type, eventIDs, hashHits, tagged, description, lod, null);
146  }
147 
148 
149  public EventCluster(TimelineEvent event, TimelineEventType type, TimelineLevelOfDetail lod) {
150  this.span = new Interval(event.getEventTimeInMs(), event.getEventTimeInMs());
151  this.type = type;
152 
153  this.eventIDs = new HashSet<>();
154  this.eventIDs.add(event.getEventID());
155  this.hashHits = event.eventSourceHasHashHits()? new HashSet<>(eventIDs) : emptySet();
156  this.tagged = event.eventSourceIsTagged()? new HashSet<>(eventIDs) : emptySet();
157  this.lod = lod;
158  this.description = event.getDescription(lod);
159  this.parent = null;
160  }
161 
168  @Override
169  public Optional<EventStripe> getParent() {
170  return Optional.ofNullable(parent);
171  }
172 
179  @Override
180  public Optional<EventStripe> getParentStripe() {
181  //since this clusters parent must be an event stripe just delegate to getParent();
182  return getParent();
183  }
184 
185  public Interval getSpan() {
186  return span;
187  }
188 
189  @Override
190  public long getStartMillis() {
191  return span.getStartMillis();
192  }
193 
194  @Override
195  public long getEndMillis() {
196  return span.getEndMillis();
197  }
198 
199  @Override
200  public Set<Long> getEventIDs() {
201  return eventIDs;
202  }
203 
204  @Override
205  public Set<Long> getEventIDsWithHashHits() {
206  return hashHits;
207  }
208 
209  @Override
210  public Set<Long> getEventIDsWithTags() {
211  return tagged;
212  }
213 
214  @Override
215  public String getDescription() {
216  return description;
217  }
218 
219  @Override
220  public TimelineEventType getEventType() {
221  return type;
222  }
223 
224  @Override
225  public TimelineLevelOfDetail getDescriptionLevel() {
226  return lod;
227  }
228 
239 
240  return new EventCluster(span, type, eventIDs, hashHits, tagged, description, lod, parent);
241  }
242 
243  @Override
244  public SortedSet<EventCluster> getClusters() {
245  return DetailsViewModel.copyAsSortedSet(singleton(this), Comparator.comparing(cluster -> true));
246  }
247 
248  @Override
249  public String toString() {
250  return "EventCluster{" + "description=" + description + ", eventIDs=" + eventIDs.size() + '}';
251  }
252 
253  @Override
254  public int hashCode() {
255  int hash = 7;
256  hash = 23 * hash + Objects.hashCode(this.type);
257  hash = 23 * hash + Objects.hashCode(this.description);
258  hash = 23 * hash + Objects.hashCode(this.lod);
259  hash = 23 * hash + Objects.hashCode(this.eventIDs);
260  return hash;
261  }
262 
263  @Override
264  public boolean equals(Object obj) {
265  if (this == obj) {
266  return true;
267  }
268  if (obj == null) {
269  return false;
270  }
271  if (getClass() != obj.getClass()) {
272  return false;
273  }
274  final EventCluster other = (EventCluster) obj;
275  if (!Objects.equals(this.description, other.description)) {
276  return false;
277  }
278  if (!Objects.equals(this.type, other.type)) {
279  return false;
280  }
281  if (this.lod != other.lod) {
282  return false;
283  }
284  return Objects.equals(this.eventIDs, other.eventIDs);
285  }
286 }
EventCluster(Interval spanningInterval, TimelineEventType type, Set< Long > eventIDs, Set< Long > hashHits, Set< Long > tagged, String description, TimelineLevelOfDetail lod, EventStripe parent)
static Interval span(Interval range, final Interval range2)
EventCluster(TimelineEvent event, TimelineEventType type, TimelineLevelOfDetail lod)
static EventCluster merge(EventCluster cluster1, EventCluster cluster2)
EventCluster(Interval spanningInterval, TimelineEventType type, Set< Long > eventIDs, Set< Long > hashHits, Set< Long > tagged, String description, TimelineLevelOfDetail lod)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.