JMS – Quick and dirty.

Up and running in 20 minutes, or less!

 

The Java Messaging System presents a very interesting model for Asynchronous messaging. In essence, it provides the plumbing for sending a messages (or serializable objects) from disparate systems to a central listener which monitors the queue. Once a message is received, by the listener, it can then take some action on it. You can think of it as e-mail or Instant Messaging for applications. The listener will receive the messages in the order they were received by the Queue.

 

NOTE: This tutorial is for Non-AsyncFW users.  While this is a good introduction for all, AsyncFW users should click here, and read the tutorial. 

 

Configure Glassfish:

 

Start Glassfish and open the Admin Console: http://localhost:4848/

 

 

 

 

To use JMS, you first need to configure a ‘Connection Factory’ and a ‘Destination Resource’.

 

Select the ‘Connection Factories’ menu tree option, and click ‘New’.

 

Next, fill out the connection factory information as shown.

 

 

…and click the ‘Save’ button.

 

NOTE: It is good practice to actually name your JNDI resources something like the following “jms/AsyncFWFactory”, but for now, the above is fine.

 

Select the ‘Destination Resources’ menu tree item, and click the ‘New’ button.

 

 

Enter the information below;

 

 

…and click the Save button.

 

NOTE: It is good practice to actually name your JNDI resources something like the following “jms/AsyncFWQ”, but for now, the above is fine.

 

That’s it! You have just completed the configuration of a JMS Queue in Glassfish.

 

Configuring the new resources in your project

 

Before your application can use the JNDI reference to the queue, you will need to configure it in your web.xml. Please add the following;

 

<resource-ref>

     <description>Default QueueFactory</description>

     <res-ref-name>AsyncFWQFactory</res-ref-name>

     <res-type>javax.jms.QueueConnectionFactory</res-type>

     <res-auth>Container</res-auth>

</resource-ref>

<resource-ref>

     <description>Default Queue</description>

     <res-ref-name>AsyncFWQ</res-ref-name>

     <res-type>javax.jms.Queue</res-type>

     <res-auth>Container</res-auth>

</resource-ref>

 

Let’s write some code.

 

Coding For The JMS Queue

 

The JMS messaging model requires that you have at least a two party conversation. Someone must talk, and someone must listenJ. You may have many talkers, and as a matter of course, only one listener.

 

So when we start coding we need to keep in mind both sides of the conversation, and the type of data that is going to be passed. To begin, we will assume that we are going to send a simple TextMessage.

 

“Talking to yourself is stupid!” – Setting up the listener:

 

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

 

public class SampleListener implements MessageListener{

    

     @Override

     public void onMessage(Message message) {

        try {

            System.out.println("\nText Message:" +

                   ((TextMessage) message).getText());

          } catch (Exception e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

         

     }

}

 

To create a listener, you must implement the MessageListener interface, and implement its onMessage method.

Initialize the Queue:

 

Consider the following design: Create a single class that will initialize the queue and the listener - as well as provide the methods to send messages. This is not required, but it makes messaging rather simple to setup.

 

 

import java.io.Serializable;

 

import javax.jms.JMSException;

import javax.jms.MessageConsumer;

import javax.jms.MessageListener;

import javax.jms.MessageProducer;

import javax.jms.ObjectMessage;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.Session;

import javax.jms.TextMessage;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

public class SampleQueue {

 

      private MessageListener Listener = null;

      private QueueConnectionFactory qFactory;

      private Queue queue;

      private Context env;

 

      public SampleQueue() throws NamingException, JMSException{

            env =(Context) new InitialContext().lookup("java:comp/env");

            initQueue();

      }

      public void postObjectMessage(Serializable msgObj) throws JMSException{

            Session session = null;

 

            javax.jms.Connection conn =

                   (QueueConnection)qFactory.createQueueConnection();

            session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);

            MessageProducer producer = session.createProducer(queue);

 

            ObjectMessage msg = session.createObjectMessage(msgObj);

 

            producer.send(msg);

            producer.close();

            session.close();

            conn.close();

      }

      public void postTextMessage(String msg) throws JMSException{

            Session session = null;

 

            javax.jms.Connection conn =

                    (QueueConnection)qFactory.createQueueConnection();

            session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);

            MessageProducer producer = session.createProducer(queue);

 

            TextMessage message = session.createTextMessage();

            message.setText(msg);

 

            producer.send(message);

            producer.close();

            session.close();

            conn.close();

      }

      private void initQueue() throws NamingException, JMSException  {

            qFactory = (QueueConnectionFactory)env.lookup("AsyncFWQFactory");

            queue =  (Queue)env.lookup("AsyncFWQ");

 

            Listener = new SampleListener();

 

            javax.jms.Connection conn =

                    (QueueConnection)qFactory.createQueueConnection();

 

            Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);

            MessageConsumer consumer = session.createConsumer(queue);

            consumer.setMessageListener(Listener);

            conn.start();

      }

 

}

 

In the above code, the SampleQueue class takes care of everything for us. Once the class is created, the listener is in place, and ready to receive Messages.  This class would be much improved as a singleton…

 

.

.

private static SampleQueue SQ = null;

     

private SampleQueue() throws NamingException, JMSException{

      env =(Context) new InitialContext().lookup("java:comp/env");

      initQueue();

}

public static SampleQueue getInstance() throws

                             NamingException, JMSException{

      if(null == SQ)

            SQ = new SampleQueue();

      return SQ;

}

.

.

 

While the above code has been developed to be easy to understand, it does lack in the area of error handling, and object clean up. I would suggest doing a bit of hardening before deploying to a non-test environment.

 

That’s it – Now you can create an instance of the class (or better yet, get an Instance), and perform a “postTestMessage()” and see the results displayed in the console as the listener process the request.

 

Trouble Shooting:


How To Get Rid Of: com.sun.messaging.jmq.io.Packet cannot be cast to com.sun.messaging.jms.ra.DirectPacket in Glassfish V2.X

 

If you are running Glassfish and using JMS (e.g. a Message Driven Bean), you probably saw already the following error in the log files: DirectConsumer:Caught Exception delivering messagecom.sun.messaging.jmq.io.Packet cannot be cast to com.sun.messaging.jms.ra.DirectPacket.

The error is caused by directly embedding the JMS-Host into Glassfish v2 - it can be easily fixed in the admin console:

 Open the admin console: http://localhost:4848

  1. Select: Configuration -> Java Message Service node in the tree on the left side.
  2. Change the type from "Embedded" into "Local". The doc says:
    "
    Choose LOCAL (the default for the server-config configuration) to access the JMS service on the local host. The JMS service is started and managed by the Application Server."
  3. Restart Glassfish

 

 

 

Copyright 2009. All rights reserved by

S. Chappell