Monday, December 12, 2011

Alternative implementation in JEE

The main goal of DDD-CQRS Leaven Project was to present some concepts of system architecture together with domain modeling. In order to avoid high entry threshold, project leaders decided to create one maven project and implement with well-known Spring framework. The JEE-based implementation emerged as an idea of providing that Spring is only a supporting framework that can be easily replaced by any other. This would make the leaven even strong and convincing. During development of the JEE-branch I ran into some interesting challenges, some of them are still unresolved. Here's a summary of what has been achieved so far.

CQRS


Command Handlers

The Spring-based HandlersProvider was based on the BeanFactory which is being processed during context refresh. In this process the BeanFactory is scanned for any implementation of CommandHandler interface. Next, these definitions are stored in a registry to map command to handler bean name. CDIHandlersProvider does exactly the same but using the CDI BeanManager. I could not find any reasonable substitute for the 'context refresh' event handler, hence whole process is initialized in the @PostConstruct method.

All the command handlers were adnotated with custom @CommandHandlerAnnotation and here I met the first obstacle. In the original implementation, this annotation has following definition:
 @Component  
 @Transactional   
 @Retention(RetentionPolicy.RUNTIME)  
 @Target(ElementType.TYPE)  
 public @interface CommandHandlerAnnotation {  
 }  
I wanted to add @Stateless in order to make all annotated command handlers transactional EJBs. That doesn't work, because EJB specification allows putting this annotation on classes only. Similar problem with @Named. The only quick solution was just adding additional annotations to command handlers and polluting them with framework-related stuff. If you know any workaround (excpt xml deployment descriptors) don't hasitate to share.

Finders

In original solution finders were implemented using JPQL (JpaOrderFinder) or JDBC (SqlProductFinder). First approach is fine since it uses a part of JEE, the second one had to be removed due to its coupling with Spring's NamedParameterJdbcOperations. I decidded to rewrite it with Jpql to keep it simple and consistent, but there is absolutely nothing wrong in writing pure SQL-based implementation even if it's strongly related to particular DB engine. For many purposes such solution is even a better choice. This subject is well covered by the CQRS Query Tier philosophy.
If this branch becomes more stable and the database will stay unchanged, I will try to rewrite the product finder with Native SQL.

Events Engine

When I first started to prepare the events engine, I was really glad that JEE6 offered cool and simple API to deal with such matters. If you're not familiar with it, let me give a quick example:
 @Inject  
 private Event<SomeDomainEvent> event;  
 public void doSomeBusiness()  
 {  
      // business code here  
      event.fire(new SomeDomainEvent(someArguments));  
 }  
In some other bean:
 public void handle(@Observes SomeDomainEvent event)  
 {  
      // reaction  
 }  
This is all, fire and forget. Of course, there are some additional mechanisms, for example possibility of adding qualifiers, but I do not want to cover it all here. Just google "cdi events" and you will find plenty of tutorials. Now, if we want to cover this engine with one common EventPublisher implementation, we will end up discovering that this framework is just not sufficient for our needs. There is no possibility to create one dispatcher that receiver any (undefined) kind of event and multiple concrete listeners. After many experiments with tricks like on this thread, I decided to give up and implement the engine just like with the HandlersProvider. As a result we have three classes:
CDIEventsInitializer: Scans the CDI BeansManager and registers listeners (as names) for events basing on annotations
CDIEventHandler: A wrapper class for instantiating appropriate real handler from the BeanManager
CDIEventPublisher: implementation of ApplicationEventPublisher and DomainEventPublisher that orchestrates handling.
As you can see, nothing new here, just the same idea as in Spring-based implementation rewritten with the BeanManager. Solution re-uses current @EventListener and @EventListeners annotations without adding anything to existing code. Asynchronous event handling is not yet available, but it should not be difficult, probably we could use the EJB 3.1 @Asynchronous annotation.

DDD

Repositories

Due to some experimental purposes the repositories were somewhat modified, but in fact there should be no need to do that. I will try to revert changes in order to bring all the JPA-based repos back to their initial form. To achieve JTA without Spring I added OpenJPA + Derby initialized by TestDBInitializer. There were some problems with Embedded in-memory database, so instead a standard network server was used (data is wiped on startup, refer to persistence.xml).

Sagas

Since no changes were needed in event handling API, the SimpleSagaEngine could be left untouched as well. The only thing to do was writing new SagaRegistry implementation, the... yes, CDISagaRegistry. Again, if you take a closer look you will see that it is almost a copy of SpringSagaRegistry using BeanManager instead of BeanFactory.

Integration Tests

I must admit that it was my first experiment with Arquillian. I had to learn how to set it up quickly due to very limited free time, so correct me if I made some dumb mistakes in my tests. This runner combined with Glassfish-embedded lets us create a fully functionable JEE sandbox environment where we can deploy our tests and run them automatically. Four tests were prepared:
ProductOrderingIT: Known as ProductsOrderingFunctionalTest in trunk
SagaIT: Known as SagaIntegrationTest in trunk
JpqlProductFinderIT: Tests different criterias of the finder against some test data
CDIEventsIT: Tests if the CDI Event dispatching/handling engine works as expected
Let me explain a few details about test names. An integration test verifies some scenario in environment of collaborating objects. Sometimes it checks whole flow between layers, soetimes only cooperation of few elements (like the CDIEventsIT). Another thing is an end-to-end test. Its scope is wider, it verifies application behavior simulating actions of end-users (for example with Selenium). This subject will be explored later after I finish some work with the UI.
The Arquillian runner is an interesting tool that certainly adds a lot of comfort, but there are two disadvantages worth mentioning:
1. The Glassfish-embedded server startup time is significant. If you want to run your test many times with continous refactoring and checking, it's probably slower than deploying the Spring solution on jetty.
2. Deployment must be described by list of classes or packages. I could not find an easy method to deploy "just the whole thing", so I was forced to redeploy many many times before my tests stopped showing the ClassNotFoundException. If you have a tip how to do it (there must be a way...), please let me know.

User Interface

I am not a big fan of tinkering with presentation, styles and all that stuff. With JSF 2.0 + JRebel creating UI is pretty simple and painless. First I spent some time struggling with Resin just to discover that its own JSF implementation is not supported by JRebel. Everything works fine on Glassfish 3.1 Web Profile, so currently I am developing the view layer. You can see first effects committed in the repository, but please remember that it's still just a draft.

Coming next

After finishing the application will be re-integrated with JBehave without using Spring. Simultaneously I am thinging about how to decouple @Named and @Stateless bean definitions from classes. As I mentioned before on the discussion board, it is hard to imagine how this branch can be merged into trunk to keep one project and still maintain its simplicity. Probably it will just stay as a fork in a role of proof of concept.
Last thing to complete is preparing other entry points for the application: remote, web services, maybe REST? Anyway these subjects are a little bit beyond proving flexibility of framework running the CQRS/DDD architecture of the Leaven.

Summary

The main concepts of DDD and CQRS are not related to particular technology and we can implement them with different frameworks without messing with API and domain model. You could leverage the Leaven as a base for your new project with your favourite toolset and environment. Comparing the Spring-based trunk and the JEE fork can help to understand boundaries between mental model, patterns and technical details. Feel free to dig in, any comments are most welcome.

2 comments:

  1. I've being aiming to write this comment ever since but never had always something distracted me. I have a tip regarding this part: "Deployment must be described by list of classes or packages. I could not find an easy method to deploy "just the whole thing", so I was forced to redeploy many many times before my tests stopped showing the ClassNotFoundException. If you have a tip how to do it (there must be a way...), please let me know."

    So, I've been testing quite a lot with OpenEJB and they have a nice 'scan the classpath and include everything' feature. I most of the cases, it's far more convenient to be picky about classes you include in the test, but "get the whole thing" is required as well. I was aiming to extract that piece of code, but David Blevins (founder of OpenEJB) did that on his own and here it is: https://gist.github.com/2880038 -> "annotation scanning code used in Apache TomEE cleaned up and as a potential commons project and independently reusable library"

    Hope that helps

    ReplyDelete
    Replies
    1. Thanks for info. Krzysiek will investigate and hopefully incorporate solution:)

      Delete