Zest™
Introduction
Tutorials
Javadoc
Samples
Core
Libraries
Extensions
Tools
Glossary 

Event Sourcing

code

docs

tests

The Event Sourcing Library supports generating, storing and replaying two types of events: application-events and domain-events.

Application events are bound to Usecase and are produced by execution of specific methods (ones with ApplicationEvent as their first parameter). Each application event holds information about Usecase, method name and JSON serialized values of method parameters.

Domain events are bound to entity instances and are produced by execution of annotated (see @DomainEvent) methods that belongs to EntityComposite. Each domain event (see DomainEventValue) holds information about entity type, identity, method name and JSON serialized values of method parameters.

Both application and domain events are captured during UnitOfWork lifetime and are stored in EventStore after successfully completed UnitOfWork as collection together (see UnitOfWorkDomainEventsValue and TransactionApplicationEvents).

There is support for replaying events. When events are replayed the same code is executed but no new events are generated.

There are helper classes that enables a service to easily track events feed, and for domain events there is EventRouter that allow to specify specification→receiver routes.

Table 29. Artifact

Group IDArtifact IDVersion

org.qi4j.library

org.qi4j.library.eventsourcing

2.1


JDBM backed store

EventStore supports indexed and streamed access to events feed. There is in-memory and JDBM backed implementations.

code

docs

tests

Table 30. Artifact

Group IDArtifact IDVersion

org.qi4j.library

org.qi4j.library.eventsourcing-jdbm

2.1


REST access

For remote access to feed there is eventsourcing-rest library that exposes events as Atom feeds.

code

docs

tests

Table 31. Artifact

Group IDArtifact IDVersion

org.qi4j.library

org.qi4j.library.eventsourcing-rest

2.1


Application Events

Assembly is done as follows:

new EventsourcingAssembler()
        .withApplicationEvents()
        .withCurrentUserFromUOWPrincipal()
        .assemble(module);

Configure application events store:

module.services( MemoryApplicationEventStoreService.class );

Actual method on composite which execution emits application event. First parameter is null on "normal" execution. If it is not null, then the method call is a replay of previously created events.

@Mixins( Users.Mixin.class )
public interface Users extends TransientComposite
{
    void signup( @Optional ApplicationEvent evt, String username, List<String> mailinglists );

To enable execution capturing, you have to configure composite with concern:

module.transients( Users.class ).withConcerns( ApplicationEventCreationConcern.class );

Domain Events

Assembly:

new EventsourcingAssembler()
        .withDomainEvents()
        .withCurrentUserFromUOWPrincipal()
        .assemble(module);

Configure domain events store:

module.services( MemoryEventStoreService.class );

Annotate your entity state changing methods. Event methods may only change state. They may not fail or thrown exceptions:

@Mixins( TestEntity.Mixin.class )
public interface TestEntity
    extends EntityComposite
{
    @UseDefaults
    Property<String> description();

    @DomainEvent
    void changedDescription( String newName );

    abstract class Mixin
        implements TestEntity
    {
        public void changedDescription( String newName )
        {
            description().set( newName );
        }
    }
}

To enable method execution capturing, you have to configure entity with concern:

module.entities( TestEntity.class ).withConcerns(DomainEventCreationConcern.class);