bea.com | products | dev2dev | support | askBEA

Download Docs | Site Map | Glossary
Search

Programming WebLogic Enterprise JavaBeans

Designing Message-Driven Beans

The following sections describe how to develop message-driven beans and to deploy then on WebLogic Server. Because message-driven beans use parts of the standard Java Messaging Service (JMS) API, you should first become familiar with the WebLogic JMS before attempting to implement message-driven beans. See the Programming WebLogic JMS document for more information.

- What Are Message-Driven Beans?

- Developing and Configuring Message-Driven Beans

- Invoking a Message-Driven Bean

- Creating and Removing Bean Instances

- Deploying Message-Driven Beans in WebLogic Server

- Using Transaction Services with Message-Driven Beans

- Message-Driven Bean Migratable Service

- Configuring Message-Driven Beans for non-BEA JMS Providers

- Reconnecting to a JMS Server or Non-BEA Service Provider

- Configuring an MDB to Listen on a JMS Distributed Destination

What Are Message-Driven Beans?

A message-driven bean is an EJB that acts as a message consumer in the WebLogic JMS messaging system. As with standard JMS message consumers, message-driven beans receive messages from a JMS Queue or Topic, and perform business logic based on the message contents.

EJB deployers create listeners to a Queue or Topic at deployment time, and WebLogic Server automatically creates and removes message-driven bean instances as needed to process incoming messages.

Differences Between Message-Driven Beans and Standard JMS Consumers

Because message-driven beans are implemented as EJBs, they benefit from several key services that are not available to standard JMS consumers. Most importantly, message-driven bean instances are wholly managed by the WebLogic Server EJB container. Using a single message-driven bean class, WebLogic Server creates multiple EJB instances as necessary to process large volumes of messages concurrently. This stands in contrast to a standard JMS messaging system, where the developer must create a MessageListener class that uses a server-wide session pool.

The WebLogic Server container provides other standard EJB services to message- driven beans, such as security services and automatic transaction management. These services are described in more detail in Transaction Managementand in Using Transaction Services with Message-Driven Beans.

Finally, message-driven beans benefit from the write-once, deploy-anywhere quality of EJBs. Whereas a JMS MessageListener is tied to specific session pools, Queues, or Topics, message-driven beans can be developed independently of available server resources. A message-driven bean's Queues and Topics are assigned only at deployment time, utilizing resources available on WebLogic Server.

Note: One limitation of message-driven beans compared to standard JMS listeners is that you can associate a given message-driven bean deployment with only one Queue or Topic, as described in Invoking a Message-Driven Bean. If your application requires a single JMS consumer to service messages from multiple Queues or Topics, you must use a standard JMS consumer, or deploy multiple message-driven bean classes.

Differences Between Message-Driven Beans and Stateless Session EJBs

The dynamic creation and allocation of message-driven bean instances partially mimics the behavior of stateless session EJB instances. However, message-driven beans differ from stateless session EJBs (and other types of EJBs) in several significant ways:

- Message-driven beans process multiple JMS messages asynchronously, rather than processing a serialized sequence of method calls.

- Message-driven beans have no home or remote interface, and therefore cannot be directly accessed by internal or external clients. Clients interact with message-driven beans only indirectly, by sending a message to a JMS Queue or Topic.

Note: Only the WebLogic Server container directly interacts with a message-driven bean by creating bean instances and passing JMS messages to those instances as necessary.

- WebLogic Server maintains the entire life cycle of a message-driven bean; instances cannot be created or removed as a result of client requests or other API calls.

Concurrent Processing for Topics and Queues

Message-driven beans (MDBs) support concurrent processing for both topics and queues. Previously, only concurrent processing for queues was supported.

To ensure concurrency, the container uses threads from the execute queue. The default setting for the max-beans-in-free-pool deployment descriptor weblogic-ejb-jar.xml file provides the most parallelism. The only reason to change this setting would be to limit the number of parallel consumers.

Note: The maximum number of MDBs configured—via the max-beans-in-free-pool deployment descriptor element—to receive messages at one time cannot exceed the maximum number of execution threads. For example, if max-beans-in-free-pool is set to 50 but 25 is the maximum number of execution threads allowed, only 25 of the MDBs will actually receive messages.

For more information on max-beans-in-free-pool, see, max-beans-in-free-pool.

Developing and Configuring Message-Driven Beans

When developing message-driven beans, follow the conventions described in the JavaSoft EJB 2.0 specification, and observe the general practices that result in proper bean behavior. Once you have created the message-driven bean class, configuring the bean for WebLogic Server by specify the bean's deployment descriptor elements in the EJB XML deployment descriptor files.

To develop a message-driven bean:

1. Create a source file (message-driven bean class) that implements both the javax.ejb.MessageDrivenBean and javax.jms.MessageListener interfaces.

   The message-driven bean class must define the following methods:

   - One ejbCreate() method that the container uses to create an instance of the message-driven bean on the free pool.

   - One onMessage() method that is called by the bean's container when a message is received. This method contains the business logic that handles processing of the message.

   - One setMessageDrivenContext{} method that provides information to the bean instance about its environment (certain deployment descriptor values); the Context is also the mechanism the bean class uses to access some services provided by the EJB container.

   - One ejbRemove() method that removes the message-driven bean instance from the free pool.

   For an example of output for a message-driven bean class, see Message-Driven Bean Class Requirements.

2. Specify the following XML deployment descriptor files for the message-driven bean.

   - ejb-jar.xml

   - weblogic-ejb-jar.xml

   - weblogic-cmp-rdbms-jar.xml

   For instructions on specifying the XML files, see Specifying and Editing the EJB Deployment Descriptors.

3. Set the message-driven element in the bean's ejb-jar.xml file to declare the bean.

4. Set the message-driven-destination element in the bean's ejb-jar.xml file to specify whether the bean is intended for a Topic or Queue.

5. Set the subscription-durability sub-element in the bean's ejb-jar.xml file when you want to specify whether an associated Topic should be durable.

6. If your bean will demarcate its own transaction boundaries, set the acknowledge-mode sub-element to specify the JMS acknowledgment semantics to use. This element has two possible values: AUTO_ACKNOWLEDGE (the default) or DUPS_OK_ACKNOWLEDGE.

7. If the container will manage the transaction boundaries, set the transaction-type element in the bean's ejb-jar.xml file to specify how the container must manage the transaction boundaries when delegating a method invocation to an enterprise bean's method.

The following sample shows how to specify a message-driven bean in the ejb-jar.xml file.

Figure 3-1 Sample XML stanza from an ejb-jar.xml file:

>     <enterprise-beans>

>     	<message-driven>

>     		<ejb-name>exampleMessageDriven1</ejb-name>

>     		<ejb-class>examples.ejb20.message.MessageTraderBean</ejb-class>

>     		<transaction-type>Container</transaction-type>

>     		<message-driven-destination>

>     			<destination-type>

>     				javax.jms.Topic

>     			</destination-type>

>     		</message-driven-destination>

>     		...

>     	</message-driven>

>     	...

>     </enterprise-beans>

1. Set the message-driven-descriptor element in the bean's weblogic-ejb-jar.xml file to associate the message-driven bean with a JMS destination in WebLogic Server.

The following sample shows how to specify a message-driven bean in an weblogic-ejb-jar.xml file.

Figure 3-2 Sample XML stanza from an weblogic-ejb-jar.xml file:

>     <message-driven-descriptor>

>     	<destination-jndi-name>...</destination-jndi-name>

>     </message-driven-descriptor>

1. Compile and generate the message-driven bean class using instructions in Packaging EJBs into a Deployment Directory.

2. Deploy the bean on WebLogic Server using the instructions in Deploying Compiled EJB Files.

The container manages the message-driven bean instances at runtime.

Message-Driven Bean Class Requirements

The EJB 2.0 specification provides detailed guidelines for defining the methods in a message-driven bean class. The following output shows the basic components of a message-driven bean class. Classes, methods, and method declarations are highlighted bold.

Figure 3-3 Sample output of basic components of message-driven beans class

>     public class MessageTraderBean implements MessageDrivenBean, MessageListener{

>     	public MessageTraderBean() {...};

>     		// An EJB constructor is required, and it must not

>     		// accept parameters. The constructor must not be declared as

>     		// final or abstract.

>     	public void ejbCreate() (...)

>     		//ejbCreate () is required and must not accept parameters.

>     		The throws clause (if used) must not include an application

>     		//exception. ejbCreate() must not be declared as final or static.

>     	public void onMessage(javax.jms.Message MessageName) {...}

>     		// onMessage() is required, and must take a single parameter of

>     		// type javax.jms.Message. The throws clause (if used) must not

>     		// include an application exception. onMessage() must not be

>     		// declared as final or static.

>     	public void ejbRemove() {...}

>     		// ejbRemove() is required and must not accept parameters.

>     		// The throws clause (if used) must not include an application

>     		//exception. ejbRemove() must not be declared as final or static.

>     	// The EJB class cannot define a finalize() method

>     }

Using the Message-Driven Bean Context

WebLogic Server calls setMessageDrivenContext() to associate the message-driven bean instance with a container context.This is not a client context; the client context is not passed along with the JMS message. WebLogic Server provides the EJB with a container context, whose properties can be accessed from within the bean's instance by using the following methods from the MessageDrivenContext interface:

- getCallerPrincipal()) — This method is inherited from the EJBContext interface and should not be called by message-driven bean instances.

- isCallerInRole()) — This method is inherited from the EJBContext interface and should not be called by message-driven bean instances.

- setRollbackOnly() — The EJB can use this method only if it uses container-managed transaction demarcation.

- getRollbackOnly() — The EJB can use this method only if it uses container-managed transaction demarcation.

- getUserTransaction() — The EJB can use this method only if it uses bean-managed transaction demarcation.

Note: Although getEJBHome() is also inherited as part of the MessageDrivenContext interface, message-driven beans do not have a home interface. Calling getEJBHome() from within a message-driven EJB instance yields an IllegalStateException.

Implementing Business Logic with onMessage()

The message-driven bean's onMessage() method implements the business logic for the EJB. WebLogic Server calls onMessage() when the EJB's associated JMS Queue or Topic receives a message, passing the full JMS message object as an argument. It is the message-driven bean's responsibility to parse the message and perform the necessary business logic in onMessage().

Make sure that the business logic accounts for asynchronous message processing. For example, it cannot be assumed that the EJB receives messages in the order they were sent by the client. Instance pooling within the container means that messages are not received or processed in a sequential order, although individual onMessage() calls to a given message-driven bean instance are serialized.

See javax.jms.MessageListener.onMessage() for more information.

Handling Exceptions

Message-driven bean methods should not throw an application exception or a RemoteException, even in onMessage(). If any method throws such an exception, WebLogic Server immediately removes the EJB instance without calling ejbRemove(). However, from the client perspective the EJB still exists, because future messages are forwarded to a new bean instance that WebLogic Server creates.

Invoking a Message-Driven Bean

When a JMS Queue or Topic receives a message, WebLogic Server calls an associated message-driven bean as follows:

1. WebLogic Server obtains a new bean instance.

   WebLogic Server uses the max-beans-in-free-pool attribute, set in the weblogic-ejb-jar.xml file, to determine if a new bean instance is available in the free pool.

2. If a bean instance is available in the free pool, WebLogic Server uses that instance.

   If no bean instance is available in the free pool and the limit specified by max-beans-in-free-pool) has been reached, WebLogic Server waits until a bean instance is free. See max-beans-in-free-pool for more information about this attribute.

   If no bean instance is located in the free pool, and the limit specified by max-beans-in-free-pool has not been reached, WebLogic Server creates a new instance by calling the bean's ejbCreate() method and then the bean's setMessageDrivenContext() to associate the instance with a container context. The bean can use elements of this context as described in Using the Message-Driven Bean Context.

   WebLogic Server calls the bean's onMessage() method to implement the business logic when the bean's associated JMS Queue or Topic receives a message.

   See Implementing Business Logic with onMessage().

Note: These instances can be pooled.

Creating and Removing Bean Instances

The WebLogic Server container calls the message-driven bean's ejbCreate() and ejbRemove() methods, to create or remove an instance of the bean class. Each message-driven bean must have at least one ejbCreate() and ejbRemove() method. The WebLogic Server container uses these methods to handle the create and remove functions when a bean instance is created, upon receipt of a message from a JMS Queue or Topic or removed, once the transaction commits. WebLogic Server receives a message from a JMS queue or Topic.

As with other EJB types, the ejbCreate() method in the bean class should prepare any resources that are required for the bean's operation. The ejbRemove() method should release those resources, so that they are freed before WebLogic Server removes the instance.

Message-driven beans should also perform some form of regular clean-up routine outside of the ejbRemove() method, because the beans cannot rely on ejbRemove() being called under all circumstances (for example, if the EJB throws a runtime exception).

Deploying Message-Driven Beans in WebLogic Server

Deploy the message-driven bean on WebLogic Server either when the server is first started or on a running server. For instructions on deploying the bean, see Deploying EJBs at WebLogic Server Startup or Deploying EJBs on a Running WebLogic Server.

Using Transaction Services with Message-Driven Beans

As with other types of EJB, message-driven beans can demarcate transaction boundaries either on their own (using bean-managed transactions), or by having the WebLogic Server container manage transactions (container-managed transactions). In either case, a message-driven bean does not receive a transaction context from the client that sends a message. WebLogic Server always calls a bean's onMessage() method by using the transaction context specified in the bean's deployment descriptor file.

Because no client provides a transaction context for calls to a message-driven bean, beans that use container-managed transactions must be deployed with the Required or NotSupported trans-attribute specified for the container-transaction element in the ejb-jar.xml file.

The following sample code from the ejb-jar.xml file shows how to specify the bean's transaction context.

Figure 3-4 Sample XML stanza from an ejb-jar.xml file:

>     <assembly-descriptor>

>     	<container-transaction>

>     		<method>

>     			<ejb-name>MyMessageDrivenBeanQueueTx</ejb-name>

>     			<method-name>*</method-name>

>     		</method>

>     	<trans-attribute>NotSupported</trans-attribute>

>     	</container-transaction>

>     </assembly-descriptor>

Message Receipts

The receipt of a JMS message that triggers a call to an EJB's onMessage() method is not generally included in the scope of a transaction. However, it is handled differently for bean-managed and container-managed transactions.

- For EJBs that use bean-managed transactions, the message receipt is always outside the scope of the bean's transaction.

- For EJBs that use container-managed transaction demarcation, WebLogic Server includes the message receipt as part of the bean's transaction only if the bean's transaction-type element in the ejb-jar.xml file is set to Required.

Message Acknowledgment

For message-driven beans that use container-managed transaction demarcation, WebLogic Server automatically acknowledges a message when the EJB transaction commits. If the EJB uses bean-managed transactions, both the receipt and the acknowledgment of a message occur outside the EJB transaction context. WebLogic Server automatically acknowledges messages for EJBs with bean-managed transactions, but you can configure acknowledgment semantics using the acknowledge-mode deployment descriptor element defined in the ejb-jar.xml file.

Message-Driven Bean Migratable Service

WebLogic Server supports migratable and recovery services for message-driven beans. To provide these migratable and recovery services, WebLogic JMS uses the migration framework provided by WebLogic Server to respond to migration requests and bring a JMS server back online after a failure. Once the JMS server migrates to an available server, you should manually migrate the associated message-driven beans from a failed server in a WebLogic Server cluster to the same available server. The Message-driven bean can only use the Migratable Service when they are on clustered servers At this time, the Migratable Service cannot span multiple clusters.

If WebLogic Server does not migrate the message-driven bean along with the JMS Server to an available server in the cluster, the JMS destination will be flooded with messages. To expedite message-driven bean recovery until the original server recovers, the message-driven bean marks itself as migratable and WebLogic Server implements the Migratable Service process. After you migrate the bean to another server, it connects to its JMS server and continues to pull messages from the JMS destination on behalf of the failed server.

Enabling the Message-Driven Bean Migratable Service

To enable the message-driven bean Migratable Service:

1. Configure the message-driven bean as described in Developing and Configuring Message-Driven Beans.

2. Specify the message-driven bean's JMS destination type as either topic or queue by setting the destination-type element in the ejb-jar.xml file. For instructions on configuring JMS destinations, see Configuring Destinations.

3. Specify one of the following deployment schemes for the JMS destination:

   - Simple destination - EJB container deploys the message-driven bean with the JMS destination when the topic or queue destination isn't distributed.

   - Distributed destination - EJB container deploys the message-driven bean with the JMS destination on every server when the topic or queue destination is distributed.

   For instructions, see Configuring Distributed Destinations.

4. Use the WebLogic Server Administration Console, configure a JMS server. For instructions see Configuring JMS Servers.

   A JMS server is deployed on a server in a WebLogic Server cluster and handles requests for a set of JMS destinations.

5. Configure JMS migratable targets for the JMS server. For instructions, see Configuring JMS Migratable Targets.

Migrating Message-Driven Beans

To migrate message-driven bean from a failed server in a WebLogic Server cluster to an available server:

1. Start the WebLogic Server Administration Console.

2. Specify one of the following deployment schemes for the JMS destination:

   - Simple destination - EJB container deploys the message-driven bean with the JMS destination when the JMS destination isn't distributed.

   - Distributed destination - EJB container deploys the message-driven bean with the JMS destination on every server when the JMS destination is distributed.

Because the message-driven bean can detect the migration target for the JMS server, you do not need to change the migration target for the message-driven bean.

However, the message-driven bean must be deployed in the cluster or all of the servers on the JMS server migration target lists because message-driven bean is not possible during migration.The message-driven bean is deployed with the a JMS destination on all servers in the migration target list, and remain inactive when the JMS destination is inactive.

When WebLogic Server activates a message-driven bean, it detects the JMS server and starts pulling the message from the JMS destination that is specified for the bean.

Configuring Message-Driven Beans for
non-BEA JMS Providers

You can configure message-driven beans to work with non-BEA JMS providers such as IBM MQSeries. Beginning with WebLogic Server 7.0, you can do this for MDBs supporting container-managed transactions ("transactional MDBs") in addition to MDBs supporting bean-managed transactions ("non-transactional MDBs").

This means that it is now possible to for applications with transactional MDBs to achieve exactly-once semantics with a non-BEA JMS provider for messages processed by an MDB. In addition, WebLogic Server will use XA to automatically enlist the non-BEA JMS provider in a transaction.

For applications with non-transactional MDBs, the MDB will provide at-least-once message processing semantics and XA is not required.

If the non-BEA JMS provider does not support XA, then you cannot deploy an MDB that supports container-managed transactions with that provider. Furthermore, if the JMS provider does support XA, you must ensure that the JMS connection factory that you specify in the weblogic-ejb-jar.xml file supports XA—each JMS provider has a different way to specify this.

Specifying an MDB as Transactional

To specify an MDB as transactional, do the following:

- Set the transaction-type element inside the message-driven element in the ejb-jar.xml file to Container.

- Set the trans-attribute element inside the container-transaction attribute in the ejb-jar.xml file to Required.

Also, sure to set destination-jndi-name, initial-context-factory, provider-url, and connection-factory-jndi-name elements in weblogic-ejb-jar.xml appropriately for the non-BEA JMS provider.

For transactional MDBs, the JMS connection factory specified in connection-factory-jndi-name must support the optional XA extensions to JMS.

Specifying an MDB as Non-Transactional

To specify an MDB as non-transactional, do the following:

- Set the transaction-type element inside the message-driven element in the ejb-jar.xml file to Bean.

- Set the trans-attribute element inside the container-transaction attribute in the ejb-jar.xml file to NotRequired.

See the white paper, "Using Foreign JMS Providers with WLS Message Driven Beans" (jmsmdb.pdf for an example of how to configure an MDB to use a non-BEA provider.

Reconnecting to a JMS Server or Non-BEA Service Provider

A message-driven bean listens to an associated JMS destination on either a JMS server deployed on a non-clustered WebLogic Server instance or a non-BEA service provider. If the connection to that destination is lost, because the server goes down, the message-driven bean attempts to reconnect to that destination at periodic intervals. You can specify the number of seconds between attempts to reconnect to the destination by setting the jms-polling-interval-seconds element in the bean's weblogic-ejb-jar.xml file.

Configuring an MDB to Listen on a JMS Distributed Destination

WebLogic JMS supports service continuity in the event of a WebLogic Server instance failure within a cluster through the configuration of multiple physical destinations (queues and topics) as members of a single distributed destination set. Once configured, your producers and consumers send and receive messages through what appears to be a single destination.

However, WebLogic JMS actually distributes the messaging load across all the available destination members within the distributed destination. In the event that a member becomes unavailable due to a server failure, traffic is then redirected toward the other available destination members in the set.

Beginning with this release, when an MDB is deployed to a server in a cluster, WebLogic Server automatically enumerates the distributed destination members and ensures that there's an MDB listening on each member.

When an MDB is deployed to a server in a cluster, WebLogic Server automatically enumerates the distributed destination members and ensures that there's an MDB listening on each member.

Follow these steps to configure a message-driven bean for a distributed destination:

1. Configure a JMS distributed destination, as described in Configuring Distributed Destinations.

2. Set the MDB's destination-jndi-name in weblogic-ejb-jar.xml to the name used to bind the distributed topic or queue into the JNDI namespace.

3. Set the target for MDB to be the same as the distributed destination. The MDB need to be deployed wherever that distributed destination exists.

4. Deploy the MDB.

At deployment time, the MDB detects the member of the distributed destination the exists on that WebLogic Server instance, pin itself to the member, and start processing messages.

Configuring a Security Identity for a Message-Driven Bean

When a message-driven bean (MDB) receives messages from a JMS queue or topic, the EJB container uses a Credential Mapping provider and a credential map to obtain the security identity (username and password) to use when establishing the JMS connection. This credential mapping occurs only once, when the MDB is started. Once the EJB container is connected, the JMS provider uses the established security identity to retrieve all messages. The security identity is especially important when using an MDB to receive messages from a non-BEA JMS provider (either a JMS provider from another vendor or a WebLogic Server JMS provider running in another WebLogic Server domain).

To configure a security identity for an MDB:

1. Create WebLogic user for the MDB. For more information, see "Users and Groups" in Securing WebLogic Resources. This WebLogic user should have the username and password required by the non-BEA JMS provider to establish a JMS connection.

2. In the ejb-jar.xml deployment descriptor, define a run-as identity for the MDB:

   <security-identity>
   <run-as>
   <role-name>admin</role-name>
   </run-as>
   </security-identity>

3. In the weblogic-ejb-jar.xml deployment descriptor, map the run-as identity to the user defined in the previous step, as shown below:

   <security-role-assignment>
   <role-name>admin</role-name>
   <principal-name>username</principal-name>
   </security-role-assignment>

   where username is the username for the user created in step 1.

4. If the JMS provider is not WebLogic JMS, configure the credential mapper:

   Note: If the JMS provider is WebLogic JMS, it is not necessary to configure a credential mapper.

   To configure the credential mapper:

   1. In the left pane of the WebLogic Server Administration Console, expand Deployments.

      The Deployments node expands to show the types of WebLogic resources that can be deployed.

   2. Right-click the EJB resource (in this case, the MDB) for which you want to create a credential map.

   3. Choose the Define Policies and Roles for Individual Beans... option.

   4. Click the [Define Credential Maps] link for the MDB for which you want to create a credential map.

   5. Click the Configure a New Credential Map link.

   6. Enter the WebLogic Server username and password you defined for the MDB in step 1 in the WLS User field.

   7. Click Apply to save your changes.