This exercise is entirely based on the beans implemented in Exercise 11.2. You’ll modify the TravelAgent EJB so it publishes a text message to a JMS topic when it completes a reservation.
You’ll learn how to create a new JMS topic in JBoss, and configure your bean to use JMS as a resource. You’ll also build a client application that will subscribe to this topic and display any published message. To complete new reservations, you’ll use one of the client applications created for the preceding example.
Because the exercise uses the ProcessPayment EJB used in recent
exercises, the database must contain the PAYMENT
table. The createdb
and dropdb
Ant targets, Java code, and clients here have been borrowed from
Exercise 11.1.
If you haven’t already dropped the
PAYMENT
table after running the examples in
Exercise 11.2, do so now by running the dropdb
Ant
target.
C:workbookex12_1>ant dropdb Buildfile: build.xml prepare: compile: dropdb: [java] Looking up home interfaces.. [java] Dropping database table... BUILD SUCCESSFUL
Then re-create the PAYMENT
database table by
running the createdb
Ant
target
C:workbookex12_1>ant createdb Buildfile: build.xml prepare: compile: ejbjar: createdb: [java] Looking up home interfaces.. [java] Creating database table...
On the JBoss console, the following lines are displayed:
INFO [STDOUT] Creating table PAYMENT... INFO [STDOUT] ...done!
If you’re having trouble creating the database, shut
down JBoss. Then run the Ant build target
clean.db
. This will remove all database files and
allow you to start fresh.
The persistence of all other entity beans used in this exercise is managed by the container (CMP), so JBoss will create the needed tables for them automatically.
Because the TravelAgent EJB will publish messages in a JMS topic, you’ll have to create this new topic in JBoss. This exercise walks you through two different ways to create a new JMS topic: through an XML configuration file and through the JBoss JMX HTTP connector.
The most common way to set up a JMS topic is to use an XML configuration file. As you learned in the installation chapter, every component in JBoss is a JMX MBean that can be hot-deployed. This part of the exercise shows you how to write a JMX MBean definition for a new JMS topic.
You can find the JMX configuration file in the
ex12_1/src/resources/services
directory.
<server> <mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Topic, name=titan-TicketTopic"> <depends optional-attribute-name="DestinationManager" >jboss.mq:service=DestinationManager</depends> </mbean> </server>
Each set of MBeans in a JMX configuration file must be defined within
a <server>
tag. An MBean itself is declared
in an <mbean>
tag. The only MBean
declaration in this file defines the actual JMS topic
you’ll use for the example code in this chapter.
Each MBean is uniquely identified by its name, called an
ObjectName. JMX ObjectNames can include any
number of key-value parameters to describe the MBean further. In our
case, the MBean class representing the JMS topic is declared first
(org.jboss.mq.server.jmx.Topic
), along with its
JMX ObjectName (jboss.mq.destination:service=Topic, name=titan-TicketTopic
). For JMS topic MBeans, a single
parameter is useful: name
. This is where the name
of the JMS topic is defined (titan-TicketTopic
).
One thing to note is that the application server must deploy the
DestinationManager
MBean before any queue or topic
is deployed. This dependency is declared in
jbossmq-titantopic-service.xml
’s
depends
tag. JBoss will take care of satisfying
this dependency and make sure the
titan-TicketTopic
isn’t started
until the DestinationManager
MBean has finished
initializing and is ready to provide services to new queues and
topics. Copying this file into the JBoss deploy directory will
hot-deploy the JMS topic and make it ready for use.
We’ve defined a make-topic
Ant
target for deploying the topic bean. Run this target to copy
jbossmq-titantopic-service.xml
into
JBoss’s deploy directory:
C:workbookex12_1>ant make-topic
Buildfile: build.xml
make-topic:
[copy] Copying 1 file to C:jboss-4.0
serverdefaultdeploy
On the server side, the following line is displayed:
[titan-TicketTopic] Bound to JNDI name: topic/titan-TicketTopic
An XML
configuration file is the preferred
means to deploy a JMS topic permanently, but for quick tests and such
an alternative approach that uses JBoss’s JMX HTTP
connector and the DestinationManager
is sometimes
better, because the topic lives in JBoss only until the application
server is shut down. First open your browser and go to http://localhost:8080/jmx-console/, where you
can browse through all deployed JBoss JMX MBeans. Scroll down to the
jboss.mq
section and find in it the MBean service
DestinationManager
(Figure 29-1).
Click on the service=DestinationManager
link and
you get a list of the MBean’s attributes and
operations. One of the operations, createTopic( )
,
allows you to create a new JMS topic (Figure 29-2).
Type the name of the new JMS topic in the text area, and click on the
Invoke button associated with the createTopic( )
operation. The Destination Manager will create the JMS topic and
display a status message (Figure 29-3).
To see your new JMS topic MBean, go back to the home page of the JMX
HTTP connector and search for the
jboss.mq.destination
domain. You should be able to
see your new topic MBean (Figure 29-4).
Note that you can use the JMX HTTP connector to see the status of your topics and queues even if you create then in an XML configuration file.
The ejb-jar.xml
deployment descriptor is
equivalent to the one for Exercise 11.2 except for the TravelAgent
EJB. The definition for this bean has been extended to reference the
JMS topics you just created.
<session> <ejb-name>TravelAgentEJB
</ejb-name> <home>com.titan.travelagent.TravelAgentHomeRemote</home> <remote>com.titan.travelagent.TravelAgentRemote</remote> <ejb-class>com.titan.travelagent.TravelAgentBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> ... <resource-ref> <res-ref-name>jdbc/titanDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <res-ref-name>jms/TopicFactory
</res-ref-name> <res-type>javax.jms.TopicConnectionFactory
</res-type> <res-auth>Container
</res-auth> </resource-ref> <resource-env-ref> <resource-env-ref-name>jms/TicketTopic
</resource-env-ref-name> <resource-env-ref-type>javax.jms.Topic
</resource-env-ref-type> </resource-env-ref> </session>
A reference to a
TopicConnectionFactory
is declared in the same way as a reference to a
DataSource
. The definition contains the name of
the resource (jms/TopicFactory
), the class of the
resource (javax.jms.TopicConnectionFactory
), and
whether the container or the bean performs the authentication.
The TravelAgentEJB definition in jboss.xml
must
be modified as well, to describe the JMS topic references declared in
ejb-jar.xml
.
... <session> <ejb-name>TravelAgentEJB
</ejb-name> <jndi-name>TravelAgentHomeRemote</jndi-name> <resource-ref> <res-ref-name>jdbc/titanDB</res-ref-name> <jndi-name>java:/DefaultDS</jndi-name> </resource-ref> <resource-ref> <res-ref-name>jms/TopicFactory
</res-ref-name> <jndi-name>java:/JmsXA
</jndi-name> </resource-ref> <resource-env-ref> <resource-env-ref-name>jms/TicketTopic
</resource-env-ref-name> <jndi-name>topic/titan-TicketTopic
</jndi-name> </resource-env-ref> </session> ...
The <resource-ref>
entry from
ejb-jar.xml
is mapped in the
jboss.xml
file to the JNDI name
java:/JmsXA
. If you take a look at the JBossMQ
default configuration file in
$JBOSS_HOME/server/default/deploy/jms/jms-ds.xml
,
you’ll see that the XA connection manager is bound
to this name by default.
The last part of the TravelAgent EJB descriptor in
jboss.xml
maps the
jms/TicketTopic
name from the JNDI ENC of the bean
to the topic/titan-TicketTopic
JNDI name. This
name corresponds to the JMS topic you just created.
Perform the following steps:
Open a command prompt or shell terminal and change to the
ex12_1
directory created by the extraction
process
Set the JAVA_HOME
and
JBOSS_HOME
environment variables to point to where
your JDK and JBoss 4.0 are installed. Examples:
Windows:C:workbookex12_1> set JAVA_HOME=C:jdk1.4.2 C:workbookex12_1> set JBOSS_HOME=C:jboss-4.0
|
Unix:$ export JAVA_HOME=/usr/local/jdk1.4.2 $ export JBOSS_HOME=/usr/local/jboss-4.0
|
Add ant
to your execution path.
Windows:C:workbookex12_1> set PATH=..antin;%PATH%
|
Unix:$ export PATH=../ant/bin:$PATH
|
Perform the build by typing ant
.
You will see titan.jar
rebuilt, copied to the
JBoss deploy
directory, and redeployed by the
application server.
This exercise includes two client applications. You can find the code
for them in the
ex12_1/src/main/com/titan/clients
directory.
The first application is the one used in Exercise 11.2 to make a
reservation. The Ant target run.client_112b
hasn’t changed, and needs no review.
The second application is new. JmsClient_1
subscribes to the titan-TicketTopic
JMS topic and
displays all messages published on it.
The application first gets an InitialContext
, and
looks up its TopicConnectionFactory
and
Topic
.
... Context jndiContext = getInitialContext( ); TopicConnectionFactory factory = (TopicConnectionFactory) jndiContext.lookup("ConnectionFactory"); Topic topic = (Topic) jndiContext.lookup("topic/titan-TicketTopic");
The name of the JMS topic is the same as the one you created in
Exercise 11.1, but the name of the
TopicConnectionFactory
is not
the same as the one used by the TravelAgent EJB.
Remember that the java:/JmsXA
connection factory
used by the EJB was in the private JNDI space of
the JBoss JVM (indicated by the java
: prefix).
Thus, the client application cannot look up this name from its JVM.
For external applications, JBoss binds a set of connection factories
within the public JNDI tree, each dedicated to a particular message
transport protocol.
JBossMQ supports several different kinds of message invocation
layers. Each layer has its own ConnectionFactory
that is bound in JNDI, as shown in Table 29-1.
Table 29-1. JBossMQ message invocation layers
Invocation Layer |
JNDI name |
---|---|
JVM Hyperefficient invocation layer using standard Java method invocation, used for in-JVM JMS clients; external clients cannot use this invocation layer |
|
RMI RMI-based invocation layer |
|
OIL (Optimized Invocation Layer) Uses custom TCP/IP sockets to obtain good network performance with a small memory footprint |
|
UIL2 Used by client applications that cannot accept network connections originating from the server |
|
We strongly suggest to use the UIL2 invocation layer; it is the most robust and efficient layer currently available.
TopicConnection connect = factory.createTopicConnection( ); TopicSession session = connect.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); TopicSubscriber subscriber = session.createSubscriber(topic); subscriber.setMessageListener(this); System.out.println ("Listening for messages on topic/titan-TicketTopic..."); connect.start( );
The end of the client application code is the same as in the EJB book.
When you redeployed titan.jar, JBoss dropped and
recreated the database tables, destroying any existing content. For
this reason, you must have Ant execute the
run.client_112a
target to repopulate the database.
The run.client_112a
target originated in Exercise
11.2, but we’ve duplicated it in the
ex12_1
directory to facilitate your work.
Here’s the output:
C:workbookex12_1>ant run.client_112a Buildfile: build.xml prepare: compile: ejbjar: run.client_112a: [java] Calling TravelAgentBean to create sample data.. [java] All customers have been removed [java] All cabins have been removed [java] All ships have been removed [java] All cruises have been removed [java] All reservations have been removed [java] Customer with ID 1 created (Burke Bill) [java] Customer with ID 2 created (Labourey Sacha) [java] Created ship with ID 101... [java] Created ship with ID 102... [java] Created cabins on Ship A with IDs 100-109 [java] Created cabins on Ship B with IDs 200-209 [java] Created Alaska Cruise with ID 0 on ShipA [java] Created Norwegian Fjords Cruise with ID 1 on ShipA [java] Created Bermuda or Bust Cruise with ID 2 on ShipA [java] Created Indian Sea Cruise with ID 3 on ShipB [java] Created Australian Highlights Cruise with ID 4 on ShipB [java] Created Three-Hour Cruise with ID 5 on ShipB [java] Made reservation for Customer 1 on Cruise 0 for Cabin 103 [java] Made reservation for Customer 1 on Cruise 5 for Cabin 208 [java] Made reservation for Customer 2 on Cruise 1 for Cabin 105 [java] Made reservation for Customer 2 on Cruise 5 for Cabin 202 BUILD SUCCESSFUL
For your new application to receive the message published on the JMS topic, you have to start it first:
C:workbookex12_1>ant run.client_121 Buildfile: build.xml prepare: compile: ejbjar: client_121: [java] Listening for messages on topic/titan-TicketTopic...
The last line of the output confirms that the client application has successfully subscribed to the topic and is waiting for messages.
Now you need to make some reservations exactly as you did in Exercise
11.2. Open a new shell and use the BookPassage
script to make a reservation for Bill Burke on the Three-Hour Cruise
for cabin 101 at $3,000.00:
C:workbookex12_1>BookPassage 1 5 101 3000.0 Buildfile: build.xml prepare: compile: ejbjar: run.client_112b: [java] Finding reference to Customer 1 [java] Starting TravelAgent Session... [java] Setting Cruise and Cabin information in TravelAgent.. [java] Booking the passage on the Cruise! [java] Ending TravelAgent Session... [java] Result of bookPassage: [java] Bill Burke has been booked for the Three-Hour Cruise cruise on ship Bohemian Rhapsody. [java] Your accommodations include Suite 101 a 1 bed cabin on deck level 1. [java] Total charge = 3000.0
In the JMS subscriber window you started, the following lines should appear:
[java] Listening for messages on topic/titan-TicketTopic... [java] [java] RESERVATION RECEIVED: [java] Bill Burke has been booked for the Three-Hour Cruise cruise on ship Bohemian Rhapsody. [java] Your accommodations include Suite 101 a 1 bed cabin on deck level 1. [java] Total charge = 3000.0
Remember from the EJB section of this book that our client application uses a nondurable subscription to the topic. Consequently, all the messages sent while the subscriber client application is not running are lost. That would not be the case if we had used a durable subscription to the topic.
To see the “many-to-many” nature of JMS topics, launch several JMS listener applications at the same time. They will all receive the messages sent to the topic.