Since no existing event store for Java fits our needs and integrates well with Java EE, I decided to write our own implementation of an event store, which is straight-forward anyways.
As for the architecture of an event store, Jonathan Oliver’s NEventStore is extremely well designed. In principle, it is exactly what we were looking for — except that it is written in C#/.NET and not Java. NEventStore nevertheless served as an architectural template for our own Java event store, which you’ll surely notice when looking at the public API, see e.g. IStoreEvents.cs and EventStore.java.
At the same time, I did not want to reinvent the wheel. In particular, although NEventStore advertises itself as a persistence agnostic Event Store for .NET, there already is a persistence API that is agnostic to the underlying database in Java EE — JPA. While JPA might mean some performance overhead, it is the standard persistence technology provided by Java EE and therefore widely supported on the containers and databases. Additionally, authentication to the database server and other infrastructure concerns such as connection pooling can be configured directly in the container.
Another (minor) problem regards asynchronicity in the Java EE context: Java EE applications must not create or fiddle with their own threads as these interfere with the container’s resources. Anything that shall be run asynchronous must therefore be done with provided Java EE APIs. On the positive side, the container guarantees thread-safety of EJBs and automatically manages a pool of stateless beans, which can be configured by the server operator. In particular, when running multiple nodes in a cluster, the container can automatically route incoming requests between cluster nodes, i.e., we get horizontal scaling almost for free.
Finally, I wanted to keep the event store modular, such that one can easily exchange, say, the underlying persistence layer (e.g., from JPA to JDBC or some NoSQL store), change the serialization format or add caching layers. Implemented properly, the injection of resources and other EJB beans into the services can be configured by the developers or the server operators as needed. This opens the door for extreme modularity. For example, suppose the team would like to add a caching layer to the serialization engine, since they found that too much time is spent in this part of the application. Easy – simply add a caching decorator of the serialization engine and inject this decorator into the event store.
This brings us to the feature wish list I had in mind when designing JEEventStore:
Some of the modularity features I had in mind: