JMS Patterns – Generic Message Handler

Refactoring some JMS code got me thinking about message validation, type casting, and payload extraction. Having recently read Adam Bien’s excellent book “Real World Java EE Patterns – Rethinking Best Practices” I decided to implement the “Payload Extractor” pattern. However, I couldn’t help feeling there’s something not quite right about it. In particular I didn’t like having to implement an empty onMessage method, and some of the reflection overhead seemed unnecessary. Don’t get me wrong; EJB 3 interceptors are great for extracting cross-cutting concerns, but in this case the implementation of the bean is entirely dependent upon the presence of the interceptor.

The alternative I came up with uses a generic abstract superclass and the Template Method pattern. In my opinion, this approach has several advantages:

  • The solution handles both message type checking and payload extraction.
  • Less reflective code. Determining the expected type happens once during object construction. Message type checking and payload extraction use simple instanceof and isAssignableFrom checks.
  • There’s no empty onMessage method in the concrete subclass.
  • Concrete subclasses can also access the dead letter handler if the need arises.
  • More robust compile time checks. The generic abstract method forces you to implement a correctly typed consume method. In the Payload Extractor pattern this check doesn’t happen until runtime, at which point any coding errors will simply masquerade as invalid messages.

You could argue that using an interceptor frees you from having to use inheritance. However, in this case, I don’t see this as a problem. It’s generally accepted best practice to not place business logic in your Message-Driven Beans, so scenarios in which your listener is required to inherit from another class should be rare.

GenericMessageHandler.java

public abstract class GenericMessageHandler<T> implements MessageListener {

    private final Class expectedType;
    @EJB
    private DeadLetterHandler deadLetterHandler;

    public GenericMessageHandler() {
        final ParameterizedType parameterizedType =
            (ParameterizedType) getClass().getGenericSuperclass();
        expectedType = (Class) parameterizedType.getActualTypeArguments()[0];
    }

    public void onMessage(final Message message) {
        if (matchesExpectedType(message)) {
            invokeConsume(message);
        } else {
            final Object payload = extractPayload(message);
            if (matchesExpectedType(payload)) {
                invokeConsume(payload);
            } else {
                deadLetterHandler.invalidMessageType(message);
            }
        }
    }

    protected DeadLetterHandler getDeadLetterHandler() {
        return deadLetterHandler;
    }

    protected abstract void consume(T obj);

    private boolean matchesExpectedType(final Object obj) {
        return obj != null && expectedType.isAssignableFrom(obj.getClass());
    }

    private Object extractPayload(final Message message) {
        try {
            if (message instanceof ObjectMessage) {
                return ((ObjectMessage) message).getObject();
            } else if (message instanceof TextMessage) {
                return ((TextMessage) message).getText();
            }
            return null;
        } catch (JMSException e) {
            throw new IllegalStateException("Error extracting payload", e);
        }
    }

    private void invokeConsume(final Object obj) {
        consume((T) obj);
    }
}

Payload Extraction Example – MailQueueHandlerBean.java

public class MailQueueHandlerBean extends GenericMessageHandler<Email> {

    @EJB
    private Mailer mailer;

    @Override
    public void consume(final Email email) {
        mailer.sendMessage(email);
    }
}

In the above example MailQueueHandlerBean expects messages of type ObjectMessage with a payload of type Email. As you can see, the implementation is super-lean and there’s no ambiguity about who’s performing what.

Message Type Check Example – RawDataQueueHandlerBean.java

public class RawDataQueueHandlerBean extends GenericMessageHandler<BytesMessage> {

    @EJB
    private DataProcessor dataProcessor;

    @Override
    public void consume(final BytesMessage bytesMessage) {
        try {
            if (bytesMessage.getBodyLength() == 0) {
                getDeadLetterHandler().invalidMessageContent(bytesMessage);
            } else {
                final byte[] data = // extract byte array
                dataProcessor.process(data);
            }
        } catch (JMSException e) {
            throw new IllegalStateException("Error extracting bytes", e);
        }
    }
}
Advertisements
Tagged with: , , , , , ,
Posted in Java EE Development
7 comments on “JMS Patterns – Generic Message Handler
  1. Adam Bien says:

    Thanks for this great post and your additional thoughts! I like your approach as well. If you have some additional thoughts about my book – just drop me an email or write a post / review!,

    thanks,

    adam!

    • Jonathan Wright says:

      Adam,

      Thanks for the feedback. I’m trying to put together a post about the JPQL SELECT NEW clause at the moment. Faster response times and reduced memory usage could be another reason to keep the DTO pattern alive, at least for read-only data..I need to do some profiling but with any luck I should have a post together in the not too distant future.

      Thanks for posting a link to your twitter feed!

      Regards,

      Jonathan

  2. michiel says:

    Cool! I was looking for this.

    But now I’m looking for a way to crack multiple messagetypes without using mutliple topics/queues or MessageListeners.

    thx,
    Michiel

    • Jonathan Wright says:

      Have you looked at message selectors?

      • michiel says:

        Yes, but I wasn’t clear. I’m looking for a way to crack multiple messagetypes without using jms facilities and switch/case/if/else.

        You solved the switch/case problem for onMessage() with an oo approach but with single inheritance. Wouldn’t it be nice to have a hierarchy thrown in?

        I’m not familiar enough with the reflection mumbojumbo you do. Those unchecked exceptions scares me but seems harmless.

        Maybe I have to look into interceptors.

        regrds,
        Michiel

      • Jonathan Wright says:

        Those unchecked exceptions scares me but seems harmless.

        Application exceptions are intended to be handled by the client. In the case of message-driven beans there is no client, only the resource adapter, so it doesn’t make sense to throw them.

        Throwing an IllegalStateException will result in the current transaction being rolled back, which in turn causes the message to placed back on the queue. The number of retries should be configurable in the application server.

  3. bob says:

    return obj != null && expectedType.isAssignableFrom(obj.getClass());

    should be written as

    return expectedType.isInstance(obj);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: