Spring JMS works on the fundamental concept of Dependency Injection which is core to the Spring framework. For a JMS Sender on a very high level, a Connection factory is injected along with the destination name to a JNDI template object, which again is then injected to the actual JMS Sender bean. The JMS Sender bean is a custom piece of code, but implements the JMSTemplate interface from Spring. Once implemented, basic JMS Operations can be easily performed.
Below I'm detailing the steps for implementing a JMS Queue Sender first, followed by a Queue Listener.
1) We will use the applicationContext.xml file to construct all our beans. First we configure the JNDI context parameters using Spring classes
Set the jndiTemplate class from Spring as a bean, and inject it's property constructor in the following manner:
<
bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"><property name="environment"><props><prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory</prop><prop key="java.naming.provider.url">localhost</prop></props></property>Note the Tibco specific factory name. I also have a Tibco EMS server running on my localhost, hence will be using localhost as the provider url ( If you use a different port, then port number needs to be part of the URL too. Please refer to the Tibco EMS documentation for more info)
2) Once the jndi template is created, we will now create the actual JNDI objects using Spring's JNDI Object Factory bean.
<
bean id="internalJmsQueueConnectionFactory"class="org.springframework.jndi.JndiObjectFactoryBean"><property name="jndiTemplate"><ref bean="jndiTemplate"/></property><property name="jndiName"><value>QueueConnectionFactory</value></property><!-- JMS Sender Destination -->
<bean id="senderdestination"class="org.springframework.jndi.JndiObjectFactoryBean"><property name="jndiTemplate"><ref bean="jndiTemplate"/></property><property name="jndiName"><value>jms/SPRING.SENDER.TEST</value></property>3) Now that we have created the JNDI template, it's time to create the JMS Queue template as below
<!-- JMS Queue Template --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory"><ref bean="internalJmsQueueConnectionFactory"/></property><property name="defaultDestination"><ref bean="senderdestination"/></property><property name="receiveTimeout"><value>30000</value></property>
4) Now we have a logical entity to send a JMS Message. But wait.. nothing refers to this entity. We need to create a simple Java bean which provides getter setter for the jmsTemplate and then use one of the factory methods to send a message. Once done the bean needs to be declared in the xml file too, so that it can be accessed by external programs ( like your jsp's and swing gui's)
EMSMessageSender.java
5) The EMS Message Creator used by the EMS Message sender above is a simple class implementing the Spring MessageCreator interface. It retuns the TextMessage that needs to be sent to the JMS queue.
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.MessageCreator;
import org.w3c.dom.Document;
public class EMSMessageCreatorImpl implements MessageCreator {
private static Log log = LogFactory.getLog(EMSMessageCreatorImpl.class);
private Session sess;
public Document doc;
public EMSMessageCreatorImpl(Document doc){
this.doc = doc;
}
@Override
public Message createMessage(Session sess) throws JMSException {
OutputStream byteOut = new ByteArrayOutputStream();
DOMSource dom = new DOMSource(doc);
TextMessage tm = null;
try {
TransformerFactory transformerfactory = TransformerFactory.newInstance(); // Getting new TransformerFactory
Transformer transformer = transformerfactory.newTransformer(); // Getting new Transformer
transformer.transform(dom, new StreamResult(byteOut)); // Transforms DOMSource to StreamResult
this.sess = sess;
tm = sess.createTextMessage();
tm.setText(byteOut.toString());
}
catch (Exception e) {
String msg = "Failed to create a message - " + e.getMessage();
log.fatal(msg, e);
throw new JMSException(msg);
}
return tm;
}
public Session getSess(){
return sess;
}
}
6) Finally, we wire the bean along with the jms template, so that it can be used externally
<bean id="jmsSender" class="EMSMessageSender"><property name="jmsTemplate"><ref bean="jmsTemplate"/></property></bean>
</bean></bean></bean>
4) Now we have a logical entity to send a JMS Message. But wait.. nothing refers to this entity. We need to create a simple Java bean which provides getter setter for the jmsTemplate and then use one of the factory methods to send a message. Once done the bean needs to be declared in the xml file too, so that it can be accessed by external programs ( like your jsp's and swing gui's)
EMSMessageSender.java
import
org.apache.commons.logging.Log;import
org.apache.commons.logging.LogFactory;import
org.springframework.jms.core.JmsTemplate;import
org.w3c.dom.Document;
public
}
class EMSMessageSender {private static Log log = LogFactory.getLog(EMSMessageSender.class);private JmsTemplate jmsTemplate;public JmsTemplate getJmsTemplate() {return jmsTemplate;/*** @param jmsTemplate The jmsTemplate to set.*/}
}
}
}5) The EMS Message Creator used by the EMS Message sender above is a simple class implementing the Spring MessageCreator interface. It retuns the TextMessage that needs to be sent to the JMS queue.
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.MessageCreator;
import org.w3c.dom.Document;
public class EMSMessageCreatorImpl implements MessageCreator {
private static Log log = LogFactory.getLog(EMSMessageCreatorImpl.class);
private Session sess;
public Document doc;
public EMSMessageCreatorImpl(Document doc){
this.doc = doc;
}
@Override
public Message createMessage(Session sess) throws JMSException {
OutputStream byteOut = new ByteArrayOutputStream();
DOMSource dom = new DOMSource(doc);
TextMessage tm = null;
try {
TransformerFactory transformerfactory = TransformerFactory.newInstance(); // Getting new TransformerFactory
Transformer transformer = transformerfactory.newTransformer(); // Getting new Transformer
transformer.transform(dom, new StreamResult(byteOut)); // Transforms DOMSource to StreamResult
this.sess = sess;
tm = sess.createTextMessage();
tm.setText(byteOut.toString());
}
catch (Exception e) {
String msg = "Failed to create a message - " + e.getMessage();
log.fatal(msg, e);
throw new JMSException(msg);
}
return tm;
}
public Session getSess(){
return sess;
}
}
6) Finally, we wire the bean along with the jms template, so that it can be used externally
<bean id="jmsSender" class="EMSMessageSender"><property name="jmsTemplate"><ref bean="jmsTemplate"/></property></bean>
7) That's it!! we're done. Let's test it out now
If our test program runs outside the application, then it will not have access to the application context, and hence the jms bean. We thus need to give it the application context manually. If our class is inside the application, we can implement the ApplicationContextAware interface by Spring, and bingo..
For our purpose, here's a test servlet. I'm using a test xml which will be converted into a DOM document, which will be then sent to the JMS queue.
java.io.IOException; org.springframework.web.context.*;
That's it. You should have successfully been able to send the JMS message, once the servlet runs.try{catch ( Exception e){System.out.println(e.getMessage());}"Got request"); com.aoc.SpringEMS.SendMessage;public class JMSSender extends javax.servlet.http.HttpServlet {static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.getServletContext();if (ctx == null){System.out.println("");}new JMSSender();out.println("test");"jmsSender");
import
java.io.*;
import
javax.servlet.ServletException;import
javax.servlet.http.HttpServletRequest;import
javax.servlet.http.HttpServletResponse;import
javax.servlet.*;
//import org.springframework.context.support.ClassPathXmlApplicationContext;
import
org.springframework.web.context.ServletContextAware;import
org.springframework.web.context.support.WebApplicationContextUtils;import
import
com.aoc.SpringEMS.EMSMessageSender;import
ServletContext ctx =
JMSSender jmssender =
System.
WebApplicationContext wc = WebApplicationContextUtils.getWebApplicationContext(ctx);
EMSMessageSender emssender = (EMSMessageSender)wc.getBean(
dbf
= DocumentBuilderFactory.newInstance();doc = dbf.newDocumentBuilder().parse("C:/test.xml");emssender.sendMessage(doc);
}
Writer resp = response.getWriter();
resp.write(
}
}That's it. You should have successfully been able to send the JMS message, once the servlet runs.try{catch ( Exception e){System.out.println(e.getMessage());}"Got request"); com.aoc.SpringEMS.SendMessage;public class JMSSender extends javax.servlet.http.HttpServlet {static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.getServletContext();if (ctx == null){System.out.println("");}new JMSSender();out.println("test");"jmsSender");
import
public void setJmsTemplate(JmsTemplate jmsTemplate) {this.jmsTemplate = jmsTemplate;public void sendMessage(Document doc) {if (doc == null) {log.warn("Document is null.");jmsTemplate.send(new EMSMessageCreatorImpl(doc));</bean>