(Quick Reference)

5 Receiving Messages

Version: 2.0.0.RC2

5 Receiving Messages

5.1 Service Listeners

Service Listeners

Service listeners are a convenient way to define one handler for JMS messages. The simplest service listener looks like…

class PersonService {
    static exposes = ["jms"]
    def onMessage(msg) {
        // handle message
    }
}

This will register the onMessage method as a listener for the JMS queue named «application name».person , where «application name» is the app.name key from the application.properties file.

Configuration

The following configuration parameters can be set as static variables on the service class…

Property NameTypeDefaultDescription
destinationString«app name».«service name»The named destination of the listener
isTopicbooleanfalseis the destination a topic ( true ) or a queue ( false )
selectorStringnullSee the “Message Selector” section of http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html
adapterString"standard"The adapter to use for this listener
containerString"standard"The container to use for this listener

class PersonService {
    static exposes = ["jms"]
    static destination = "somethingHappened"
    static isTopic = true
    static adapter = "custom"

def onMessage(msg) { // handle message } }

5.2 Service Method Listeners

Service Method Listeners

Another avenue is to expose specific methods as message listeners via annotations. This looks like…

import grails.plugin.jms.*

class PersonService { static exposes = ["jms"]

@Queue def addPerson(msg) { }

@Subscriber def somethingHappened(msg) { } }

The above configuration binds the personService.addPerson() method to a queue named «app name».person.addPerson and binds the method personService.somethingHappened() as a listener to the topic named somethingHappened .

Note that you still need to expose the class via ' static exposes = ["jms"] .

@Queue Configuration

The following configuration parameters can be set as annotation parameters…

Property NameTypeDefaultDescription
nameString«app name».«service name».«method name»The destination name for the queue
selectorStringnullThe message selector to apply (See the “Message Selector” section of http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html)
adapterString"standard"The adapter to use for this listener
containerString"standard"The container to use for this listener

Example…

import grails.plugin.jms.*

class PersonService { static exposes = ["jms"]

@Queue( name = "myQueue", selector = "name IS NOT NULL" ) def addPerson(msg) { } }

@Subscriber Configuration

The following configuration parameters can be set as annotation parameters…

Property NameTypeDefaultDescription
topicString«method name»The name of the topic to subscribe to
selectorStringnullThe message selector to apply (See the “Message Selector” section of )
adapterString"standard"The adapter to use for this listener
containerString"standard"The container to use for this listener

Example…

import grails.plugin.jms.*

class PersonService { static exposes = ["jms"]

@Subscriber(topic = "aTopic") def somethingHappened(msg) { } }

Defining the Queue names and Subscriber topics through configuration.

You can specify the names of the given destinations , queues and topics , described through the Queue and Subscriber annotations by prefixing the key with a Dollar sign ( $ ). The key needs to be available through the Config.groovy file in the jms.destinations space, if its not available an error will be thrown.

Example…

PersonService.groovy

import grails.plugin.jms.*

class PersonService { static exposes = ["jms"]

@Subscriber(topic = '$topic.key.in.config') def somethingHappened(msg) { }

@Queue(name = '$queue.key.in.config') def someWorkToDo(msg) { } }

Config.groovy

jms {
    destinations {
        //Name of the topic in the JMS server will be person.somethingHappened
        topic.key.in.config = 'person.somethingHappened'

//Name of the queue in the JMS server will be person.sendSomeWork queue.key.in.config = 'person.sendSomeWork' } }

5.3 Listener Return Values

Spring's MessageListenerAdapter adds some special handling of listener method return values.

From MessageListenerAdapter's JavaDoc: "If a target listener method returns a non-null object (typically of a message content type such as String or byte array), it will get wrapped in a JMS Message and sent to the response destination (either the JMS "reply-to" destination or a specified default destination)."

Be careful with Groovy's implicit return mechanism; ensure that you return null explicitly if you want nothing to be sent to the reply destination. If you accidentally return a value that cannot be sent to the reply destination, you may have odd side effects like messages never being removed from the queue (due to implicit rollbacks!).

5.4 Using Other Containers Or Adapters

Here is an example of using a container and adapter other than standard.

resources.groovy

import org.apache.activemq.ActiveMQConnectionFactory
import org.springframework.jms.connection.SingleConnectionFactory

beans = { // used by the standard template by convention jmsConnectionFactory(SingleConnectionFactory) { targetConnectionFactory = { ActiveMQConnectionFactory cf -> brokerURL = 'vm://localhost' } }

otherJmsConnectionFactory(SingleConnectionFactory) { targetConnectionFactory = { ActiveMQConnectionFactory cf -> brokerURL = // … something else } } }

Config.groovy

jms {
    containers {
        other {
            meta {
                parentBean = 'standardJmsListenerContainer'
            }
            concurrentConsumers = 5
            connectionFactoryBean = "otherJmsConnectionFactory"
        }
    }
    adapters {
        other {
            meta {
                parentBean = 'standardJmsListenerAdapter'
            }
            messageConverter = null // do no message conversion
        }
    }
}

Sending messages

class ListeningService {
    static exposes = ["jms"]
    static adapter = "other"
    static container = "other"

def onMessage(msg) { // handle message } }

import grails.plugin.jms.*

class ListeningService { static exposes = ["jms"]

@Queue(adapter = "other", container = "other") def receive(msg) { // handle message } }