Sunday, December 21, 2008

Sending JMS message to ActiveMQ using Spring 2.5 from a web application

In this post I will show how you can send JMS message to ActiveMQ from your Spring web application. I have a Spring 2.5 + JBOSS Richfaces based web application that runs on Tomcat 6 running on JDK 5. Figure 1. depicts what I intend to do.

F1

Figure 1. - Send JMS Message to ActiveMQ using Spring from a web application.

Step 1: Drop in the following jars to WEB-INF/lib

  • activemq-core-5.2.0.jar
  • jms.jar
  • geronimo-j2ee-management_1.0_spec-1.0.jar

Step 2: Create the destination/Queue using the ActiveMQ admin web application.

Launch your browser and point it to - http://localhost:8161/admin/

 image

Figure 2. - ActiveMQ admin console.

Click on 'Queues' to navigate to queue list and create screen. You will need to supply the queue name and click on 'Create' to create a new queue destination on ActiveMQ server. This is shown in Figure 3.

image

Figure 3 - Create a new Queue.

Step 3. Create a message producer interface.

This may not be necessary, but since I prefer to implement Program to Interface in my application i define a message producer interface. This is shown in Listing 1.

Listing 1 - MessageProducer.java

/**
*
*/
package org.opengarage.pingscape.mq.producer;

/**
* @author dhrubo
*
*/
public interface MessageProducer {
    public void send(Object message);
}

This interface defines a single method(can have more, but for now this will suffice) which accepts an object (Java bean) which will be passed to the Queue.

Step 4. An implementation of the MessageProducer interface

This class is responsible for sending a particular Javabean object to the queue (your goal may be different / may want to send something different).

Listing 2 - EventInvitationMessageProducer.java

/**
*
*/
package org.opengarage.pingscape.mq.producer;

import javax.jms.Queue;

import org.opengarage.pingscape.bean.Event;
import org.springframework.jms.core.JmsTemplate;

/**
* @author dhrubo
*
*/
public class EventInvitationMessageProducer implements MessageProducer{
    private JmsTemplate jmsTemplate;
    private Queue queue;
    private EventMessageCreator messageCreator;
    /**
     * @param jmsTemplate the jmsTemplate to set
     */
    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }
    /**
     * @param queue the queue to set
     */
    public void setQueue(Queue queue) {
        this.queue = queue;
    }

    /**
     * @param messageCreator the messageCreator to set
     */
    public void setMessageCreator(EventMessageCreator messageCreator) {
        this.messageCreator = messageCreator;
    }

    public void send(Object message) {
        this.messageCreator.setEvent((Event)message);
        this.jmsTemplate.send(this.queue, this.messageCreator);
    }

}

The key is the send method. It uses a MessageCreator to consume the supplied Event object. It then uses the JmsTemplate to send this message to the destination.

Step 5. Provide the message creator implementation

Listing 3 - EventMessageCreator.java

/**
*
*/
package org.opengarage.pingscape.mq.producer;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;

import org.opengarage.pingscape.bean.Event;
import org.springframework.jms.core.MessageCreator;

/**
* @author dhrubo
*
*/
public class EventMessageCreator implements MessageCreator {
    private Event event;
    /* (non-Javadoc)
     * @see org.springframework.jms.core.MessageCreator#createMessage(javax.jms.Session)
     */
    public Message createMessage(Session session) throws JMSException {
        ObjectMessage objectMsg = session.createObjectMessage();
        objectMsg.setObject(event);
        return objectMsg;
    }
    /**
     * @param event the event to set
     */
    public void setEvent(Event event) {
        this.event = event;
    }

}

Step 6 - Wire up in Spring configuration

Listing 4 - spring-activemq-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <bean id="jmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL">
            <value>tcp://localhost:61616</value>
        </property>
    </bean>
    <bean id="queue" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>queue.opengarage</value>
        </constructor-arg>
    </bean>
    <!-- Spring JMS Template -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory">
      <!-- lets wrap in a pool to avoid creating a connection per send -->
            <bean class="org.springframework.jms.connection.SingleConnectionFactory">
                <property name="targetConnectionFactory">
                    <ref local="jmsFactory" />
                </property>
            </bean>
        </property>
    </bean>
    <!-- a sample POJO message producer which uses a Spring JmsTemplate -->
    <bean id="messageProducer" class="org.opengarage.pingscape.mq.producer.EventInvitationMessageProducer">
        <property name="jmsTemplate" ref="jmsTemplate"/>
        <property name="queue" ref="queue"/>
        <property name="messageCreator">
            <bean class="org.opengarage.pingscape.mq.producer.EventMessageCreator"/>
        </property>
    </bean>
</beans>

Step 7 - Client of the message producer

Now we need a client to use the message producer. The Event business service class will use this message producer. This is shown in Listing 5.

Listing 5 - EventServiceImpl.java

/**
*
*/
package org.opengarage.pingscape.service.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengarage.pingscape.bean.Event;
import org.opengarage.pingscape.business.api.EventService;
import org.opengarage.pingscape.mq.producer.MessageProducer;

/**
* @author dhrubo
*
*/
public class EventServiceImpl implements EventService {
    private static final Log _LOG = LogFactory.getLog(EventServiceImpl.class);
   
    private MessageProducer messageProducer;

    /* (non-Javadoc)
     * @see org.opengarage.pingscape.business.api.EventService#saveEvent(org.opengarage.pingscape.bean.Event)
     */
    public void saveEvent(Event event) {
        messageProducer.send(event);
    }
   
     /**
     * @param messageProducer the messageProducer to set
     */
    public void setMessageProducer(MessageProducer messageProducer) {
        this.messageProducer = messageProducer;
    }

}

Step 8 - Configure in Spring application context.

The message producer is injected by the Spring framework. Here is the configuration snippet from the service configuration.

Listing 6 - spring-service-config.xml

<!-- Other beans -->

<bean name="eventService"
        class="org.opengarage.pingscape.business.impl.EventServiceImpl">
         <property name="messageProducer" ref="messageProducer" />
    </bean>

Step 9 - Test for message

Finally I restart my Tomcat when everything is ready, launch the event entry form, fill in data and click on Send button in the screen. The event details are now in the queue. You can test this in the ActiveMQ admin web console as shown in the Figure - 4 below.

image

Figure 4 - New message now in the Queue.

0 comments:

Post a Comment