org.sleuthkit.autopsy.timeline.datamodel.EventCluster.java Source code

Java tutorial

Introduction

Here is the source code for org.sleuthkit.autopsy.timeline.datamodel.EventCluster.java

Source

/*
 * Autopsy Forensic Browser
 *
 * Copyright 2011-2016 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> 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;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.SortedSet;
import javax.annotation.concurrent.Immutable;
import org.joda.time.Interval;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
import org.sleuthkit.autopsy.timeline.utils.IntervalUtils;
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;

/**
 * Represents a set of other events clustered together. All the sub events
 * should have the same type and matching descriptions at the designated "zoom
 * level", and be "close together" in time.
 */
@Immutable
public class EventCluster implements MultiEvent<EventStripe> {

    /**
     * merge two event clusters into one new event cluster.
     *
     * @param cluster1
     * @param cluster2
     *
     * @return a new event cluster that is the result of merging the given
     *         events clusters
     */
    public static EventCluster merge(EventCluster cluster1, EventCluster cluster2) {
        if (cluster1.getEventType() != cluster2.getEventType()) {
            throw new IllegalArgumentException("event clusters are not compatible: they have different types");
        }

        if (!cluster1.getDescription().equals(cluster2.getDescription())) {
            throw new IllegalArgumentException(
                    "event clusters are not compatible: they have different descriptions");
        }
        Sets.SetView<Long> idsUnion = Sets.union(cluster1.getEventIDs(), cluster2.getEventIDs());
        Sets.SetView<Long> hashHitsUnion = Sets.union(cluster1.getEventIDsWithHashHits(),
                cluster2.getEventIDsWithHashHits());
        Sets.SetView<Long> taggedUnion = Sets.union(cluster1.getEventIDsWithTags(), cluster2.getEventIDsWithTags());

        return new EventCluster(IntervalUtils.span(cluster1.span, cluster2.span), cluster1.getEventType(), idsUnion,
                hashHitsUnion, taggedUnion, cluster1.getDescription(), cluster1.lod);
    }

    final private EventStripe parent;

    /**
     * the smallest time interval containing all the clustered events
     */
    final private Interval span;

    /**
     * the type of all the clustered events
     */
    final private EventType type;

    /**
     * the common description of all the clustered events
     */
    final private String description;

    /**
     * the description level of detail that the events were clustered at.
     */
    private final DescriptionLoD lod;

    /**
     * the set of ids of the clustered events
     */
    final private ImmutableSet<Long> eventIDs;

    /**
     * the ids of the subset of clustered events that have at least one tag
     * applied to them
     */
    private final ImmutableSet<Long> tagged;

    /**
     * the ids of the subset of clustered events that have at least one hash set
     * hit
     */
    private final ImmutableSet<Long> hashHits;

    private EventCluster(Interval spanningInterval, EventType type, Collection<Long> eventIDs,
            Collection<Long> hashHits, Collection<Long> tagged, String description, DescriptionLoD lod,
            EventStripe parent) {

        this.span = spanningInterval;
        this.type = type;
        this.hashHits = ImmutableSet.copyOf(hashHits);
        this.tagged = ImmutableSet.copyOf(tagged);
        this.description = description;
        this.eventIDs = ImmutableSet.copyOf(eventIDs);
        this.lod = lod;
        this.parent = parent;
    }

    public EventCluster(Interval spanningInterval, EventType type, Collection<Long> eventIDs,
            Collection<Long> hashHits, Collection<Long> tagged, String description, DescriptionLoD lod) {
        this(spanningInterval, type, eventIDs, hashHits, tagged, description, lod, null);
    }

    /**
     * get the EventStripe (if any) that contains this cluster
     *
     * @return an Optional containg the parent stripe of this cluster, or is
     *         empty if the cluster has no parent set.
     */
    @Override
    public Optional<EventStripe> getParent() {
        return Optional.ofNullable(parent);
    }

    /**
     * get the EventStripe (if any) that contains this cluster
     *
     * @return an Optional containg the parent stripe of this cluster, or is
     *         empty if the cluster has no parent set.
     */
    @Override
    public Optional<EventStripe> getParentStripe() {
        //since this clusters parent must be an event stripe just delegate to getParent();
        return getParent();
    }

    public Interval getSpan() {
        return span;
    }

    @Override
    public long getStartMillis() {
        return span.getStartMillis();
    }

    @Override
    public long getEndMillis() {
        return span.getEndMillis();
    }

    @Override
    public ImmutableSet<Long> getEventIDs() {
        return eventIDs;
    }

    @Override
    public ImmutableSet<Long> getEventIDsWithHashHits() {
        return hashHits;
    }

    @Override
    public ImmutableSet<Long> getEventIDsWithTags() {
        return tagged;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public EventType getEventType() {
        return type;
    }

    @Override
    public DescriptionLoD getDescriptionLoD() {
        return lod;
    }

    /**
     * return a new EventCluster identical to this one, except with the given
     * EventBundle as the parent.
     *
     * @param parent
     *
     * @return a new EventCluster identical to this one, except with the given
     *         EventBundle as the parent.
     */
    public EventCluster withParent(EventStripe parent) {
        return new EventCluster(span, type, eventIDs, hashHits, tagged, description, lod, parent);
    }

    @Override
    public SortedSet<EventCluster> getClusters() {
        return ImmutableSortedSet.orderedBy(Comparator.comparing(EventCluster::getStartMillis)).add(this).build();
    }

    @Override
    public String toString() {
        return "EventCluster{" + "description=" + description + ", eventIDs=" + eventIDs.size() + '}';
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 23 * hash + Objects.hashCode(this.type);
        hash = 23 * hash + Objects.hashCode(this.description);
        hash = 23 * hash + Objects.hashCode(this.lod);
        hash = 23 * hash + Objects.hashCode(this.eventIDs);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final EventCluster other = (EventCluster) obj;
        if (!Objects.equals(this.description, other.description)) {
            return false;
        }
        if (!Objects.equals(this.type, other.type)) {
            return false;
        }
        if (this.lod != other.lod) {
            return false;
        }
        if (!Objects.equals(this.eventIDs, other.eventIDs)) {
            return false;
        }
        return true;
    }
}