Friday, February 7, 2014

HornetQ-Spring integration tutorial


What is HORNETQ?
HORNETQ is the default messaging system in JBOSS application server. It is an open source project used to build clustered, and asynchronous messaging system. More information can be found here. In my old blog posts I discussed about basic concepts such as how to create users to consume and produce messages in the messgaing system, and REST interface support . Please find tutorials below
  1.  HORNETQ- JMS REST tutorial
  2. HORNETQ JMS Tutorial  
While the above tutorial discuss about how to use HORNETQ through REST and JMS API, this tutorial will focus on how to integrate the highly scalable messaging system with Spring JMS module and the advantages one gets by doing so.
Technologies used in this tutorial are given below
  1. Spring 3.2
  2. JBOSS eap-6.1
  3. Maven
  4. HORNETQ 2.3.1
NOTE:Before getting starting create users,queues as shown in this post.
Spring-JMS has many advantages
  1. Avoid repetitive code
  2. Easy maintenance
  3. Exception translation etc.
This tutorial can be mainly divided into three parts. First we will try to produce a message to the queue. Second we will consume it through spring JMS template. Third we will have a simple POJO to consume the message.A simple POJO to consume a message!!! How cool is that!!! Thanks to spring-jms module.
Below is the controller which will be used to produce messages. For simplicity sake we will create a TextMessage and push it to the queue
package com.blogspot.itsvenkis;

import org.apache.log4j.Logger;
import org.springframework.http.MediaType;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.jms.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * User: itsvenkis
 * Date: 07/02/14
 */

@Controller
@RequestMapping(value ="/spring-jms")
public class SpringJmsController {

    private JmsTemplate jmsTemplate;
    private Logger logger = Logger.getLogger(SpringJmsController.class);

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    private Queue ticketQueue;
    public Queue getTicketQueue() {
        return ticketQueue;
    }

    public void setTicketQueue(Queue ticketQueue) {
        this.ticketQueue = ticketQueue;
    }

    @RequestMapping(value = "/produce-me", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public void saveMessage( HttpServletRequest request, HttpServletResponse response) throws IOException, JMSException {
         getJmsTemplate().send(getTicketQueue(),new MessageCreator() {
             @Override
             public Message createMessage(Session session) throws JMSException {
                 return session.createTextMessage("Hello Spring JMS!!!");
             }
         });
         logger.info("Sent message to the queue ....");
         response.setStatus(HttpServletResponse.SC_ACCEPTED);
    }

    @RequestMapping(value = "/consume-me", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public void consumeMessage(HttpServletRequest request, HttpServletResponse response) throws JMSException {
        TextMessage message = (TextMessage) getJmsTemplate().receive(getTicketQueue());
        logger.info("Received message "+message.getText());
    }

}

ConnectionFactory consists of various connection configuration parameters as defined by the admin user. A client i.e. SpringJMSTemplate uses it to create connections to the destinations. ConnectionFactories and destinations i.e. Queues/Topics are defined in standalone-full.xml . Below is the code snippet from standalone-full.xml

            
                true
                NIO
                2

                
                    
                    
                        
                    
                    
                

                
                    
                    
                        
                        
                    
                    
                

                
                    
                        
                        
                        
                        
                        
                        
                        
                    
                

                
                    
                        jms.queue.DLQ
                        jms.queue.ExpiryQueue
                        0
                        10485760
                        BLOCK
                        10
                    
                

                
                    
                        
                            
                        
                        
                            
                        
                    
                    
                        
                            
                        
                        
                            
                        
                    
                    
                        
                        
                            
                        
                        
                            
                        
                    
                

                
                    
                        
                    
                
            
        

Kindly note that ConnectionFactories are exposed as JNDI objects.We can use JNDI-lookups to get the ConenctionFactory in our spring application context. Below is the code snippet of applicationContext.xml


    
    

    
        
        
        
    

    
    

    
    

    
       
    

    
    


Doing a POST request to http://localhost:8080/spring-hornetq/spring-jms/produce-me will produce a message and push it to 'ticketOrderQueue'

The receipt of this message can be confirmed from the below screenshot
Let us do a GET request to http://localhost:8080/spring-hornetq/spring-jms/consume-me to consume the message.

Log messages
While everything is good so far!!! Dont you see a big disadvantage with this approach? Consuming message through an explicit GET request. Well!!! JMS is all about asynchronous message processing. So we would like to react to a message in the queue rather than doing a polling. In my previous blog posts you can notice that I used message driven beans to consume the message asynchronously.
Message Driven Beans was included in EJB 2 specification.Basically MDBs are EJBs that process messages asynchronously. With EJB 3 specification, we can just implement MessageListener interface for asynchronous processing. Spring-JMS module has its own implementation of MessageDriven beans by which we can convert a simple POJO to process the messages asynchronously. Below is the code snippet of our POJO
package com.blogspot.itsvenkis.mdp;


import org.apache.log4j.Logger;

/**
 * User: itsvenkis
 * Date: 07/02/14
 */
public class TicketQueueConsumer {
    private Logger logger = Logger.getLogger(TicketQueueConsumer.class);

    public void processTickets(String message){
        logger.info("Received message "+message);
    }
}
Just by adding two lines in applicationContext.xml, this simple POJO will be able to process the messages asynchronously. That is the beauty of Spring framework :)
   
        
    
web.xml

  
    org.springframework.web.context.ContextLoaderListener
  
  
    org.springframework.web.context.request.RequestContextListener
  
 
     spring-jms
     org.springframework.web.servlet.DispatcherServlet
     
         contextConfigLocation
         /WEB-INF/applicationContext.xml
     
 
 
     spring-jms
     /*
 

pom.xml

  4.0.0
  war
  spring-hornetq
  spring-hornetq
  spring-hornetq
  1.0-SNAPSHOT
  
        
            jboss
            http://repository.jboss.org/maven2
        
  
  
    
      
        org.mortbay.jetty
        maven-jetty-plugin
        6.1.7
        
          
            
              8888
              30000
            
          
          ${project.build.directory}/${pom.artifactId}-${pom.version}
          /
        
      
    
      spring-hornetq
  
  
      
          org.springframework
          spring-core
          3.2.0.RELEASE
      
      
          org.springframework
          spring-jms
          3.2.0.RELEASE
      
      
          org.springframework
          spring-webmvc
          3.2.0.RELEASE
      
      
          javax.servlet
          servlet-api
          2.5
          provided
      
      
          org.springframework
          spring-webmvc
          3.2.0.RELEASE
      
      
          org.hornetq
          hornetq-core-client
          2.3.1.Final
          provided
      
      
          org.hornetq
          hornetq-jms-client
          2.3.1.Final
          provided
      
      
          log4j
          log4j
          1.2.16
          provided
      
  

Happy learning!!!!
If you have any questions please do not hesitate to ask it in comments section. I will be very happy to answer them.
Dear Readers, kindly like this post on facebook or follow me on Google+

3 comments:

  1. Hi Venkat, Could you share the source code of your demo? Thanks :)

    ReplyDelete
  2. Hi Venkat, where I can find the standalone-full.xml? Thanks

    ReplyDelete
    Replies
    1. Assuming you are using jboss, standalone-full.xml should be available on your AS.If it is not jboss, HornetQ has its own way of configuring the queues. Kindly refer to its documentation here http://hornetq.jboss.org/docs

      Delete