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

com.opencredo.concourse.domain.events.sourcing.EventReplayer Maven / Gradle / Ivy

package com.opencredo.concourse.domain.events.sourcing;

import com.opencredo.concourse.domain.events.Event;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Organises a collection of {@link Event}s for replaying or collection in the desired order.
 */
public final class EventReplayer {

    /**
     * Create an {@link EventReplayer} replaying the supplied {@link Event}s.
     * @param events The {@link Event}s to replay.
     * @return The constructed {@link EventReplayer}.
     */
    public static EventReplayer of(List events) {
        return new EventReplayer(events, List::stream, Optional.empty());
    }

    private final List events;
    private final Function, Stream> orderedStreamer;
    private final Optional> filter;

    private EventReplayer(List events, Function, Stream> orderedStreamer, Optional> filter) {
        this.events = events;
        this.orderedStreamer = orderedStreamer;
        this.filter = filter;
    }

    /**
     * Set the order to ascending.
     * @return An {@link EventReplayer} replaying events in time-ascending order.
     */
    public EventReplayer inAscendingOrder() {
        return new EventReplayer(events, this::reverseStream, filter);
    }

    /**
     * Set the order to ascending, sorted by the supplied {@link Comparator}.
     * @param comparator The {@link Comparator} comparator to use to sort events.
     * @return An {@link EventReplayer} replaying events in time-ascending order.
     */
    public EventReplayer inAscendingOrder(Comparator comparator) {
        return new EventReplayer(events, eventList -> reverseStream(eventList).sorted(comparator), filter);
    }

    /**
     * Set the order to descending.
     * @return An {@link EventReplayer} replaying events in time-descending order.
     */
    public EventReplayer inDescendingOrder() {
        return new EventReplayer(events, List::stream, filter);
    }

    /**
     * Set the order to descending, sorted by the supplied {@link Comparator}.
     * @param comparator The {@link Comparator} comparator to use to sort events.
     * @return An {@link EventReplayer} replaying events in time-descending order.
     */
    public EventReplayer inDescendingOrder(Comparator comparator) {
        return new EventReplayer(events, eventList -> eventList.stream().sorted(comparator.reversed()), filter);
    }

    private Stream reverseStream(List eventList) {
        return StreamSupport.stream(ReverseListSpliterator.over(eventList), false);
    }

    /**
     * Apply a filter to the events
     * @param predicate The {@link Predicate} to use to filter events.
     * @return An {@link EventReplayer} replaying events which match the filter.
     */
    public EventReplayer filter(Predicate predicate) {
        return new EventReplayer(events, orderedStreamer, Optional.of(predicate));
    }

    /**
     * Replay only the first {@link Event} in the sequence.
     * @param consumer The event consumer to replay the event to.
     */
    public void replayFirst(Consumer consumer) {
        stream().findFirst().ifPresent(consumer);
    }

    private Stream stream() {
        return filter.map(orderedStreamer.apply(events)::filter)
                .orElseGet(() -> orderedStreamer.apply(events));
    }

    /**
     * Replay all of the {@link Event}s in the sequence.
     * @param consumer The event consumer to replay the events to.
     */
    public void replayAll(Consumer consumer) {
        stream().forEach(consumer);
    }

    /**
     * Collect only the first {@link Event} in the sequence.
     * @param collector The collector to collect the event with.
     * @param  The type of value returned by the collector.
     * @return The collected value, or {@link Optional}::empty if the sequence is empty.
     */
    public  Optional collectFirst(Function, Consumer> collector) {
        AtomicReference ref = new AtomicReference<>();
        Consumer consumer = collector.apply(ref::set);
        replayFirst(consumer);
        return Optional.ofNullable(ref.get());
    }

    /**
     * Collect all of the {@link Event}s in the sequence.
     * @param collector The collector to collect the events with.
     * @param  The type of value returned by the collector.
     * @return The collected values.
     */
    public  List collectAll(Function, Consumer> collector) {
        List result = new ArrayList<>();
        Consumer consumer = collector.apply(result::add);
        replayAll(consumer);
        return result;
    }

    /**
     * Collect all of the {@link Event}s in the sequence into a {@link List}.
     * @return The collected events.
     */
    public List toList() {
        return stream().collect(Collectors.toList());
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy