The Java 2 Enterprise Edition (J2EE) specification contains the powerful server-side technology of Enterprise JavaBeans (EJB), components managing the lion's share of an application's functionality. The EJB architecture functions as a modified client-server paradigm: A client (such as a Java servlet) makes a request to an EJB; the EJB handles the request, perhaps passing it along to another EJB component or a JDBC-compliant database. Eventually, the EJB returns a response to the client. Session and Entity beans both behave this way, synchronously channeling information. In both cases, the client waits for some sort of response from the bean.
The EJB 2.0 specification addressed this potential bottleneck, introducing message-driven beans. Message-driven beans function asynchronously—once receiving information, the bean processes it accordingly. The client does not wait for a response and the bean never sends one.
Take a few steps back
For more information, you can read the earlier installments of this series.
"Get started with Enterprise JavaBeans"
"Session Beans: The EJB star performer"
"Being persistent: Tackling Entity JavaBeans"
You can download the code for this article here.
Understanding Java Message Service (JMS)
To fully understand the concepts behind message-driven beans, developers need a sense of how the JMS works. In essence, a JMS message server provides two alternatives for message delivery: message topics and message queues. A topic acts as a subscription: Message clients receive only messages corresponding to a particular topic. Message clients on the less discriminating queues receive all messages posted to the queue. An application registers with a message server in either fashion, listening for messages. When the listening application gets a message from the server, it processes the information.
Message-driven beans function in the same way, except with the added benefits of EJB context. The complexities of developing for JMS also disappear, since the javax.ejb.MessageDrivenBean interface, which all message-driven beans implement, extends the javax.jms.MessageListener class. This encapsulates the more difficult aspects of message application development—connecting to a JMS server, retrieving messages, and so on—allowing the developer to focus more on functionality than on implementation details.
Message-driven bean biography
Similar to stateless Session beans, message-driven beans lack a sense of the application's state. Once a message-driven bean processes its intended information, the EJB container returns it to the pool of available instances, awaiting the next message. Unlike all other types of beans, message-driven beans do not need a home or remote interface, since they merely listen for messages instead of responding to a direct call from a client.
Operating asynchronously, message-driven beans do not consume processing time by returning responses to calling clients. An additional benefit of message-driven beans manifests itself in the concept of automatic message delivery. Picture this worst-case scenario: A Session bean doubling as a JMS client posts a message to a JMS server, which returns a "message posted" response. The EJB container crashes. The JMS server holds the posted message until a message listener—in this case, a message-driven bean—retrieves the information. When the EJB container restarts, the message-driven bean takes the message from the JMS server and processes it as if no container crash occurred. Of course, this behavior depends on the JMS server not crashing as well, but that's the subject for another article.
Since asynchronous behavior founds the operation of message-driven beans, they are ideal to use as façades, driving functionality of other beans. A message-driven bean receives a message and then calls other EJB to process it. This way, the initiator of the message (the client) does not have to wait for each response from numerous beans. This requires tight coding to ensure the message is passed and handled properly but speeds the overall processing time of the application.
Step by step
The order of events in the life of a message-driven bean begins with a JMS-enabled object publishing a message to the JMS server. This object may be an EJB, a desktop client, or another application with the ability to communicate with the JMS server. Once the message resides on the JMS server, it notifies a listening EJB container of the new message. If the EJB container holds beans subscribing to the topic (or listening to the queue), the message passes to the container. The message then moves to the corresponding bean via the onMessage() method, which processes the message according to the design of the bean. After returning from this method, the EJB container returns the bean to the instance pool.
Deployment descriptors form the basis of the message-driven bean life cycle. One descriptor identifies the type of JMS message to listen for, either provided by topic or queue. This information, in ejb-jar.xml, looks like Listing A.
The second, vendor-specific, descriptor identifies the JMS server to the EJB container. In the case of a BEA WebLogic server, the descriptor named weblogic-ejb-jar.xml contains an entry looking like this:
Thanks to the Java Naming and Directory Interface (JNDI), the EJB container locates the JMS server in the same way it would find a JDBC connection pool or other J2EE resource.
In addition to the required onMessage() method, message-driven beans contain other necessary methods. The setMessageDrivenContext() method informs the bean of its context, such as environment variables. The EJB container also requires a no-argument ejbCreate() method and an ejbRemove() method that bookend the functionality of the bean.
Developers should note the inability of message-driven beans to throw application-level exceptions. Because the bean lacks direct interaction with a client, nothing can catch a thrown exception. Instead, the EJB container responds only to runtime exceptions, calling ejbRemove() and, if applicable, rolling back the transaction.
Listing B illustrates a bean that listens for a javax.jms.TextMessage from a JMS server. This example uses the onMessage() method simply to display the text of the message, but that same text could easily pass to another bean, perhaps changing information in a database or starting a child process.
End of message
Message-driven beans function in unique fashion: as part of an EJB container but not directly tied to it. If an application needs the benefits of asynchronous processing, if developers seek a way to guarantee task execution, or if your design dictates a facade pattern, the message-driven beans of EJB 2.0 deliver.
Pass the beans
Do you want more EJB articles? Tell us what you want to see or post a comment below?