I have been looking for a solution to the same problem in Java EE for a while. I looked at Axon and jdon (the page is actually not very good) :). Both include Event Sourcing, which I could not “sell” to my employers / clients. I wanted to have domain events, although I was very used to them in .NET / C # projects. So I came up with the following ...
I used a similar static DomainEvents object to give me access to the publishing engine without actual implementation data flowing through all the objects in the domain model. So it calls something like this:
DomainEvents.fire(new MySampleEvent(...some params...));
An example and mechanism available in the CDI specification are Events with @Observes , which allow you to respond to certain events in normal beans with all available services. This is similar to what I'm used to when I used DI frameworks like Castle Windsor , where I could register common handlers by interface. So, I have observers (handlers, listeners, everything you want to call them). Example:
@Stateless public class MySampleEventObserver { public void listen(@Observes MySampleEvent event) { ... doSomethingWithEvent(); } }
Now for publication (firing in CDI). Since there is no access to CDI in entities (with good reason!), I decided to use JNDI and BeanManager . I used JNDI to get the BeanManager and use its fireEvent . To place a bean manager solution (like here) in code:
public class BeanHelper { public static BeanManager getBeanManager() { try { InitialContext initialContext = new InitialContext(); return (BeanManager) initialContext.lookup("java:comp/BeanManager"); } catch (NamingException e) { e.printStackTrace(); return null; } }
}
The final step is the DomainEvents object itself:
public class DomainEvents { private static boolean mNopMode = false; public static void setNopMode() { mNopMode = true; } public static void reset() { mNopMode = false; } public static <TDomainEvent> void fire(TDomainEvent event) { if (mNopMode) { return; } BeanManager manager = BeanHelper.getBeanManager(); manager.fireEvent(event); }
}
Parts of setNopMode and reset exist for testing purposes when there is no context. Manual mocking basically. Set it to NOP mode before unit tests and reset after them.
Works great as a POC. I do not know if there are any serious restrictions for use. I leave asynchronous internetworking and similarly implement listeners.
Love any comments.