The following topics provide information on how to program and implement EJB 3.0 compliant MDBs:
To implement EJB 3.0 compliant MDBs, follow the steps described in "Overview of the EJB 3.0 Development Process" in Programming WebLogic Enterprise JavaBeans, Version 3.0 for Oracle WebLogic Server.
To program EJB 3.0 compliant MDBs, follow the steps described in "Programming the Bean File: Typical Steps" in Programming WebLogic Enterprise JavaBeans, Version 3.0 for Oracle WebLogic Server.
You must use the @javax.ejb.MessageDriven
annotation to declare the EJB type as message-driven. You can specify the following optional attributes:
messageListenerInterface
—Specifies the message listener interface, if you haven't explicitly implemented it or if the bean implements additional interfaces.
Note:
The bean class must implement, directly or indirectly, the message listener interface required by the messaging type that it supports or the methods of the message listener interface. In the case of JMS, this is thejavax.jms.MessageListener
interface.activationConfig
—Specifies an array of activation configuration properties that configure the bean in its operational environment.
Activation configuration properties are name-value pairs that are passed to the MDB container when an MDB is deployed. The properties can be declared in either an ejb-jar.xml
deployment descriptor or by using the @ActivationConfigProperty
annotation on the MDB bean class. An example using the @ActivationConfigProperty
annotation is shown in Example 7-1. An example using the
ejb-jar.xml
deployment descriptor is shown in Example 7-2.
Example 7-1 Example @ActivationConfigProperty Code
. . . @ActivationConfigProperties( { @ActivationConfigProperty( name="connectionFactoryJndiName", value="JNDINameOfMDBSourceCF" ), @ActivationConfigProperty( name="initialContextFactory", value="weblogic.jndi.WLInitialContextFactory" ) } ) . . .
To set activation configuration properties in the ejb-jar.xml
descriptor, use the activation-config-property
element in the message-driven
stanza, as shown in Example 7-2.
Example 7-2 Activation Configuration Properties Set in ejb-jar.xml
<message-driven> . . . <activation-config> <activation-config-property> <activation-config-property-name>destinationJNDIName</activation-config-property-name> <activation-config-property-value>myQueue</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>destinationType</activation-config-property-name> <activation-config-property-value>javax.jms.Queue</activation-config-property-value> <activation-config-property> </activation-config> . . . </message-driven> <message-driven> . . . <activation-config> <activation-config-property> <activation-config-property-name>destinationJNDIName</activation-config-property-name> <activation-config-property-value>myQueue</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>destinationType</activation-config-property-name> <activation-config-property-value>javax.jms.Queue</activation-config-property-value> <activation-config-property> </activation-config> . . . </message-driven>
Because activation configuration properties can be set in an ejb.jar
deployment descriptor or by using activationConfigProperty
annotation properties, conflicts may result if the same name is used in both places. Conflicts may also result from using same-named properties from pre-3.0 versions of EJB or from proprietary WebLogic Server EJB annotations. Such conflicts are resolved following the following priority order, in sequence from high to low is
Properties set in the weblogic-ejb-jar.xml
deployment descriptor
Proprietary WebLogic Server 10.0 (and later) annotations
activation-config-property
properties set in the ejb-jar.xml
deployment descriptor
activationConfigProperty
annotation properties
For example, if the same property exists in the weblogic-ejb-jar.xml
descriptor and the ejb-jar.xml
descriptor, the one in weblogic-ejb-jar.xml
has the higher priority and overrides the one in ejb-jar.xml
value. Or, if the same property is set in both an ejb-jar.xml
descriptor element and in an activationConfigProperty
annotation, the descriptor element takes precedence and the annotation is ignored.
For more information about activation configuration properties, see "javax.ejb.ActivationConfigProperty" in Programming WebLogic Enterprise JavaBeans, Version 3.0 for Oracle WebLogic Server. Also see Table 11-1
, which summarizes the activation configuration properties supported by WebLogic Server.
For detailed information on developing MDBs to support the messaging modes as described in MDBs and Messaging Models, see Programming and Configuring MDBs: Details.
Example 7-3 shows a WebLogic MDB that uses a subscription to a WebLogic JMS queue (from WebLogic Server 10.3.4 or later), transactionally processes the messages, and forwards the messages to a target destination.
The MDB connects using JMS connection factory MyCF
to receive from queue MyQueue
. It forwards the messages to MyTargetDest
using a connection generated from connection factory MyTargetCF
.
Resource reference pooling note: The MDB uses a resource reference to access MyTargetCF
. The resource reference automatically enables JMS producer pooling, as described in "Enhanced Support for Using WebLogic JMS with EJBs and Servlets" in Programming JMS for Oracle WebLogic Server.
For a similar sample using topics instead of queues, see Example 10-1, "Sample MDB Using Distributed Topics".
Example 7-3 Sample MDB Using Distributed Queues
package test; import javax.annotation.Resources; import javax.annotation.Resource; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.ejb.MessageDrivenContext; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.jms.*; @MessageDriven( name = "MyMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "MyCF"), // External JNDI Name @ActivationConfigProperty(propertyName = "destinationJndiName", propertyValue = "MyQueue") // Ext. JNDI Name } ) @Resources ({ @Resource(name="targetCFRef", mappedName="MyTargetCF", // External JNDI name type=javax.jms.ConnectionFactory.class), @Resource(name="targetDestRef", mappedName="MyTargetDest", // External JNDI name type=javax.jms.Destination.class) }) public class MyMDB implements MessageListener { // inject a reference to the MDB context @Resource private MessageDrivenContext mdctx; // cache targetCF and targetDest for re-use (performance) private ConnectionFactory targetCF; private Destination targetDest; @TransactionAttribute(value = TransactionAttributeType.REQUIRED) public void onMessage(Message message) { System.out.println("My MDB got message: " + message); // Forward the message to "MyTargetDest" using "MyTargetCF" Connection jmsConnection = null; try { if (targetCF == null) targetCF = (javax.jms.ConnectionFactory)mdctx.lookup("targetCFRef"); if (targetDest == null) targetDest = (javax.jms.Destination)mdctx.lookup("targetDestRef"); jmsConnection = targetCF.createConnection(); Session s = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer mp = s.createProducer(null); mp.send(targetDest, message); } catch (JMSException e) { System.out.println("Forcing rollback due to exception " + e); e.printStackTrace(); mdctx.setRollbackOnly(); } finally { // Closing a connection automatically returns the connection and // its session plus producer to the resource reference pool. try { if (jmsConnection != null) jmsConnection.close(); } catch (JMSException ignored) {}; } // emulate 1 second of "think" time try { Thread.currentThread().sleep(1000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // Restore the interrupted status } } }