Friday, December 11, 2015

JMS Implementation in Grails using ActiveMQ message broker

Hello All,

I have faced a lot of problems while implementing JMS to grails application, finally, I have succeeded in that. I just want to help the people who stuck with their implementation of JMS in grails.

There are two different implementations of JMS in grails:
  1. External Message Broker
  2. Embedded Message Broker
JMS Implementation using External Broker:

     To use external broker download the latest ActiveMQ broker from here. Once downloaded go to bin folder there you will find the activemq.bat file, click on the file to run it. This is the way we will create an external message broker using ActiveMQ. Once you click on it, it will show the following statements in command prompt.

Listening for connections at: tcp://{IP}:61616?maximumConnections=1000&wireFormat.max
FrameSize=104857600
Connector openwire started

Listening for connections at: amqp://{IP}:5672?maximumConnections=1000&wireFormat.max
FrameSize=104857600
Connector amqp started

Listening for connections at: stomp://{IP}:61613?maximumConnections=1000&wireFormat.m
axFrameSize=104857600
Connector stomp started

Listening for connections at: mqtt://{IP}:1883?maximumConnections=1000&wireFormat.max
FrameSize=104857600

We use TCP protocol to connect to this message broker from our app so copy the URL to the future configuration. Apart from these, you will find an admin URL in the same command prompt like this.

       ActiveMQ WebConsole available at http://localhost:8161/

This will be the ActiveMQ admin console URL, you can go to the link and see the messages queues, topics and no of pending messages etc...

Now let's start with our sender app.
Create a simple grails spring application with a controller and the service. Now we need to configure the JMS to the sender app.  Add the following dependencies to Build.config.

   compile 'org.grails.plugins:jms:1.3'
   runtime 'org.apache.activemq:activemq-spring:5.12.1'

Then we have to create the connection to message broker this will be in your resources.groovy.

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

  beans = {
      jmsConnectionFactory(SingleConnectionFactory) {
          targetConnectionFactory = { ActiveMQConnectionFactory  cf ->
              brokerURL = "tcp://localhost:61616"          }
       }
   }



Now your configuration is done, now you can able to send the message to the message broker using jmsService. Here is an example service to send the message.

    class MessageSenderService {
    def jmsService
    def sendMessage(String message) {
        jmsService.send(queue: "queue:message", message) // this method is used to send message to queue called 'queue:message'
    }
   }

When you call this method from any controller you will be getting a log message like this.

   INFO  jms.JmsService  - Sending JMS message 'abc' to  queue 'queue:message'

This will be the confirmation of sending your message, let's go to the ActiveMQ admin page and see whether the message stored or not.

Go to the following URL: http://localhost:8161/admin/index.jsp

There you will see queues menu. When you click on that menu you will see the following list of queues.

The name will be our queue name, no of pending messages are the messages you have sent but not received by any consumer.

Now let's build our Receiver app:

 For receiver the configuration part remains same, only the difference is the receiver service. Here is an example of message receiver service.

import grails.plugin.jms.Queue

class JMSMessageReceiverService {

    static exposes = ["jms"]
    @Queue(name = "queue.message") //this name should be the queue name.
    def receiveMessage(message){
        log.info "message received.."+message
    }
}

The above receiveMessage() method will be invoked when you send a message from the sender app.

JMS Implementation using Embedded Broker:
 
     Here embedded broker means one of our apps will run the message broker service in it. To start with this, we choose our Receiver app to hold the message broker init and the Sender will app will have the same configuration like above.

Let's start with the Receiver App:-

  To add message broker into our app we need the following dependencies.
 
  compile 'org.grails.plugins:jms:1.3'  
  compile 'org.apache.activemq:activemq-core:5.7.0'
  compile 'org.apache.xbean:xbean-spring:4.1'

once you add the above dependencies you can able to configure the message broker in resources.groovy as follows:

import org.apache.activemq.broker.TransportConnector
import org.apache.activemq.xbean.XBeanBrokerService
import org.springframework.jms.connection.SingleConnectionFactory

tcpConnector(TransportConnector,uri:'tcp://localhost:61616'){} 

connectors(ArrayList,[ref('tcpConnector')]){}
myBrokerService(XBeanBrokerService){bean->
myBrokerService.useJmx = false
myBrokerService.persistent = true
myBrokerService.dataDirectory = 'my-activemq_data'
myBrokerService.transportConnectors = ref('connectors')
}
amqConnectionFactory(org.apache.activemq.ActiveMQConnectionFactory) {
    brokerURL = 'vm://localhost'
}

jmsConnectionFactory(SingleConnectionFactory) { bean ->
    targetConnectionFactory = ref(amqConnectionFactory)
}

Now you are enabled embedded broker in  your app. When you start the app you will be seeing the message broker logs in your console like this.

INFO  broker.BrokerService  - Apache ActiveMQ 5.7.0 (localhost, ID:GGKU3SYS111-53040-1450084654453-0:1) is starting
INFO  transport.TransportServerThreadSupport  - Listening for connections at: tcp://127.0.0.1:61616
INFO  broker.TransportConnector  - Connector tcp://localhost:61616 Started
INFO broker.BrokerService  - Apache ActiveMQ 5.7.0 (localhost, ID:{IP}-53040-1450084654453-0:1) started
INFO  broker.BrokerService  - For help or more information please see: http://activemq.apache.org
INFO  plist.PListStore  - PListStore:[E:\Projects\GitDemo\JMSReceiver\my-activemq_data\localhost\tmp_storage] started
INFO  broker.TransportConnector  - Connector vm://localhost Started

Now you can use the same sender app and the receiver app  services to send and receive the messages. Only the configuration part is different every thing else remains same.

Please find the following examples code here:

JMSReceiverApp

JMSSenderApp

3 comments: