Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Feb02: Java Q&A


Feb02: Java Q&A

Surlu is a Java architect for Iflex Consulting Ltd. and can be contacted at [email protected].


Message-driven beans combine the features of container-managed Enterprise JavaBean (EJB) and the Java Messaging Service (JMS). The reason Message-driven beans were introduced in the EJB 2.0 specification is that there was no way in EJB 1.1 to handle asynchronous invocation. Instead, EJB services could only be invoked through remote interfaces and the bean could never set itself up as a listener for asynchronous invocation. In this article, I examine Message-driven beans, show how to use them, and explain how they differ from the other two EJB components — Entity and Session beans.

JMS Overview

When developing distributed systems, most developers employ techniques that make use of synchronous, block-and-wait behavior. In this instance, each client thread of control has a single execution path that can be traced from the client to the server and back. This makes development straightforward, especially when debugging distributed systems.

However, there are areas where synchronous services are not appropriate for client applications; for example, when clients are not interested in receiving responses from servers. Asynchronous services are those that let clients make a request without waiting for a response. There are many benefits to using asynchronous development, including:

  • Clients can process and execute other functions while waiting for a response from a request. For example, when new users register in many e-commerce systems, e-mail is sent as a confirmation. This can be done in parallel to the registration activity.
  • Requests can be sent to servers that are not running at the time the clients send the request.

  • The service can decouple an invoker from the invoked, enabling more flexibility in assembling distributed computing environments.

  • Assuming the method never returns an exception, synchronous methods that return void may benefit by using an asynchronous invocation instead.

  • Asynchronous servers can queue, prioritize, and process messages in a different order than they arrive into the system.

JMS is an API for message-based systems that is generic enough for existing proprietary messaging systems (like IBM's MQSeries) to incorporate it, yet powerful and flexible enough to enable custom enterprise-level messaging development on its own. JMS bridges many of the gaps presented by proprietary Message-Oriented Middleware (MOM) formats. Like other J2EE APIs, JMS has a client-based API and vendor-based SPI so that existing organizations can use JMS to enable their applications without impacting client-side development. JMS provides publish-and-subscribe (pub/sub) through "topics" and point-to-point (PTP) messaging through "queues." JMS also has extensions for performing request/reply domain processing as an extension of pub/sub and PTP messaging. It provides the ability to acknowledge that a message was received and is being processed, as well as guarantee message delivery even when the receiver isn't available. JMS messages can also be transactional to provide reliable delivery and handling of mission-critical messages. (For more information, see http://java.sun.com/products/jms/index.html and http://java.sun.com/products/jms/tutorial/index.html.)

Message-Driven Bean Overview

A Message-driven bean is an EJB that is a Java Messaging Service (JMS) consumer. It consumes messages from queues or topics that are sent by any valid JMS client. When there is a new message waiting to be processed, the container — which manages the Message-driven bean and the JMS destination — uses an existing instance or activates a new bean instance to service the message. Message-driven beans are stateless, so any instance may service a message equally well. They are decoupled from the clients that send messages to them and the client cannot access them through a programmatic interface directly.

Why use Message-driven beans? Why not just use JMS as is in your EJB applications? Why is it a significant addition to the EJB specification? Before answering these questions, look at the structure of a typical asynchronous application setup with Message-driven beans; see Figure 1. Clients look up the JMS destination by using JNDI and send messages. The application container uses an existing instance (or creates a new one) to service the message. The Message-driven beans may invoke other EJBs or resources to handle the message processing.

The most important advantage of a Message-driven bean is that it provides a component model around JMS messaging. The JMS destination can either be a Topic or a Queue, allowing for both publish/subscribe and point-to-point messaging. Since the whole setup is managed within an application-server-managed container, scalability and portability are good.

Scalability in this architecture can be achieved by taking advantage of the container's ability to pool bean instances and other resources, such as JDBC connections. Because the Message-driven bean is deployed like an EJB, the deployment descriptor is the only change needed to port it to another J2EE-compliant container, consequently increasing portability.

Coding a Bean

To illustrate how you build a Message-driven bean, I use Weblogic 6.0sp1, although the bean should be deployable to any EJB 2.0-compliant server. There are two steps involved:

  1. Create the bean's class.

  2. Create the deployment descriptor.

Listing One is the code for a typical bean that picks up a message from a topic and prints it out. As you can see from the code, developing a Message-driven bean is significantly less complicated than developing a Session or Entity bean. All Message-driven beans follow a typical EJB contract. They must implement the interfaces javax.ejb.MessageDrivenBean and javax.jms.MessageListener.

The javax.ejb.MessageDrivenBean interface extends the EnterpriseBean and contains the setMessageDrivenBeanContext(MessageDrivenBeanContext ctx) method, which has to be implemented here. This method is called as part of the event transition that a Message-driven bean goes through when it is being added to a pool. The input parameter gives the bean access to information about the environment that it executes within.

Since the Message-driven bean is a JMS listener, the bean class must implement the javax.jms.MessageListener interface, either directly or indirectly, by inheriting from another class that implements the interface. This interface contains the core onMessage method that performs the business logic required to process the message. The TextMessage type inside this method is a particular type of JMS message that has methods for getting and setting the text as the body of the message. In this example, it is a simple method that prints out the message to the system. All the exceptions are caught and handled here, since none of the exceptions are propagated to the client. Since the container is responsible for all threading issues, this method should not have any synchronization code within it.

The bean is stateless and does not contain any client-specific state that spans messages. So each bean is identical and has the same initialization method, which is an ejbCreate() method that takes no arguments. When the bean is destroyed, there is nothing to clean up — you have an ejbRemove() method.

The Deployment Descriptor

Listing Two, the deployment descriptor for the piper bean, defines the bean assembly information and helps the container in managing the component and is located in an ejb-jar file. For each Message-driven bean in the ejb-jar file, you have to define a <message-driven> entry tag that tells the container it is a Message-driven bean. This tag must be defined as a subelement of the <enterprise-beans> tag. How does the application server know whether the bean should consume a queue or topic messages? The <message-driven-destination> tag is the key. It informs the container the type of message consumption. There is no mention of which topic or queue the bean should be bound to. This is the feature that makes the Message-driven bean portable across application servers. Because the names of the topics and queues deployed into a JMS server are application-server specific, the mapping of a bean to a specific JMS destination has to be done in an application-server-specific deployment descriptor, as in Listing Three. The example Message-driven bean here maps to a topic called MsgPipeTopic defined by the <destination-jndi-name> tag. In addition, application server vendors can provide value-added extensions in an application-server-specific deployment descriptor. For example, the server vendor may provide a parameter that defines the maximum size of a Message-driven bean pool, which in this case is <max-beans-in-free-pool>.

Client Code

The client code, Client.java (available electronically, see "Resource Center," page 5), is totally independent of the Message-driven bean. It is not directly accessing the Message-driven bean itself, rather, it is looking up the JMS destination through JNDI. So the context of the client application is restricted to the point of looking up the JMS topic and placing the message on the topic. Here the client accesses the topic MsgPipeTopic as the JMS topic destination and sets the message sent by the users as a parameter.

Message-Driven, Session, and Entity Beans

How do Message-driven beans compare to Session and Entity beans? In the world of EJBs, Session and Entity EJBs are purely synchronous components and Message-driven beans are asynchronous components. Despite this simple distinction between the types of EJBs, there are many other differences between the types of EJBs that revolve around semantic behavior, functional capability, and messaging integration. These differences include:

  • Message-driven beans cannot propagate exceptions back to clients. It is not possible to propagate an application or system exception that is generated within the bean to the message producer, since Message-driven beans are decoupled from message producers. However, a Message-driven bean is allowed to generate application and system exceptions that are handled by the container.
  • Message-driven beans have weakly typed input parameters. The only input parameter that a Message-driven bean can accept is an object that implements the JMS Message interface. Input parameters defined in the home, component, local home, or local interfaces of methods of a session or Entity bean are strongly typed.

  • Message-driven beans do not have home, component, local home, or local interfaces. Session and Entity beans have a well-defined interface that all clients have to use to access the business operations of the bean. Message-driven beans do not have defined contract for client accessibility since they do not have home, component, local home, or local interfaces

  • Message-driven beans do not have any return values. All methods listed in the home, component, local home, and local interfaces of Session and Entity beans have a strongly typed return parameter that is returned to the client, including methods that return void.

Conclusion

The addition of a Message-driven bean enhances the J2EE platform by simplifying enterprise development, allowing loosely coupled, reliable, and asynchronous interactions among J2EE components and legacy systems capable of messaging. Message-driven beans fill a void in the EJB architecture, which previously defined a model only for synchronous processing. You can easily add new behavior to a J2EE application with existing business events by adding a new Message-driven bean to operate on specific business events. Message-driven beans will be used to offload simple functionality that will separate processes and enable the development of asynchronous, mission-critical applications.

DDJ

Listing One

package example.MDBean;

import javax.ejb.CreateException;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/** @author Surlu M. Rao */
public class MessagePipeBean implements MessageDrivenBean, MessageListener {
  private MessageDrivenContext m_context;
  /** This method is required by the EJB Specification */
  public void ejbActivate() {
  }
  /** This method is required by the EJB Specification */
  public void ejbRemove() {
    m_context = null;
  }
  /** This method is required by the EJB Specification */
  public void ejbPassivate() {
  }
  /** Sets the session context. 
   * @param ctx     MessageDrivenContext Context for session
   */
  public void setMessageDrivenContext(MessageDrivenContext ctx) {
    m_context = ctx;
  }
  /** ejbCreate() with no arguments is required by EJB 2.0 specification */
  public void ejbCreate () throws CreateException {
  }
  /** MessageListener implementation
   * This method just takes the message and pipes to the system output.
   * @exception  completely handles all exceptions
   */
  public void onMessage(Message msg) {
    TextMessage tm = (TextMessage) msg;
    try {
      String text = tm.getText();
      System.out.println("MessagePipeBean piped : " + text);
    }
    catch(Exception ex) {
      ex.printStackTrace();
    }
  }
}

Back to Article

Listing Two

<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise 
JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd">
<
ejb-jar>
 <enterprise-beans>
    <message-driven>
      <ejb-name>MessagePipeBean</ejb-name>
      <ejb-class>example.MDBean.MessagePipeBean</ejb-class>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
        <jms-destination-type>javax.jms.Topic</jms-destination-type>
      </message-driven-destination>
      <security-identity>
        <run-as-specified-identity>
          <role-name>everyone</role-name>
        </run-as-specified-identity>
      </security-identity>
    </message-driven>
 </enterprise-beans>
</ejb-jar>

Back to Article

Listing Three

<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC "-//BEA Systems, Inc.
//DTD WebLogic 6.0.0 EJB//EN" "http://cool.mdb.bean">
<
!-- MessageDriven bean Weblogic deployment descriptor -->
<weblogic-ejb-jar>
  <weblogic-enterprise-bean>
    <ejb-name>MessagePipeBean</ejb-name>
    <message-driven-descriptor>
      <pool>
        <max-beans-in-free-pool>100</max-beans-in-free-pool>
        <initial-beans-in-free-pool>10</initial-beans-in-free-pool>
      </pool>
      <destination-jndi-name>MsgPipeTopic</destination-jndi-name>
    </message-driven-descriptor>
    <jndi-name>MessagePipeBean</jndi-name>
  </weblogic-enterprise-bean>
</weblogic-ejb-jar>


Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.