Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide 10g (10.1.3.5.0) Part Number E13981-01 |
|
|
View PDF |
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 Implements Implements |
For more information, see "What is a Message-Driven Bean?".
To implement an EJB 2.1 message-driven bean, do the following:
Implement the MDB entity bean:
Implement a public
, zero-argument constructor.
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.
Implement the ejbCreate
method. The container invokes this method when it instantiates the MDB.
The return type of the ebjCreate
methods is void
.
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".
Implement a setMessageDrivenContext
method that takes an instance of MessageDrivenContext
(see "Implementing the setMessageDrivenContext Method").
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.
Configure message service provider information (see "Using Deployment XML":
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:
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
).
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 theejbCreate
method and destroying them in the ejbRemove
method.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 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
.
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".
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 }