7 Using EJB 4.0 Compliant MDBs
This chapter includes the following sections:
Implementing EJB 4.0 Compliant MDBs
To implement EJB 4.0 compliant MDBs, follow the steps described in Overview of the EJB Development Process in Developing Jakarta Enterprise Beans for Oracle WebLogic Server.
Programming EJB 4.0 Compliant MDBs
To program EJB 4.0 compliant MDBs, follow the steps described in Programming the Bean File: Typical Steps in Developing Jakarta Enterprise Beans for Oracle WebLogic Server.
To declare an MDB with annotations, annotate its bean class with @jakarta.ejb.MessageDriven. Alternatively, declare the MDB using the message-driven element in ejb-jar.xml. The annotation provides the following optional attributes:
-
messageListenerInterface—Specifies the message listener interface, if you have not 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 the
jakarta.jms.MessageListenerinterface. -
activationConfig—Specifies an array of activation configuration properties that configure the bean in its operational environment.Activation configuration properties are name-value pairs used to configure an MDB. Declare them in the
activation-configelement ofejb-jar.xml, or as@ActivationConfigPropertyentries in theactivationConfigattribute of@MessageDriven. If an activation configuration property is specified in both the annotation and the deployment descriptor, the deployment descriptor value takes precedence. An example using the@ActivationConfigPropertyannotation is shown in Example 7-1. An example using theejb-jar.xmldeployment descriptor is shown in Example 7-2.To set activation configuration properties in
ejb-jar.xml, add anactivation-configelement within the MDB'smessage-drivendeclaration, and put eachactivation-config-propertyinside it, as shown in Example 7-2.Because activation configuration properties can be set in an
ejb-jar.xmldeployment descriptor or by using@ActivationConfigPropertyannotation 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 Oracle WebLogic Server EJB annotations. For overlapping settings, WebLogic Server applies the following precedence, from highest to lowest:-
Properties set in the
weblogic-ejb-jar.xmldeployment descriptor -
Proprietary Oracle WebLogic Server 10.0 (and later) annotations
-
activation-config-propertyproperties set in theejb-jar.xmldeployment descriptor -
@ActivationConfigPropertyannotation properties
For example, if the same property exists in the
weblogic-ejb-jar.xmldescriptor and theejb-jar.xmldescriptor, the one inweblogic-ejb-jar.xmlhas the higher priority and overrides the value inejb-jar.xml. Or, if the same property is set in both anejb-jar.xmldescriptor element and in an@ActivationConfigPropertyannotation, the descriptor element takes precedence and the annotation is ignored.For more information about activation configuration properties, see jakarta.ejb.ActivationConfigProperty in the Jakarta EE Platform API. Also see Table 11-1, which summarizes the activation configuration properties supported by Oracle WebLogic Server.
Note:
Based on the Enterprise Bean specification, the
jakarta.ejb.ActivationConfigPropertyannotation is used for MDBs only. This annotation is not used for session or entity beans. -
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-1 Example @ActivationConfigProperty Code
Apply the following annotation to the MDB class. This example uses the WebLogic-specific connectionFactoryJndiName and initialContextFactory activation properties for a JMS MDB. Configure the MDB's destination as described in Configuring MDBs for Destinations.
import jakarta.ejb.ActivationConfigProperty;
import jakarta.ejb.MessageDriven;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(
propertyName = "connectionFactoryJndiName",
propertyValue = "JNDINameOfMDBSourceCF"),
@ActivationConfigProperty(
propertyName = "initialContextFactory",
propertyValue = "weblogic.jndi.WLInitialContextFactory")
})Example 7-2 Activation Configuration Properties Set in ejb-jar.xml
Insert the following fragment in the MDB's existing message-driven declaration. The queue must already be available under the JNDI name myQueue.
<activation-config> <activation-config-property> <activation-config-property-name>destinationLookup</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>jakarta.jms.Queue</activation-config-property-value> </activation-config-property> </activation-config>
MDB Sample Using Annotations
Example 7-3 shows an MDB that receives messages from a WebLogic JMS queue, processes them in a container-managed transaction, and forwards them 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.
This example assumes that MyQueue, MyCF, MyTargetCF and MyTargetDest are configured and available in the MDB's local JNDI tree. For WebLogic JMS connection factories defined in a JMS module, enable XAConnectionFactoryEnabled on both MyCF and MyTargetCF to support transactional receipt and forwarding. For more about MDB connection-factory configuration, see How to Set connection-factory-jndi-name.
The Required transaction attribute causes onMessage to execute in a container-managed transaction. Message receipt and JMS operations that participate in that transaction are committed or rolled back together. The call to createSession(false, Session.AUTO_ACKNOWLEDGE) does not, by itself, exclude a WebLogic-managed JMS session from participating in the container transaction.
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 Developing JMS Applications for Oracle WebLogic Server.
For a similar sample using topics instead of queues, see Example 10-1.
Example 7-3 Sample MDB Using Distributed Queues
package test;
import jakarta.annotation.Resources;
import jakarta.annotation.Resource;
import jakarta.ejb.ActivationConfigProperty;
import jakarta.ejb.MessageDriven;
import jakarta.ejb.MessageDrivenContext;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.jms.*;
@MessageDriven(
name = "MyMDB",
activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "jakarta.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=jakarta.jms.ConnectionFactory.class),
@Resource(name="targetDestRef",
mappedName="MyTargetDest", // External JNDI name
type=jakarta.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 = (jakarta.jms.ConnectionFactory)mdctx.lookup("targetCFRef");
if (targetDest == null)
targetDest = (jakarta.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) {};
}
}
}