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 Name | Type | Default | Description |
|---|
| destination | String | «app name».«service name» | The named destination of the listener |
| isTopic | boolean | false | is the destination a topic ( true ) or a queue ( false ) |
| selector | String | null | See the “Message Selector” section of http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html |
| adapter | String | "standard" | The adapter to use for this listener |
| container | String | "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
}
}
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 Name | Type | Default | Description |
|---|
| name | String | «app name».«service name».«method name» | The destination name for the queue |
| selector | String | null | The message selector to apply (See the “Message Selector” section of http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html) |
| adapter | String | "standard" | The adapter to use for this listener |
| container | String | "standard" | The container to use for this listener |
Example…import grails.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 Name | Type | Default | Description |
|---|
| topic | String | «method name» | The name of the topic to subscribe to |
| selector | String | null | The message selector to apply (See the “Message Selector” section of ) |
| adapter | String | "standard" | The adapter to use for this listener |
| container | String | "standard" | The container to use for this listener |
Example…import grails.jms.*class PersonService {
static exposes = ["jms"] @Subscriber(topic = "aTopic")
def somethingHappened(msg) { }
} 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!).
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.SingleConnectionFactorybeans = {
// 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
}
}