Skip Headers
Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 3 (10.1.3)
B14428-02
  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
 

17 Implementing an EJB 2.1 MDB

This chapter explains how to implement an EJB 2.1 message-driven bean.

For more information, see:

Implementing an EJB 2.1 MDB

Table 17-1 summarizes the important parts of an EJB 2.1 MDB entity 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 lifecycle 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: http://www.oracle.com/technology/tech/java/oc4j/demos.

To implement an EJB 2.1 message-driven bean:

  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.

    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:

    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 OracleAS JMS (see "Oracle Application Server JMS (OracleAS JMS) Provider: File-Based"), 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()
    {
    }

    /* 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;
    }

// Lifecycle Methods

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


    /* ------------------------------------------------------
    * Begin 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)
    {
       /* 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();

            // 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 Use a Non-J2CA Message Service Provider".

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 Enterprise JavaBeans 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 EJBs, 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
}