Skip to content

ApplicationService

Layer 1: Domain events · Added in 0.2.0 · Modules: occurrent-application-service-blocking

Occurrent provides a generic application service that is a good starting point for most use cases. First add the module as a dependency to your project:

<dependency>
<groupId>org.occurrent</groupId>
<artifactId>occurrent-application-service-blocking</artifactId>
<version>0.34.0</version>
</dependency>

This module provides an interface, org.occurrent.application.service.blocking.ApplicationService, and a default implementation, org.occurrent.application.service.blocking.generic.GenericApplicationService. The GenericApplicationService takes an EventStore and a org.occurrent.application.converter.CloudEventConverter implementation as parameters. The latter is used to convert domain events to and from cloud events when loaded/written to the event store. There’s a default implementation that you may decide to use called, org.occurrent.application.converter.implementation.GenericCloudEventConverter available in the org.occurrent:occurrent-cloudevent-converter-generic module. You can see an example in the next section.

As of version 0.11.0, the GenericApplicationService also takes a RetryStrategy as an optional third parameter.
By default, the retry strategy uses exponential backoff starting with 100 ms and progressively go up to max 2 seconds wait time between each retry, if a WriteConditionNotFulfilledException is caught (see write condition docs). It will, again by default, only retry 5 times before giving up, rethrowing the original exception. You can override the default strategy by calling new GenericApplicationService(eventStore, cloudEventConverter, retryStrategy). Use new GenericApplicationService(eventStore, cloudEventConverter, RetryStrategy.none()) to disable retry. This is also useful if you want to use another retry library.

That retry runs wherever execute runs, so if you wrap the call in your own @Transactional it retries inside your transaction, where it cannot succeed. See Retry and Transactions.

Now you can instantiate the (blocking) GenericApplicationService:

EventStore eventStore = ..
CloudEventConverter<DomainEvent> cloudEventConverter = ..
ApplicationService<DomainEvent> applicationService = new GenericApplicationService<>(eventStore, cloudEventConverter);

You’re now ready to use the generic application service in your application.

As an example let’s say you have a domain model with a method defined like this:

public class WordGuessingGame {
public static List<DomainEvent> guessWord(List<DomainEvent> events, String guess) {
// Implementation
}
}

You can call it using the application service:

applicationService.execute(gameId, events -> WordGuessingGame.guessWord(events, guess));

For more control over a call, for example to read only some of the events in the stream or to run a side effect after the write, pass ExecuteOptions. The next sections describe both.

org.occurrent.application.service.blocking.ExecuteOptions configures a single execute call. It says which events to read before your domain function runs, which synchronous side effects to run after a successful write, or both:

WriteResult result = applicationService.execute(
gameId,
ExecuteOptions.<DomainEvent>options()
.filter(ExecuteFilter.type(GameWasStarted.class)),
events -> WordGuessingGame.guessWord(events, guess)
);

The typed filter resolves the event class to its cloud event type using the application service’s configured type mapper, so it keeps working even if you map event types to custom names. You can still pass a raw StreamReadFilter to filter(...) when you want to filter on an explicit type string or on other attributes.

Filtering is a read optimization, not a correctness feature. Don’t filter away events that are needed to enforce invariants, rebuild state correctly, or make valid domain decisions. If the command depends on the whole stream, read the whole stream.

For which event stores support filtered reads, the filtering semantics, and examples that use the EventStore directly, see Stream Filtering.