bea.com | products | dev2dev | support | askBEA |
|
e-docs > WebLogic Server > Programming WebLogic Enterprise JavaBeans > Designing Message-Driven Beans |
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 Messing Service (JMS) API, you should first become familiar with the WebLogic JMS before attempting to implement message-driven beans. See Programming WebLogic JMS for more information.
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 When you configure a cluster, you supply a cluster address that identifies the Managed Servers in the cluster. The cluster address is used in entity and stateless beans to construct the host name portion of URLs. If the cluster address is not set, EJB handles may not work properly. For more information on cluster addresses, see Using WebLogic Server Clusters.and 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:
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.
Concurrent Processing for Topics and Queues
Message-Driven Beans 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 found in the 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. For more information on this element 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:
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>
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>
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:
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.
Specifying Principals and Setting Permissions for JMS Destinations
Message-driven beans connect to the JMS destination using the run-as principal. The run-as principal maps to the run-as element that is set in the ejb-jar.xml file. This setting specifies the run-as identity used for the execution of the message-driven bean's methods. A message-driven bean is associated with a JMS destination when you deploy the bean in the WebLogic Server EJB container. The JMS destination can either be a queue or a topic. You specify the JMS destination by setting the destination-type element to either queue or topic in the message-driven bean's ejb-jar.xml file.
Set the permissions for the bean's run-as principal to receive, as described below, when connecting message-driven beans to the JMS destinations. This allows the message-driven bean to connect to remote queues in the same domain or in another domain as long as the same principal is defined in the other domain. WebLogic Server uses the default guest user if you do not specify the run-as principal. However, whether you use the run-as principal or guest, you must assign the receive permission to the security principal.
To set the receive permission, you must first create a new access control list (ACL) or modify an existing one. ACLs are lists of Users and Groups that have permission to access the resources. Permissions are the privileges required to access resources, such as permission to read, write, send, and receive files and load servlets, and link to libraries.
Note: Do not use the system user for message-driven beans that connect to JMS destinations because system prevents the message-driven bean from connecting to a destination in another domain.
For more information on security principal users, see Defining Users.
See the following instructions to create the ACL, specify principals, and set permissions:
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:
If no bean instance is located in the free pool, 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.
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>
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 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:
Migrating Message-Driven Beans
To migrate message-driven bean from a failed server in a WebLogic Server cluster to an available server:
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.
As of WebLogic Server 7.0, you can deploy an MDB that supports container-managed transactions against a foreign JMS provider. If the MDB is configured with a "transaction-type" attribute of "Container" and a "trans-attribute" of "Required", then WLS will use XA to automatically enlist the foreign JMS provider in a transaction.
If the foreign 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.
See the white paper, "Using Foreign JMS Providers with WLS Message Driven Beans" (jmsmdb.doc for an example of how to configure an MDB to use a foreign provider.