Thursday, January 29, 2009

JMS Request-Response Messaging

JMS applications are often used to create event-driven style applications where an application creates a message listener and just continues on its own business. When a message arrives, the message listener's onMessage(Message m) method is called and the message is passed to the application as the method's parameter.

There are occasions when applications require using a request-response style messaging. A message producer sends a message containing a request and waits for the message consumer to respond. The producer determines its subsequent actions based on the response message.

The JMS API provides two simple classes, QueueRequestor and TopicRequestor, that are useful for implementing the request-response style messaging. However, these classes only provide an API that blocks on waiting for the response message until the response message is received. An application could block and "hang" if the response message never arrives.

This article introduces a simple mechanism to implement request-response style messaging with a timed wait on the response message. A TemporaryDestination (refers to a TemporaryQueue or a TemporaryTopic) can be used as the mechanism to implement this requirement.

A TemporaryDestination has the following characteristics.

  • It is created from the Session or its subclass. It is a destination object that does not require using the administrator's utility.
  • It has the lifetime of the connection in which it was created.
  • It is (in practice) set in a message using the Message.setJMSReplyTo() API.
  • It is (in practice) obtained using the Message.getJMSReplyTo() API.
  • It can only be consumed by the same connection that created it.

The following example uses a TemporaryQueue mechanism to implement a Ping utility. The Ping utility can be used to check if a queue message listener is active.

The example consists of three components.

1. The Ping message.

A simple ping message is defined as follows so that the message listener can tell that it received a ping message (not a business message).

A Ping Message is a Message type that contains a boolean property named "emessaging_ping_message" with its value set to true.


2. The message listener.

When a listener receives a ping message, it simply sends a ping reply to the temporary topic obtained from the ping message.

The pseudo code looks like this:

onMessage (Message msg) {
if (msg == PingMessage) {

//get the destination instance where the ping reply is to be sent.
Destination dest = msg.getJMSReplyTo();

//create a producer instance
producer = session.createProducer(dest);

//create ping reply message
Message pingReply = session.createMessage();
pingReply.setBooleanProperty(EMPing.PING_MESSAGE_REPLY, true);


producer.send(pingReply);
} else {
process_msg;
}
}


3. The Ping program.

This is a simple JMS application that sends a message to a destination and expects a response from the consumer (message listener).

The pseudo code looks like this:
//create a message producer on the destination
MessageProducer producer = session.createProducer(dest);

//create a ping message
Message m = session.createMessage();
//set ping message property
m.setBooleanProperty(PING_MESSAGE, true);

//create a temporary destination
TemporaryTopic respDest = session.createTemporaryTopic();

//set destination for the ping_reply message
m.setJMSReplyTo(respDest);

//create a message consumer to receive the ping_reply message
//This statement must be in front of the send statement
MessageConsumer consumer = session.createConsumer(respDest);

//tell the connection I am ready to receive the reply
conn.start();

//send the ping message
producer.send(m);

//receive ping reply message with max timeout 10 seconds.
Message rm = consumer.receive(10000);

if (rm == null) {
System.out.println ("\nlistener on destination is non-responsive:\n ");
} else {
System.out.println ("\nlistener on destination is alive.");
}


The complete code example is attached to this article.

3 comments: