JMS and GlassFish 4–The Overview

As part of the latest Java EE release (version 7), the JMS component has been reviewed and revamped. I was recently fortunate enough to attend the inaugural London GlassFish Users Group earlier this week where Nigel Deakin from Oracle was presenting the latest features and developments.

This blog post is really to expand my knowledge, test some of the things mentioned, and to act as reference to my future self.

1. Getting Started

All examples in this blog post are going to be using GlassFish 4.0 and NetBeans 7.3.

1.1 Queue Creation

First of all start the GlassFish server, and then log into the Admin Console (localhost:4848). We’re then going to create our Queue and Connection Factory to handle the queue.

Next up, create the queue by navigating to Resources –> JMS Resources –> Destination Resources, and click New. Then enter the following parameters:

image

Then create the Connection Factory by going to Resources –> JMS Resources –> Destination Resources, and enter the following parameters:

image

Thats us got the infrastructure for the queue to function. (I’ve subsequently discovered there is no need for the Connection Factory, GF4 provides a default one that would be used if no others have been created!).

1.2 Sending First Message (using JMS 1.1)

Now return to NetBeans and lets create a servlet to send the first message. We’re going to use JMS 1.1 for this example, before then doing JMS 2.0 which will hopefully show some of the simplifications that have been made.

In NetBeans create a new servlet, named something like JMSOne. Then add the following code to the processRequest() method.


Connection connection = null;
ConnectionFactory connectionFactory = null;
Destination dest = null;
Context jndiContext = null;

try {
   jndiContext = new InitialContext();
   connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/testQueueFactory");
   dest = (Destination) jndiContext.lookup("jms/testQueue");

   connection = connectionFactory.createConnection();

   // The 2 parameters passed here do not make any difference in GF!
   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   MessageProducer producer = session.createProducer(dest);
   TextMessage message = session.createTextMessage();
   message.setText("First test message!");
   producer.send(message);
} catch (NamingException | JMSException e) {
   System.err.println("Exception raised: " + e.getMessage());
   e.printStackTrace(System.err);
} finally {
   if (connection != null) {
      connection.close();
   }

   if (jndiContext != null) {
      jndiContext.close();
   }
}

Run the servlet, and perhaps have some output, either to the screen or to the GlassFish log and your message should send. (How do I know its been sent? Well, this is something that I think is lacking in GF – or I’m missing something simple. I can’t see where you can see the current status of the queue – but I’ll see if I can address this later in this blog post).

1.3 Retrieving the Message

Now we need to create a message consumer to read the message that we have just sent. NetBeans makes this incredible straight-forward to do by providing most of the code for you.

Right click the project and create New->Enterprise Java Beans –> Message Driven Beans and then enter the parameters for the queue that we created previously.

The code to retrieve the bean is entered into the onMessage() method and looks like:

@Override
public void onMessage(Message message) {
   String msg;
   try {
      msg = ((TextMessage) message).getText();
      Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, msg);
   } catch (JMSException ex) {
      Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, null, ex);
   }
}

1.4 Sending using JMS 2.0

So the code previous is straight-forward, but slightly long winded. Admittedly some could be removed with try with resources functionality introduced in JavaEE 7, but still. Now create a new Java Servlet, along the lines of JMSTwo.

The code to send the message now looks like this (using JMS 2.0) (note, I’m calling sendMessage() from my processRequest method):

@Resource(lookup = "jms/testQueue")
private Queue queue;
@Inject
private JMSContext jmsContext;

private void sendMessage() {
   String msg = "My JMS 2.0 Message";
   jmsContext.createProducer().send(queue, msg);
}

The code is now down to 2 lines, and 1 of those is to declare the data to send. There is no need for the session, connection factory or connection. Everything is taken care of.

2. Other JMS 2.0 Improvements

Alongside the simplifications to sending a message, JMS 2.0 has brought about a few other enhancements. These are:

  • Delayed Delivery
  • Async Sending
  • Improvements to Poison Message Handling

2.1 Delayed Delivery Example

The code for this a very straight-forward. The time is in milliseconds, so the code below delays sending the message for 60 seconds. Note this doesn’t hold the servlet from continuing. By watching my server.log for the 60 seconds after, we see the text from the message appear.

jmsContext.createProducer().setDeliveryDelay(60000).send(queue, msg);

2.2 Async Sending

This doesn’t fit well into this blog post – its for use with standalone applications outside of the Java EE Web and EJB containers. It does however allow the application to send a message and then continue processing further steps without the need to wait for a reply.

A future blog post may look into standalone applications sending messages.

2.3 Poison Message Handling

Poison Message Handling really comes into effect when a message is returned to the queue for re-processing for whatever reason. The most obvious example would be when a connection to the database cannot be obtained (e.g. due to network or infrastructure issues). An improvement that has been made in JMS 2.0 is that the number of times a message has been processed can be retrieved.

For this we’re going to update the onMessage() received bean. The code below throws a dummy exception to return the message back to the queue. After the 3rd attempt, it writes the message contents to the server.log for later processing.

By updating the receiving code to look like this, we can see the message redelivery count increasing:

String msg;
try {
   msg = ((TextMessage) message).getText();
   int deliveryCount = message.getIntProperty("JMSXDeliveryCount");
   String deliveryCountStr = "Received this message " + deliveryCount + " times.";
   Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, deliveryCountStr);

   if (deliveryCount == 2) {
      Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, "Message can''t be processed. Details...: {0}", msg);
   } else {
      Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, "Throwing a dummy runtime exception");
      throw new RuntimeException("Dummy Exception");
   }
} catch (JMSException ex) {
   Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, null, ex);
}

And the truncated version of the server.log file now looks like this (removing the stack traces for brevity):

SEVERE:   Received this message 1 times.
SEVERE:   Throwing a dummy runtime exception
WARNING:   MQJMSRA_MR2001: run:Caught Exception from onMessage():Redelivering:
SEVERE:   Received this message 2 times.
SEVERE:   Message can’t be processed. Details…: My JMS 2.0 Message

A more suitable use case for myself in this scenario is actually getting the message queue to stop processing messages in this scenario. I’d like then to build up whilst the reason for failure is detected (normally due to it being a networking / database issue).

I’ve yet to find something that I’m completely comfortable with, but provided this message doesn’t return, no further messages will be process. So prior to throwing a RuntimeException, I can put in place a Thread.sleep(milliseconds) to sleep for a period of time.

Logger.getLogger(NewMessageBean.class.getName()).log(Level.SEVERE, "Throwing a dummy runtime exception");
Thread.sleep(60000);
throw new RuntimeException("Dummy Exception");

This would allow messages to build up. The time to hold the queue for would need to be specific for the scenario being catered for. Ultimately it could be for an hour or so, and then remove the check for the number of times the message has been processed and just allow it to continue re-processing the message.

3. Monitoring the Queue(s)

3.1 imqadmin Tool

I said earlier that there is no default out-of-the-box monitoring within GlassFish for JMS. Thats not strictly true. Unfortunately (unless I’m missing something?) its not available in the Admin Console.

GlassFish does come bundled with a number of command line utilities, one of which being the Admin Manager for MQ. This utility can be found in \glassfish4\mq\bin and launched via imqadmin.

image

You then need to add a broker to localhost (Right-click on Brokers and Add…). The settings should be localhost, 7676, admin and admin (unless you’ve changed your localhost Admin password). Once added, you can then click the ‘Physical Destinations’ under your broker and the testQueue created earlier will appear.

By selecting the queue, and then clicking Properties (either via the Icon on the Toolbar or via Actions-Properties menu). This will show you details about the queue, including the number of messages sitting in it (0 at this stage).

To show some messages sitting in the queue, we can head back to our code and rename the queue being processed by the Message Bean to be testQueue2. Then running the sendMessage servlet we can populate the queue, with no listeners to pick the messages up. (For this to deploy correctly, you’ll need to create testQueue2 as per steps at the start of this post) (Further note – I also had to restart GlassFish after creating the 2nd queue – the broker and the application got completely confused and started only displaying the new queue?!? – Yet another reason to re-start GF?)

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/testQueue2")
})

By running the send message servlet 5 times and then restarting the imqadmin client and connecting to localhost and viewing properties for queueTest I can see 5 message waiting in the queue.

image

3.2 Monitoring via a Servlet

This all seems quite long winded, so I put together a little servlet that would do something similar, using the QueueBrowser class. The QueueBrowser allows you to peek at the Message Queue without stripping the messages out.

I’ve yet to discover a way of listening all the queues on the server, but can’t imagine this would be difficult. Could quite easily create a JSP to ask the user to enter the queue name and then retrieve the messages and count from this servlet with some simple modifications.

try {
   QueueBrowser queueBrowser = jmsContext.createBrowser(queue);
   out.println("Queue Name: " + queueBrowser.getQueue().getQueueName() + "<br/>");
   Enumeration messages = queueBrowser.getEnumeration();
   int count = 0;
   while (messages.hasMoreElements()) {
      count++;
      TextMessage msg = (TextMessage) messages.nextElement();
      out.println("Message [" + count + "] contains " + msg.getText() + "<br/>");
   }
   out.println("Number of messages = " + count);
} catch (JMSException ex) {
   Logger.getLogger(queueViewer.class.getName()).log(Level.SEVERE, null, ex);
} finally {
   out.close();
}

4. Safety of Messages

One benefit from my experience in the MS world of MSMQ is the way messages are safely stored in cash of unexpected system restarts etc. With my 5 messages safely in the queue I’m going to restart GlassFish to see what happens to them.

And I’m pleased to say its kept them safe.

image

5. Conclusion

All in all this has been a whirlwind tour of JMS in general, but with a glance towards some of the new functionality in JMS 2.0. If anything is wrong in this post please let me know – I’m completely acknowledging my ‘learning’ position with regards to this technology.

Likewise, if anything is missing that you’d like me to research and cover, please let me know.

I’m already looking forward to the next GlassFish Users Group next month.

2 thoughts on “JMS and GlassFish 4–The Overview

  1. Thanks very much for your detailed jms tutorials. Please i am looking for a situation where JMS message can be configured dynamically from the java code instead of configuring in the glassfish server before writing the code. Thanks.

  2. HI
    thanks for this guide
    i fllowed euther the2 mehodes but no wrking
    the firs (without using JSCNTEXT gives tis eror
    Exception raised: com.sun.messaging.jms.ra.DirectConnectionFactory cannot be cast to javax.xml.registry.ConnectionFactory
    Infos: java.lang.ClassCastException: com.sun.messaging.jms.ra.DirectConnectionFactory cannot be cast to javax.xml.registry.ConnectionFactory
    at servlets.MyJMS_WithoutEJC.sendMessage0(MyJMS_WithoutEJC.java:128)
    at servlets.MyJMS_WithoutEJC.processRequest(MyJMS_WithoutEJC.java:64)
    at servlets.MyJMS_WithoutEJC.doPost(MyJMS_WithoutEJC.java:104)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)

    the second return Nulointer for jmscontext (not injected)

    could u please tell me what’s error
    best regads

Leave a comment