The Java EE 5 Tutorial

Chapter 23 A Message-Driven Bean Example

Message-driven beans can implement any messaging type. Most commonly, they implement the Java Message Service (JMS) technology. The example in this chapter uses JMS technology, so you should be familiar with basic JMS concepts such as queues and messages. To learn about these concepts, see Chapter 31, The Java Message Service API.

This chapter describes the source code of a simple message-driven bean example. Before proceeding, you should read the basic conceptual information in the section What Is a Message-Driven Bean? as well as Using Message-Driven Beans to Receive Messages Asynchronously in Chapter 31, The Java Message Service API.

simplemessage Example Application Overview

The simplemessage application has the following components:

Figure 23–1 illustrates the structure of this application. The application client sends messages to the queue, which was created administratively using the Admin Console. The JMS provider (in this case, the Application Server) delivers the messages to the instances of the message-driven bean, which then processes the messages.

Figure 23–1 The simplemessage Application

Diagram of application showing an application client
sending a message to a queue, and the message being delivered to a message-driven
bean

The source code for this application is in the tut-install/javaeetutorial5/examples/ejb/simplemessage/ directory.

The simplemessage Application Client

The SimpleMessageClient sends messages to the queue that the SimpleMessageBean listens to. The client starts by injecting the the connection factory and queue resources:

@Resource(mappedName="jms/ConnectionFactory")
private static ConnectionFactory connectionFactory;

@Resource(mappedName=”jms/Queue”)
private static Queue queue;

Next, the client creates the connection, session, and message producer:

connection = connectionFactory.createConnection();
session = connection.createSession(false,
    Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(queue);

Finally, the client sends several messages to the queue:

message = session.createTextMessage();

for (int i = 0; i < NUM_MSGS; i++) {
    message.setText("This is message " + (i + 1));
    System.out.println("Sending message: " +
        message.getText());
    messageProducer.send(message);
}

The Message-Driven Bean Class

The code for the SimpleMessageBean class illustrates the requirements of a message-driven bean class:

It is recommended, but not required, that a message-driven bean class implement the message listener interface for the message type it supports. A bean that supports the JMS API implements the javax.jms.MessageListener interface.

Unlike session beans and entities, message-driven beans do not have the remote or local interfaces that define client access. Client components do not locate message-driven beans and invoke methods on them. Although message-driven beans do not have business methods, they may contain helper methods that are invoked internally by the onMessage method.

For the Application Server, the @MessageDriven annotation typically contains a mappedName element that specifies the JNDI name of the destination from which the bean will consume messages. For complex message-driven beans there can also be an activationconfig element containing @ActivationConfigProperty annotations used by the bean. See A Java EE Application That Uses the JMS API with a Session Bean for an example.

A message-driven bean can also inject a MessageDrivenContext resource. Commonly you use this resource to call the setRollbackOnly method to handle exceptions for a bean that uses container-managed transactions.

Therefore, the first few lines of the SimpleMessageBean class look like this:

@MessageDriven(mappedName="jms/Queue")
public class SimpleMessageBean implements MessageListener {
    @Resource
    private MessageDrivenContext mdc;
    ...

The onMessage Method

When the queue receives a message, the EJB container invokes the message listener method or methods. For a bean that uses JMS, this is the onMessage method of the MessageListener interface.

A message listener method must follow these rules:

The onMessage method is called by the bean’s container when a message has arrived for the bean to service. This method contains the business logic that handles the processing of the message. It is the message-driven bean’s responsibility to parse the message and perform the necessary business logic.

The onMessage method has a single argument: the incoming message.

The signature of the onMessage method must follow these rules:

In the SimpleMessageBean class, the onMessage method casts the incoming message to a TextMessage and displays the text:

public void onMessage(Message inMessage) {
    TextMessage msg = null;

    try {
        if (inMessage instanceof TextMessage) {
            msg = (TextMessage) inMessage;
            logger.info("MESSAGE BEAN: Message received: " +
                msg.getText());
        } else {
            logger.warning("Message of wrong type: " +
                inMessage.getClass().getName());
        }
    } catch (JMSException e) {
        e.printStackTrace();
        mdc.setRollbackOnly();
    } catch (Throwable te) {
        te.printStackTrace();
    }
}

Packaging, Deploying, and Running the simplemessage Example

To package, deploy and run this example, go to the tut-install/javaeetutorial5/examples/ejb/simplemessage/ directory.

Creating the Administered Objects for the simplemessage Example

This example requires the following:

If you have run the simple JMS examples in Chapter 31, The Java Message Service API and have not deleted the resources, you already have these resources and do not need to perform these steps.

You can use Ant targets to create the resources. The Ant targets, which are defined in the build.xml file for this example, use the asadmin command. To create the resources needed for this example, use the following commands:


ant create-cf
ant create-queue

These commands do the following:

The Ant targets for these commands refer to other targets that are defined in the tut-install/javaeetutorial5/examples/bp-project/app-server-ant.xml file.

Building, Deploying, and Running the simplemessage Application Using NetBeans IDE

    To build, deploy, and run the application using NetBeans IDE, do the following:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the simplemessage folder.

  4. Select the Open as Main Project check box and the Open Required Projects check box.

  5. Click Open Project.

  6. Right-click the simplemessage project and choose Build.

    This task packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the dist directory.

  7. Right-click the project and choose Undeploy and Deploy.

  8. Right-click the project and choose Run.

    This command returns a JAR file named simplemessageClient.jar and then executes it.

The output of the application client in the Output pane looks like this:


Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
 check <install_dir>/domains/domain1/logs/server.log.

The output from the message-driven bean appears in the server log (domain-dir/logs/server.log), wrapped in logging information.


MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3

The received messages often appear in a different order from the order in which they were sent.

    Undeploy the application after you finish running the client. To undeploy the application, follow these steps:

  1. Click the Services tab.

  2. Expand the Servers node.

  3. Expand the Sun Java System Application Server node.

  4. Expand the Applications node.

  5. Expand the Enterprise Applications node.

  6. Right-click simplemessage and choose Undeploy.

To remove the generated files, right-click the simplemessage project and choose Clean.

Building, Deploying, and Running the simplemessage Application Using Ant

To create and package the application using Ant, use the default target for the build.xml file:


ant

This target packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the dist directory.

By using resource injection and annotations, you avoid having to create deployment descriptor files for the message-driven bean and application client. You need to use deployment descriptors only if you want to override the values specified in the annotated source files.

To deploy the application and run the client using Ant, use the following command:


ant run

Ignore the message that states that the application is deployed at a URL.

The output in the terminal window looks like this:


running application client container.
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
 check <install_dir>/domains/domain1/logs/server.log.

In the server log file, the following lines should be displayed, wrapped in logging information:


MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3

The received messages often appear in a different order from the order in which they were sent.

Undeploy the application after you finish running the client. Use the following command:


ant undeploy

To remove the generated files, use the following command:


ant clean

Removing the Administered Objects for the simplemessage Example

After you run the example, you can use the following Ant targets to delete the connection factory and queue:


ant delete-cf
ant delete-queue

Creating Deployment Descriptors for Message-Driven Beans

By using resource injection and annotations, you avoid having to create a standard ejb-jar.xml deployment descriptor file for a message-driven bean. However, in certain situations you still need a deployment descriptor specific to the Application Server, in the file sun-ejb-jar.xml.

You are likely to need a deployment descriptor if the message-driven bean will consume messages from a remote system. You use the deployment descriptor to specify the connection factory that points to the remote system. The deployment descriptor would look something like this:

<sun-ejb-jar>
  <enterprise-beans>
    <ejb>
      <ejb-name>MessageBean</ejb-name>
      <mdb-connection-factory>
        <jndi-name>jms/JupiterConnectionFactory</jndi-name>
      </mdb-connection-factory>
    </ejb>
  </enterprise-beans>
</sun-ejb-jar>

The ejb element for the message-driven bean contains the following:

For an example of the use of such a deployment descriptor, see An Application Example That Consumes Messages from a Remote Server.