Skip Headers
Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide
10g (10.1.3.5.0)

Part Number E13981-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

Implementing an EJB 2.1 MDB

Table 17-1 summarizes the important parts of an EJB 2.1 message-driven bean and the following procedure describes how to implement these parts. For a typical implementation, see "Using Java".

Table 17-1 Parts of an EJB 2.1 MDB Entity Bean

Part Description

Bean implementation

This class must be declared as public, contain a public, empty, default constructor, one public, void ejbCreate method with no arguments, and no finalize() method.

Implements javax.ejb.MessageDrivenBean to provide an empty implementation for life cycle method ejbRemove and an implementation of the setMessageDrivenContext method.

Implements javax.jms.MessageListener to provide an implementation of the onMessage method.


For more information, see "What is a Message-Driven Bean?".

Note:

You can download EJB code examples from:.

To implement an EJB 2.1 message-driven bean, do the following:

  1. Implement the MDB entity bean:

    1. Implement a public, zero-argument constructor.

    2. Implement any methods that are private to the bean or package used for facilitating the business logic. This includes private methods that your public methods use for completing the tasks requested of them.

    3. Implement the ejbCreate method. The container invokes this method when it instantiates the MDB.

      The return type of the ebjCreate methods is void.

    4. Provide an empty implementation for each of the javax.ejb.MessageDrivenBean interface container callback methods.

      For more information, see "Configuring a Life Cycle Callback Method for an EJB 2.1 MDB".

    5. Implement a setMessageDrivenContext method that takes an instance of MessageDrivenContext (see "Implementing the setMessageDrivenContext Method").

    6. Implement the appropriate message listener interface:

      For a JMS message-driven bean, implement the javax.jms.MessageListener interface to provide the onMessages method with signature:

      public void onMessage(javax.jms.Message message)
      

      For a non-JMS message service provider, implement the message listener interface (or interfaces) it specifies.

      This method processes the incoming message. Most MDBs receive messages from a queue or a topic, then invoke an entity bean to process the request contained within the message.

  2. Configure message service provider information (see "Using Deployment XML":

    1. Define the message connection factory and Destination used in the EJB deployment descriptor (ejb-jar.xml). Define if any durable subscriptions or message selectors are used.

      For more information, see the following:

    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.

      In general, do not create the message service connection and session in the ejbCreate method.

      Note:

      If you are using OEMS JMS (see "OEMS JMS: In-Memory or File-Based Provider"), then you can optimize your MDB by creating the JMS connection and session in the ejbCreate method and destroying them in the ejbRemove method.

Using Java

Example 17-1 shows a typical implementation of an EJB 2.1 MDB.

Example 17-1 EJB 2.1 MDB Implementation

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() {
    }

    /**
     * Begin private methods. The following methods
     * are used internally.
     */

...

    /**
     * Begin EJB-required methods. The following methods are called
     * by the container, and never called by client code.
     */

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

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

    // life cycle Methods

    public void ejbRemove() {
    }


    /**
     * JMS MessageListener-required methods. The following
     * methods are called by the container, and never called by
     * client code.
     */

    // Receives the incoming Message and displays the text.
    public void onMessage(Message msg) {
       // 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();

            // 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();
        }
    }
}

Using Deployment XML

Using the ejb-jar.xml file, 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.

Example 17-2 shows the ejb-jar.xml file message-driven element corresponding to the MDB shown in Example 17-1.

Note the following:

  • 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.

Example 17-2 ejb-jar.xml For an EJB 2.1 MDB

...
    <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> 
...

If you were going to configure a durable Topic instead, then the <message-driven-destination> element would be configured Example 17-3.

Example 17-3 ejb-jar.xml For an EJB 2.1 MDB for a Durable Topic

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

For more information, see "Configuring an EJB 2.1 MDB to Access a Message Service Provider Directly".

Implementing the setMessageDrivenContext Method

An MDB instance uses this method to retain a reference to its context. Message-driven beans have contexts that the container maintains and makes available to the beans. The bean may use the methods in the message-driven context to retrieve information about the bean, such as security, and transactional role. Refer to the EJB specification from Sun Microsystems for the full range of information that you can retrieve about the bean from the context.

The container invokes the setMessageDrivenContext method, after it first instantiates the bean, to enable the bean to retrieve the context. The container will never call this method from within a transaction context. If the bean does not save the context at this point, the bean will never gain access to the context.

Example 17-4 shows an MDB saving the message-driven context in the ctx variable.

Example 17-4 Implementing the setMessageDrivenContext Methods

import javax.ejb.*;

public class myBean implements MessageDrivenBean, MessageListener {

   MessageDrivenContext m_ctx;

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

   // other methods in the bean
}