He estado buscando una solución al mismo problema en Java EE desde hace un tiempo. Miré Axon y jdon (la página tampoco es un buen presagio :)). Ambos involucran Event Sourcing que no pude "vender" a mis empleadores/clientes. Quería tener Eventos de Dominio aunque ya me acostumbré mucho a ellos en proyectos .NET/C#. Así que se me ocurrió lo siguiente ...
Utilicé un objeto DomainEvents estático similar para darme acceso a un mecanismo de publicación sin que los detalles reales de la implementación se filtraran en todas las entidades modelo de mi dominio. Por lo que el pide algo como esto:
DomainEvents.fire(new MySampleEvent(...some params...));
Un patrón y el mecanismo que está disponible en la especificación CDI son la Events with @Observes que le permiten responder a ciertos eventos en los granos normales con todos los servicios disponibles. Eso es similar a lo que estaba acostumbrado al usar marcos DI como Castle Windsor donde podía registrar manipuladores genéricos por interfaz. Así que tengo a los observadores (manejadores, oyentes, como quieran llamarlos) cubiertos. Ejemplo:
@Stateless
public class MySampleEventObserver {
public void listen(@Observes MySampleEvent event) {
...
doSomethingWithEvent();
}
}
Ahora para la parte de publicación (activación en CDI). Como no hay forma de acceder a CDI en las entidades (¡con buenas razones!) Resolví usar JNDI y BeanManager. Usé JNDI para obtener BeanManager y usar su método fireEvent.Para poner gestor de beans de resolver (como seen here) en código:
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;
}
}
}
El paso final es la DomainEvents objeto en sí:
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);
}
}
Los setNopMode
y reset
piezas están ahí para propósitos de prueba cuando no hay contexto. Burla manual, básicamente. Configúrelo en modo de operación NOP antes de que la unidad lo pruebe y reinicie después de ellos.
Funciona bien como un POC. Sin embargo, no sé si existen limitaciones serias para su uso. Dejo las interacciones del bus asíncrono y de forma similar a la implementación de los oyentes.
Me encantaría cualquier comentario.
Gracias Stephen, eso está muy bien-- No sabía sobre la guayaba. Realmente estoy tratando de mantener mi dominio ignorante de los detalles de implementación, pero le daré una idea a Guava EventBus. Quizás podría envolver EventBus para ocultar la implementación de mi dominio ... – HolySamosa
Sí @HolySamosa - Voy a envolverlo cuando lo puse, pero mantener la interfaz simple 'register()' y 'post()' para eso. –
Supongo que solo vas a mantener la anotación Guava Subscribe en tu modelo de dominio? Me gusta la idea de usar una anotación para las suscripciones vinculantes, pero prefiero no permitir que un detalle de implementación se deslice en mi modelo de dominio agradable y limpio. – HolySamosa