Java EE6 Events, a lightweight alternative to JMS

A few weeks ago I attended a bejug meeting about Java EE 6, Building next generation enterprise applications. Having read much about it, I did not expect to see much shocking hidden features. But there was one part of the demo I really found impressive. Due to its loose coupling, Enterprise possibilities and simplicity. The feature I’m going to talk about today is the event mechanism that is in java EE 6.
The general idea is to fire an event and let an eventlistener pick it up. I have created this example that is totally useless, but it simplicity helps me to focus on the important stuff. I’m going to fire a LogEvent from my backing action, that will log to the java.util.Logger.
The first thing I need is to create a pojo that contains my log message and my LogLevel.

public class LogMessage implements Serializable {

    private final String message;
    private final Level level;

    LogMessage(String message, Level level) {
        this.message = message;
        this.level = level;
    }

    public String getMessage() {
        return message;
    }

    public Level getLevel() {
        return level;
    }
} 

easy peasy.
Now that I have my data wrapper, I need something to fire the event and something to pick it up. The first thing I create is my method where I fire the event.
Due to CDI I can inject an event.

 @Inject Event<LogMessage> event;

So we just need to fire it.

 event.fire(new LogMessage("Log it baby!", Level.INFO));

Now the event is fired, If no one is registerd to pick it up, it disappears into oblivion, thus we create a listener. The listeners needs a method that has one parameter, the generic type that is given to the previous event. LogMessage.

public class LogListener {
    private static final Logger LOGGER = Logger.getAnonymousLogger();
    public void process(@Observes LogMessage message){
        LOGGER.log(message.getLevel(), message.getMessage());
    } 
}

The @Observes annotation listens to all events with a LogMessage. When the event is fired, this method will be triggered.
This is a very nice way to create a loosely coupled application, you can separate heavy operations or encapsulate less essential operations in these event listeners.
All of this all happens synchronously. When we want to replace the log statement with a slow database call to a logging table, we could make our operation heavier than it should be. What I’m looking for is to create an asynchronous call.
As long as we support EJB, we can transform our Listener to an EJB by adding the @Stateless annotation on top of it. Now it’s a statless enterprise bean. This changes nothing to our sync/async problem, but EJB 3.1 support async operations. So if we also add the @Asynchronous annotation on top of it. It will asynchronously execute our logging statement.

@Stateless
@Asynchronous
public class LogListener {
    private static final Logger LOGGER = Logger.getAnonymousLogger();
    public void process(@Observes LogMessage message){
        LOGGER.log(message.getLevel(), message.getMessage());
    }
}

If we would want to combine the database logging and the console logging, we can just create multiple methods that listen to the same event.
This is a great way to create a lightweight application with a very flexible components. The alternative solution to this problem is to use JMS, but you don’t want a heavyweight configuration for this kind of loosely coupling.
Java EE has worked hard to get rid of the stigma of being heavyweight, I think they are getting there :-)

13 thoughts on “Java EE6 Events, a lightweight alternative to JMS”

  1. I think it should be noted that this (like some of other jee6 features) sounds like another feature from spring.

    I think I’d still prefer the spring version; it looks like the jee6 board has gone overboard with annotations. Just because they misused interfaces in the past does not mean they are inheritly bad.

    See ApplicationListener, ApplicationEventPublisher interfaces.

  2. The problem of this solution is the way in which observers are executed. They stay in the same thread and the event firing is a blocking operation for the call, so the decoupling is rather logical than “real”, like it is the case with JMS (another thread, another E bean, asynchroneous).
    Best,
    TC

    1. But isn’t that exactly what the final example with @Asynchronous is doing? I think I like this method better because you can _evolve_ into a more powerful solution as it is warranted. Start off small with in-thread event handling, which can then evolve to multi-thread @Asynchronous, and even multiple, distributed processes via an Observer that simply posts the message to JMS.

  3. Does this work with clustering? Will the message be delivered to every node of the cluster or processed only once?

  4. CDI events is a nice feature, but I discovered now an estrange behavior.

    An event generated by a ApplicationScope bean will not be propagated to all SessionScope bean listeners.

    For example: supose that you call ‘fire(“text”)’ on Producer, and we have 2 instances of Consumer bean. The ‘fired’ method on Consumer bean will be invoked only for one instance! It’s very bad.

    @Named
    @ApplicationScoped
    public class Producer {
    @Inject @Any
    private Event event;

    public void fire(String message) {
    event.fire(message);
    }
    }

    @Named
    @SessionScoped
    public class Consumer {
    public void fired(@Observes String event) {
    // do something…
    }
    }

  5. Is the order of messages kept intact when using @Asynchronous with Events? I’m thinking of something like Akka when I ask this. With Akka you can asynchronously send messages to Actors, and the Actors will process the messages in the order that they were sent.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>