Section 7.8. Sending a JMS Message


7.8. Sending a JMS Message

Now that we know the basics of JMS, we'll take the following steps to send a message:

  • Look up a ConnectionFactory using JNDI.

  • Get a Connection from the ConnectionFactory.

  • Create a Session associated with the Connection.

  • Look up a Destination using JNDI.

  • Create a Message Producer tied to the Destination.

  • Create a Message.

  • Send the Message.

  • Tear down the Message Producer, Session, and Connection.

JMS requires a lot of low-level tedious API calls to send a message, so Example 7-4 encapsulates everything into a JmsProducer utility object.

Example 7-4. JmsProducer.java
 package com.jbossatwork.util; import java.io.*; import javax.jms.*; /**  * <code>JmsProducer</code> encapsulates sending a JMS Message.  *  */ public class JmsProducer {     /**      * Making the default (no arg) constructor private      * ensures that this class cannnot be instantiated.      */     private JmsProducer(  ) {  }     public static void sendMessage(Serializable payload,           String connectionFactoryJndiName, String destinationJndiName)           throws JmsProducerException {         try {             ConnectionFactory connectionFactory = null;             Connection connection = null;             Session session = null;             Destination destination = null;             MessageProducer messageProducer = null;             ObjectMessage message = null;             connectionFactory = ServiceLocator.getJmsConnectionFactory(                                                      connectionFactoryJndiName);             connection = connectionFactory.createConnection(  );             session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);             destination = ServiceLocator.getJmsDestination(destinationJndiName);             messageProducer = session.createProducer(destination);             message = session.createObjectMessage(payload);             messageProducer.send(message);             messageProducer.close(  );             session.close(  );             connection.close(  );         } catch (JMSException je) {             throw new JmsProducerException(je);         } catch (ServiceLocatorException sle) {             throw new JmsProducerException(sle);         }     } } 

The JMS ConnectionFactory and Connection are both JNDI-based resources, so we've encapsulated the JNDI lookups with the ServiceLocatorwe'll show the look-up code in detail in the "Factoring Out the JNDI Calls" section. The ServiceLocator.getJmsConnectionFactory( ) call finds and instantiates the ConnectionFactory to gain access to the JMS provider. The ConnectionFactory creates a Connection. Use the following parameters in the Connection.createSession( ) call to create the Session:

  • The first parameter is a boolean that determines whether the Session is transacted. We've set this value to false because we don't want to manage the transaction programmatically. As you'll see in the later sections on deployment, we use Container-Managed Transactions so that JBoss manages the transaction for us.

  • The second parameter sets the acknowledgment mode. Using AUTO_ACKNOWLEDGE means that once the Consumer receives a message, an acknowledgment is sent to the JMS server automatically. Usually, you should use AUTO_ACKNOWLEDGE and let the container do all the work for you.

After we've created the Session, the ServiceLocator.getJmsDestination( ) call finds the Destination, a proxy to the actual destination (a queue, in this case, because of how it's deployed) on the JMS server. The Session's createProducer( ) method creates the MessageProducer, which sends messages to a destination asynchronously. The call to the Session's createObjectMessage( ) method creates an ObjectMessage method that contains the object passed into the JmsProducer's sendMessage( ) method. The MessageProducer's send( ) method sends the message to the destination, and we wrap up by closing the MessageProducer, Session, and Connection.

The code above may look a bit strange to readers experienced with previous releases of JMS (1.0.2 or earlier) and J2EE 1.3. What happened to the QueueConnectionFactory, QueueSender, QueueSession, QueueConnection, and the Queue? We don't need them anymore. Instead, use the JMS Unified Client API.

7.8.1. JMS Unified Client API

As of JMS 1.1, the Unified API is now available and works with both the Publish-Subscribe and Point-to-Point models. The JMS 1.1 specification encourages you to write all your new JMS code by using the Unified API, since the Queue and Topic-based APIs could become deprecated in a future version of JMS. However, the model-specific APIs will last for a while because so much production code uses them. Don't get the wrong ideathe physical JMS Queues and Topics are not going away. You'll still use them with the Unified API. The Unified API resembles the Queue and Topic-based APIs because it follows the same calling sequence. The big difference is that your code doesn't really care if you use Queues or Topics. All you need to provide are the JNDI names for Queue/Topic Connection Factory and Queue/Topic.

We recommend using the Unified API because it simplifies developmentyou don't need the Queue or Topic APIs anymore. You'll still send messages to a Queue or Topic (depending on the JNDI name you use), but this is now just a configuration issue. Your code becomes much more generic because it no longer uses queue or topic-specific API calls. With the Unified API, you always access JMS-based resources in the same way, regardless of your JMS messaging model.

We've wrapped the JMS API calls in the JmsProducer utility to make it easy to send a JMS message from the Controller Servlet. The JmsProducer used the ServiceLocator utility to find the ConnectionFactory and the JMS Destination using JNDI. Let's take a closer look at the ServiceLocator.

7.8.2. Factoring Out the JNDI Calls

We used the ServiceLocator throughout this book to wrap JNDI lookup calls Example 7-5 shows the new JMS-related methods.

Example 7-5. ServiceLocator.java
 package com.jbossatwork.util; ... import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.naming.*; ... public class ServiceLocator {     ...     public static ConnectionFactory getJmsConnectionFactory(         String jmsConnectionFactoryJndiName) throws ServiceLocatorException {         ConnectionFactory jmsConnectionFactory = null;         try {             Context ctx = new InitialContext(  );             jmsConnectionFactory = (ConnectionFactory)                     ctx.lookup(jmsConnectionFactoryJndiName);         } catch (ClassCastException cce) {             throw new ServiceLocatorException(cce);         } catch (NamingException ne) {             throw new ServiceLocatorException(ne);         }         return jmsConnectionFactory;     }     ...     public static Destination getJmsDestination(String jmsDestinationJndiName)     throws ServiceLocatorException {         Destination jmsDestination = null;         try {             Context ctx = new InitialContext(  );             jmsDestination = (Destination) ctx.lookup(jmsDestinationJndiName);         } catch (ClassCastException cce) {             throw new ServiceLocatorException(cce);         } catch (NamingException ne) {             throw new ServiceLocatorException(ne);         }         return jmsDestination;     } } 

The getJmsConnectionFactory( ) and getJmsDestination( ) methods, respectively, encapsulate a JNDI lookup for a JMS ConnectionFactory or JMS Destination. Both methods have the following steps in common:

  • Create the InitialContext to access the JNDI tree.

  • Perform a JNDI lookup.

  • Cast the object returned from JNDI to the correct JMS object type (ConnectionFactory or Destination) .

  • Throw a ServiceLocatorException that chains a low-level JNDI-related exception and contains a corresponding error message.

We've written all the code necessary to send a JMS message, and now we need to add JMS to our deployment. We'll start by adding JMS-based JNDI references to our web deployment descriptors.



JBoss at Work. A Practical Guide
JBoss at Work: A Practical Guide
ISBN: 0596007345
EAN: 2147483647
Year: 2004
Pages: 197

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net