Apache ActiveMQ and Tomcat
Today I want to investigate how to integrate JMS functionality into a web application running within a Tomcat servlet container (7.x). As we do not use a fully fledged application server, we have to care about registering the ConnectionFactory and Queue within the JNDI context. In this exmple I chose Apache ActiveMQ as a JMS provider. As a simple example, I want to have two Servlets: The first Servlet pushes messages into a queue, whereas the second Servlet pulls them out of the queue and displays the messages as an HTML page.
Let’s add the necessary maven dependencies to our pom.xml:
<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-core</artifactId> <version>5.7.0</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency>
As Tomcat has only a static JNDI, we add the ConnectionFactory and the Queue via the context.xml:
<?xml version='1.0' encoding='utf-8'?> <Context> <Resource name="jms/ConnectionFactory" auth="Container" type="org.apache.activemq.ActiveMQConnectionFactory" description="JMS Connection Factory" factory="org.apache.activemq.jndi.JNDIReferenceFactory" brokerURL="vm://localhost" brokerName="LocalActiveMQBroker" useEmbeddedBroker="true"/> <Resource name="jms/queue/MyQueue" auth="Container" type="org.apache.activemq.command.ActiveMQQueue" factory="org.apache.activemq.jndi.JNDIReferenceFactory" physicalName="MY.TEST.FOO.QUEUE"/> </Context>
Let’s setup a simple Servlet that listens to the URL /sendMessage:
@WebServlet(name = "SendMessageServlet", urlPatterns = "/sendMessage") public class SendMessageServlet extends HttpServlet { private static final Logger logger = LoggerFactory.getLogger(SendMessageServlet.class); @Override protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { logger.info("doGet() called"); String parameter = getTextParameter(httpServletRequest); sendMessage(parameter); writeResponse(httpServletResponse, parameter); } [...] }
The text to send is given as a GET-Parameter to the URL. The method sendMessage() contains the relevant code. Here we can access the ConnectionFactory through our JNDI Context:
InitialContext initCtx = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory) initCtx.lookup("java:comp/env/jms/ConnectionFactory"); Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer((Destination) initCtx.lookup("java:comp/env/jms/queue/MyQueue"));
Thus, sending a text message to the queue is quite simple:
TextMessage testMessage = session.createTextMessage(); testMessage.setText(text); testMessage.setStringProperty("aKey", "someRandomTestValue"); producer.send(testMessage);
Now it is time to setup a second Servlet that enables us to read all messages from the queue. The code for the sceleton is quite similar to the first Servlet:
@WebServlet(name = "ReceiveMessageServlet", urlPatterns = "/receiveMessage") public class ReceiveMessageServlet extends HttpServlet { private static final Logger logger = LoggerFactory.getLogger(ReceiveMessageServlet.class); @Override protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { logger.info("doGet() called"); Optional<String> text = receiveMessages(); writeRepsonse(httpServletResponse, text); } [...] }
In our receiving Servlet we use the following code to create a QueueReceiver:
InitialContext initCtx = new InitialContext(); QueueConnectionFactory connectionFactory = (QueueConnectionFactory) initCtx.lookup("java:comp/env/jms/ConnectionFactory"); QueueConnection queueConnection = connectionFactory.createQueueConnection(); QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) initCtx.lookup("java:comp/env/jms/queue/MyQueue"); QueueReceiver receiver = queueSession.createReceiver(queue);
Finally, we can receive the text message, we have sent before:
queueConnection.start(); try { Message m = receiver.receive(1000); if (m != null && m instanceof TextMessage) { TextMessage tm = (TextMessage) m; text = Optional.of(tm.getText()); logger.debug(String.format("Received TextMessage with text '%s'.", text)); } else { logger.debug(String.format("No TextMessage received: '%s'", m)); } } finally { queueSession.close(); queueConnection.close(); }
The whole source code can be found on github: https://github.com/siom79/jms-and-tomcat.