A Message-Driven Bean Example

 


Overview

Since message-driven beans are based on the Java Message Service (JMS) technology, to understand the example in this chapter you should already be familiar with basic JMS concepts such as queues and messages.

http://java.sun.com/products/jms/tutorial/index.html

 


Example Application Overview

This app has the following components:

  • SimpleMessageClient: A J2EE app client that sends several messages to a queue.
  • SimpleMessageEJB: A message-driven bean that asynchronously receives and processes the messages that are sent to the queue.

Figure 7-1 illustrates the structure of this app. The app client sends messages to the queue, which was created administratively using the j2eeadmin command. The JMS provider (in this, case the J2EE server) delivers the messages to the instances of the message-driven bean, which then processes the messages.

Figure 7-1 The SimpleMessageApp Application

The source code for this app is in the j2eetutorial/examples/src/ejb/simplemessage directory. To compile the code, go to the j2eetutorial/examples directory and type ant simplemessage. A sample SimpleMessageApp.ear file is in the j2eetutorial/examples/ears directory.

 


The J2EE Application Client

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

queueConnectionFactory = (QueueConnectionFactory)
    jndiContext.lookup
    ("java:comp/env/jms/MyQueueConnectionFactory");
queue = (Queue)
     jndiContext.lookup("java:comp/env/jms/QueueName");

Next, the client creates the queue connection, session, and sender:

queueConnection = 
    queueConnectionFactory.createQueueConnection();
queueSession =
    queueConnection.createQueueSession(false,
    Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queue);

Finally, the client sends several messages to the queue:

message = queueSession.createTextMessage();

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

 


The Message-Driven Bean Class

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

  • It implements the MessageDrivenBean and MessageListener interfaces.
  • The class is defined as public.
  • The class cannot be defined as abstract or final.
  • It implements one onMessage method.
  • It implements one ejbCreate method and one ejbRemove method.
  • It contains a public constructor with no arguments.
  • It must not define the finalize method.

Unlike session and entity beans, 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.

 

The onMessage Method

When the queue receives a message, the EJB container invokes the onMessage method of the message-driven bean. 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;
            System.out.println
                ("MESSAGE BEAN: Message received: " 
                + msg.getText());
        } else {
            System.out.println
                ("Message of wrong type: " 
                + inMessage.getClass().getName());
        }
    } catch (JMSException e) {
        e.printStackTrace();
        mdc.setRollbackOnly();
    } catch (Throwable te) {
        te.printStackTrace();
    }
}

 

The ejbCreate and ejbRemove Methods

The signatures of these methods have the following requirements:

  • The access control modifier must be public.
  • The return type must be void.
  • The modifier cannot be static or final.
  • The throws clause must not define any app exceptions.
  • The method has no arguments.

In the SimpleMessageBean class, the ejbCreate and ejbRemove methods are empty.

 


Running the SimpleMessageEJB Example

 

Starting the J2EE Server

To view the output of the message-driven bean, start the server in verbose mode:

j2ee -verbose

 

Creating the Queue

  1. Create the queue with the j2eeadmin command:
       j2eeadmin -addJmsDestination jms/MyQueue queue
    
    
  2. Verify that the queue was created:
       j2eeadmin -listJmsDestination
    
    

 

Deploying the Application

  1. In deploytool, open the j2eetutorial/examples/ears/SimpleMessageApp.ear file (FileOpen).
  2. Deploy the SimpleMessageApp app (ToolsDeploy). In the Introduction dialog box, make sure that you select the Return Client JAR checkbox. For detailed instructions, see Deploying the J2EE Application.

 

Running the Client

  1. In a terminal window, go to the j2eetutorial/examples/ears directory.
  2. Set the APPCPATH environment variable to SimpleMessageAppClient.jar.
  3. Type the following command on a single line:
       runclient -client SimpleMessageApp.ear -name
          SimpleMessageClient -textauth
    
    
  4. At the login prompts, enter j2ee for the user name and j2ee for the password.
  5. The client displays these lines:
       Sending message: This is message 1
       Sending message: This is message 2
       Sending message: This is message 3
    
    
    
  6. In the terminal window in which you've started the J2EE server (in verbose mode), the following lines should be displayed:
       MESSAGE BEAN: Message received: This is message 1
       MESSAGE BEAN: Message received: This is message 2
       MESSAGE BEAN: Message received: This is message 3
    
    
    

 


deploytool Tips for Message-Driven Beans

Chapter 2 covered the basic steps for building and packaging enterprise beans. This section describes the tasks in deploytool that are necessary for message-driven beans. To view an example in deploytool, open the j2eetutorial/examples/ears/SimpleMessageApp.ear file and select SimpleMessageEJB from the tree view.

 

Specifying the Bean's Type and Transaction Management

You specify the type when you create the bean with the New Enterprise Bean wizard.

  1. To start the wizard, select FileNewEnterprise Bean.
  2. In the General dialog box of the wizard, select the Message-Driven radio button.
  3. In the Transaction Management dialog box, you may select either the Container-Managed or Bean-Managed radio button. If you select the Bean-Managed button, then in step 4 of the next section, you may select the acknowledgment type.

 

Setting the Message-Driven Bean's Characteristics

You may specify these settings in two places:

  • The Message-Driven Bean Settings dialog box of the New Enterprise Bean wizard
  • The Message tab of the bean (see Figure 7-2)

These settings are as follows:

  1. For the Destination Type, select either the Queue or Topic radio button. A queue uses the point-to-point messaging domain and may have at most one consumer. A topic uses the publish-subscribe messaging domain; it may have zero, one, or many consumers.
  2. In the Destination combo box, select the JNDI name of the destination that you have created administratively. For an example, see the section Creating the Queue. The destination is either a Queue or a Topic object; it represents the source of incoming messages and the target of outgoing messages.
  3. In the Connection Factory combo box, select the appropriate object, either a QueueConnectionFactory or a TopicConnectionFactory. These objects produce the connections through which J2EE components access the messaging service.
  4. If you've specified bean-managed transactions, then you may select the acknowledgment type--either Auto-Acknowledge or Duplicates-OK-- from the Acknowledgement combo box. The Auto-Acknowledge type instructs the session to automatically acknowledge that the bean has consumed the message. The Duplicates-OK type instructs the session to lazily acknowledge the delivery of messages; this type may result in duplicate messages, but it reduces session overhead.
  5. In the JMS Message Selector field, you may enter a statement that filters the messages received by the bean.

Figure 7-2 Message Tab of SimpleMessageEJB

 


deploytool Tips for JMS Clients

http://java.sun.com/products/jms/tutorial/index.html

 

Setting the Resource References

  1. In the tree view, select the client's node.
  2. Select the Resource Refs tab.
  3. Click Add.
  4. In the Coded Name field, enter the name that matches the parameter of the lookup method in the client's code. For example, if the lookup parameter is java:comp/env/jms/MyQueueConnectionFactory, the Coded Name should be jms/QueueConnectionFactory.
  5. In the Type field, select the connection factory class that matches the destination type.
  6. In the Authentication field, in most cases you will select Container. You would select Application if your code explicitly logs on to the messaging service.
  7. In the Sharable field, make sure the checkbox is selected. This choice allows the container to optimize connections.
  8. Enter strings in the User Name and Password fields. The authentication service of the J2EE SDK will prompt you for these fields when you run the client.

 

Setting the Resource Environment References

  1. Select the Resource Env. Refs tab.
  2. Click Add.
  3. In the Coded Name field, enter a name that matches the parameter of the lookup call that locates the queue or topic. For example, if the lookup parameter is java:comp/env/jms/QueueName, the Coded Name should be jms/QueueName.
  4. In the Type field, select the class that matches the destination type.

 

Specifying the JNDI Names

  1. In the tree view, select the app's node.
  2. Select the JNDI Names tab and enter the appropriate names. For example, the SimpleMessageApp discussed in this chapter uses the JNDI names shown in Table 7-1.

     

    Table 7-1 JNDI Names for the SimpleMessageApp Application
    Component or Reference Name
    JNDI Name
    SimpleMessageEJB jms/MyQueue
    jms/MyQueueConnectionFactory jms/QueueConnectionFactory
    jms/QueueName jms/MyQueue