com.eventsourcing.Command Maven / Gradle / Ivy
Show all versions of eventsourcing-core Show documentation
/**
* Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.eventsourcing;
import com.eventsourcing.events.CommandTerminatedExceptionally;
import com.eventsourcing.events.EventCausalityEstablished;
import com.eventsourcing.events.JavaExceptionOccurred;
import com.googlecode.cqengine.resultset.ResultSet;
import static com.eventsourcing.index.EntityQueryFactory.*;
/**
* Command is a request for changes in the domain. Unlike an event,
* it is not a statement of fact as it might be rejected.
*
* For example, ConfirmOrder command may or may not result in an
* OrderConfirmed event being produced.
*
* @param state type
* @param result type
*/
public interface Command extends Entity> {
/**
* Returns a stream of events that should be recorded. By default, an empty stream returned.
*
* This version of the function receives a {@link LockProvider} if one is needed. {@link Repository}
* will pass a special "tracking" provider that will release the locks in two situations:
*
*
* - {@link #events(Repository, LockProvider)} threw an exception
* - {@link #result(Object, Repository, LockProvider)} did not release any locks
*
*
* @param repository Configured repository
* @param lockProvider Lock provider
* @return stream of events
* @throws Exception if the command is to be rejected, an exception has to be thrown. In this case, no events will
* be recorded
*/
default EventStream events(Repository repository, LockProvider lockProvider) throws Exception {
return EventStream.empty();
}
/**
* Once all events are recorded, this callback will be invoked
*
* By default, it does nothing and it is meant to be overridden when necessary. For example,
* if upon the successful recording of events an email has to be sent, this is the place
* to do it.
*
* @return Result
*/
default R result(S state, Repository repository, LockProvider lockProvider) {
return null;
}
/**
* Figure out if the command has terminated exceptionally by testing the presence of an associated
* {@link CommandTerminatedExceptionally} event.
* @param repository
* @return true
if the command has terminated exceptionally
*/
default boolean hasTerminatedExceptionally(Repository repository) {
try (ResultSet> resultSet = repository
.query(CommandTerminatedExceptionally.class,
and(all(CommandTerminatedExceptionally.class),
existsIn(
repository.getIndexEngine().getIndexedCollection(EventCausalityEstablished.class),
CommandTerminatedExceptionally.ID, EventCausalityEstablished.EVENT)))) {
return resultSet.isNotEmpty();
}
}
/**
* Figure out the cause of command termination by searching for {@link JavaExceptionOccurred} events, associated
* with the commend.
* @param repository
* @return an instance of {@link JavaExceptionOccurred} or null
if none found
*/
default JavaExceptionOccurred exceptionalTerminationCause(Repository repository) {
try (ResultSet> resultSet = repository
.query(JavaExceptionOccurred.class,
and(all(JavaExceptionOccurred.class),
existsIn(
repository.getIndexEngine().getIndexedCollection(EventCausalityEstablished.class),
JavaExceptionOccurred.ID, EventCausalityEstablished.EVENT)))) {
if (resultSet.isEmpty()) {
return null;
}
return resultSet.uniqueResult().get();
}
}
}