How to listen to a message queue from a web application? (Tomcat, ActiveMQ)

Dimitri Dewaele picture Dimitri Dewaele · Jul 28, 2015 · Viewed 16.3k times · Source

I'm happily improving my web application that runs on a Apache Tomcat. An ActiveMQ JMS server is added to send and receive messages.

I already can send and receive messages, but need help on the receiver side.

How should my web app continuously listen to one queue to receive messages?

New messages arrive and the server should act on them. Ex: add data to the DB or or send an message back.

I can already send messages. This is code.

ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("clientQueue");
MessageProducer publisher = session.createProducer(queue);
connection.start();

Message message = null;
message = session.createTextMessage("Text Message");
publisher.send(message);

I can already receive a message after a request (a click ;-))

connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("serverQueue");
consumer = session.createConsumer(destination);

while (true) {
    Message message = consumer.receive(300000);
    //Do message stuff
}

How should I let the web application listen to the queue continuously? What is the advised way?

All help is warmly appreciated. Thanks.

EDIT - SOLUTION

Current working solution with the proposals from DaveH

I have added a ServletContextListener to listen to my message continuously.

web.xml

<listener>
    <listener-class>com.test.JMSContextListener</listener-class>
</listener>

The Listeren:

public class JMSContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        Thread thread = new Thread(new JMSConnector());
        thread.start();
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        //Nothing
    }
}

The Connection:

public class JMSConnector implements Runnable {
    public void run() {
        try {
            Context context = new InitialContext();
            QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup("java:comp/env/jms/ConnectionFactory");            
            Connection connection = factory.createConnection();
            Queue queue = (javax.jms.Queue) context.lookup("java:comp/env/jms/serverQueue");
            Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);

            MessageConsumer consumer = session.createConsumer(queue);

            //This MessageListener will do stuff with the message
            MessageListenerImpl messageListener = new MessageListenerImpl();
            consumer.setMessageListener(messageListener);
            connection.start();

            // Start connection or nothing will happen!!!
            connection.start();
        } catch (JMSException ex) {
            //TODO
        } catch (NamingException ex) {
            //TODO
        }
    }
}

Is this an advised way or should this be improved?

All help is warmly appreciated. Thanks.

Answer

DaveH picture DaveH · Jul 28, 2015

If you have code that already can consume messages from the queue ( which it appears you do ), then I think your problem comes down to how do you get that piece of code to run.

It appears you aren't using any frameworks so I think the approach that I would take would be to take that code that can retrieve messages from the queue and run it in a separate thread in the application server. Get that thread to start up at application server start time, and tidy up itself as the application server closes down.

Easiest way to start the thread on app server startup is to introduce a ServletContextListener ( an example here.) In the Context Listener start your queue listening code in a separate thread.

EDIT: I used this proposed solution and added the code above to the question.