C H A P T E R 5 |
Scenario: Web Module and Queue-mode Message-driven Bean |
FIGURE 5-1 shows a J2EE application consisting of a web module front end and an EJB module with business logic. The distinguishing feature of this application is the asynchronous communication between the modules, which is initiated by the web module and processed by the EJB module.
This scenario looks at a J2EE application that implements the kind of interaction shown in FIGURE 5-1. This application is part of a retail web site. Within the web site, the asynchronous communication with a message-driven bean is used in the check-out process. The asynchronous interaction is used as follows:
1. An online shopper interacts with the front end provided by the web module. The user searches for merchandise and adds items to an online shopping cart managed by the web module. This activity opens a number of static HTML pages, servlets, and JSP pages in the module. Some of these components invoke the business methods of an EJB module, especially to obtain or record persistent data, but all of this done is synchronously--you user requests some information and then waits for the application to return before continuing. The web module covered in demonstrates this kind of application logic.
2. Eventually, your user does something that you want to handle asynchronously. A typical example is completing the checkout procedure. At this point your user has already reviewed the contents of the shopping cart, selected a shipping method, and provided a credit card number. Your application needs to complete the order process and then notify the user via email that the items are in stock and will be shipped.
3. The web module initiates this asynchronous processing by sending a message that identifies the customer and the order to a message queue. (The actual customer and order details are in an order database.) The message queue is outside the application--it is maintained by the application server.
4. A message-driven enterprise bean reads this message off the queue. The container takes the message from the queue, and relays it to the message-driven bean by invoking the message-driven bean's onMessage method. The container passes the message as an onMessage parameter.
5. The message-driven bean does not contain all the business logic to process the order. It just examines the message and initiates the necessary processing. In this scenario, the MDB initiates processing by invoking the business methods of other enterprise beans in the module. This is likely to be a typical strategy. If you are the developer of the EJB module you may well develop the session and entity enterprise beans (write their business methods) that perform the actual processing, as well as the message-driven bean.
There are other programming issues in this application, such as mapping URLs to web module resources and programming the interactions between the session and entity enterprise beans. These are covered in other scenarios that focus on those issues.
Now that you have seen how queue-based message-driven communication can be used in a business application, you can see the programming that you, that application developer, need to do to make it work.
The sections that follow use the scenario to explain each of these items in detail.
The front end of your message-driven application sends messages to a message queue, and the back end, where most of the business logic resides, reads these messages from the queue. The queue itself is created and maintained by the application server. In a production environment, system administration will probably define, configure, and manage the queues.
You can use the application server's default queue, but to be certain that there is no contention for messages, you may want to create a separate queue for you application.
In a development or test environment, you can create and manage the queue. For an example of the set up you need to perform, the steps for using the J2EE reference implementation's administration tool to add a queue to the Reference Implementation server are provided below:
1. Use the J2EE RI admin tool from the command line. Your working directory should be <j2sdkee1.3_home>/bin.
j2eeadmin -addJMSDestination jms/MyQueue queue
3. To confirm that you have added the queue:
The startup messages should show the presence of jms/MyQueue.
When your application is deployed into a production environment or a managed test environment, its queue and queue connection factory references can be linked to the queue designated by the system administrators.
To use a queue, your application needs to open a queue connection. It does this by calling the methods of a queue connection factory. (A queue connection factory is a driver for the messaging system--the application calls the JMS API methods of the connection factory, which interprets them for the particular implementation of JMS API that is installed. Each application server is likely to have its own queue connection factory, for its own implementation of the JMS APIs.)
Application servers may have default queue connection factories that are suitable for development and testing. The J2EE reference implementation, for example, comes with a default queue connection factory named jms/QueueConnectionFactory. It should be suitable for development and testing purposes, and it is used by the code in this scenario.
In a production environment, system administrators will probably configure queue connection factories that are configured for a specific environment and its security needs. When your application is deployed into a production environment or a managed test environment, it can be configured to use the queue connection factory designated by system administration.
In this scenario, messages are sent by a servlet in the web module. To send a message, the servlet needs to use the queue and queue connection factory designated for the application. It gets references to the queue and queue connection factory from the application server environment, by means of JNDI lookup.
Like most J2EE references, these queue and queue connection factory references consist of two parts, a declared reference in the web module's deployment descriptor and JNDI lookup code in the servlet. This section looks first at the declared references and then at how the code uses the references.
In the Sun ONE Studio 4 IDE, reference declarations are set up as properties of the servlet. The queue reference is a resource environment reference which is set up on the web module's resource environment property editor. FIGURE 5-1 shows the values used in this scenario.
Notice that there is a layer of indirection here. The name set up on the Standard tab of this property editor is the name used in the JNDI lookup. But this is the name of the reference, and not the actual JNDI name. The JNDI name is set up on one of the server-specific tabs of this property editor. FIGURE 5-3 shows the reference name, "QueueName," mapped to the JNDI name "MyQueue." If you turn back to Setting up the Application Server, you will see that this is the queue created in the J2EE RI and designated for this application. When the servlet's JNDI code performs a lookup on "QueueName," it is automatically mapped to the JNDI name "MyQueue," and application server returns a reference to that queue.
Declaring the reference for the queue connection factory references is similar. It is a Resource Reference, and you set it up on the servlet's resource reference property editor. FIGURE 5-4 shows the values used in this scenario.
For information on the other authorization types, see the coverage of message-driven beans in Building Enterprise JavaBeans Components.
This reference uses the same indirection as the queue references. FIGURE 5-5 shows the "defaultconnectionfactory" references mapped to the JNDI name for the J2EE RI's default queue connection factory.
Like other types of J2EE references, the declared references for a JMS queue and a JMS connection factory are used in application code. The application performs JNDI lookups to obtain references to objects named in the declared references, then uses the references to request services. In this scenario, a servlet in the web module performs the JNDI lookups and uses the queue and queue connection factory references to open a connection to the queue and send a message to it.
CODE EXAMPLE 5-1 shows the code that performs the JNDI lookup, creates a message, and sends it. It is in the servlet's processRequest method. The code is commented to identify each of the operations it performs.
Note that any type of client would use similar code to perform the same operations. You could use similar code in an application client, or in an enterprise bean that was acting as a message provider.
For more information on creating and sending messages, see Building Enterprise JavaBeans Components.
In this scenario, the business logic for processing a shopper's checkout request is in the EJB module. It is initiated by a message from the web module front end. For this to work, the EJB module needs to receive the message that the web module sends to the queue.
To do this, it you create a message-driven enterprise bean that reads from the queue. This section shows you how to program a message-driven bean so that it reads from the designated queue. When the application is deployed, the container uses the queue connection factory you specify for the bean to open a connection to the queue you specify. You use references to specify the queue and queue connection factory.
The first thing you need to do is configure your message-driven bean to read messages from a specific queue. In the Sun ONE Studio 4 IDE you do this on the bean's property sheet. FIGURE 5-6 shows the property sheet for the message-driven bean used in this scenario. The Message Driven Destination property configures this bean as the consumer of a queue.
You also need to identify the queue and the queue connection factory that will be used to open a queue connection. In the Sun ONE Studio 4 IDE, you do this on the server-specific tab for the application server you will be using. FIGURE 5-7 shows the J2EE RI properties tab for the same message-driven bean. The Connection Factory Name property has been set to the JNDI name for the default J2EE connection factory (jms/QueueConnectionFactory), and the Destination JNDI Name property has been set the JNDI name for the J2EE RI queue that you created for this application (jms/MyQueue).
When this message-driven bean is deployed, the RI container will automatically open a connection to the queue you've specified, using the queue connection factory you've specified.
The tabs for the other application servers have similar properties for specifying queues and connection factories.
You add business logic to a message-driven bean by completing its onMessage method. This method is automatically invoked when the container delivers a message to the message-driven bean. In this example, the message-driven bean immediately calls the appropriate business method of another enterprise bean in the module. This is likely to be typical onMessage behavior. For more information about writing onMessage methods, see Building Enterprise JavaBeans Components.
Figure FIGURE 5-1 shows both the servlet (in a web module) and the message-driven bean (in an EJB module) in a J2EE application To put these modules into a single application, you simply create the application and add both modules to it. The two modules contain all of the information needed to deploy and execute the message-driven communication. There is no need to open the J2EE application's property sheet and perform any additional assembly work.
For information about creating an application and adding modules, see Assembling the J2EE Application.
Copyright © 2002, Sun Microsystems, Inc. All rights reserved.