Asynchronous event handling in CUBA

Asynchronous event handling in CUBA

Event handling in an asynchronous fashion oftentimes leads to an architecture that is more flexible and decoupled. In this article we will have a look at how to implement a CUBA application mostly communicating through messages.

The life before messages

To start with this whole topic, we can have a look at a sample application. We will use (once again) an ordermanagement application. A customer can have orders that might have order lines etc.

Let’s look at the following requirement:

“When a customer is created, a user account should get generated for this customer as well, so that the persons can have a look at their own orders”.

Another requirement might be

“When a customer is created, detailed information should be logged into a particular file that gets displayed on a monitor on the wall of the office”

The list might be continued, but we will leave it for now. The traditional approach in most applications (and in a CUBA app as well) is to have an implementation of the following kind:

public class CustomerServiceBean implements CustomerService {

    @Inject DataManager dataManager;
    @Inject UsermanagementService usermanagementService;
    @Inject OfficeWallService officeWallService;

    @Override
    public void createCustomer(Customer customer) {

        // 1. persist customer in DB
        dataManager.commit(customer);

        // 2. create user account for customer
        usermanagementService.createUserForCustomer(customer);

        // 3. log customer information into the office wall file
        officeWallService.logCustomerinformation(customer);

       // ...
    }
}

The CustomerService gets called from the UI and will do all necessary things that have to be done when a customer is created.

So the problem with this is the coupling between the different parts of the system. When thinking about, you might notice that for the CustomerService it does not really need to know about the effects that its action - “to create a customer” - has.

If you don’t care about it, the CustomerServiceBean is going to be the God object of your system in the long run. It will violate the single responsibility priciple, because instead of changing the class for the one reason “the storate of a customer”, you will end up in a situation where changing the class for one of any reasons that are related to the customer storage is the actual situation.

Event based architectures to the rescue

Because of this, we want to have a look at one option for us to improve the design with an event based architecture. A lot has been written about this stuff and it is already been around for a very long time.

There are a lot of examples of event based architectures in totally different granularities and time frames. Starting with something like UI events in visual basic, over to event driven architectures in a SOA context or with something more modern: reactive programming.

One major difference between the example above and the event based approach is the removal of the dependencies between the CustomerService as the caller to the OfficeWallService as the callee goes away. Instead, both services depend on the “contract”: CustomerCreatedEvent.

Direct dependency (synchnous way - left) --> no dependency between services (asynchronous way - right)

With this approach we are closer to fulfilling the single responsiblity principle. Additionally, testing way gets easier, because the need to mock the different collaborators will go down dramatically. We will close the theoretical (nevertheless important) part and have a look at how we can do this sort of things in CUBA.

Application events in CUBA

CUBA already has a lot of events that are created from the framework. On the persistence layer, there is the feature of Entity Listeners, where you can create classes that react to certain actions during the persistence process. Then, there are a lot of UI-related events that can be catched and act on your UI needs. But these are all framework –> application events.

What we want take a look at instead is the possibility to create custom application events that can be send and received within your CUBA application. This is more like application –> application.

Spring application events

Luckily, CUBA as a meta-framework is nested on top of very major and feature-rich frameworks that themselfs have a lot of stuff to offer. One of these frameworks is Spring. The Spring framework has an event-mechanism baked in from the very beginning (which is a fairly long time actually). The main purposes for an application developer is to get notified when certain technical things in the running application occur (like ContextStartedEvent).

Nevertheless, custom application events are supported as well. In fact, in recent versions Spring improved the creation and handling of these events even futher (see the docs for more information).

So, basically it boils down to the three major parts of the actual event object, the event sender and the event receiver. Let’s take a closer look at those.

1. Event object

You have to create a PO(J|G)O class that represents an event like this:

// Application event when a order is created
class OrderCreatedEvent {
    String source
    Order order
}

2. Event publisher

Having that, we need a publisher of an event. Here’s an example of a service that does that:

import org.springframework.context.ApplicationEventPublisher

class ApplicationEventProducerService {

    @Inject
    ApplicationEventPublisher publisher;

    void produceApplicationEvent(Object event) {
        publisher.publishEvent(event)
    }

    void produceOrderCreatedEvent(Order order, String source) {
        publisher.publishEvent(new OrderCreatedEvent(order: order, source: source))
    }
}

The ApplicationEventProducerService is responsible for pushing an event into the atmosphere, so that other parts of the system can see it flying and catch it if they want. The service (which acts as an example for your business logic that creates events) uses org.springframework.context.ApplicationEventPublisher to fulfil its purpose. This bean is the point in the Spring framework which lets us publish application events. As you might have noticed, the method publishEvent can take any object to publish, it does not require a certain class type to do that (anymore…).

3. Event receiver

The last part is the receiving part - which is called EventListener. An event listener qualifies itself by having a particular method annotation that should handle a certain event. Here’s an example:

@Component
class CustomerUserCreator {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Async
    @EventListener
    void handleCustomerCreated(CustomerCreatedEvent event) {
        User user = createUserFromCustomer(event.customer)
        log.warn("The user ${user.login} was created...".toString())
    }

CustomerUserCreator creates a user account in our application when a Customer has been created. The handleCustomerCreated(CustomerCreatedEvent event) method is the actual handler of the event due to the @EventListener annotation.

The parameter in the method definition qualifies which event is handled in this method. The qualification is normally done on a class level (through the type of the parameter).

If you want to define even further for what events of a particular times this method should get called, you can either do a big if-statement within the method, or you can set the condition attribute like this:@EventListener(condition = "someCondition") (while someCondition has to be a valid SpEL expression).

One important point is, that in order to have multiple actions in your application that have to be executed when a customer is created, you just have to create another event listener bean. So, going back to our example from above, we would have another bean called OfficeWallService that would look like this:

@Component
class OfficeWallService {

    @Inject
    OfficeWall officeWall

    @Async
    @EventListener
    void handleCustomerCreated(CustomerCreatedEvent event) {
        officeWall.renderText("${event.customer.name} is our new and hopefully the best customer ever...")
    }

With this, everything is in place to create an event based application. There are many more options to consider, but as I will not mirror the Spring docs, I will leave it at this point. You can read more about this in the Spring docs. Another very good article is the following: Better application events in Spring Framework 4.2.

Sync or Async - depending on your needs

As you might have seen, I used the @Async annotation in the handlers. The reason for that is, that I want to execute the stuff that happens when is user is created independently of the thread where it is created. There are some situations where you want a synchronous execution, but in this example I want the execution in another thread.

To make that happen, one thing is to add the above mentioned annotation. Another thing is, that there needs to be a configuration in the spring.xml that defines futher information about the asynchronous execution.

<beans>
    <task:annotation-driven executor="scheduler"/>
    <bean id="exceptionHandler" class="com.company.ceae.listener.application.ExecutorExceptionHandler"/>
</beans>

The “scheduler” reference is an existing CUBA bean (CubaThreadPoolTaskScheduler) which is an implementation of Springs ThreadPoolTaskScheduler.

The task:annotation-driven tag defines that Spring will scan the classpath for beans for the corresponding annotations.

CUBA application event example

Let’s have a look at how we can create a running example of this approach in CUBA. The complete example can be found on github: mariodavid/cuba-example-application-events.

The example does the following things:

Activity graph in the CUBA example

First, the user creates a customer through the standard editor for the customer entity. After that, the registered CustomerCreatedEntityListener which is a normal CUBA entity listener, creates a CustomerCreatedEvent through the above mentioned ApplicationEventProducerService. The events get fired aynchronously, so the DB transaction of storing the customer is finished independently of everything else that might happen with the CustomerCreatedEvent.

The event is catched by multiple event handlers. The CustomerUserCreator which creates a corresponding user for the customer so that the customer is capable of login to the system and see its own orders. The next event handler is the CustomerCreatedUserNotificator, which creates a notification for every user that is subscribed on these events. This leads to the UI that updates itself for the corresponding user and shows a new notification message. As the last part has some more business logic, let’s have a closer look at it.

Users can subscribe to application events

One example of what can be done as a useful event handler is to notify users through the UI that certain things happend in the application.

This example of notifiing users does not have a direct correlation between itself and the fact that we use application events. Although they play nicely together, these things are orthogonal. We could implement a notification system without using an event based architecture, as well as using an event based architecture without showing these notifications on the UI.

In order to allow the user to subscribe to certain events, we have to create an entity that stores these subscriptions. The user can define the class of the nofitication and a condition that has to be true in order to get a notification.

The CustomerCreatedUserNotificator will pick up all subscriptions of every user where the event fulfils the entity class criteria as well as the condition. For each of those subscriptions it will create a new Notification entity for the corresponding user. It will additionally link the entity where the notification comes from in the entity, so that the user can hit a link to go directly to this entity instance.

After the notifications have been persisted in the database, we can have a look at how to get the information in the users UI.

Update the UI through polling

The MainWindow of the app uses the recently added SideMenu component. I decided to do a polling of the database through the trigger option we have in CUBA for UI screens. The timer calls updateCounters which will ask the database for notifications for the current user, that are unread and update the badge text of the menu item accordingly.

The resulting user interface looks like this:

User notification screen with unread notifications

This might be a reasonable solution for the problem. We could have done it differently, e.g. when there are a lot of users and the polling will result in a large amount of load for the database. In this case, it might be worth finding the corresponding sessions and set a session attribute with the counter. But I think that this shows the basic functionality. Everything else is up to the specific application.

I hope you got a basic idea of what application events can bring on the table and if they are suitable for your needs. If you have any questions or comments - please let me know.

Mario David

Mario David
Software developer with passion on agile, web and fast development, blogger, father, family guy

CUBA to Heroku in 10 steps

In this blog post I will show you how to deploy a CUBA app to Heroku in ten simple steps Continue reading

Salesforce through the Lens of a Java Dev

Published on March 02, 2020

Salesforce through the Lens of a Java Dev

Published on February 14, 2020