package org.myeslib.hazelcast.storage;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.myeslib.util.EventSourcingMagicHelper.applyEventsOn;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.myeslib.core.AggregateRoot;
import org.myeslib.core.Event;
import org.myeslib.core.data.AggregateRootHistory;
import org.myeslib.core.data.Snapshot;
import org.myeslib.core.storage.SnapshotReader;
import com.google.common.base.Function;
public class HzSnapshotReader<K, A extends AggregateRoot> implements SnapshotReader<K, A> {
private final Map<K, AggregateRootHistory> aggregateRootHistoryMap ;
private final Map<K, Snapshot<A>> lastSnapshotMap ;
private final Function<Void, A> newInstanceFactory ;
@Inject
public HzSnapshotReader(Map<K, AggregateRootHistory> aggregateRootHistoryMap,
Map<K, Snapshot<A>> lastSnapshotMap,
Function<Void, A> newInstanceFactory) {
checkNotNull(aggregateRootHistoryMap);
checkNotNull(lastSnapshotMap);
this.aggregateRootHistoryMap = aggregateRootHistoryMap;
this.lastSnapshotMap = lastSnapshotMap;
this.newInstanceFactory = newInstanceFactory;
}
/*
* (non-Javadoc)
* @see org.myeslib.core.storage.SnapshotReader#get(java.lang.Object)
*/
public Snapshot<A> get(final K id) {
checkNotNull(id);
final A aggregateRootFreshInstance = newInstanceFactory.apply(null);
final AggregateRootHistory transactionHistory = getEventsOrEmptyIfNull(id);
final Long lastVersion = transactionHistory.getLastVersion();
final Snapshot<A> lastSnapshot = lastSnapshotMap.get(id);
final Snapshot<A> resultingSnapshot;
if (lastSnapshot==null){
resultingSnapshot = applyAllEventsOnFreshInstance(transactionHistory, aggregateRootFreshInstance);
} else {
if (lastSnapshot.getVersion() < lastVersion) {
resultingSnapshot = applyEventsSinceLastSnapshot(transactionHistory, lastSnapshot);
} else {
resultingSnapshot = lastSnapshot;
}
}
return resultingSnapshot;
}
private AggregateRootHistory getEventsOrEmptyIfNull(final K id) {
final AggregateRootHistory events = aggregateRootHistoryMap.get(id);
return events == null ? new AggregateRootHistory() : events;
}
private Snapshot<A> applyAllEventsOnFreshInstance(final AggregateRootHistory transactionHistory,
final A aggregateRootFreshInstance) {
final Long lastVersion = transactionHistory.getLastVersion();
final List<? extends Event> eventsToApply = transactionHistory.getEventsUntil(lastVersion);
applyEventsOn(eventsToApply, aggregateRootFreshInstance);
return new Snapshot<A>(aggregateRootFreshInstance, lastVersion);
}
private Snapshot<A> applyEventsSinceLastSnapshot(final AggregateRootHistory transactionHistory,
final Snapshot<A> lastSnapshot) {
final Long lastVersion = transactionHistory.getLastVersion();
final List<? extends Event> eventsToApply = transactionHistory.getEventsAfterUntil(lastSnapshot.getVersion(), lastVersion);
applyEventsOn(eventsToApply, lastSnapshot.getAggregateInstance());
return new Snapshot<A>(lastSnapshot.getAggregateInstance(), lastVersion);
}
}