7.8. Sending a JMS MessageNow that we know the basics of JMS, we'll take the following steps to send a message:
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.javapackage 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:
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 APIAs 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 CallsWe used the ServiceLocator throughout this book to wrap JNDI lookup calls Example 7-5 shows the new JMS-related methods. Example 7-5. ServiceLocator.javapackage 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:
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. |