All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opencredo.concourse.domain.events.Event Maven / Gradle / Ivy

package com.opencredo.concourse.domain.events;

import com.opencredo.concourse.data.tuples.Tuple;
import com.opencredo.concourse.domain.common.AggregateId;
import com.opencredo.concourse.domain.common.VersionedName;
import com.opencredo.concourse.domain.time.StreamTimestamp;
import com.opencredo.concourse.domain.time.TimeUUID;

import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.IntStream;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * An event in the system.
 */
public final class Event {

    /**
     * Create a processed {@link Event} with the supplied properties.
     * @param aggregateId The {@link AggregateId} of the aggregate to which the event occurred.
     * @param eventTimestamp The {@link StreamTimestamp} representing the time at which the event occurred.
     * @param processingId The processing {@link UUID} of the event (should be present only if the event has actually
     *                     been processed). This must be a type 1 UUID, as it encodes the event's processing timestamp.
     * @param eventName The {@link VersionedName} of the event.
     * @param parameters The event's parameters.
     * @param characteristics The event's characteristics, e.g. whether it is an initial or terminal event.
     * @return The constructed {@link Event}.
     */
    public static Event of(AggregateId aggregateId, StreamTimestamp eventTimestamp, UUID processingId, VersionedName eventName, Tuple parameters, int...characteristics) {
        checkNotNull(processingId, "processingId must not be null");
        checkArgument(processingId.version() == 1, "processingId must be type 1 UUID");

        return of(aggregateId, eventTimestamp, Optional.of(processingId), eventName, parameters, characteristics);
    }

    /**
     * Create an unprocessed {@link Event} with the supplied properties.
     * @param aggregateId The {@link AggregateId} of the aggregate to which the event occurred.
     * @param eventTimestamp The {@link StreamTimestamp} representing the time at which the event occurred.
     * @param eventName The {@link VersionedName} of the event.
     * @param parameters The event's parameters.
     * @param characteristics The event's characteristics, e.g. whether it is an initial or terminal event.
     * @return The constructed {@link Event}.
     */
    public static Event of(AggregateId aggregateId, StreamTimestamp eventTimestamp, VersionedName eventName, Tuple parameters, int...characteristics) {
        return of(aggregateId, eventTimestamp, Optional.empty(), eventName, parameters, characteristics);
    }

    private static Event of(AggregateId aggregateId, StreamTimestamp eventTimestamp, Optional processingId, VersionedName eventName, Tuple parameters, int...characteristics) {
        checkNotNull(aggregateId, "aggregateId must not be null");
        checkNotNull(eventTimestamp, "eventTimestamp must not be null");
        checkNotNull(eventName, "eventName must not be null");
        checkNotNull(parameters, "parameters must not be null");

        return new Event(aggregateId, eventTimestamp, processingId, eventName, parameters, IntStream.of(characteristics).reduce((l, r) -> l & r).orElse(0));
    }

    private final AggregateId aggregateId;
    private final StreamTimestamp eventTimestamp;

    private final Optional processingId;

    private final VersionedName eventName;
    private final Tuple parameters;

    private final int characteristics;

    private Event(AggregateId aggregateId, StreamTimestamp eventTimestamp, Optional processingId, VersionedName eventName, Tuple parameters, int characteristics) {
        this.aggregateId = aggregateId;
        this.eventTimestamp = eventTimestamp;
        this.processingId = processingId;
        this.eventName = eventName;
        this.parameters = parameters;
        this.characteristics = characteristics;
    }

    /**
     * Make a copy of this {@link Event} with the processing Id set to the supplied processing id.
     * @param processingId The processing {@link UUID} of the event. This must be a type 1 UUID, as it encodes the
     *                     event's processing timestamp.
     * @return The updated {@link Event}.
     */
    public Event processed(UUID processingId) {
        checkNotNull(processingId, "processingId must not be null");
        checkArgument(processingId.version() == 1, "processingId must be type 1 UUID");

        return new Event(aggregateId, eventTimestamp, Optional.of(processingId), eventName, parameters, characteristics);
    }

    /**
     * Get the processing time of this event.
     * @return An {@link Optional} containing {@link Instant} at which the event was processed, or
     * {@link Optional}::empty if it has not.
     */
    public Optional getProcessingTime() {
        return processingId.map(TimeUUID::getInstant);
    }

    /**
     * Get the {@link AggregateId} of the aggregate to which this event occurred.
     * @return The {@link AggregateId} of the aggregate to which this event occurred.
     */
    public AggregateId getAggregateId() {
        return aggregateId;
    }

    /**
     * Get the {@link StreamTimestamp} of the time at which this event occurred.
     * @return The {@link StreamTimestamp} of the time at which this event occurred.
     */
    public StreamTimestamp getEventTimestamp() {
        return eventTimestamp;
    }

    /**
     * Get the processing ID of this event (if it has been processed).
     * @return An {@link Optional} containing the event's processing {@link UUID} if it has been processed, or
     * {@link Optional}::empty if it has not.
     */
    public Optional getProcessingId() {
        return processingId;
    }

    /**
     * Get the {@link VersionedName} of the event.
     * @return The {@link VersionedName} of the event
     */
    public VersionedName getEventName() {
        return eventName;
    }

    /**
     * Get the event's parameters.
     * @return The event's parameters, encoded as a {@link Tuple}.
     */
    public Tuple getParameters() {
        return parameters;
    }

    /**
     * Get the event's characteristics.
     * @return The event's characteristics, encoded as an {@link int} bitfield.
     */
    public int getCharacteristics() {
        return characteristics;
    }

    /**
     * Test whether the event has the given characteristic.
     * @param characteristic The characteristic to test for.
     * @return True if the event has the given characteristic, false otherwise.
     */
    public boolean hasCharacteristic(int characteristic) {
        return (characteristics & characteristic) > 0;
    }

    @Override
    public boolean equals(Object o) {
        return this == o || (o instanceof Event && equals(Event.class.cast(o)));
    }

    private boolean equals(Event o) {
        return aggregateId.equals(o.aggregateId)
                && eventTimestamp.equals(o.eventTimestamp)
                && processingId.equals(o.processingId)
                && eventName.equals(o.eventName)
                && parameters.equals(o.parameters)
                && characteristics == o.characteristics;
    }

    @Override
    public int hashCode() {
        return Objects.hash(aggregateId, eventTimestamp, processingId, eventName, parameters, characteristics);
    }

    @Override
    public String toString() {
        return getProcessingTime().map(processingTime ->
                String.format("%s %s\nat %s\nwith %s\nprocessed at %s",
                        aggregateId, eventName, eventTimestamp, parameters, processingTime))
                .orElseGet(() -> String.format("%s %s\nat %s\nwith %s",
                        aggregateId, eventName, eventTimestamp, parameters));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy