axon_logo.pngAllard has been working on a new framework to make it easier to create a CQRS application. CQRS is short for Command Query Responsibility Segregation. An architecture that separates data sources for storing state and querying data. The query datasource should be easy to use when creating screens. The framework Allard created is the Axon Framework. This framework makes it a lot easier to use commands, events, event sourcing. If these terms are not known to you, I suggest you start reading the reference manual that comes with axon.

grailslogo.pngWhat does grails do in this picture. Isn’t grails about rapid application creation? Well, yes. It is a good platform to rapidly create web applications using the groovy language and still be able to use existing libraries. Personally I really like the Gorm library of grails. I think that gorm would be an excellent choice to wrap the query datasource. Of course the gsp technology and the groovy language are nice to have when working with the web applications as well.

In this blog post I’ll discuss the integration between grails and axon. How can we create an application with grails that makes use of Axon to implement CQRS. I’ll discuss the way to create commands and send these to axon. I’ll also discuss responding to events coming from axon. First I have to show some aspects of a grails project that you need to know before you can use Axon. I’ll try to take you with me when I take the steps to create a good integration between Axon and Grails.


Sources

The sample I am using is the same sample that is provided by axon with a flex client. The AddressBook is used to show the different possibilities of axon and a client. You can create contacts, and register addresses of a certain type for contacts. You can register home, work and holiday addresses.

You can find the sources of the sample at github:

http://github.com/jettro/axon-addressbook-grails

Configure grails to use Axon

Grails has a pretty elegant way to configure libraries to be used by the project. You can make grails look for libraries in remote maven repositories as well as your local repository. I need to enable the local repository since I am working with a SNAPSHOT version of axon at the moment of writing.

Each normal grails project contains a folder grails-app/conf. In this folder is a file called BuildConfig.groovy. This file contains the build configuration, you did not see that one coming did you? In this file there is a closure called grails.project.dependency.resolution. Within this closure you can configure the repositories and the dependencies. As I said before you need to uncomment the mavenLocal() and add the following two lines to the dependencies.

compile 'org.axonframework:axon-core:0.5-SNAPSHOT'
runtime 'com.thoughtworks.xstream:xstream:1.3.1'

I did not get the grails project to work in a way that SNAPSHOT dependencies are updated. So if I compile a new version of axon, I manually delete the library in the grails cache. The libraries are stored in the ivy cache on your computer. In my case the jars are in the folder:

<user_home>/.ivy2/cache/org.axonframework/axon-core/jars/axon-core-0.5-SNAPSHOT.jar

Structure of the project

If you create a normal grails application you usually stick to the conventional project setup. Within the grails-app folder you have folders for domain classes, controllers, services, and others.

The domain model

When creating a CQRS application the domain becomes a different beast. It is the domain that commands act upon and the events are generated by the domain. For now let us call the domain from CQRS perspective the core-domain and the grails domain classes the query domain. The query domain resides in the normal grails location. Each grails project also contains a src folder with the groovy and java classes. This is where we will store the core domain.

A very important thing to stick in your brain is that the controllers must not use the standard way of grails to save domain objects. If you would do that, you only update the query database and no commands are created and send to the Axon backend.

Grails services and axon commands

We interact with axon by making use of command objects. To make this easy from the grails perspective we create a service class around the command creation. This makes it easier to create a transactional scope and to have just one location where we actually send data to axon. This service is more like a proxy to the Axon command bus.

Grails controllers

The controllers are normal grails controllers, they make use of services to send data to the backend and they use gorm to query the data.

Axon event listeners

The event listeners are used to receive updates about the core domain and reflect this in the query domain. The listeners make extensive use of gorm to update data in the query domain.

The following image gives you an idea about the directory layout of the project.

Screen shot 2010-04-06 at 18.48.39.png

Scaffolding

One of the nice options of grails to create applications very fast is to use scaffolding. When using axon this is still possible, but only to do the first steps very fast. I recommend creating your own views and controllers when you know what you want and you need to create better useable screens. You cannot use the scaffolding controllers. They would only use the query domain. We need to call the services from the controllers. I do generate the controllers and then adjust them to my needs.

To get an idea what I reused from the generated controllers, let us have a look at the changes I made to the generated controller methods. For now I did not change views, so they are still using the scaffolding versions. Beware that this is not a final solution. To give you an idea, registering an address for a contact means that you have to manually copy the uuid of the contact to the create new address screen. Of course I will change this as well, but that will be the topic of a next blog post.

As a rule of thumb, all methods that actually change data need to be altered.

def save = {
    def contactEntryInstance = new ContactEntry(params)
    if (contactEntryInstance.validate()) {
        def uuid = contactCommandHandlerService.createContact(contactEntryInstance.name)
        def foundContact = ContactEntry.findByIdentifier(uuid)

        flash.message = "${message(code: 'default.created.message', args: [message(code: 'contactEntry.label', default: 'ContactEntry'), foundContact.name])}"
        redirect(action: "show", id: foundContact.id)
    }
    else {
        render(view: "create", model: [contactEntryInstance: contactEntryInstance])
    }
}

Line 4 show that we use the service instead of the query domain object. In line 5 we do use the query domain object to find the created contact.

Configuring the event and command bus using grails and spring

Grails uses a lot of spring udner the hood. But they also give you a very easy way to use spring yourself as well. Grails comes with a special domain specific language for configuring spring. You can find the file resources.groovy in the grails-app/conf/spring folder. In this file we configure the event bus, the command bus, the event listener and the command handlers. The following code block shows the beans, it should be straightforward and not to hard to understand.

beans = {
    contactRepository(ContactRepository) {
        eventBus = ref("eventBus")
        eventStore = ref("eventStore")
    }

    contactEventListener(ContactEventListener, ref("eventBus"))

    createContactCommandHandler(CreateContactCommandHandler, ref("contactRepository"), ref("commandBus"))
    updateContactCommandHandler(UpdateContactCommandHandler, ref("contactRepository"), ref("commandBus"))
    removeContactCommandHandler(RemoveContactCommandHandler, ref("contactRepository"), ref("commandBus"))
    registerAddressCommandHandler(RegisterAddressCommandHandler, ref("contactRepository"), ref("commandBus"))

    // axon beans
    commandBus(SimpleCommandBus)

    eventBus(SimpleEventBus)

    eventStore(FileSystemEventStore, ref("xstreamSerializer")) {
        baseDir = "file:/Users/jcoenradie/temp/axonrepo"
    }

    xstreamSerializer(XStreamEventSerializer)
}

Creating a bean is easy, some of the beans are direct axon classes. The contactRepository, contactEventListener and all the command handlers are not. These are groovy classes that reside in the src directory.

Axon components in groovy

I am not going to write extensively about Axon. The website from Axon does a much better job. I do want to mention the most important components and show some of the groovy code to make it work.

Sending data using commands

The data send is in the command objects. The commandBus is used to dispatch the commands. Each command must have a registered command handler. Axon provided a special mechanism to use annotations to register handlers. For now I register the handlers manually. Let us have a look at the handler for contact creation. The spring configuration already shows that the handlers use the contactRepository as well as the commandBus.

class CreateContactCommandHandler implements CommandHandler<CreateContactCommand> {
    ContactRepository contactRepository

    def CreateContactCommandHandler(contactRepository, commandBus) {
        this.contactRepository = contactRepository;
        commandBus.subscribe(CreateContactCommand.class, this)
    }

    Object handle(CreateContactCommand command) {
        ContactAggregate contact = new ContactAggregate(command.newContactName)
        contactRepository.save contact
        return contact.identifier.toString()
    }
}

As you can see we need to implement the interface CommandHandler. In the constructor we subscribe the handler with the command bus. Now focus on the handle method. We create the contact aggregate and store it in the repository by calling the save method.

Core domain

Now the contact is created, but we also must update our query database. To understand what happens there, we must have a look at the core domain class. The following code block shows the constructor and that it applies an event for a contact being created.

    ContactAggregate(String name) {
        apply(new ContactCreatedEvent(name))
    }

Event listener

Now that we have the events, we want to listen for them and update our query database. When creating the event listener, we need to provide the eventBus. In the constructor of the listener we register the listener with the eventBus. The handle method receives the events. In this method we check if we support the provided event. If we support it, we call one of the available doHandle methods that make use of overloading to determine the right method. The following code block shows the handle method and two of the doHandle methods.

void handle(Event event) {
    println "Contact event listener recevied an event : ${event.class.simpleName}"
    if (event.class in [ContactCreatedEvent, ContactNameChangedEvent, ContactDeletedEvent, AddressAddedEvent]) {
        doHandle(event)
    } else {
        println "Event not supported"
    }
}

private void doHandle(ContactCreatedEvent event) {
    def contact = new ContactEntry(name: event.name, identifier: event.aggregateIdentifier.toString())
    contact.save()
}

private void doHandle(ContactNameChangedEvent event) {
    ContactEntry foundContact = ContactEntry.findByIdentifier(event.aggregateIdentifier.toString())
    foundContact.name = event.newName
    foundContact.save()
}

The ContactEntry is the query domain object. See how we query for an existing contact and how we store the new or updated contact in the query database.

Summary

That is about it for now. I have showed you some basic Axon components in groovy. I introduced you to the concept of a state datastore and a query datastore. Next to that I also told you about the commands. I did not tell you anything about the datastore used for storing the state. The sample makes use of the file based event sourcing datastore. Check the Axon documentation to find out more.

In the following blog posts I will improve the sample by making better screens and controllers. i will also talk more about the axon options. Try to use annotations to see if that makes the event listeners and the command handlers easier to understan.

Hope to see yo back.

Tagged on: