Skip Headers

Oracle® Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 2 (10.1.2)
Part No. B15505-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

MDB Example

The MDB can process incoming asynchronous requests. Any message for the MDB is routed to the onMessage method of the MDB from the queue or topic. Other clients may have access to the same queue or topic to send messages for the MDB. Most MDBs receive messages from a queue or a topic, then invoke an entity bean to process the request contained within the message.

The steps to create an MDB, which are shown in the following sections, are as follows:

  1. Implement the bean, as shown in "MDB Example".

  2. Create the MDB deployment descriptors.

    1. Define the JMS connection factory and Destination used in the EJB deployment descriptor (ejb-jar.xml). Define if any durable subscriptions or message selectors are used. See "EJB Deployment Descriptor (ejb-jar.xml) for the MDB" for details.

    2. If using resource references, define these in the ejb-jar.xml file and map them to their actual JNDI names in the OC4J-specific deployment descriptor (orion-ejb-jar.xml).

    3. If the MDB uses container-managed transaction demarcation, specify the onMessage method in the <container-transaction> element in the ejb-jar.xml file. All of the steps for an MDB should be in the onMessage method. Since the MDB is stateless, the onMessage method should perform all duties. Do not create the JMS connection and session in the ejbCreate method. However, if you are using OracleAS JMS, then you can optimize your MDB by creating the JMS connection and session in the ejbCreate method and destroying them in the ejbRemove method.

  3. Create an EJB JAR file containing the bean and the deployment descriptors. Configure the application-specific application.xml file, create an EAR file, and install the EJB in OC4J.

The MDB implementation and the ejb-jar.xml deployment descriptor can be exactly the same for the OracleAS JMS or Oracle JMS providers—if you use resource references for the JNDI lookup of the connection factory and the Destination object. The orion-ejb-jar.xml deployment descriptor contains provider-specific configuration, including the mapping of the resource references. See "MDB Using OracleAS JMS" and "MDB Using Oracle JMS" for the specific configuration in the orion-ejb-jar.xml deployment descriptor.


Note:

The example used for the MDB example uses resource references, so that the MDB is generic. If you want to see how to explicitly define a JNDI string for each JMS provider, see "Client Access of MDB", as the client uses both explicit JNDI strings as well as resource references.

MDB Implementation Example

The major points to do when you implement an MDB are as follows:


Note:

See the EJB specification for the full details on all aspects of implementing a MDB.

  1. The bean class must be defined as public (not final or abstract).

  2. The bean class must implement the javax.ejb.MessageDrivenBean and javax.jms.MessageListener interfaces, which include the following:

    • the onMessage method in the MessageListener interface

    • the setMessageDrivenContext method in the MessageDrivenBean interface

  3. The bean class must implement the container callback methods that normally match methods in the EJB home interface. Remote, local, and home interfaces are not implemented with an MDB. However, some of the callback methods required for these interfaces are implemented in the bean implementation. These methods include the following:

    • an ejbCreate method

    • an ejbRemove method

Example 9-1 MDB Implementation

The following MDB example—rpTestMdb MDB—prints out a message sent to it through a queue and responds. The queue is identified in the deployment descriptors and the JMS configuration. In the onMessage method, the MDB creates a new message to be sent to the client. It sets the message selector property RECIPIENT to be for the CLIENT. Then, it sets the reply destination and sends the new message to the JMS client.

This example shows how to receive a message from a queue and send out a response. You can receive a message in several ways. This example uses the methods of the Message object to retrieve all attributes of the message.

To send out a response to a queue, you must first set up a sender, which requires the following:

  1. Retrieve the QueueConnectionFactory object. This example uses a resource reference of "jms/myQueueConnectionFactory," which is defined in the ejb-jar.xml file and mapped to the actual JNDI name in the orion-ejb-jar.xml file.

  2. Create the JMS queue connection using the createQueueConnection method of the QueueConnectionFactory object.

  3. Create a JMS session over the connection using the createQueueSession method of the QueueConnection object.

  4. Once the session is set up, then create a sender that uses the session through the createSender method of the QueueSession object.

    These steps are implemented as follows:

    private QueueConnection         m_qc    = null;
    private QueueSession            m_qs    = null;
    private QueueSender             m_snd   = null;
    QueueConnectionFactory qcf = (QueueConnectionFactory)
         ctx.lookup("java:comp/env/jms/myQueueConnectionFactory");
    m_qc = qcf.createQueueConnection(); 
    m_qs = m_qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    m_snd = m_qs.createSender(null);
    
    

    Once the sender is created, you can send any message using the send method of the QueueSender object. This example puts together a response from the received message and then use the sender to send out that response.

  5. Create a message using the createMessage method of the Message object.

  6. Set properties of the message using methods of the Message object, such as setStringProperty and setIntProperty.

  7. This example retrieves the destination for its response through the getJMSReplyTo method of the Message object. The destination was initialized in the message by the sender.

  8. Send out the response using the sender through the send method of the QueueSender object. Provide the destination and the response message.

    Message rmsg = m_qs.createMessage();
    rmsg.setStringProperty("RECIPIENT", "CLIENT");
    rmsg.setIntProperty("count",
    msg.getIntProperty("JMSXDeliveryCount"));
    rmsg.setJMSCorrelationID(msg.getJMSMessageID());
    Destination d = msg.getJMSReplyTo();
    m_snd.send((Queue) d, rmsg);
    

Example 9-2 MDB Implementation

The following is the complete example of the MDB that receives a message and sends back a response.

import java.util.*;
import javax.ejb.*;
import javax.jms.*;
import javax.naming.*;

public class rpTestMdb implements MessageDrivenBean, MessageListener
{
    private QueueConnection         m_qc    = null;
    private QueueSession            m_qs    = null;
    private QueueSender             m_snd   = null;
    private MessageDrivenContext    m_ctx   = null;

    /* Constructor, which is public and takes no arguments.*/
    public rpTestMdb()
    {    }

    /* setMessageDrivenContext method */
    public void setMessageDrivenContext(MessageDrivenContext ctx)
    {
      /* As with all EJBs, you must set the context in order to be 
         able to use it at another time within the MDB methods. */
      m_ctx = ctx;
    }

   /* ejbCreate method, declared as public (but not final or 
    * static), with a return type of void, and with no arguments.
    */
    public void ejbCreate()
    {    }

    /* ejbRemove method */
    public void ejbRemove()
    {    }

   /**
    * onMessage method
    * Receives the incoming Message and displays the text.
    */
    public void onMessage(Message msg)
    {
       /* An MDB does not carry state for an individual client. */
       try
        {
            Context ctx = new InitialContext(); 
          // 1. Retrieve the QueueConnectionFactory using a 
          // resource reference defined in the ejb-jar.xml file.
            QueueConnectionFactory qcf = (QueueConnectionFactory)
                ctx.lookup("java:comp/env/jms/myQueueConnectionFactory");
            ctx.close();

            /*You create the queue connection first, then a session 
              over the connection. Once the session is set up, then
              you create a sender */
          // 2. Create the queue connection
            m_qc = qcf.createQueueConnection(); 
          // 3. Create the session over the queue connection.
            m_qs = m_qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
	// 4. Create the sender to send messages over the session.
            m_snd = m_qs.createSender(null);
     
            /* When the onMessage method is called, a message has
               been sent. You can retrieve attributes of the message using the 
             Message object. */
            String txt = ("mdb rcv: " + msg.getJMSMessageID());
            System.out.println(txt + " redel="
                + msg.getJMSRedelivered() + " cnt="
                + msg.getIntProperty("JMSXDeliveryCount"));

            /* Create a new message using the createMessage 
              method. To send it back to the originator of the other message, 
            set the String property of "RECIPIENT" to "CLIENT."
            The client only looks for messages with string property CLIENT.
            Copy the original message ID into new msg's Correlation ID for
            tracking purposes using the setJMSCorrelationID method. Finally,
              set the destination for the message using the getJMSReplyTo method
            on the previously received message. Send the message using the  
            send method on the queue sender.
          */
           // 5. Create a message using the createMessage method 
            Message rmsg = m_qs.createMessage();
           // 6. Set properties of the message.
            rmsg.setStringProperty("RECIPIENT", "CLIENT");
            rmsg.setIntProperty("count",
                msg.getIntProperty("JMSXDeliveryCount"));
            rmsg.setJMSCorrelationID(msg.getJMSMessageID());
            // 7. Retrieve the reply destination.
            Destination d = msg.getJMSReplyTo();
              //  8. Send the message using the send method of the sender.
            m_snd.send((Queue) d, rmsg);

            System.out.println(txt + " snd: " + rmsg.getJMSMessageID());

            /* close the connection*/
            m_qc.close();
        }
        catch (Throwable ex)
        {
            ex.printStackTrace();
        }
    }
}

Note:

The entire MDB example is available on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.

EJB Deployment Descriptor (ejb-jar.xml) for the MDB

Within the EJB deployment descriptor (ejb-jar.xml), define the MDB name, class, JNDI reference, and JMS Destination type (queue or topic) in the <message-driven> element. If a topic is specified, you define whether it is durable. If you have used resource references, define the resource reference for both the connection factory and the Destination object.

The following example demonstrates the deployment information for the rpTestMdb MDB in the <message-driven> element, as follows:

  • MDB name specified in the <ejb-name> element.

  • MDB class defined in the <ejb-class> element, which ties the <message-driven> element to the specific MDB implementation.

  • JMS Destination type is a Queue that is specified in the <message-driven-destination><destination-type> element.

  • Message selector specifies that this MDB only receives messages where the RECIPIENT is MDB.


    Note:

    You could also specify a topic in this type definition. If you did specify a Topic in the type, then you could also define the durability of the topic, which is specified in the <message-driven-destination> <subscription-durability> element as "Durable" or "nonDurable."

  • The type of transaction to use is defined in the <transaction-type> element. The value can be Container or Bean. If Container is specified, define the onMessage method within the <container-transaction> element with the type of CMT support.

  • The resource reference for the connection factory is defined in the <resource-ref> element; the resource reference for the Destination object is defined in the <resource-env-ref> element. See "Using a Logical Name When Client Accesses the MDB" for a full discussion on resource references for JMS object types.

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>

<ejb-jar>
    <display-name>Mdb Test</display-name> 
    <enterprise-beans>
        <message-driven>
            <display-name>testMdb</display-name>
            <ejb-name>testMdb</ejb-name>
            <ejb-class>rpTestMdb</ejb-class>
            <transaction-type>Container</transaction-type>
            <message-selector>RECIPIENT='MDB'</message-selector>
            <message-driven-destination>
                <destination-type>javax.jms.Queue</destination-type>
            </message-driven-destination> 
	            <resource-ref>
                <description>description</description>
                <res-ref-name>jms/myQueueConnectionFactory</res-ref-name>
                <res-type>javax.jms.QueueConnectionFactory</res-type>
                <res-auth>Application</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>
            </resource-ref> 
            <resource-env-ref>
               <resource-env-ref-name>jms/persistentQueue             </resource-env-ref-name>
             <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
            </resource-env-ref> 
        </message-driven>
    </enterprise-beans>

    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>testMdb</ejb-name>
                <method-name>onMessage</method-name>
                <method-params>
                    <method-param>javax.jms.Message</method-param>
                </method-params>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor> 
</ejb-jar>

If you were going to configure a durable Topic instead, then the <message-driven-destination> element would be configured as follows:

<message-driven-destination>
  <destination-type>javax.jms.Topic</destination-type>
  <subscription-durability>Durable</subscription-durability>
</message-driven-destination>

Note:

The entire MDB example is available on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.

The OC4J-specific deployment descriptor (orion-ejb-jar.xml) for this MDB and the JMS provider configuration necessary is shown in the following sections:

Instructions on how a client sends a JMS message to the MDB is discussed in "Client Access of MDB".