An Application Example That Deploys a Message-Driven Bean on Two J2EE Servers

This section, like the preceding one, explains how to write, compile, package, deploy, and run a pair of J2EE applications that use the JMS API and run on two J2EE servers. The applications are slightly more complex than the ones in the first example.

The applications use the following components:

In this section, the term local server means the server on which both the application client and the message-driven bean are deployed (earth in the preceding example). The term remote server means the server on which only the message-driven bean is deployed (jupiter in the preceding example).

The section covers the following topics:

You will find the source files for this section in <INSTALL>/j2eetutorial14/examples/jms/sendremote/. Path names in this section are relative to this directory.

Overview of the Applications

This pair of applications is somewhat similar to the applications in An Application Example That Consumes Messages from a Remote J2EE Server in that the only components are a client and a message-driven bean. However, the applications here use these components in more complex ways. One application consists of the application client. The other application contains only the message-driven bean and is deployed twice, once on each server.

The basic steps of the applications are as follows.

  1. You start two J2EE servers, one on each system.
  2. On the local server (earth), you create two connection factories: one local and one that communicates with the remote server (jupiter). On the remote server, you create a connection factory that has the same name.
  3. The application client looks up the two connection factories--the local one and the one that communicates with the remote server--to create two connections, sessions, publishers, and subscribers. The subscribers use a message listener.
  4. Each publisher publishes five messages.
  5. Each of the local and the remote message-driven beans receives five messages and sends replies.
  6. The client's message listener consumes the replies.

Figure 34-4 illustrates the structure of this application. M1 represents the first message sent using the local connection factory, and RM1 represents the first reply message sent by the local MDB. M2 represents the first message sent using the remote connection factory, and RM2 represents the first reply message sent by the remote MDB.

A J2EE Application that Sends Messages to Two Servers

Figure 34-4 A J2EE Application That Sends Messages to Two Servers

Writing the Application Components

Writing the components of the applications involves two tasks:

Coding the Application Client: MultiAppServerClient.java

The application client class, multiclient/src/MultiAppServerClient.java, does the following.

  1. It uses the JNDI naming context java:comp/env to look up two connection factories and a topic.
  2. For each connection factory, it creates a connection, a publisher session, a publisher, a subscriber session, a subscriber, and a temporary topic for replies.
  3. Each subscriber sets its message listener, ReplyListener, and starts the connection.
  4. Each publisher publishes five messages and creates a list of the messages the listener should expect.
  5. When each reply arrives, the message listener displays its contents and removes it from the list of expected messages.
  6. When all the messages have arrived, the client exits.

Coding the Message-Driven Bean: ReplyMsgBean.java

The onMessage method of the message-driven bean class, replybean/src/ReplyMsgBean.java, does the following:

  1. Casts the incoming message to a TextMessage and displays the text
  2. Creates a connection, a session, and a publisher for the reply message
  3. Publishes the message to the reply topic
  4. Closes the connection

On both servers, the bean will consume messages from the topic jms/Topic.

Creating and Packaging the Applications

This example uses the connection factory named jms/ConnectionFactory and the topic named jms/Topic. These objects must exist on both the local and the remote servers. If you need to, you can create the objects there using the Admin Console, as described in Creating JMS Administered Objects.

This example uses an additional connection factory, jms/JupiterConnectionFactory, which communicates with the remote system; you created it in Creating Administered Objects for Multiple Systems. This connection factory needs exist only on the local server.

Creating and packaging this application involve six steps:

  1. Creating the connection factories
  2. Compiling the source files
  3. Creating the applications
  4. Packaging the application client
  5. Packaging the message-driven bean
  6. Updating the JNDI names

You can package the applications yourself as an exercise. Use the asant build targets in the multiclient and replybean directories to compile the source files.

This section uses the prepackaged EAR files to show how to create and package the applications. You can use the systems earth and jupiter for the local and remote systems.

The Application Server must be running on both systems. You package, deploy, and run the application from the local system.

Examining the Applications

  1. In deploytool, on the local system, open the two EAR files MultiClientApp.ear and ReplyBeanApp.ear, which reside in the directory <INSTALL>/j2eetutorial14/jms/provided-ears.
  2. In MultiClientApp.ear, select the application client node, MultiAppServerClient.
    1. Click the Resource Ref's tab. The client looks up two connection factories and casts them to objects of type javax.jms.ConnectionFactory. The coded name jms/ConnectionFactory1 refers to jms/ConnectionFactory, and the coded name jms/ConnectionFactory2 refers to jms/JupiterConnectionFactory.
    2. Click the Msg Dest Ref's tab. The coded name jms/TopicName refers to the target destination PhysicalTopic. Its type is javax.jms.Topic, and its usage is set to Produces.
    3. Click the Message Destinations tab, and then click PhysicalTopic. The client appears in the Producers area. It refers to the JNDI name jms/Topic. This is the destination where messages are sent. Replies will come to a temporary destination.
  3. In ReplyBeanApp.ear, expand the MDBJAR node and select ReplyMsgBean.
    1. Click the Message-Driven tab. The bean uses the PhysicalTopic target destination and the connection factory jms/ConnectionFactory.
    2. Click the Resource Ref's tab. The bean uses the connection factory jms/ConnectionFactory to send reply messages. The bean looks up the coded name jms/MyConnectionFactory and casts the object to an object of type javax.jms.ConnectionFactory. The bean does not look up a topic for the reply messages; instead, it uses the temporary topic specified in the incoming message's JMSReplyTo header field.
    3. Click the Transactions tab. The bean uses container-managed transactions.
  4. Select the MDBJAR node, click the Message Destinations tab, and then click PhysicalTopic. The message-driven bean appears in the Consumers area. The destination refers to the JNDI name jms/Topic.
  5. Select the ReplyBeanApp node and click Sun-specific Settings on the General page. The JNDI name for the message-driven bean is the topic destination resource, jms/Topic.

Verify that the JNDI names for the applications are correct.

The Application pane for ReplyBeanApp should appear as shown in Table 34-7.

Table 34-7 Application Pane for ReplyBeanApp
Component Type
Component
JNDI Name
EJB
ReplyMsgBean
jms/Topic

The References pane for ReplyBeanApp should appear as shown in Table 34-8.

Table 34-8 References Pane for ReplyBeanApp
Ref. Type
Referenced By
Reference Name
JNDI Name
Resource
ReplyMsgBean
jms/MyConnectionFactory
jms/ConnectionFactory

Select the MultiClientApp application and click the JNDI Names tab.

The JNDI names for the application should appear as shown in Table 34-9. Only the References pane has any content.

Table 34-9 References Pane for MultiClientApp
Ref. Type
Referenced By
Reference Name
JNDI Name
Resource
MultiAppServerClient
jms/ConnectionFactory1
jms/ConnectionFactory
Resource
MultiAppServerClient
jms/ConnectionFactory2
jms/JupiterConnectionFactory

Deploying the Applications

To deploy the MultiClientApp application and the ReplyBeanApp application on the local server, perform the following steps for each application:

  1. Make localhost the current target server by selecting it and choosing FileRight ArrowSet Current Target Server.
  2. Save the application.
  3. Choose ToolsRight ArrowDeploy.
  4. Type your administrative user name and password (if they are not already filled in).
  5. For the MultiClientApp application, select the Return Client Jar checkbox in the Application Client Stub Directory area. If you wish to run the client in a directory other than the default, click Browse and use the file chooser to specify it.
  6. Click OK.
  7. In the Distribute Module dialog box, click Close when the process completes. For the MultiClientApp application, you will find a file named MultiClientAppClient.jar in the specified directory.

Before you can deploy the ReplyBeanApp application on the remote server, you must add the remote server. If you did not do so before, perform the following steps:

  1. Choose FileRight ArrowAdd Server.
  2. Type the name of the server in the Server Name field, and click OK.
  3. The server appears in the tree under Servers. Select it.
  4. In the dialog box that appears, type the administrative user name and password for the server in the Connection Settings area, and click OK.

To deploy the ReplyBeanApp application on the remote server, perform the following steps:

  1. Make the remote server the current target server by selecting it and choosing FileRight ArrowSet Current Target Server.
  2. Select the application.
  3. Choose ToolsRight ArrowDeploy.
  4. Type your administrative user name and password (if they are not already filled in), and click OK.
  5. In the Distribute Module dialog box, click Close when the process completes.

Running the Application Client

To run the client, use the following command:

appclient -client MultiClientAppClient.jar 

On the local system, the output of the appclient command looks something like this:

Sent message: text: id=1 to local app server
Sent message: text: id=2 to remote app server
ReplyListener: Received message: id=1, text=ReplyMsgBean 
processed message: text: id=1 to local app server
Sent message: text: id=3 to local app server
ReplyListener: Received message: id=3, text=ReplyMsgBean 
processed message: text: id=3 to local app server
ReplyListener: Received message: id=2, text=ReplyMsgBean 
processed message: text: id=2 to remote app server
Sent message: text: id=4 to remote app server
ReplyListener: Received message: id=4, text=ReplyMsgBean 
processed message: text: id=4 to remote app server
Sent message: text: id=5 to local app server
ReplyListener: Received message: id=5, text=ReplyMsgBean 
processed message: text: id=5 to local app server
Sent message: text: id=6 to remote app server
ReplyListener: Received message: id=6, text=ReplyMsgBean 
processed message: text: id=6 to remote app server
Sent message: text: id=7 to local app server
ReplyListener: Received message: id=7, text=ReplyMsgBean 
processed message: text: id=7 to local app server
Sent message: text: id=8 to remote app server
ReplyListener: Received message: id=8, text=ReplyMsgBean 
processed message: text: id=8 to remote app server
Sent message: text: id=9 to local app server
ReplyListener: Received message: id=9, text=ReplyMsgBean 
processed message: text: id=9 to local app server
Sent message: text: id=10 to remote app server
ReplyListener: Received message: id=10, text=ReplyMsgBean 
processed message: text: id=10 to remote app server
Waiting for 0 message(s) from local app server
Waiting for 0 message(s) from remote app server
Finished
Closing connection 1
Closing connection 2 

On the local system, where the message-driven bean receives the odd-numbered messages, the output in the server log looks like this (wrapped in logging information):

In ReplyMsgBean.ReplyMsgBean()
In ReplyMsgBean.setMessageDrivenContext()
In ReplyMsgBean.ejbCreate()
ReplyMsgBean: Received message: text: id=1 to local app server
ReplyMsgBean: Received message: text: id=3 to local app server
ReplyMsgBean: Received message: text: id=5 to local app server
ReplyMsgBean: Received message: text: id=7 to local app server
ReplyMsgBean: Received message: text: id=9 to local app server 

On the remote system, where the bean receives the even-numbered messages, the output in the server log looks like this (wrapped in logging information):

In ReplyMsgBean.ReplyMsgBean()
In ReplyMsgBean.setMessageDrivenContext()
In ReplyMsgBean.ejbCreate()
ReplyMsgBean: Received message: text: id=2 to remote app server
ReplyMsgBean: Received message: text: id=4 to remote app server
ReplyMsgBean: Received message: text: id=6 to remote app server
ReplyMsgBean: Received message: text: id=8 to remote app server
ReplyMsgBean: Received message: text: id=10 to remote app server 

Undeploy the applications after you finish running the client.