The JMS Resource in J2EE

The JNDI Environment Naming Context (ENC) is central to the J2EE platform. The JNDI ENC specifies that JMS connection factories (Topic-ConnectionFactory and QueueConnectionFactory) can be bound within a JNDI namespace and made available to any J2EE component at runtime. This allows any J2EE component to become a JMS client.

For example, the Wholesaler JMS client developed in Chapter 4, could be modeled as a J2EE application client, which would allow it to access a JMS connection factory through the JNDI ENC:

public class Wholesaler implements javax.jms.MessageListener{   
   public Wholesaler(String username, String password){
      try{

         InitialContext jndiEnc = new InitialContext( );
                  
         TopicConnectionFactory factory = (TopicConnectionFactory)
            jndiEnc.lookup("java:comp/env/jms/broker");
         connect = factory.createTopicConnection (username, password);

         session = 
          connect.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
         
         hotDealsTopic=(Topic)
             jndiEnc.lookup("java:comp/env/jms/HotDeals");
         publisher = session.createPublisher(hotDealsTopic);

         ...
         
      } catch (javax.jms.JMSException jmse){
         jmse.printStackTrace( ); System.exit(1);
      } catch (javax.naming.NamingException jne){
         jne.printStackTrace( ); System.exit(1);
      }
   }
...

Notice that the InitialContext did not need a set of vendor specific properties and that the lookup( ) operations referenced a special namespace, "java:comp/env/jms/", to access the connection factories. The JNDI ENC allows the J2EE component to remain ignorant of the actual network location of the administered objects, and even of the vendor that implements them. This allows the J2EE components to be portable across JMS providers as well as J2EE platforms. In addition, the JNDI names used to locate objects are logical bindings, so the topics or queues bound to these names can change independently of the actual bindings used by the JMS provider.

In the XML deployment descriptor for the Wholesaler application client, the component developer declares that a JMS connection factory and destination need to be bound within the JNDI ENC:

<application-client>
  <display-name>Wholesaler Applicaton</display-name>
    <resource-ref>
      <description>Hot Deals Broker</description>
      <res-ref-name>jms/broker</res-ref-name>
      <res-type>javax.jms.TopicConnectionFactory</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>
...
    <resource-env-ref>
      <description>Hot Deals Topic</description>
      <resource-env-ref-name>jms/HotDeals</resource-env-ref-name>
      <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
    </resource-env-ref>
...

When the component is deployed, the J2EE vendor tools generate code to translate the JNDI ENC resource references into JMS-administered objects. This translation is done when the bean is deployed using administration tools.

Any J2EE component can access JMS connection factories and destinations using the JNDI ENC. As an example, the Wholesaler client can be rewritten as a stateless session bean that uses the JNDI ENC to obtain a JMS connection factory and destination:

public class WholesalerBean implements javax.ejb.SessionBean{

   ...

   public void setSessionContext(SessionContext cntx){
      try {

         InitialContext jndiEnc = new InitialContext( );
                  
            TopicConnectionFactory factory = (TopicConnectionFactory)
            jndiEnc.lookup("java:comp/env/jms/broker");
         connect = factory.createTopicConnection (username, password);

         session = 
          connect.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
         
         hotDealsTopic=(Topic)
             jndiEnc.lookup("java:comp/env/jms/HotDeals");
         publisher = session.createPublisher(hotDealsTopic);

         ...
         
      }
      ...
   }
   public void publishPriceQuotes(String dealDesc, String username, 
                                   String itemDesc,  float oldPrice, 
                                   float newPrice){
      try {
        javax.jms.StreamMessage message = 
                  session.createStreamMessage( );
        message.writeString(dealDesc);
        ...               
                   
        publisher.publish(
            message,
            javax.jms.DeliveryMode.PERSISTENT,
            javax.jms.Message.DEFAULT_PRIORITY,
            1800000);
            
      } catch ( javax.jms.JMSException jmse ){
         jmse.printStackTrace( );
      }      
   }
   ...
}

Although session, entity, and web components can all act as JMS producers, these components can only consume JMS messages synchronously using the MessageConsumer.receive( ) methods. Calling one of the receive( ) methods causes the JMS client to pole the queue or topic and wait for a message.[1] These methods are used to consume messages synchronously, while MessageListener objects are used to consume messages asynchronously.

Only the message-driven bean and application client components can both produce and consume asynchronous messages. The web, session, and entity components cannot act as asynchronous JMS consumers because they are driven by synchronous request-reply protocols, not asynchronous messages. Web components respond to HTTP requests while entity and session beans respond to Java RMI-IIOP requests.

The fact that neither web components nor session and entity beans can asynchronously consume JMS messages was one of the things that led to development of the message-driven bean. The message-driven bean provides J2EE developers with a server-side JMS consumer that can consume asynchronous messages, something they didn't have before EJB 2.0.



[1] It's recommended that the component developer use the nonblocking method, receiveNoWait( ), to conserve resources and avoid blocking. Unrestricted blocking is not limited to any length of time, and is therefore risky.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset