In a previous
article
, we explored the details of entity beans and how they are used to
encapsulate data entities to be accessed by business objects. In this article
we will look at message-driven beans and how they can be used to listen for Java
Message Service
(JMS) messages.

Talk with your MOM

Message-oriented middleware (MOM) is a category of interapplication
communication software that presents an asynchronous message-passing model as
opposed to a request/response model. Most MOM systems are based around a
message queuing system. The primary advantage of a message-oriented
communications protocol is the ability to store, route, and resend a message
that is to be delivered.

Most MOM systems provide a persistent storage to hold
messages until they are successfully transferred. This means that it is not
necessary for both the sender and receiver to be connected at the same time.
This is useful for dealing with faulty connections, unreliable networks, and
timed connections. It also means that if a receiver fails to receive a message
for any reason, the sender can continue unaffected, since the messages will be
held in the message store and will be transmitted when the receiver reconnects.

MOM systems present two messaging models:

  • Point-to-point–This model is
    based on message stores known as queues. A sender sends a message to a
    specified queue. A receiver receives messages from the queue. A queue can
    have multiple senders and receivers, but an individual message can only be
    delivered to one receiver. If multiple receivers are listening for
    messages on a queue, the underlying MOM system usually determines which
    receiver will receive the next message. If no receivers are listening on
    the queue, messages remain in the queue until a receiver attaches to the
    queue.
  • Publish-Subscribe–This model is
    based on message stores known as topics. Publishers send messages to a
    topic. Subscribers retrieve messages from a topic. Unlike the
    point-to-point model, many subscribers can receive the same message.

The diagram in Figure
A
illustrates the relationships and interactions for sending a message from
one publisher to a topic where multiple subscribers are registered to receive
the message:

Figure A

Interactions between a publisher, some subscribers, and a topic

JMS meets your MOM

An increasingly important requirement of J2EE application
systems is their ability to handle asynchronous messages passed from MOM
systems. Java provides the Java Message Service (JMS) for handling MOM
messages, which is an application programming interface (API) abstraction of
common concepts found in all MOM systems. However, JMS does not define wire
protocols or message-content formats.

In a publish-and-subscribe messaging model, a producer sends
messages to consumers by delivering the message to a single intermediary topic.
A message producer is also called a publisher. The publisher acts as a message
transmitter to be used to pass messages from a client or server object to the
topic.

Listing A
illustrates a method called sendRequest
which is used by publishers to send map messages to a topic.

You can create your own asynchronous, JMS-enabled, message
listener/receiver, which will receive messages from a topic in its onMessage callback, as shown in
Listing B.


Additional resources


Overview of message-driven beans

A message-driven bean (MDB) is an EJB that functions as a
JMS message consumer. Unlike session beans or entity beans, clients cannot
access message-driven beans directly. Also, unlike session beans and entity
beans, a message-driven bean does not have remote or home interfaces. The only
access a client has to a message-driven bean is through a JMS destination
(topic or queue) of which the message-driven bean is listening.

A MDB must implement two interfaces:

  1. javax.jms.MessageListenerThis
    interface defines the onMessage
    callback method. When a message is put on the queue/topic, the onMessage method of the
    message-driven bean is called by the EJB container and passed the actual
    message.
  2. javax.ejb.MessageDrivenBeanThis
    is the EJB interface that contains the EJB lifecycle methods:
    ejbCreate()called
    by the EJB container when the message-driven bean is created
    ejbRemove()called
    by the EJB container when the message-driven bean is destroyed or removed
    from the EJB pool
    setMessageDrivenContext(MessageDrivenContext
    context)
    called prior to ejbCreate
    and passed the message-driven context by the EJB container

The context has runtime information such as transaction
data.

The diagram in Figure
B
illustrates the interactions between a JMS message, a client, a topic, an
application server, an EJB container, and message-driven bean instances.

Figure B

Interactions

The deployment descriptor

A message-driven bean must declare deployment information
about itself in a deployment-descriptor file named ejb-jar-xml. The EJB
container handles the duties of subscribing the bean to the topic or connecting
it to the queue based on information placed in the deployment descriptor.

  • The ejb-jar.xml file contains:
  • The
    fully-qualified class name of the message-driven bean
  • A
    name for the message-driven bean
  • The
    destination type of the bean
  • Transaction
    attributes
  • Security
    information

The following is an example of a typical ejb-jar.xml file:

<ejb-jar>
   <enterprise-beans>
      <message-driven>
         <ejb-name>MyMDB</ejb-name>
         <ejb-class>com.jeffhanson.ejb.MyMDB</ejb-class>
         <transaction-type>Container</transaction-type>
         <message-driven-destination>
            <destination-type>javax.jms.Topic</destination-type>
         </message-driven-destination>
         <security-identity>
            <run-as-specified-identity>
               <role-name>system</role-name>
            </run-as-specified-identity>
         </security-identity>
      </message-driven>
   </enterprise-beans>
</ejb-jar>

The message-driven bean implementation

As mentioned before, message-driven beans do not have remote
or local interfaces as with session beans and entity beans. Message-driven
beans are not located by client classes, and client classes do not directly
invoke methods on them. All access to a message-driven bean is through a JMS topic
or queue which directs messages at the message-driven bean through the EJB
container. The EJB container ultimately passes the JMS message to the
message-driven bean through the bean’s onMessage
method. All message-driven beans must implement the javax.ejb.MessageDrivenBean and javax.jms.MessageListener
interfaces, as the example in Listing C illustrates.