Package com.xebia.cqrs.eventstore.inmemory

Source Code of com.xebia.cqrs.eventstore.inmemory.InMemoryEventStore$VersionedEvent

package com.xebia.cqrs.eventstore.inmemory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.OptimisticLockingFailureException;

import com.xebia.cqrs.eventstore.EventSink;
import com.xebia.cqrs.eventstore.EventSource;
import com.xebia.cqrs.eventstore.EventStore;

/**
* Stores and tracks ordered streams of events.
*/
public class InMemoryEventStore<E> implements EventStore<E> {
   
    public Map<UUID, EventStream<E>> eventStreams = new HashMap<UUID, EventStream<E>>();
   
    public void createEventStream(UUID streamId, EventSource<E> source) {
        if (eventStreams.containsKey(streamId)) {
            throw new DataIntegrityViolationException("stream already exists " + streamId);
        }
        eventStreams.put(streamId, new EventStream<E>(source.getType(), source.getVersion(), source.getTimestamp(), source.getEvents()));
    }
   
    public void storeEventsIntoStream(UUID streamId, long expectedVersion, EventSource<E> source) {
        EventStream<E> stream = getStream(streamId);
        if (stream.getVersion() != expectedVersion) {
            throw new OptimisticLockingFailureException("stream " + streamId + ", actual version: " + stream.getVersion() + ", expected version: " + expectedVersion);
        }
        stream.setVersion(source.getVersion());
        stream.setTimestamp(source.getTimestamp());
        stream.addEvents(source.getEvents());
    }

    public void loadEventsFromLatestStreamVersion(UUID streamId, EventSink<E> sink) {
        EventStream<E> stream = getStream(streamId);
        sink.setType(stream.getType());
        stream.sendEventsAtVersionToSink(stream.getVersion(), sink);
    }
   
    public void loadEventsFromExpectedStreamVersion(UUID streamId, long expectedVersion, EventSink<E> sink) {
        EventStream<E> stream = getStream(streamId);
        if (stream.getVersion() != expectedVersion) {
            throw new OptimisticLockingFailureException("stream " + streamId + ", actual version: " + stream.getVersion() + ", expected version: " + expectedVersion);
        }
        sink.setType(stream.getType());
        stream.sendEventsAtVersionToSink(stream.getVersion(), sink);
    }
   
    public void loadEventsFromStreamUptoVersion(UUID streamId, long version, EventSink<E> sink) {
        EventStream<E> stream = getStream(streamId);
        sink.setType(stream.getType());

        long actualVersion = Math.min(stream.getVersion(), version);
        stream.sendEventsAtVersionToSink(actualVersion, sink);
    }
   
    public void loadEventsFromStreamUptoTimestamp(UUID streamId, long timestamp, EventSink<E> sink) {
        EventStream<E> stream = getStream(streamId);
        sink.setType(stream.getType());

        long actualTimestamp = Math.min(stream.getTimestamp(), timestamp);
        stream.sendEventsAtTimestampToSink(actualTimestamp, sink);
    }

    public EventStream<E> getStream(UUID streamId) {
        EventStream<E> stream = eventStreams.get(streamId);
        if (stream == null) {
            throw new EmptyResultDataAccessException("unknown event stream " + streamId, 1);
        }
        return stream;
    }
   
    private static class VersionedEvent<E> {
        private final long version;
        private final long timestamp;
        private final E event;

        public VersionedEvent(long version, long timestamp, E event) {
            this.version = version;
            this.timestamp = timestamp;
            this.event = event;
        }
       
        public long getVersion() {
            return version;
        }
       
        public long getTimestamp() {
            return timestamp;
        }
       
        public E getEvent() {
            return event;
        }
    }
   
    public static class EventStream<E> {
        private final String type;
        private long version;
        private long timestamp;
        private final List<VersionedEvent<E>> events = new ArrayList<VersionedEvent<E>>();
       
        public EventStream(String type, long version, long timestamp, Iterable<? extends E> initialEvents) {
            this.type = type;
            this.version = version;
            this.timestamp = timestamp;
            addEvents(initialEvents);
        }

        public void sendEventsAtVersionToSink(long version, EventSink<E> sink) {
            List<E> result = new ArrayList<E>();
            VersionedEvent<E> lastEvent = null;
            for (VersionedEvent<E> event : events) {
                if (event.getVersion() > version) {
                    break;
                }
                lastEvent = event;
                result.add(event.getEvent());
            }

            sendEventsToSink(result, lastEvent, sink);
        }

        public void sendEventsAtTimestampToSink(long timestamp, EventSink<E> sink) {
            List<E> result = new ArrayList<E>();
            VersionedEvent<E> lastEvent = null;
            for (VersionedEvent<E> event : events) {
                if (event.getTimestamp() > timestamp) {
                    break;
                }
                lastEvent = event;
                result.add(event.getEvent());
            }
           
            sendEventsToSink(result, lastEvent, sink);
        }

        private void sendEventsToSink(List<E> events, VersionedEvent<E> lastEvent, EventSink<E> sink) {
            if (lastEvent == null) {
                throw new EmptyResultDataAccessException("no event found for specified version or timestamp", 1);
            }
            sink.setVersion(lastEvent.getVersion());
            sink.setTimestamp(lastEvent.getTimestamp());
            sink.setEvents(events);
        }

        public String getType() {
            return type;
        }

        public long getVersion() {
            return version;
        }

        public void setVersion(long version) {
            if (this.version > version) {
                throw new IllegalArgumentException("version cannot decrease");
            }
            this.version = version;
        }
       
        public long getTimestamp() {
            return timestamp;
        }
       
        public void setTimestamp(long timestamp) {
            if (this.timestamp > timestamp) {
                throw new IllegalArgumentException("timestamp cannot decrease");
            }
            this.timestamp = timestamp;
        }

        public void addEvents(Iterable<? extends E> eventsToAdd) {
            for (E event : eventsToAdd) {
                this.events.add(new VersionedEvent<E>(this.version, this.timestamp, event));
            }
        }

    }

}
TOP

Related Classes of com.xebia.cqrs.eventstore.inmemory.InMemoryEventStore$VersionedEvent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.