Trifork Blog

Tutorial – Getting started with CQRS and Axon Framework

November 12th, 2010 by
|

Axon Framework greatly simplifies building CQRS based Event Driven architectures in Java. Such an architecture provides very powerful options in terms of application scalability and extensibility. In this tutorial, I want to go though the process of setting up a basic application architecture with the Axon Framework.

Building a foundation for your application can be divided in roughly four steps. First, we need to set up the project infrastructure. Which modules to we need? Which dependencies? The second step is to define the core API. What do we want our application to do? How can we tell it to do those things? This is when the definition of the commands and events is made. Building the command handling component, the one that consumes commands and produces events, is the third step. Lastly, in step four, the query component is build that turns events into a queryable data source for your application’s client.

Although this tutorial explains the process in a serial fashion, once you have done step 2, the definition of the core API, one team could work on the command handling component, while another team works on the query component.

In this tutorial, I will focus on the backend development. There is nothing special going on in the UI, other than that it will need to send commands and call a “service layer” to execute queries.

If you’re getting stuck somewhere, or just want to take the easy route through this tutorial, you can download the sources at: http://axonframework.googlecode.com/files/axon_tutorial.zip

Step 1 – Project infrastructure

Before we can get started, we need to set up a basic project infrastructure. You can do this in any IDE and using any dependency management system you like to use, albeit maven, ant or just plain manual labor.

To keep things, simple, we can use a single java source directory (src/main/java when using Maven). Inside we’ll create a few packages that make it clear in which “module” we are working. In a real project, you’d probably want to separate these packages over multiple modules/jar files.

Let’s assume we are building an order management system for the Acme company. You need the following packages to get started:

  • com.acme.oms.api – will contain the API classes (i.e. commands and events)
  • com.acme.oms.commandhandling – contains the command handling classes
  • com.acme.oms.query – contains the event handlers and query API

You also need the following dependencies:

  • org.axonframework:axon-core 0.7 (since 0.7 wasn’t released yet at the time of writing, 0.7-SNAPSHOT was the version used in this tutorial)
  • org.springframework:spring-context 3.0.5.RELEASE

If you need database support, you’ll also need to add dependencies to spring-orm, hibernate-entitymanager and your database driver.

For logging (this tutorial uses log4j):

  • org.slf4j:slf4j-log4j 1.5.8
  • org.slf4j:slf4j-log4j12 1.5.8
  • org.slf4j:jcl-over-slf4j 1.5.8

And for testing:

  • junit:junit 4.8.1
  • org.axonframework:axon-test 0.7

Configuring these dependencies using Maven is the easiest way to also get the transitive dependencies.

You application will also need a spring application context, which glues all infrastructure components together. What we need for now is some persistence configuration, and two infrastructure items Axon provides: the command bus and the event bus. Here is some contents of the application context

<!-- Automatically find any command and event handlers in our application -->
    <ctx:component-scan base-package="com.acme.oms.commandhandling" />
    <ctx:component-scan base-package="com.acme.oms.query" />

    <!-- Axon infrastructure -->
    <axon:annotation-config />
    <axon:event-bus id="eventBus" />
    <axon:command-bus id="commandBus" />

Step 2 – Your application’s core API

In this tutorial, we’re going to keep it simple. The Acme company has a rather simplistic view on order management. The system should be allows to create orders. An order always contains a single product. Orders can be cancelled, and confirmed. Once an order is cancelled, it can no longer be confirmed.

To build our API, we should focus on the activity of our application. What can we do, and what can happen?

In this application, we can do three things, which leads us to the following commands:

  • CreateOrderCommand
  • ConfirmOrderCommand
  • CancelOrderCommand

Notice that all command are in the imperative tense. That’s because we’re telling the system to do something. Commands should be clear about what the user expects. Here is the code for one of the commands:

public class CreateOrderCommand {

    private final String orderId;
    private final String productId;

    public CreateOrderCommand(String orderId, String productId) {
        this.orderId = orderId;
        this.productId = productId;
    }

    public String getOrderId() {
        return orderId;
    }

    public String getProductId() {
        return productId;
    }
}

Note that the identifier of the order to create is included in the command. Client-provided identifiers are a powerful way to improve (perceived) performance in a client. A client sending this command does not need to wait for the server to return an identifier. All it needs is the confidence that the server will execute the command. Sometime…

Since our application is straightforward, the each event simply maps to one of the commands. Be aware that not every system allows such a simplistic approach. Listen carefully to your domain expert for hints of events.

  • OrderCreatedEvent
  • OrderConfirmedEvent
  • OrderCancelledEvent

Since all these events come from the “Order” concept, let’s create an abstract parent event called AbstractOrderEvent. Here is some code of the abstract event and one of its implementations:

import org.axonframework.domain.DomainEvent;

public abstract class AbstractOrderEvent extends DomainEvent {
    public String getOrderId() {
        return getAggregateIdentifier().asString();
    }
}
public class OrderCreatedEvent extends AbstractOrderEvent {

    private final String productId;

    public OrderCreatedEvent(String productId) {
        this.productId = productId;
    }

    public String getProductId() {
        return productId;
    }
}

The other events are quite similar. Note that the aggregate identifier in Axon’s DomainEvent class contains the ID of the aggregate that published the event. In our case, that’s the Order. So we don’t need to add the order ID to our own event definitions. To make things more explicit, the AbstractOrderEvent contains a getOrderId(), which exposes this aggregate identifier using our own domain language.

Step 3 – Command Handling component

Now that we have our API, we can start building the command handling component. Well, if we really want to do it the right way, we can’t. First, we should build our tests. For our command handling component, we’re going to use an event sourced aggregate, which makes things really easy to test.

We have a few cases to test. When we send a CreateOrderCommand, we expect an order to be created. When we confirm an order, well, if we haven’t cancelled it, we expect it to be confirmed. If it has been cancelled, we expect nothing to happen.

Lets translate this to given-when-then tests in Axon. First, we need to set up the test fixture in the setUp (or @Before) method of a JUnit test. The empty shells of the necessary production classes can be created “on the fly”.

public class OrderCommandHandlerTest {

    private FixtureConfiguration fixture;

    @Before
    public void setUp() throws Exception {
        fixture = Fixtures.newGivenWhenThenFixture();
        OrderCommandHandler commandHandler = new OrderCommandHandler();
        commandHandler.setOrderRepository(fixture.createGenericRepository(Order.class));
        fixture.registerAnnotatedCommandHandler(commandHandler);
    }
}

We have injected a GenericRepository in our command handler. This allows the command handler to retrieve the correct domain object (an Order).

Creating test cases is pretty straightforward from here. The special cases of the confirmed order can be written as follows:

@Test
public void testConfirmOrder_Open() {
    fixture.given(new OrderCreatedEvent("Chair1"))
            .when(new ConfirmOrderCommand(fixture.getAggregateIdentifier().asString()))
            .expectEvents(new OrderConfirmedEvent());
}

@Test
public void testConfirmOrder_WasAlreadyCancelled() {
    fixture.given(new OrderCreatedEvent("Chair1"), new OrderCancelledEvent())
            .when(new ConfirmOrderCommand(fixture.getAggregateIdentifier().asString()))
            .expectEvents();
}

When you run these tests, they will fail: The aggregate [Order] does not have a suitable constructor. But just before we move to the Order aggregate, let’s fix the OrderCommandHandler. We need to be able to inject a Repository<Order> in it. Let’s create a field and a setter to inject them.

Next, we need a method to accept each type of command. Each of these three methods needs to be annotated with @CommandHandler, to tell Axon it should receive commands. Here is some code for two of the command handlers (the third is quite similar to the second one):

@CommandHandler
public void createOrder(CreateOrderCommand command) {
    orderRepository.add(new Order(command.getOrderId(), command.getProductId()));
}

@CommandHandler
public void confirmOrder(ConfirmOrderCommand command) {
    Order order = orderRepository.load(new StringAggregateIdentifier(command.getOrderId()));
    order.confirm();
}

Note that we don’t need to do any “save” or “commit” operation on the repository. Axon takes care of that for you. In this example, the commands return the orderId as a String, which is wrapped in a StringAggregateIdentifier. You could also pass around the AggregateIdentifier instance itself. Whatever you like most.

Now we’re ready to go to the core of the command handling component: the Order aggregate. Since we’ve decided to use event sourcing, we need to create an Order class and make it extend AbstractAnnotatedAggregateRoot.

Let’s start with the constructor. It should do two things: call the super constructor with an explicit aggregate identifier to force our own identifier on the instance, and initialize the Order’s status to “Open”.

Here is what the constructor would look like:

public Order(String orderId, String productId) {
    super(new StringAggregateIdentifier(orderId));
    this.status = Status.OPEN; // just an enum with OPEN, CANCELLED and CONFIRMED
}

But that’s not really event sourcing! State changes should be the result of an event. In Axon, it’s easy to convert this constructor to a truly event sourced one. Here’s how:

public Order(String orderId, String productId) {
    super(new StringAggregateIdentifier(orderId));
    apply(new OrderCreatedEvent(productId));
}

@EventHandler
private void onCreate(OrderCreatedEvent event) {
    status = Status.OPEN;
    productId = event.getProductId();
}

The apply method will record the event and keep it prepared for publishing, but also invokes the correct event handler method inside the aggregate itself. The latter is reponsible for applying the actual state changes involved with the creation of a new Order.

The code for confirming an order is build up in a similar fashion. The confirm() method does the validation, the event handler does the state changes

public void confirm() {
// we can only confirm an open order.
    if (status == Status.OPEN) {
        apply(new OrderConfirmedEvent());
    }
}

@EventHandler
private void onConfirm(OrderConfirmedEvent event) {
    status = Status.CONFIRMED;
}

We’re almost done. If you run the test, you’ll notice that the error still appears. That’s because Axon’s Generic repository expects the aggregate to have a special constructor: one that only accepts an AggregateIdentifier. So, just add that constructor and simply make it call the superconstructor with the same parameters. Now run the tests again. They should all pass.

Everything works in the test fixture. But to get things working in production too, you need to add the @Component annotation (by Spring) to your command handler and add two beans to your Spring application context:

<axon:event-sourcing-repository id="orderRepository" aggregate-type="com.acme.oms.commandhandling.Order" />
<axon:jpa-event-store id="eventStore" />

Step 4 – Query component

In the tutorial, let’s keep the event query component simple. Let’s “write” all the events to the System.out first. I assume that you know how to insert data into a database and read it back out.

The most important component in the query component is the event handlers. With Axon, creating a query component is really simple. Just create a class, make it a Spring bean by adding the @Component annotation and add methods that handle events.

Here is example:

@Component
public class OrderEventHandler {

    @EventHandler
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println(String.format("An order is created: [%s] for product: [%s]",
                                         event.getOrderId(),
                                         event.getProductId()));
    }

    @EventHandler
    public void handleOrderCancelled(OrderCancelledEvent event) {
        System.out.println(String.format("An order is cancelled: [%s]", event.getOrderId()));
    }

    @EventHandler
    public void handleOrderConfirmed(OrderConfirmedEvent event) {
        System.out.println(String.format("An order is confirmed: [%s]", event.getOrderId()));
    }
}

That’s it! Axon’s annotation config together with Spring’s classpath scanning will automatically find this class and register it with the event bus as an event listener. Just create a simple Runner class with a main method to start the Spring context and fire some commands at the command bus. Or, just download the tutorial code and run the Runner class.

Conclusion

It is some wiring to get started. But once that’s all in place you’re good to go for quite a while. Adding command handlers or event handlers is just a matter of creating a class and annotating the methods on them.

To find out more about the Axon Framework, visit www.axonframework.org. From there, you can download the binaries and documentation in case you need some help on the advanced topics.

Enjoy.

5 Responses

  1. January 24, 2013 at 10:49 by Viswanath

    Thanks for the tutorial. I am unable to download the source code from the location
    http://axonframework.googlecode.com/files/axon_tutorial.zip that’s pointed in this blog entry. Can you please let me know how I can get hold of it?

  2. November 13, 2013 at 14:10 by Adrian

    Sorry, I don’t understand what “load” and “add” repository methods do ? Something like “read” and “save” ?
    Thank you

  3. October 17, 2014 at 03:06 by Naresh

    this example looks simple and easy to understand for the beginners, is there any way you can publish this code somewhere ..?

  4. April 9, 2015 at 12:26 by atao60

    The code is the quite the same as the code of oms-core from https://code.google.com/p/study-axon-vaadin/.

    I just put in line an updated version (the “legacy” one) and also enhanced projects with Vaadin 7 and Xtend: https://github.com/atao60/study-axon-vaadin