Jan 4, 2014

JMS with Spring 4

Extract this zip file on your local machine and now start activeMQ by running following command in bin folder of activeMQ
%ACTIVEMQ_HOME%\bin>activemq start
Following screen show successful start of ActiveMQ.



Ensure you are able to login to admin console from http://localhost:8161/admin/ with id and password as admin (i.e. id and password same 'admin'). Now go to tab "Queues" give queue name as 'springtest' and click on button "Create". This will create a queue named 'springtest' as shown below.



Now we will create two classes (spring beans). One to send a message to this queue and one to consume this message. so lets create following two classes.
HelloMessageProvider: Class that will read a product name by Calling DAO and send a message to queue “springtest”
HelloMessageConsumer: Class that will listen to “springtest” queue and print the message.
Also we need to tell these classes what JMS configurations they will use for sending and receiving messages. So we will provide following beans.
connectionFactory: Connection factory that will be used to connect to ActiveMQ server. This attribute is identified as brokerURL and its value will be tcp://localhost:61616.
defaultDestination: Destination Queue that will be used as default for sending or receiving message. We will use queue name springtest for this.
jmsTemplate: Spring JMSTemplate class (org.springframework.jms.core.JmsTemplate) that will be used to send and receive message.
We are keeping bean tags for sessionFactory and dataSource that was created in last article as it is since we want to use DAO class for getting product name from product id.
So our new spring-config.xml will look like following.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd">

      <!-- This sescion tells Spring context where to look for bean classes with appropriate annotations -->
      <context:component-scan base-package="com.techcielo.spring4"></context:component-scan>

      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://localhost:3306/northwind" />
            <property name="username" value="root" />
            <property name="password" value="" />
      </bean>

      <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
            <property name="brokerURL" value="tcp://localhost:61616" />
      </bean>

      <bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg index="0" value="springtest" />
      </bean>

      <bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
            <property name="connectionFactory" ref="connectionFactory" />
            <property name="defaultDestination" ref="defaultDestination" />
      </bean>

      <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="hibernateProperties">
                  <props>
                        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                        <prop key="hibernate.show_sql">true</prop>
                  </props>
            </property>

            <property name="annotatedClasses">
                  <list>
                        <value>com.techcielo.spring4.bean.Product</value>
                  </list>
            </property>
      </bean>
</beans>

Now we will create two classes as shown below.

package com.techcielo.spring4.jms.provider;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;

import com.techcielo.spring4.bean.Product;
import com.techcielo.spring4.dao.ProductDAO;

@Service("msgProviderSvc")
public class HelloMessageProvider
{     
       @Resource(name="jmstemplate")
       private JmsTemplate jmsTemplate;

       @Autowired
       private ProductDAO prodDAO;
       public void setProdDAO(ProductDAO prodDAO) {
              this.prodDAO = prodDAO;
       };
       public void sendMessage(int id){
              final Product prod = prodDAO.getProduct(id);
              System.out.println(prod.getName());
              jmsTemplate.send(new MessageCreator() {               
                     @Override
                     public Message createMessage(Session session) throws JMSException {
                           TextMessage msg = session.createTextMessage(prod.getName());
                           return msg;
                     }
              });
       }
}

And Consumer as follows
package com.techcielo.spring4.jms.consumer;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

@Service("msgConsumerSvc")
public class HelloMessageConsumer {
       @Resource(name="jmstemplate")
       private JmsTemplate jmsTemplate;
      
       public void readMessage() throws JMSException{
              System.out.println("Reading message");
              Message msg = jmsTemplate.receive();
              msg.acknowledge();
              msg.getJMSDestination();
              if (msg instanceof TextMessage) {
                     TextMessage txtmsg = (TextMessage) msg;
                     System.out.println(txtmsg.getText());
                    
              }
              System.out.println(msg.getClass());
              System.out.println("Done");
       }
}

Now we will write our Main class as follows to produce and consume messages.
package com.techcielo.spring4.main;

import javax.jms.JMSException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.techcielo.spring4.jms.consumer.HelloMessageConsumer;
import com.techcielo.spring4.jms.provider.HelloMessageProvider;

public class Main {
       public static void main(String[] args)
       {
              //Build application context by reading spring-config.xml
              ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"});
             
              //Get an instance of ProductService class;
              HelloMessageProvider prdSvc = (HelloMessageProvider) ctx.getBean("msgProviderSvc");
             
              HelloMessageConsumer conSvc = (HelloMessageConsumer) ctx.getBean("msgConsumerSvc");
             
              //Call getProduct method of ProductService
              prdSvc.sendMessage(1);
              try {
                     conSvc.readMessage();
              } catch (JMSException e) {
                     e.printStackTrace();
              }
       }
}

When we run this code following will be output.

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
In DAO class
Hibernate: select product0_.ProductID as ProductID0_0_, product0_.ProductName as ProductN2_0_0_ from products product0_ where product0_.ProductID=?
Sending Message:Chai
Reading message
Chai
class org.apache.activemq.command.ActiveMQTextMessage
Done

So that's all :). Please share your feedback.