Using JMS in Grails

The Java Message Service (JMS) API is one of the cornerstones of the Java Enterprise Edition that allows applications to reliably communicate using asynchronous messages sent via a message broker. This article provides an introduction to JMS, the JMS support in the Spring Framework and then provides practical examples of usage within Grails using the JMS plugin.

This article originally appeared in the June 2011 edition of GroovyMag.

Why would I want to use JMS?

JMS is very good for integrating distributed systems or offloading task processing, which can help with scalability. For example JMS is used in many financial services systems for sending trade messages or in internet telephony providers for sending call detail records.

How does it work?

There are two key application roles in a messaging system: Producers & Consumers; a producer sends messages and a consumer receives messages.

Furthermore, JMS has two primary styles for sending messages to consuming applications: Queues & Topics (collectively known as destinations).

Figure 1 shows a queue, which is a point-to-point mechanism that utilizes the store & forward approach to deliver a message from a producer to a consumer.

Figure 1: A point-to-point queue

A topic is a publish-subscribe (pub-sub) mechanism where an application publishes a message to a topic. As shown in Figure 2, this message is received by all the active applications that have subscribed to that topic. Durable subscriptions enable subscribing applications to receive all topic messages, even those published whilst the application was off-line.

Figure 2: A publish-subscribe topic

Your application can receive messages by adding a message listener. The Spring Framework JMS support allows you to have a Message-Driven POJO so that you don’t need to code to the JMS MessageListener interface. Depending upon the underlying JMS implementation, some message listeners may actually use JMS clients that poll behind the scenes.

Messages

Messages are comprised of a header and a body – the header and acknowledge method are defined by the javax.jms.Message interface and the body is covered by type using sub-interfaces for Bytes / Text / Map / Object / Stream messages.
Generally short text-based messages are preferable to sending large binary messages to keep your message fabric fast. See the section on Enterprise Integration Patterns and the ‘Claim Check’ pattern for further inspiration.

Message headers and properties

The standard message includes headers for conveying message IDs, delivery modes, priority, expiry etc.

If you want to use a request-response model (rather than ‘fire & forget’), then there are two very important headers: the Correlation ID and the Reply To destination. As shown in Figure 3, the ID from the request message header is placed into the Correlation ID header of the response message, which is sent to the Reply To destination. This way, the originator of the message exchange can match the reply to the original request (this might use a message log table in a database).

Figure 3: Correlating requests and responses

The Message interface also allows you to add custom properties to the message header – these are often used for message filtering (see Message Selectors). Properties have a String name and the value can be boolean, byte, short, int, long, float, double, or String.

If you need to group messages or have messages processed in a certain sequence, then you can utilize the standard JMSXGroupID and JMSXGroupSeq properties.

Message selectors

Message selectors allow consumers to selectively consume messages based on headers / properties (they cannot reference the body of the message). The selector syntax is based on a subset of the SQL conditional syntax (where clauses) e.g.
Country IN (' UK', 'US', 'France')

Is the API stable?

The current version of the JMS API is 1.1, which was developed as JSR 914. The last maintenance release to 1.1 was in April 2002, yet amazingly Spring JMS still has support for JMS 1.0.2!
Though there are plans to produce JMS 2.0 through the Java Community Process under JSR 343 (http://jcp.org/en/jsr/detail?id=343).

Which products support JMS?

There are many middleware messaging products that support JMS, examples include IBM MQ Series (AKA WebSphere MQ) or Apache ActiveMQ. Some Java application servers also supply a JMS implementation such as JBoss with JBoss Messaging.

Are there any limitations to JMS?

The main downside is that it adds complexity to a system and is therefore harder for the operations team to get an accurate view of system health. Another challenge is managing the ‘dead letter queue’ where ‘poison’ messages end up after their delivery has been attempted a set number of times.

Also, if you are transactionally consuming messages and writing them to the database then you may want to utilize two-phase commit (2PC) to ensure that the message is removed from the queue if & only if the database record is written correctly. XA-compliant data sources are beyond the scope of this article.

Lastly interoperability may be a concern; if your company has two messaging systems then you may need to bridge between them, or if you utilize multiple development languages you may need to select a JMS offering that has the appropriate client API/protocol support (e.g. ActiveMQ supports STOMP – Streaming Text-Oriented Messaging Protocol).

What about AMQP?

Sticking with interoperability, if you’ve heard about the Advanced Message Queuing Protocol (AMQP), as used by RabbitMQ, you may be wondering how this relates to JMS. Well firstly AMQP and JMS are at different levels in the stack. JMS is an API to be implemented by enterprise messaging products to enable Java client support, whereas the AMQP specification defines a vendor-neutral interoperable wire protocol.
Therefore, a messaging product may layer JMS on top of AMQP – this is done by projects such as Apache Qpid / Red Hat MRG Messaging.

Enterprise Integration Patterns

There are many different ways of integrating applications using enterprise messaging systems; luckily the majority of these approaches have been documented as patterns and given a de-facto language by the invaluable Enterprise Integration Patterns book (Enterprise Integration Patterns, Gregor Hohpe & Bobby Woolf, Addison Wesley, ISBN 0321200683).

Claim check

This is a useful pattern (Figure 4 – created using the Visio Hohpe EIP shapes) whereby a reference to a large item (e.g. a URL for a document) is passed in the message instead of transmitting the large item across the messaging channel. The receiving application can then fetch the large item when it is required.


Figure 4: Claim Check enterprise integration pattern

Framework support

As EIP is a de-facto pattern language, its use has been picked up by lightweight integration tools such as Apache Camel and Spring Integration. Spring Integration encourages a message channel-based approach, but that is a subject for another article.

The Grails JMS plugin

Grails has a rich ecosystem of over 560 plugins – for the remainder of this article we’ll be using the JMS plugin that is maintained by the hard-working ‘Grails Plugin Collective’. Naturally, as many things do in Grails, the JMS plugin builds upon the venerable Spring Framework.

The JMS plugin supplies a jmsService bean which we’ll use for sending messages, and it manages ListenerContainer configuration for Grails services which we’ll use to consume messages.

The plugin jmsService.send method invokes jmsTemplate.convertAndSend (optionally with a MessagePostProcessor callback). Whilst the plugin masks most of the details and has good documentation (http://gpc.github.com/grails-jms/docs/manual/index.html), it is useful to have a basic understanding of the Spring JMS support classes (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jms.html) in case you need to modify the default behavior.

JMSTemplate

The xyzTemplate is a common pattern within the Spring Framework, the JmsTemplate class is central to the JMS support and handles resource management for sending messages via its convenience methods. The JmsTemplate needs a JMS ConnectionFactory reference to enable the JMS client to connect to the JMS Provider.
Note: It is recommended to read about JMS connection pooling configuration as this will reduce the overhead of establishing and tearing down a high number of connections.

MessageConverter

This interface defines a contract to convert between Java objects and JMS messages. By default, the JMS plugin jmsService.send method (via jmsTemplate.convertAndSend) uses the SimpleMessageConverter implementation supplied by Spring. This is able to handle conversion to/from TextMessage, BytesMessage, MapMessage and ObjectMessage.

MessagePostProcessor

This callback interface allows for manipulation of a message once it has been created by a MessageConverter prior to transmission. The primary use case is for setting JMS Headers and/or Properties.

MessageListenerContainer

The message listener container receives a message from the configured destination (queue/topic) and dispatches it to the MessageListener implementation (a MessageListenerAdapter is used to allow for message-driven POJOs, though typically only the message payload is delivered to the POJO method).
The JMS plugin uses the DefaultMessageListenerContainer which can participate in XA transactions if it is configured with a JtaTransactionManager.

Putting it into action with Grails

Version 1.1 of the JMS plugin requires Grails 1.2+ and the example code is based on Grails 1.3.7 with ActiveMQ as the JMS Provider.
The full source code for this article is available from GitHub: https://github.com/rbramley/GroovyMagJMS (this also includes the code for the subsequent article on pushing event-driven updates to the browser) .

Plugin installation

Assuming you’ve already created your Grails application, the next step is to install the JMS plugin with the following command:
grails install-plugin jms

Dependency declaration

The JMS plugin is provider-agnostic, so we have to declare a dependency on ActiveMQ in grails-app/conf/BuildConfig.groovy (Listing 1 – for simplicity we can borrow the dependency from the plugin test scope) and uncomment the mavenCentral() repository.

compile('org.apache.activemq:activemq-core:5.3.0',
 'org.apache.activemq:activeio-core:3.1.2',
 'org.apache.xbean:xbean-spring:3.7') {
  excludes 'activemq-openwire-generator'
  excludes 'commons-logging'
  excludes 'xalan'
  excludes 'xml-apis'
  exported = false
}

Listing 1: ActiveMQ dependency

Spring bean configuration

Next we need to configure the ActiveMQ JMS ConnectionFactory implementation in grails-app/conf/spring/resources.groovy, as shown in Listing 2.

beans = {
  jmsConnectionFactory(org.apache.activemq.ActiveMQConnectionFactory) {
    brokerURL = 'vm://localhost'
  }
}

Listing 2: Spring bean configuration

The brokerURL setting in Listing 2 instructs ActiveMQ to run an embedded in-process broker; if you already have a standalone ActiveMQ broker set-up, then you may choose to use that instead (e.g. for a local broker this might be brokerURL = ‘tcp://localhost:61616′ along with any required username/password credentials).

The Application code

For this scenario, we’ll be queuing our database write operations, so let’s pretend that we have a database topology where the applications query read-only replicas and send writes back to a central master database.

We’ll start by creating a very simple Message domain class that has a String body property and a Date dateCreated property.

Next we’ll need a controller for this domain class. We can enable scaffolding but will need to declare the jmsService and override the save and update closures, which we do in Listing 3.

class MessageController {
 
  def jmsService
  def scaffold = true
 
  def save = {
    jmsService.send(queue:'msg.new', params.body)
    flash.message = "Message queued for persistence"
    redirect(action: "list")
  }
 
  def update = {
    jmsService.send(queue:'msg.update', [id:params.id, body:params.body])
    flash.message = "Message queued for update"
    redirect(action: "list")
  }
}

Listing 3: Controller code

There is some plugin magic going on in Listing 3 that is worth explaining – the second argument to the send method is the message. This is being converted by the Spring SimpleMessageConverter. The controller save method will result in a TextMessage being transmitted, and the controller update will result in a MapMessage being sent.

Now we’ll need a listening service to receive these messages and persist them to the database, as demonstrated in Listing 4. This states that the service is exposed via JMS (static exposes = ['jms']) and uses Queue annotations to instruct the JMS plugin how to route messages from queues to service methods.

  @Queue(name='msg.new')
  def createMessage(msg) {
    def messageInstance = new Message(body:msg)
    if (messageInstance.save(flush: true)) {
      log.info "Saved message: id = ${messageInstance.id}"
    } else {
      log.warn 'Could not save message'
    }
 
    // explicitly return null to prevent unwanted replyTo queue attempt
    return null
  }
 
  @Queue(name='msg.update')
  def updateMessage(msg) {
    def messageInstance
    if(msg instanceof Map) {
      messageInstance = Message.get(msg.id)
      if(messageInstance) {
        messageInstance.body = msg.body
        if (!messageInstance.hasErrors() && messageInstance.save(flush: true)) {
          log.info "Saved message: id = ${messageInstance.id}"
        } else {
          log.warn 'Could not update message'
        }
      } else {
        log.warn "No message instance for ID ${msg.id}"
      }
    } else {
      log.warn "Could not determine what to do with ${msg}"
    }
 
    // explicitly return null to prevent unwanted replyTo queue attempt
    return null
  }

Listing 4: Listening Service

In Listing 3, the messages are being sent to two different queues, and received by the service code in Listing 4. Alternative approaches might be to use a MessagePostProcessor to add an ‘operation’ header to the produced message and then use a Message Selector; or encode the message as JSON (or XML) with an ‘operation’ attribute which can be processed & routed by an onMessage method, etc.

In action

If we run the application using grails run-app, select the message controller, click on ‘New Message’ and create a message (Figure 5), we are told by a flash message on the list screen that it has been queued (Figure 6). If we now refresh the page, we can see our message in the list (Figure 7).


Figure 5: Creating a message


Figure 6: Flash message


Figure 7: The refreshed list

Summary

The example application has demonstrated usage of queues so far, topics are coded in a very similar fashion. As an exercise for the reader, you could make the service methods publish event messages to a topic. Potential topic subscribers could include a ‘Business Activity Monitor’ that might maintain an audit trail of data change activities or they could be sent to a Complex Event Processing system (e.g. Esper)…

Disclaimer: The sample code is used to illustrate the concepts, techniques and configuration – it is not production-grade code.

About these ads

12 responses to “Using JMS in Grails

  1. Nicely detailed. Any info on setting up a durable Topic subscriber in Grails?

    • At first glance it isn’t particularly obvious how this is supported by the current version of the JMS Plugin (an old version of the plugin had explicit configuration parameters for durable subscriptions).

      The way to do this is to set up a different container in your Config.groovy:

      jms {
        containers {
          durable {
              subscriptionDurable = true
              ...
          }
        }
      }

      and then reference this in your listening service Subscriber:

        @Subscriber(topic='msgevent', container='durable')
        def onEvent(msg) {

      See section 3. The Configuration Mechanism and section 5.4 Using Other Containers Or Adapters for more information.

  2. Pingback: Using Browser Push in Grails | Lean Java Engineering

  3. Hi,

    This worked for me like charm in grails 1.3.7,

    The only issue I see is after upgrading it to 2.0.1 grails and groovy compiler 1.8.6 It says

    Running Grails application
    | Error 2012-02-24 18:02:13,490 [pool-6-thread-1] ERROR spring.GrailsRuntimeConfigurator – [RuntimeConfiguration] Unable to load beans from resources.groovy
    Message: No such property: org for class: resources
    Line | Method
    ->> 3 | doCall in resources$_run_closure1

    Also See: http://stackoverflow.com/questions/9453115/grails-2-0-1-wierd-issue

    Any clue ?

  4. Under “Spring Bean Configuration” you note that we need to configure the ActiveMQ JMS ConnectionFactory in grails-app/conf/resources.groovy. Shouldn’t that be grails-app/conf/spring/resources.groovy ?

  5. Pingback: Jms | TagHall

  6. Pingback: JMS configuración rápida en Grails | GrailsMX

  7. Hi,
    is it possible to send messages with different priorities using the JMS plugin?

    • Using the Grails JMS plugin means two layers between your code and the JMS API.

      The JMS spec defines priority as a range between 0-9 with 4 as the default defined on javax.jms.Message. The control of the priority value is typically handled by the javax.jms.MessageProducer – it has two ways of specifying priority, either a default priority for the producer or per message on the send method.

      The Spring JmsTemplate uses the latter if isExplicitQosEnabled() returns true. JmsTemplate also has a void setPriority(int priority) method.

      To access this through the Grails JMS plugin jmsService requires the use of the jmsTemplateBeanName in the send call (see here for an example of how to set up another JMS Template).

      e.g. you might want to configure a highPriorityJmsTemplate with explicitQosEnabled = true and priority = 7

      Alternatively you can modify the Message priority (using Message.setJMSPriority(int priority)) through a Spring MessagePostProcessor – the use of post-processing is detailed here.

      Hope that helps!

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