Develop a J2EE application to use JMS
Use this task to develop a J2EE application to use the JMS API directly for asynchronous messaging.
Overview
This topic gives an overview of the steps needed to develop a J2EE application (servlet or enterprise bean) to use the JMS API directly for asynchronous messaging.
This topic only describes the JMS-related considerations; it does not describe general J2EE application programming, which you should already be familiar with. For detailed information about these steps, and for examples of developing a J2EE application to use JMS, see the Java Message Service Documentation
Details of JMS resources that are used by J2EE applications are defined to WAS and bound into the JNDI namespace by the WebSphere administrative support.
To use JMS, any method of a J2EE application completes the following general steps:
Procedure
- Import JMS packages. A J2EE application that uses JMS starts with a number of import statements for JMS, which should include at least the following
import javax.jms.*; //JMS interfaces import javax.naming.*; //Used for JNDI lookup of administered objects- Get an initial context.
try { ctx = new InitialContext(env); ...- Retrieve administered objects from the JNDI namespace. The InitialContext.lookup() method is used to retrieve administered objects (a JMS connection factory and JMS destinations); for example, to receive a message from a queue
qcf = (QueueConnectionFactory)ctx.lookup( qcfName ); ... inQueue = (Queue)ctx.lookup( qnameIn ); ...
An alternative, but less manageable, approach to obtaining administratively-defined JMS destination objects by JNDI lookup is to use the Session.createQueue(String) method or Session.createTopic(String) method. For example
creates a JMS Queue instance that can be used to reference the existing destination Q1.Queue q = mySession.createQueue("Q1");
In its simplest form, the parameter to these create methods is the name of an existing destination. For more complex situations, applications can use a URI-based format, which allows an arbitrary number of name value pairs to be supplied to set various properties of the JMS destination object.
connection = qcf.createQueueConnection();
The JMS specification defines that connections should be created in the stopped state. Until the connection starts, MessageConsumers that are associated with the connection cannot receive any messages. To start the connection, issue the following command
connection.start();
boolean transacted = false; session = connection.createQueueSession( transacted, Session.AUTO_ACKNOWLEDGE);
In this example, the session is not transacted, and it should automatically acknowledge received messages. With these settings, a message is backed out only after a system error or if the application terminates unexpectedly.
The following points, as defined in the EJB specification, apply to these flags:
QueueSender queueSender = session.createSender(inQueue);
JMS provides several message types, each of which embodies some knowledge of its content. To avoid referencing the vendor-specific class names for the message types, methods are provided on the Session object for message creation.
In this example, a text message is created from the outString property
TextMessage outMessage = session.createTextMessage(outString);
To send the message, the message is passed to the send method on the QueueSender
queueSender.send(outMessage);
messageID = outMessage.getJMSMessageID();
The correlation ID is then used in a message selector, to select only messages that have that ID
String selector = "JMSCorrelationID = '"+messageID+"'";
QueueReceiver queueReceiver = session.createReceiver(outQueue, selector);
Message inMessage = queueReceiver.receive(2000);
The parameter in the receive call is a timeout in milliseconds. This parameter defines how long the method should wait if there is no message available immediately. If you omit this parameter, the call blocks indefinitely. If you do not want any delay, use the receiveNoWait()method. In this example, the receive call returns when the message arrives, or after 2000ms, whichever is sooner.
In this example, the instanceof operator is used to check that the message received is of the TextMessage type. The message content is then extracted by casting to the TextMessage subclass.
if ( inMessage instanceof TextMessage ) ... String replyString = ((TextMessage) inMessage).getText();
queueReceiver.close(); ... queueSender.close(); ... session.close(); session = null; ... connection.close(); connection = null;
// Creating a TopicPublisher TopicPublisher pub = session.createPublisher(topic); ... pub.publish(outMessage); ... // Closing TopicPublisher pub.close();
Unlike normal Java exceptions, a JMSException can contain another exception embedded in it. The implementation of JMSException does not include the embedded exception in the output of its toString()method. Therefore, we need to check explicitly for an embedded exception and print it out, as shown in the following example:
catch (JMSException je) { System.out.println("JMS failed with "+je); Exception le = je.getLinkedException(); if (le != null) { System.out.println("linked exception "+le); } }