ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Using a JMS Provider with MDBs via the J2EE Connector Architecture Using a JMS Provider with MDBs via the J2EE Connector Architecture

by Debu Panda
06/23/2004

Messaging software packages such as OracleAQ, Websphere MQ, and Tibco have been an integral part of enterprise business applications. If you have been a Java developer for long, then you are probably aware how difficult it was to build messaging applications using J2EE before Message-Driven Beans (MDBs) were introduced as part of J2EE 1.3. The great thing about MDBs are that they make the life of an application developer simpler by delegating the responsibility of providing infrastructure for transactions, security, and concurrently processing messages to the EJB container. However, if you jumped on the MDB bandwagon very early, you might have found a few restrictions, such as:

  1. MDB was only meant for JMS messages.
  2. There was no standard way to integrate messaging providers with J2EE containers, and this led to limited support for messaging providers from each J2EE vendor.

You are not alone if you found that your favorite J2EE container had issues supporting the messaging provider of your choice. The J2EE 1.4 specification addresses these two issues by:

For example, Oracle Corporation has built a generic resource adapter for OracleAS Containers for J2EE (OC4J) to support major JMS providers such as Websphere MQ, Tibco, etc. Also, SwiftMQ has built a resource adapter to integrate its messaging software with J2EE-1.4-compliant application servers such as OC4J.

In this article I will provide a brief introduction to MDB and the J2EE Connector Architecture (JCA), examining how MDBs can be deployed with the JCA 1.5 resource adapter to use a JMS provider. I will also provide some best practices for using MDBs with resource adapters.

Introduction to Message-Driven Beans

An MDB is essentially a message consumer that can listen to a message destination or a message endpoint and gets activated when a message arrives. By design, MDBs are anonymous in nature and hence cannot be directly invoked by a client. The only way to invoke an MDB is to send a message to the destination or endpoint to which it is listening. As MDBs are stateless in nature and are not related to any specific client, they can be pooled for concurrent processing of messages. Figure 1 depicts a simple diagram of how an MDB works.

Figure 1
Figure 1. MDB relationships in OC4J

You should consider using MDBs if your business application requires any of the following:

  • Asynchronous processing of messages.
  • Integration of applications required in a loosely coupled manner.
  • Processing of business rules (workflow) on message delivery.

An MDB does not have interfaces like other types of EJBs; it only has a bean-implementation class. The MDB bean class has to implement the javax.ejb.MessageDrivenBean interface. It must also implement the message listener interface required by the messaging type that it supports. For example, if the MDB supports JMS, then it must implement the javax.jms.MessageListener interface. If the MDB supports the Java API for XML Messaging (JAXM), it should implement either the javax.xml.messaging.OnewayListener or javax.xml.messaging.ReqRespListener interfaces.

Here is a code example for a very simple MDB that supports JMS messages. It is clear from the code that the MDB is a concrete class and MDB has a method named onMessage() that needs to be implemented by the bean developer. The onMessage() method gets executed when a message arrives at the destination or endpoint where the MDB is listening. The MDB lifecycle methods ejbCreate() and ejbRemove() are executed when an MDB instance is created or removed.

import javax.ejb.*;
import javax.jms.*;
import javax.naming.*; 
public class simpleMdb
  implements MessageDrivenBean, MessageListener
  {
  private XAQueueConnectionFactory m_xaqcf = null;
  private Queue m_replyq = null;
  private QueueConnection m_qc = null;
  private QueueSession m_qs = null;
  private QueueSender m_snd = null;
  private MessageDrivenContext m_ctx = null;

  public simpleMdb()
  {
  }
 public void setMessageDrivenContext(MessageDrivenContext ctx)
  {
  m_ctx = ctx;
  }
 public void ejbCreate()
  {
  try
  {
  Context ctx = new InitialContext();
  m_xaqcf = (XAQueueConnectionFactory)
  ctx.lookup("java:comp/env/jms/XAQCF");
  m_replyq = (Queue) ctx.lookup("java:comp/env/jms/QUEUE1");
  ctx.close();
  }
  catch (Throwable ex)
  {
   ex.printStackTrace();
  }
  }
 public void ejbRemove()
  {
  try
  {
  if (m_qc != null)
  m_qc.close();
  }
  catch (Throwable ex)
  {
   ex.printStackTrace();
  }
  }
 public void onMessage(Message msg)
  {
  try
  {
   String txt = ("MDB rcv: " + msg.getJMSMessageID());
   System.out.println(txt + " redel="
    + msg.getJMSRedelivered() + " cnt="
    + msg.getIntProperty("JMSXDeliveryCount"));

   /* Create connection, session and sender */
   QueueConnection qcon = m_xaqcf.createQueueConnection();
   QueueSession qsess = qcon.createQueueSession
    (false, Session.AUTO_ACKNOWLEDGE);
   QueueSender snd = qsess.createSender(m_replyq);
   boolean ignore = msg.getBooleanProperty ("ignoreMsg");
   if (ignore)
   {
     System.out.println(txt + " noreply");
     return;
   }
   Message rmsg = qsess.createMessage();
   rmsg.setStringProperty("RECIPIENT", "CLIENT");
   rmsg.setIntProperty("count",
   msg.getIntProperty("JMSXDeliveryCount"));
   rmsg.setJMSCorrelationID(msg.getJMSMessageID());
   snd.send(rmsg);
   if (msg.getBooleanProperty("doRollback")
    && (!msg.getJMSRedelivered()))
   {
    System.out.println(txt + " rollback: " +
     rmsg.getJMSMessageID());
    m_ctx.setRollbackOnly();
   }
  else
  {
   System.out.println(txt + " snd: " +
     rmsg.getJMSMessageID());
  }
  qcon.close();
  }
  catch (Throwable ex)
  {
  ex.printStackTrace();
  }
 }
}

With an MDB, you need to identify the destination types and configure the JMS providers to create the message destination (such as a Queue or Topic) for the MDBs. You can deploy the MDB to use the JMS provider via the proprietary interface provided by your J2EE container or use a JCA resource adapter.

Now let us turn our attention to the J2EE Connector Architecture before jumping into the details of how MDBs can be deployed using the JMS providers and JCA resource adapter.

Pages: 1, 2

Next Pagearrow