The Java EE 5 Tutorial

Chapter 32 Java EE Examples Using the JMS API

This chapter provides examples that show how to use the JMS API within a Java EE application in the following ways:

The examples are in the following directory:

tut-install/javaeetutorial5/examples/jms/

    To build and run the examples, you will do the following:

  1. Use NetBeans IDE or the Ant tool to compile and package the example.

  2. Use the Ant tool to create resources.

  3. Use NetBeans IDE or the Ant tool to deploy the example.

  4. Use NetBeans IDE or the Ant tool to run the client.

Each example has a build.xml file that refers to files in the following directory:

tut-install/javaeetutorial5/examples/bp-project/

See Chapter 23, A Message-Driven Bean Example for a simpler example of a Java EE application that uses the JMS API.

A Java EE Application That Uses the JMS API with a Session Bean

This section explains how to write, compile, package, deploy, and run a Java EE application that uses the JMS API in conjunction with a session bean. The application contains the following components:

The section covers the following topics:

You will find the source files for this section in the directory tut-install/javaeetutorial5/examples/jms/clientsessionmdb/. Path names in this section are relative to this directory.

Writing the Application Components for the clientsessionmdb Example

This application demonstrates how to send messages from an enterprise bean (in this case, a session bean) rather than from an application client, as in the example in Chapter 23, A Message-Driven Bean Example. Figure 32–1 illustrates the structure of this application.

Figure 32–1 A Java EE Application: Client to Session Bean to Message-Driven Bean

Diagram of application showing an application client
calling a session bean, which publishes a message that is consumed by a message-driven
bean

The Publisher enterprise bean in this example is the enterprise-application equivalent of a wire-service news feed that categorizes news events into six news categories. The message-driven bean could represent a newsroom, where the sports desk, for example, would set up a subscription for all news events pertaining to sports.

The application client in the example injects the Publisher enterprise bean’s remote home interface and then calls the bean’s business method. The enterprise bean creates 18 text messages. For each message, it sets a String property randomly to one of six values representing the news categories and then publishes the message to a topic. The message-driven bean uses a message selector for the property to limit which of the published messages it receives.

Writing the components of the application involves the following:

Coding the Application Client: MyAppClient.java

The application client program, clientsessionmdb-app-client/src/java/MyAppClient.java, performs no JMS API operations and so is simpler than the client program in Chapter 23, A Message-Driven Bean Example. The program uses dependency injection to obtain the Publisher enterprise bean’s business interface:

@EJB(name="PublisherRemote")
static private PublisherRemote publisher;

The program then calls the bean’s business method twice.

Coding the Publisher Session Bean

The Publisher bean is a stateless session bean that has one business method. The Publisher bean uses a remote interface rather than a local interface because it is accessed from the application client.

The remote interface, clientsessionmdb-ejb/src/java/sb/PublisherRemote.java, declares a single business method, publishNews.

The bean class, clientsessionmdb-ejb/src/java/sb/PublisherBean.java, implements the publishNews method and its helper method chooseType. The bean class also injects SessionContext, ConnectionFactory, and Topic resources and implements @PostConstruct and @PreDestroy callback methods. The bean class begins as follows:

@Stateless
@Remote({PublisherRemote.class})
public class PublisherBean implements PublisherRemote {

    @Resource
    private SessionContext sc;

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

    @Resource(mappedName="jms/Topic")
    private Topic topic;
    ...

The @PostConstruct callback method of the bean class, makeConnection, creates the Connection used by the bean. The business method publishNews creates a Session and a MessageProducer and publishes the messages.

The @PreDestroy callback method, endConnection, deallocates the resources that were allocated by the @PostConstruct callback method. In this case, the method closes the Connection.

Coding the Message-Driven Bean: MessageBean.java

The message-driven bean class, clientsessionmdb-ejb/src/java/mdb/MessageBean.java, is almost identical to the one in Chapter 23, A Message-Driven Bean Example. However, the @MessageDriven annotation is different, because instead of a queue the bean is using a topic with a durable subscription, and it is also using a message selector. Therefore, the annotation sets the activation config properties messageSelector, subscriptionDurability, clientId, and subscriptionName, as follows:

@MessageDriven(mappedName="jms/Topic",
activationConfig=
{ @ActivationConfigProperty(propertyName="messageSelector",
    propertyValue="NewsType = ’Sports’ OR NewsType = ’Opinion’"),
  @ActivationConfigProperty(
    propertyName="subscriptionDurability",
    propertyValue="Durable"),
  @ActivationConfigProperty(propertyName="clientId",
    propertyValue="MyID"),
  @ActivationConfigProperty(propertyName="subscriptionName",
    propertyValue="MySub")
 })

The JMS resource adapter uses these properties to create a connection factory for the message-driven bean that allows the bean to use a durable subscriber.

Creating Resources for the clientsessionmdb Example

This example uses the topic named jms/Topic and the connection factory jms/ConnectionFactory, which you created in Creating JMS Administered Objects for the Synchronous Receive Example. If you deleted the connection factory or topic, you can create them again using targets in the build.xml file for this example. Use the following commands to create the resources:


ant create-cf
ant create-topic

Building, Deploying, and Running the clientsessionmdb Example Using NetBeans IDE

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

  1. Start the Application Server, if it is not already running.

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

  3. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jms/.

  4. Select the clientsessionmdb folder.

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

  6. Click Open Project.

  7. Right-click the clientsessionmdb project and choose Build.

    This task creates the following:

    • An application client JAR file that contains the client class file and the session bean’s remote interface, along with a manifest file that specifies the main class

    • An EJB JAR file that contains both the session bean and the message-driven bean

    • An application EAR file that contains the two JAR files

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

  9. Right-click the project and choose Run.

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

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


To view the bean output,
 check <install_dir>/domains/domain1/logs/server.log.

The output from the enterprise beans appears in the server log (domain-dir/logs/server.log), wrapped in logging information. The Publisher session bean sends two sets of 18 messages numbered 0 through 17. Because of the message selector, the message-driven bean receives only the messages whose NewsType property is Sports or Opinion.

    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 clientsessionmdb and choose Undeploy.

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

Building, Deploying, and Running the clientsessionmdb Example Using Ant

    To build the application using Ant, do the following:

  1. Start the Application Server, if it is not already running.

  2. Go to the following directory:

    tut-install/javaeetutorial5/examples/jms/clientsessionmdb/
    
  3. To compile the source files and package the application, use the following command:


    ant
    

The ant command creates the following:

The clientsessionmdb.ear file is created in the clientsessionmdb/dist directory.

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


ant run

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

The client displays these lines:

running application client container.
To view the bean output,
 check <install_dir>/domains/domain1/logs/server.log.

The output from the enterprise beans appears in the server log (domain-dir/logs/server.log), wrapped in logging information. The Publisher session bean sends two sets of 18 messages numbered 0 through 17. Because of the message selector, the message-driven bean receives only the messages whose NewsType property is Sports or Opinion.

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


ant undeploy

To remove the generated files, use the following command in the clientsessionmdb, clientsessionmdb-app-client, and clientsessionmdb-ejb directories:


ant clean

A Java EE Application That Uses the JMS API with an Entity

This section explains how to write, compile, package, deploy, and run a Java EE application that uses the JMS API with an entity. The application uses the following components:

This section covers the following topics:

You will find the source files for this section in the directory tut-install/javaeetutorial5/examples/jms/clientmdbentity/. Path names in this section are relative to this directory.

Overview of the clientmdbentity Example Application

This application simulates, in a simplified way, the work flow of a company’s human resources (HR) department when it processes a new hire. This application also demonstrates how to use the Java EE platform to accomplish a task that many JMS client applications perform.

A JMS client must often wait for several messages from various sources. It then uses the information in all these messages to assemble a message that it then sends to another destination. The common term for this process is joining messages. Such a task must be transactional, with all the receives and the send as a single transaction. If not all the messages are received successfully, the transaction can be rolled back. For a client example that illustrates this task, see A Local Transaction Example.

A message-driven bean can process only one message at a time in a transaction. To provide the ability to join messages, a Java EE application can have the message-driven bean store the interim information in an entity. The entity can then determine whether all the information has been received; when it has, the entity can report this back to one of the message-driven beans, which then creates and sends the message to the other destination. After it has completed its task, the entity can be removed.

The basic steps of the application are as follows.

  1. The HR department’s application client generates an employee ID for each new hire and then publishes a message (M1) containing the new hire’s name, employee ID, and position. The client then creates a temporary queue, ReplyQueue, with a message listener that waits for a reply to the message. (See Creating Temporary Destinations, for more information.)

  2. Two message-driven beans process each message: One bean, OfficeMDB, assigns the new hire’s office number, and the other bean, EquipmentMDB, assigns the new hire’s equipment. The first bean to process the message creates and persists an entity named SetupOffice, then calls a business method of the entity to store the information it has generated. The second bean locates the existing entity and calls another business method to add its information.

  3. When both the office and the equipment have been assigned, the entity business method returns a value of true to the message-driven bean that called the method. The message-driven bean then sends to the reply queue a message (M2) describing the assignments. Then it removes the entity. The application client’s message listener retrieves the information.

Figure 32–2 illustrates the structure of this application. Of course, an actual HR application would have more components; other beans could set up payroll and benefits records, schedule orientation, and so on.

Figure 32–2 assumes that OfficeMDB is the first message-driven bean to consume the message from the client. OfficeMDB then creates and persists the SetupOffice entity and stores the office information. EquipmentMDB then finds the entity, stores the equipment information, and learns that the entity has completed its work. EquipmentMDB then sends the message to the reply queue and removes the entity.

Figure 32–2 A Java EE Application: Client to Message-Driven Beans to Entity

Diagram of application showing an application client,
two message-driven beans, and an entity

Writing the Application Components for the clientmdbentity Example

Writing the components of the application involves the following:

Coding the Application Client: HumanResourceClient.java

    The application client program, clientmdbentity-app-client/src/java/HumanResourceClient.java, performs the following steps:

  1. Injects ConnectionFactory and Topic resources

  2. Creates a TemporaryQueue to receive notification of processing that occurs, based on new-hire events it has published

  3. Creates a MessageConsumer for the TemporaryQueue, sets the MessageConsumer’s message listener, and starts the connection

  4. Creates a MessageProducer and a MapMessage

  5. Creates five new employees with randomly generated names, positions, and ID numbers (in sequence) and publishes five messages containing this information

The message listener, HRListener, waits for messages that contain the assigned office and equipment for each employee. When a message arrives, the message listener displays the information received and determines whether all five messages have arrived. When they have, the message listener notifies the main program, which then exits.

Coding the Message-Driven Beans for the clientmdbentity Example

This example uses two message-driven beans:

    The beans take the following steps:

  1. They inject MessageDrivenContext and ConnectionFactory resources.

  2. The onMessage method retrieves the information in the message. The EquipmentMDB’s onMessage method chooses equipment, based on the new hire’s position; the OfficeMDB’s onMessage method randomly generates an office number.

  3. After a slight delay to simulate real world processing hitches, the onMessage method calls a helper method, compose.

  4. The compose method takes the following steps:

    1. It either creates and persists the SetupOffice entity or finds it by primary key.

    2. It uses the entity to store the equipment or the office information in the database, calling either the doEquipmentList or the doOfficeNumber business method.

    3. If the business method returns true, meaning that all of the information has been stored, it creates a connection and a session, retrieves the reply destination information from the message, creates a MessageProducer, and sends a reply message that contains the information stored in the entity.

    4. It removes the entity.

Coding the Entity Class for the clientmdbentity Example

The SetupOffice class, SetupOffice.java, is an entity class. The entity and the message-driven beans are packaged together in an EJB JAR file. The entity class is declared as follows:

@Entity
public class SetupOffice implements Serializable {

The class contains a no-argument constructor and a constructor that takes two arguments, the employee ID and name. It also contains getter and setter methods for the employee ID, name, office number, and equipment list. The getter method for the employee ID has the @Id annotation to indicate that this field is the primary key:

@Id public String getEmployeeId() {
    return id;
}

The class also implements the two business methods, doEquipmentList and doOfficeNumber, and their helper method, checkIfSetupComplete.

The message-driven beans call the business methods and the getter methods.

The persistence.xml file for the entity specifies the most basic settings:

<persistence>
    <persistence-unit name="clientmdbentity">
        <jta-data-source>jdbc/__default</jta-data-source>
        <class>eb.SetupOffice</class>
        <properties>
            <property name="toplink.ddl-generation"
                 value="drop-and-create-tables"/>
        </properties>
    </persistence-unit>
</persistence>

Creating Resources for the clientmdbentity Example

This example uses the connection factory jms/ConnectionFactory and the topic jms/Topic, both of which you used in A Java EE Application That Uses the JMS API with a Session Bean. It also uses the JDBC resource named jdbc/__default, which is enabled by default when you start the Application Server.

If you deleted the connection factory or topic, you can create them again using targets in the build.xml file for this example. Use the following commands to create the resources:


ant create-cf
ant create-topic

Building, Deploying, and Running the clientmdbentity Example Using NetBeans IDE

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

  1. Start the Application Server, if it is not already running.

  2. Start the database server as described in Starting and Stopping the Java DB Database Server, if it is not already running.

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

  4. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jms/.

  5. Select the clientmdbentity folder.

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

  7. Click Open Project.

  8. Right-click the clientmdbentity project and choose Build.

    This task creates the following:

    • An application client JAR file that contains the client class and listener class files, along with a manifest file that specifies the main class

    • An EJB JAR file that contains the message-driven beans and the entity class, along with the persistence.xml file

    • An application EAR file that contains the two JAR files along with an application.xml file

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

  10. Right-click the project and choose Run.

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

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


PUBLISHER: Setting hire ID to 25, name Gertrude Bourbon, position Senior Programmer
PUBLISHER: Setting hire ID to 26, name Jack Verdon, position Manager
PUBLISHER: Setting hire ID to 27, name Fred Tudor, position Manager
PUBLISHER: Setting hire ID to 28, name Fred Martin, position Programmer
PUBLISHER: Setting hire ID to 29, name Mary Stuart, position Manager
Waiting for 5 message(s)
New hire event processed:
  Employee ID: 25
  Name: Gertrude Bourbon
  Equipment: Laptop
  Office number: 183
Waiting for 4 message(s)
New hire event processed:
  Employee ID: 26
  Name: Jack Verdon
  Equipment: Pager
  Office number: 20
Waiting for 3 message(s)
New hire event processed:
  Employee ID: 27
  Name: Fred Tudor
  Equipment: Pager
  Office number: 51
Waiting for 2 message(s)
New hire event processed:
  Employee ID: 28
  Name: Fred Martin
  Equipment: Desktop System
  Office number: 141
Waiting for 1 message(s)
New hire event processed:
  Employee ID: 29
  Name: Mary Stuart
  Equipment: Pager
  Office number: 238

The output from the message-driven beans and the entity class appears in the server log, wrapped in logging information.

For each employee, the application first creates the entity and then finds it. You may see runtime errors in the server log, and transaction rollbacks may occur. The errors occur if both of the message-driven beans discover at the same time that the entity does not yet exist, so they both try to create it. The first attempt succeeds, but the second fails because the bean already exists. After the rollback, the second message-driven bean tries again and succeeds in finding the entity. Container-managed transactions allow the application to run correctly, in spite of these errors, with no special programming.

You can run the application client repeatedly.

    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 clientmdbentity and choose Undeploy.

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

Building, Deploying, and Running the clientmdbentity Example Using Ant

    To create and package the application using Ant, perform these steps:

  1. Start the Application Server, if it is not already running.

  2. Start the database server as described in Starting and Stopping the Java DB Database Server.

  3. Go to the following directory:

    tut-install/javaeetutorial5/examples/jms/clientmdbentity/
    
  4. To compile the source files and package the application, use the following command:


    ant
    

The ant command creates the following:

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


ant run

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

The program output in the terminal window looks something like this:


running application client container.
PUBLISHER: Setting hire ID to 25, name Gertrude Bourbon, position Senior Programmer
PUBLISHER: Setting hire ID to 26, name Jack Verdon, position Manager
PUBLISHER: Setting hire ID to 27, name Fred Tudor, position Manager
PUBLISHER: Setting hire ID to 28, name Fred Martin, position Programmer
PUBLISHER: Setting hire ID to 29, name Mary Stuart, position Manager
Waiting for 5 message(s)
New hire event processed:
  Employee ID: 25
  Name: Gertrude Bourbon
  Equipment: Laptop
  Office number: 183
Waiting for 4 message(s)
New hire event processed:
  Employee ID: 26
  Name: Jack Verdon
  Equipment: Pager
  Office number: 20
Waiting for 3 message(s)
New hire event processed:
  Employee ID: 27
  Name: Fred Tudor
  Equipment: Pager
  Office number: 51
Waiting for 2 message(s)
New hire event processed:
  Employee ID: 28
  Name: Fred Martin
  Equipment: Desktop System
  Office number: 141
Waiting for 1 message(s)
New hire event processed:
  Employee ID: 29
  Name: Mary Stuart
  Equipment: Pager
  Office number: 238

The output from the message-driven beans and the entity class appears in the server log, wrapped in logging information.

For each employee, the application first creates the entity and then finds it. You may see runtime errors in the server log, and transaction rollbacks may occur. The errors occur if both of the message-driven beans discover at the same time that the entity does not yet exist, so they both try to create it. The first attempt succeeds, but the second fails because the bean already exists. After the rollback, the second message-driven bean tries again and succeeds in finding the entity. Container-managed transactions allow the application to run correctly, in spite of these errors, with no special programming.

Undeploy the application after you finish running the client:


ant undeploy

To remove the generated files, use the following command in the clientmdbentity, clientmdbentity-app-client, and clientmdbentity-ejb directories:


ant clean

An Application Example That Consumes Messages from a Remote Server

This section and the following section explain how to write, compile, package, deploy, and run a pair of Java EE modules that run on two Java EE servers and that use the JMS API to interchange messages with each other. It is a common practice to deploy different components of an enterprise application on different systems within a company, and these examples illustrate on a small scale how to do this for an application that uses the JMS API.

However, the two examples work in slightly different ways. In this first example, the deployment information for a message-driven bean specifies the remote server from which it will consume messages. In the next example, the same bean is deployed on two different servers, so it is the client module that specifies the servers (one local, one remote) to which it is sending messages.

This first example divides the example in Chapter 23, A Message-Driven Bean Example into two modules (not applications): one containing the application client, and the other containing the message-driven bean.

This section covers the following topics:

You will find the source files for this section in tut-install/javaeetutorial5/examples/jms/consumeremote/. Path names in this section are relative to this directory.

Overview of the consumeremote Example Modules

Except for the fact that it is packaged as two separate modules, this example is very similar to the one in Chapter 23, A Message-Driven Bean Example:

The basic steps of the modules are as follows.

  1. The administrator starts two Java EE servers, one on each system.

  2. On the local server, the administrator deploys the message-driven bean module, which uses a connection factory that specifies the remote server where the client is deployed.

  3. On the remote server, the administrator places the client JAR file.

  4. The client module sends three messages to a queue.

  5. The message-driven bean consumes the messages.

Figure 32–3 illustrates the structure of this application. You can see that it is almost identical to Figure 23–1 except that there are two Java EE servers. The queue used is the one on the remote server; the queue must also exist on the local server for resource injection to succeed.

Figure 32–3 A Java EE Application That Consumes Messages from a Remote Server

Diagram of application showing a message-driven bean
that consumes messages from an application client on a remote server

Writing the Module Components for the consumeremote Example

Writing the components of the modules involves

The application client, jupiterclient/src/java/SimpleClient.java, is almost identical to the one in The simplemessage Application Client.

Similarly, the message-driven bean, earthmdb/src/java/MessageBean.java, is almost identical to the one in The Message-Driven Bean Class.

The only major difference is that the client and the bean are packaged in two separate modules.

Creating Resources for the consumeremote Example

For this example, the message-driven bean uses the connection factory named jms/JupiterConnectionFactory, which you created in Creating Administered Objects for Multiple Systems. Use the Admin Console to verify that the connection factory still exists and that its AddressList property is set to the name of the remote system. Because this bean must use a specific connection factory, the connection factory is specified in the mdb-connection-factory element of the sun-ejb-jar.xml file.

    If you deleted the connection factory, you can recreate it as follows:

  1. Go to the following directory:

    tut-install/javaeetutorial5/examples/jms/consumeremote/earthmdb/
    
  2. Type the following command:


    ant create-remote-factory -Dsys=remote-system-name
    

    Replace remote-system-name with the actual name of the remote system.

The application client can use any connection factory that exists on the remote server; it uses jms/ConnectionFactory. Both components use the queue named jms/Queue, which you created in Creating JMS Administered Objects for the Synchronous Receive Example.

Using Two Application Servers for the consumeremote Example

As in Running JMS Client Programs on Multiple Systems, the two servers are named earth and jupiter.

The Application Server must be running on both systems.

Which system you use to package and deploy the modules and which system you use to run the client depend on your network configuration (which file system you can access remotely). These instructions assume that you can access the file system of jupiter from earth but cannot access the file system of earth from jupiter. (You can use the same systems for jupiter and earth that you used in Running JMS Client Programs on Multiple Systems.)

You can package both modules on earth and deploy the message-driven bean there. The only action you perform on jupiter is running the client module.

Building, Deploying, and Running the consumeremoteModules Using NetBeans IDE

    To package the modules using NetBeans IDE, perform these steps:

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

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

  3. Select the earthmdb folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

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

    This command creates a JAR file that contains the bean class file and the sun-ejb-jar.xml deployment descriptor file.

  7. Choose Open Project from the File menu.

  8. Select the jupiterclient folder.

  9. Select the Open as Main Project check box.

  10. Click Open Project.

  11. Right-click the jupiterclient project and choose Build.

    This target creates a JAR file that contains the client class file and a manifest file.

    To deploy the earthmdb module and run the application client, perform these steps:

  1. Right-click the earthmdb project and choose Set as Main Project.

  2. Right-click the earthmdb project and choose Undeploy and Deploy.

  3. Copy the jupiterclient module to the remote system (jupiter):

    1. In a terminal window, change to the directory tut-install/javaeetutorial5/examples/jms/consumeremote/jupiterclient/dist/.

    2. Type a command like the following:


      cp jupiterclient.jar F:/
      

      That is, copy the client JAR file to a location on the remote filesystem.

  4. Go to the directory on the remote system where you copied the client JAR file.

  5. Use the following command:


    appclient -client jupiterclient.jar
    

On jupiter, the output of the appclient command looks like this:


Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3

On earth, the output in the server log looks something like this (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

    Undeploy the message-driven bean after you finish running the client. To undeploy the earthmdb module, perform 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 EJB Modules node.

  6. Right-click earthmdb and choose Undeploy.

    To remove the generated files, follow these steps:

  1. Right-click the earthmdb project and choose Clean.

  2. In the command line window from which you copied the client JAR file, go to a directory other than the jupiterclient/dist directory.

  3. Right-click the jupiterclient project and choose Clean.

You can also delete the jupiterclient.jar file from the remote filesystem.

Building, Deploying, and Running the consumeremote Modules Using Ant

    To package the modules using Ant, perform these steps:

  1. Go to the following directory:

    tut-install/javaeetutorial5/examples/jms/consumeremote/earthmdb/
    
  2. Type the following command:


    ant
    

    This command creates a JAR file that contains the bean class file and the sun-ejb-jar.xml deployment descriptor file.

  3. Go to the jupiterclient directory:


    cd ../jupiterclient
    
  4. Type the following command:


    ant
    

    This target creates a JAR file that contains the client class file and a manifest file.

    To deploy the earthmdb module, perform these steps:

  1. Change to the directory earthmdb:


    cd ../earthmdb
    
  2. Type the following command:


    ant deploy
    

    To copy the jupiterclient module to the remote system, perform these steps:

  1. Change to the directory jupiterclient/dist:


    cd ../jupiterclient/dist
    
  2. Type a command like the following:


    cp jupiterclient.jar F:/
    

    That is, copy the client JAR file to a location on the remote filesystem.

    To run the client, perform the following steps:

  1. Go to the directory on the remote system (jupiter) where you copied the client JAR file.

  2. Use the following command:


    appclient -client jupiterclient.jar
    

On jupiter, the output of the appclient command looks like this:


Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3

On earth, the output in the server log looks something like this (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

    Undeploy the message-driven bean after you finish running the client. To undeploy the earthmdb module, perform these steps:

  1. Change to the directory earthmdb.

  2. Type the following command:


    ant undeploy
    

You can also delete the jupiterclient.jar file from the remote filesystem.

To remove the generated files, use the following command in both the earthmdb and jupiterclient directories:


ant clean

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

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

The modules 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 tut-install/javaeetutorial5/examples/jms/sendremote/. Path names in this section are relative to this directory.

Overview of the sendremote Example Modules

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

The basic steps of the modules are as follows.

  1. You start two Java EE 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 32–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.

Figure 32–4 A Java EE Application That Sends Messages to Two Servers

Diagram of application showing an application client
sending messages to two servers and receiving the replies

Writing the Module Components for the sendremote Example

Writing the components of the modules involves two tasks:

Coding the Application Client: MultiAppServerClient.java

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

  1. It injects resources for 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 message-driven bean class, replybean/src/ReplyMsgBean.java, does the following:

  1. Uses the @MessageDriven annotation:

    @MessageDriven(mappedName="jms/Topic")
  2. Injects resources for the MessageDrivenContext and for a connection factory. It does not need a destination resource because it uses the value of the incoming message’s JMSReplyTo header as the destination.

  3. Uses a @PostConstruct callback method to create the connection, and a @PreDestroy callback method to close the connection.

    The onMessage method of the message-driven bean class 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 Resources for the sendremote Example

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.

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 must exist on the local server.

The build.xml file for the multiclient module contains targets that you can use to create these resources if you deleted them previously.

Using Two Application Servers for the sendremote Example

    If you are using NetBeans IDE, you need to add the remote server in order to deploy the message-driven bean there. To do so, perform these steps:

  1. In NetBeans IDE, click the Services tab.

  2. Right-click the Servers node and choose Add Server. In the Add Server Instance dialog, perform these steps:

    1. Select Sun Java System Application Server (the default) from the Server list.

    2. In the Name field, specify a name slightly different from that of the local server, such as Sun Java System Application Server (1).

    3. Click Next.

    4. For the Platform Folder location, you can either browse to the location of the Application Server on the remote system or, if that location is not visible from the local system, use the default location on the local system.

    5. Select the Register Remote Domain radio button.

    6. Click Next.

    7. Type the system name of the host in the Host field.

    8. Click Next.

    9. Type the administrative username and password for the remote system in the Admin Username and Admin Password fields.

    10. Click Finish.

      There may be a delay while NetBeans IDE registers the remote domain.

Building, Deploying, and Running the sendremote Modules Using NetBeans IDE

    To package the modules using NetBeans IDE, perform these steps:

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

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

  3. Select the replybean folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

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

    This command creates a JAR file that contains the bean class file.

  7. Choose Open Project from the File menu.

  8. Select the multiclient folder.

  9. Select the Open as Main Project check box.

  10. Click Open Project.

  11. Right-click the multiclient project and choose Build.

    This command creates a JAR file that contains the client class file and a manifest file.

    To deploy the multiclient module on the local server, perform these steps:

  1. Right-click the multiclient project and choose Properties.

  2. Select Run from the Categories tree.

  3. From the Server list, select Sun Java System Application Server (the local server).

  4. Click OK.

  5. Right-click the multiclient project and choose Undeploy and Deploy.

    To deploy the replybean module on the local and remote servers, perform these steps:

  1. Right-click the replybean project and choose Properties.

  2. Select Run from the Categories tree.

  3. From the Server list, select Sun Java System Application Server(the local server).

  4. Click OK.

  5. Right-click the replybean project and choose Undeploy and Deploy.

  6. Right-click the replybean project again and choose Properties.

  7. Select Run from the Categories tree.

  8. From the Server list, select Sun Java System Application Server (1) (the remote server).

  9. Click OK.

  10. Right-click the replybean project and choose Undeploy and Deploy.

You can use the Services tab to verify that multiclient is deployed as an App Client Module on the local server and that replybean is deployed as an EJB Module on both servers.

To run the application client, right-click the multiclient project and choose Run.

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

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


running application client container.
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):


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):


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 modules after you finish running the client. To undeploy the modules, perform these steps:

  1. Click the Services tab.

  2. Expand the Servers node.

  3. Expand the Sun Java System Application Server node (the local system).

  4. Expand the Applications node.

  5. Expand the EJB Modules node.

  6. Right-click replybean and choose Undeploy.

  7. Expand the App Client Modules node.

  8. Right-click multiclient and choose Undeploy.

  9. Expand the Sun Java System Application Server (1) node (the remote system).

  10. Expand the Applications node.

  11. Expand the EJB Modules node.

  12. Right-click replybean and choose Undeploy.

    To remove the generated files, follow these steps:

  1. Right-click the replybean project and choose Clean.

  2. Right-click the multiclient project and choose Clean.

Building, Deploying, and Running the sendremote Modules Using Ant

    To package the modules, perform these steps:

  1. Go to the following directory:

    tut-install/javaeetutorial5/examples/jms/sendremote/multiclient/
    
  2. Type the following command:


    ant
    

    This command creates a JAR file that contains the client class file and a manifest file.

  3. Change to the directory replybean:


    cd ../replybean
    
  4. Type the following command:


    ant
    

    This command creates a JAR file that contains the bean class file.

    To deploy the replybean module on the local and remote servers, perform the following steps:

  1. Verify that you are still in the directory replybean.

  2. Type the following command:


    ant deploy
    

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

  3. Type the following command:


    ant deploy-remote -Dsys=remote-system-name
    

    Replace remote-system-name with the actual name of the remote system.

    To deploy and run the client, perform these steps:

  1. Change to the directory multiclient:


    cd ../multiclient
    
  2. Type the following command:


    ant run
    

On the local system, the output looks something like this:


running application client container.
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):


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):


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 modules after you finish running the client. To undeploy the multiclient module, perform these steps:

  1. Verify that you are still in the directory multiclient.

  2. Type the following command:


    ant undeploy
    

    To undeploy the replybean module, perform these steps:

  1. Change to the directory replybean:


    cd ../replybean
    
  2. Type the following command:


    ant undeploy
    
  3. Type the following command:


    ant undeploy-remote -Dsys=remote-system-name
    

    Replace remote-system-name with the actual name of the remote system.

To remove the generated files, use the following command in both the replybean and multiclient directories:


ant clean