C H A P T E R  5

Scenario: Web Module and Queue-Mode Message-Driven Bean

FIGURE 5-1 shows a web module and an Enterprise JavaBeans (EJB) module assembled into a Java 2 Platform, Enterprise Edition (J2EE platform) application. The interaction between the modules is asynchronous messaging. The web module sends a message to a queue, and a message-driven enterprise bean in the EJB module reads the message from the queue. Sending the message to the queue is represented in the figure by the arrow labeled #1. Reading the message from the queue is represented by the arrow labeled #2. The message-driven bean reads the message and then initiates processing by calling methods of other enterprise beans in the module.


FIGURE 5-1 J2EE Application With Queue-Mode Message-Driven Bean

Diagram of the J2EE application covered in this chapter, containing a web module and an EJB module.[ D ]



The Interactions in This Application

This scenario describes one possible use of the J2EE application and the interactions illustrated in FIGURE 5-1. This scenario continues the retail web site application, but it explores a different type of interaction, which is implemented in a different EJB module.

In this scenario, a shopper interacts with web pages that are defined in the web module by selecting items and adding them to a shopping cart. Once the shopper is ready to complete the purchase, synchronous interaction with the EJB module is performed. Chapter 2, Chapter 3, and Chapter 4 show you how to implement this type of logic in a J2EE application.

Eventually the shopper is ready to check out. The shopper reviews the contents of the shopping cart, selects a shipping method, approves the total amount, and provides a credit card number. The shopper reviews and approves the order and leaves the site. Sometime later, the application processes the order and notifies the shopper by email. The specific interactions in this checkout scenario are outlined in the following process:

1. The web module displays a page that shows the items ordered, the delivery address, the shipping method, and the payment method. The shopper approves the order.

2. When the shopper approves the order, the web module sends a message to a message queue. The message identifies the order to be processed.

3. The message queue is outside the application. It is maintained by the application server.

4. The queue notifies a message-driven enterprise bean in an EJB module that performs order processing. The queue notifies the message-driven bean by the onMessage event, passing the message as a parameter.

5. The message-driven bean does not contain the business logic for processing the order. It only examines the message and initiates order completion processing.

The message-driven bean initiates order completion processing by calling business methods of other enterprise beans in the module, which is a typical way of using a message-driven bean. The details of the order are saved in a database.

6. When the order is processed, the application sends an email message to notify the shopper.

The procedures in this chapter show you how to set up a message queue and a queue connection factory and how to configure the sending module and the receiving module to use the queue.


Programming the Message-Driven Communication

TABLE 5-1 summarizes the programming required to implement the message-driven interaction described in this scenario and illustrated in FIGURE 5-1.


TABLE 5-1 Programming Required by This Application

Application Element

Setup Needed

Application Server

Set up a queue name CheckoutQueue and a queue connection factory name CheckoutQCF in the integrated development environment (IDE) with the application server's administration tools.

Web Module

Create the servlet CheckoutServlet that sends the message. Add code to the processRequest method of CheckoutServlet that:

  1. Uses Java Naming and Directory Interface (JNDI) lookups to obtain references to CheckoutQueue and CheckoutQCF
  2. Calls CheckoutQueue methods to format and send a message

EJB Module

Create the message-driven enterprise bean CheckoutMDB.

Use the CheckoutMDB property sheet to configure CheckoutMDB as a message destination for the CheckoutQueue.

Code the onMessage method of CheckoutMDB.


The sections that follow show you how to perform these programming tasks.

Other programming tasks are required to program the complete application. These tasks include creating the web components and the web module, creating the session and entity enterprise beans, and creating the EJB module. These tasks are covered in other chapters that focus on those issues. This chapter focuses on the message-driven interaction.

Setting up the Application Server

The design for the checkout interaction calls for the web module to send messages to a queue and for the EJB module to read the messages from the queue and then process the orders identified in the messages. This interaction requires a queue and a queue connection factory.

An application server resource representing the Java Message Service (JMS) queue and queue connection factory must be created in the application server. The creation of a queue is required to establish the mapping between the web module and the message-driven bean. The queue and queue connection factory are resources of the application server that are created outside the IDE.

Before you can complete the procedures in this section, you must have an application server and an IDE application server plug-in installed. You also need an application server instance. The application server plug-in and the server instance are represented by nodes that appear in the Runtime window. For more information on the application server plug-in and application server instance nodes, see The Server Product Nodes.

Setting up a Queue

This section explains how to set up a message queue for the Sun Java System application server. Procedures for other application servers should be similar.

To add a queue to the Sun Java System application server, use the following procedure:

1. Click the Runtime window.

2. Expand the Sun Java System Application Server 7 node.

3. Right-click the Unregistered JMS Resources node and choose Add New JMS Resource.

The New wizard's JMS Resources page opens.

4. Define the queue.

a. In the JNDI Name field, type jms/CheckoutQueue.

b. Make sure that the Resource Type field is set to javax.jms.Queue.

c. Click Next.

The New wizard's Properties page opens.

5. Define an imqDestinationName property.

a. Click Add.

The first property line is activated.

b. In the Name field, select imqDestinationName.

c. In the Value field, type Checkout.

Checkout is the name for the physical queue that you are creating. Your J2EE application will use the JNDI name that you assigned, CheckoutQueue, to access the queue named Checkout.

d. Click Finish.

The Do you want to continue with registration dialog box opens.

6. Register the queue.

a. Click Register.

The Java Resouce Registration dialog box opens.

b. In the Server Instance field, select the application server instance with which you are registering the queue.

Select the application server to which you will deploy your J2EE application.

c. Click Register.

A message that reads Resource Registered Successfully displays.

d. Click Close.

Setting up a Queue Connection Factory

This section explains how to set up a queue connection factory for the Sun Java System application server. Procedures for other application servers should be similar.

To add a queue connection factory to the Sun Java System application server, use the following procedure:

1. Right-click the Unregistered JMS Resources node and choose Add New JMS Resource.

The New wizard's JMS Resources page opens.

2. Define the queue connection factory.

a. In the JNDI Name field, type jms/CheckoutQCF.

b. Make sure that the Resource Type field is set to javax.jms.QueueConnectionFactory.

c. Click Finish.

The Do you want to continue with registration dialog box opens.

3. Register the queue connection factory.

a. Click Register.

The Java Resource Registration dialog box opens.

b. In the Server Instance field, select the application server instance with which you want to register the queue connection factory.

Select the application server instance you selected when you created the queue.

c. Click Register.

A message that reads Resource Registered Successfully displays.

d. Click Close.

Programming the Web Module

In this scenario, CheckoutServlet sends a message that requests final processing of an order. The message identifies the order to be processed. To send a message, CheckoutServlet calls methods of the queue connection factory and the queue.

To call queue and queue connection factory methods, CheckoutServlet needs references to the queue and queue connection factory. CheckoutServlet uses JNDI lookups to obtain queue and queue connection factory references from the application server environment.

Like most J2EE reference lookups, the queue and queue connection factory reference lookups have two parts:

The queue and queue connection factory are named resources of the application server. Your application components use JNDI names to obtain the references. To see how JNDI names are assigned to the queue and queue connection factory, see Setting up the Application Server.

The JNDI Lookup Code

CODE EXAMPLE 5-1 shows the processRequest method of CheckoutServlet. The processRequest method performs the JNDI lookups. After obtaining queue and queue connection factory references, processRequest calls methods of the queue and queue connection factory to create and send message. The code example contains comments that identify these operations.

CODE EXAMPLE 5-1 is from a servlet, but any type of J2EE component can use similar code to send a message. You can reuse this code in an application client or in an enterprise bean that acts as a message sender.

For more information on creating and sending messages, see Building Enterprise JavaBeans Components.


CODE EXAMPLE 5-1 The processRequest Method of CheckoutServlet
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.jms.*;
import javax.naming.*;
 
// ...
 
protected void processRequest(HttpServletRequest request, 
                              HttpServletResponse response)
                              throws ServletException, IOException {
  response.setContentType("text/html");
  PrintWriter out = response.getWriter();
  //output your page here
 
  // Delete the default method body and insert the following lines:
  Context jndiContext = null;
  javax.jms.TextMessage msg = null;
  QueueConnectionFactory queueConnectionFactory = null;
  QueueConnection queueConnection = null;
  QueueSession queueSession = null;
  Queue queue = null;
  QueueSender queueSender = null;
  TextMessage message = null;
 
  out.println("<html>");
  out.println("<head>");
  out.println("<title>Servlet</title>");
  out.println("</head>");
  out.println("<body>");
 
  try {
    // Connect to default naming service -- managed by app server
    jndiContext = new InitialContext();
  } 
  catch (NamingException e) {
    out.println("Could not create JNDI " + "context: " + 
    e.toString());
  }
 
  try {
    // Perform JNDI lookup for default QueueConnectionFactory and the
    // Queue created in this scenario.
    queueConnectionFactory = (QueueConnectionFactory)
                 jndiContext.lookup("java:comp/env/jms/CheckoutQCF");
    queue = (Queue) 
                jndiContext.lookup("java:comp/env/jms/CheckoutQueue");
  } 
  catch (NamingException e) {
    out.println("JNDI lookup failed: " + e.toString());
  }
 
  try {
    // Use references to connect to the queue and send a message.
    queueConnection = 
                      queueConnectionFactory.createQueueConnection();
    queueSession = queueConnection.createQueueSession(false,
                                          Session.AUTO_ACKNOWLEDGE);
    queueSender = queueSession.createSender(queue);
    message = queueSession.createTextMessage();
    message.setText("Order #33454344");
    queueSender.send(message);
  } 
  catch (JMSException e) {
    out.println("Exception occurred: " + e.toString());
  } 
  finally {
    if (queueConnection != null) {
      try {
        queueConnection.close();
      } 
      catch (JMSException e) {}
    } // end of if
  } // end of finally 
  // and the end of code to insert
 
  out.close();
}

The Resource Environment Reference for the Queue

Resource environment references appear in the module's deployment descriptor. A resource environment reference maps the reference name used in the lookup statement to a JNDI name in the application server environment.

To set up a resource environment reference for a queue, use the following procedure:

1. Right-click the web module's web node and choose Properties. In the References section, click the Resource Environment References ellipsis (...) button.

The Resource Environment Reference property editor opens.

2. Click the Add button.

The Add Resource Environment Reference dialog box opens.

3. Declare the Resource Environment Reference.

a. In the Name field, type the reference name that appears in the lookup statement.

FIGURE 5-1 shows the value jms/CheckoutQueue in the Name field, which is the reference name used in CODE EXAMPLE 5-1.

b. In the Type field, select javax.jms.Queue.


FIGURE 5-2 Adding a Resource Environment Reference for CheckoutQueue

Screenshot of the web module node's Add Resource Environment Reference dialog.[ D ]


4. Map the reference name to a JNDI name.

a. Click the Add dialog box's Sun Java System App Server tab.

b. In the JNDI Name field, type the JNDI name of the queue.

FIGURE 5-3 shows the value jms/CheckoutQueue in the JNDI Name field. This value maps the reference name on the Standard tab to the queue named CheckoutQueue. To see how the queue was named, see Setting up the Application Server.


FIGURE 5-3 Supplying JNDI Name for the Queue Reference

Screenshot of the web module Add Resource Environment Reference dialog's Sun Java System App Server tab. The JNDI Name field has the value jms/CheckoutQueue.


The Resource Reference for the Queue Connection Factory

To set up a resource reference for a queue connection factory, use the following procedure:

1. Right-click the web module's web node and choose Properties. In the References section, click the Resource References ellipsis (...) button.

The Resource Reference property editor opens.

2. Click the Add button.

The Add Resource References dialog box opens.

3. Declare the resource reference.

a. In the Name field, type the reference name that appears in the lookup statement.

FIGURE 5-4 shows the value jms/CheckoutQCF in the Name field, which is the reference name used in CODE EXAMPLE 5-1.

b. In the Type field, select javax.jms.QueueConnectionFactory.


FIGURE 5-4 Resource Reference for Queue Connection Factory

Screenshot of the web module's Add Resource Reference dialog.[ D ]


4. Map the reference name to a JNDI name.

a. Click the Add dialog box's Sun Java System App Server tab.

b. In the JNDI Name field, type the JNDI name of the queue connection factory.

FIGURE 5-5 shows the value jms/CheckoutQCF in the JNDI Name field. This value maps the reference name on the Standard tab to the queue connection factory named CheckoutQCF. To see how the queue connection factory was named, see Setting up the Application Server.

For information on the other authorization types, see the coverage of message-driven beans in Building Enterprise JavaBeans Components.


FIGURE 5-5 JNDI Name for the QueueConnectionFactory Reference

Screenshot of the Add Resource Reference dialog's Sun Java System App Server tab.[ D ]


Programming the EJB Module

In this checkout scenario, the business logic for processing a shopper's checkout request is in the Checkout EJB module. Programming the Web Module shows how the web module looks up a queue reference and a queue connection factory reference and sends a message. To complete this interaction, a message-driven bean in the EJB module must receive the message from the queue.

A message-driven bean does not use programmatic references. The message-driven bean does not need JNDI lookup code. You use the property sheet of the message-driven bean to specify the queue and queue connection factory that should be used. Setting these properties sets up tags in the deployment descriptor.

The properties that you set to configure a message-driven bean are listed as follows:

When the application is deployed, the application server automatically uses the queue connection factory specified in the deployment descriptor to open a connection from the message-driven bean to the queue that is specified in the deployment descriptor.

Configuring the Message-Driven Destination Property

Before you specify the queue and queue connection factory, you must configure the message-driven bean as a queue consumer.

To configure a message-driven bean as a queue consumer, use the following procedure:

1. Right-click the logical node of the message-driven bean and choose Properties. In the Properties section, click the Message-Driven Destination ellipsis (...) button.

The Message-Driven Destination property editor opens.

2. Identify the message-driven bean as a queue consumer.

a. In the Destination Type field, select Queue.


FIGURE 5-6 Message-Driven Bean Property Sheet

Screenshot of the message-driven bean's Message-Driven Destination property editor. The Destination Type property is set to Queue.


b. Click OK.

Specifying the Connection Factory

To configure a message-driven bean for a queue connection factory, use the following procedure:

1. Right-click the logical node of the message-driven bean and choose Properties. In the Sun Java System AS section, click the Mdb Connection Factory ellipsis (...) button.

The Mdb Connection Factory property editor opens.

2. Specify the queue connection factory.

a. In the Jndi Name field, type the queue connection factory's JNDI name.

FIGURE 5-7 shows the value jms/CheckoutQCF in the Jndi Name field. jms/CheckoutQCF is the queue connection factory that was specified in the sending web module.

b. If a user name and password are needed, type them in the Name and Password fields.


FIGURE 5-7 The Message-Driven Bean Connection Factory Property Editor

Mdb Connection Factory property editor.[ D ]


c. Click OK.

Specifying the Queue

To configure a message-driven bean for a queue, use the following procedure:

1. Right-click the local node of the message-driven bean and choose Properties. In the Sun Java System AS section, click the JNDI Name ellipsis (...) button.

The JNDI Name property editor opens.

2. Specify the queue.

In this scenario, use jms/CheckoutQueue. jms/CheckoutQueue is the queue that was specified in the sending web module.

Coding the onMessage Method

The application server delivers messages to the message-driven bean by calling the onMessage method of the bean. The message is delivered as a parameter of the onMessage method. CODE EXAMPLE 5-2 shows the onMessage method. You can see the message passed as a parameter and where you add your message-handling code.


CODE EXAMPLE 5-2 The onMessage Method
public void onMessage(javax.jms.Message aMessage) {
        // Process the message here.
    }

In this scenario, as shown in FIGURE 5-1, the message-driven bean immediately calls a business method of a session bean in the same EJB module. The session bean controls the processing of the order, which is typical onMessage behavior. For more information about writing onMessage methods, see Building Enterprise JavaBeans Components.

The message-driven bean calls the session bean using an EJB local reference. For information about how you implement method calls using EJB local references, see JNDI Lookup Code for Local EJB References and Local EJB Resource References.

Assembling the J2EE Application

Figure FIGURE 5-1 shows a web module that sends messages and an EJB module that receives messages assembled into a J2EE application. The modules are programmed as described in this chapter. The application is created and the two modules are added to the application. Both modules have been configured to use CheckoutQueue and CheckoutQCF. For the message-driven interaction, there is no need to open the J2EE application property sheet and perform any additional assembly work.

For information about creating an application and adding modules, see Creating the J2EE Application.