Chapter 6. JMS and Message-Driven Beans

One thing that’s missing from the Duke’s Bank application is any use of JMS messaging, so we’ll work through the tutorial example on Message Driven Beans (MDBs) to see how to use messaging in JBoss. We’ll assume you’re already familiar with general JMS and MDB concepts. The J2EE tutorial code for the MDB is in j2eetutorial14/examples/ejb/simplemessage. We’ve supplied a jboss-build.xml file in the simplemessage directory which will allow you to build the example from scratch and run it in JBoss.

The example code is very simple. There are only two classes, one for the client and one for the bean (unlike normal EJBs, MDBs don’t need any interfaces). The client publishes messages to a JMS Queue and the MDB handles them via its standard onMessage method. The messages are all of type javax.jms.TextMessage and the bean simply prints out the text contained in each message.

The only container-specific tasks required are setting up the Queue in JBoss, and configuring the MDB to accept messages from it.

6.1. Building the Example

6.1.1. Compiling and Packaging the MDB and Client

To compile the files, invoke the compile-mdb target from the simplemessage directory.

ant -f jboss-build.xml compile-mdb

Then run the following targets to produce archives for the bean and the client and a combined EAR file in the jar directory.

ant -f jboss-build.xml package-mdb 
ant -f jboss-build.xml package-mdb-client 
ant -f jboss-build.xml assemble-mdb

We’ve retained the same layout we used in the Duke’s Bank build, with a dd directory containing the deployment descriptors and the jar directory containing the archives produced by the build.

6.1.1.1. Specifying the Source Queue for the MDB

As with other container-specific information, the queue name for the MDB is specified in the jboss.xml file:

<jboss> 
    <enterprise-beans> 
        <message-driven> 
            <ejb-name>SimpleMessageBean</ejb-name> 
            <destination-jndi-name>queue/MyQueue</destination-jndi-name> 
        </message-driven> 
    </enterprise-beans> 
</jboss> 

The MDB will receive messages from the queue with JNDI name queue/MyQueue.

6.2. Deploying and Running the Example

To deploy the MDB, copy the SimpleMessage.ear file to the JBoss deploy directory. The deploy-mdb target does this:

ant -f jboss-build.xml deploy-mdb

A successful deployment should look something like this:

08:20:08,188 INFO  [EARDeployer] Init J2EE application: 
file:/tmp/jboss-4.0.4.GA/server/default/deploy/SimpleMessage.ear
08:20:08,370 INFO  [EjbModule] Deploying SimpleMessageEJB
08:20:08,565 INFO  [ClientDeployer] Client ENC bound under: SimpleMessageClient
08:20:08,712 WARN  [JMSContainerInvoker] Could not find the queue 
destination-jndi-name=queue/MyQueue
08:20:08,719 WARN  [JMSContainerInvoker] destination not found: queue/MyQueue 
reason: javax.naming.NameNotFoundException: MyQueue not bound
08:20:08,719 WARN  [JMSContainerInvoker] creating a new temporary destination: queue/MyQueue
08:20:08,772 INFO  [MyQueue] Bound to JNDI name: queue/MyQueue
08:20:08,952 INFO  [EJBDeployer] Deployed: 
file:/tmp/jboss-4.0.4.GA/server/default/tmp/deploy/tmp51464SimpleMessage.ear-contents
/simplemessage.jar
08:20:08,996 INFO  [EARDeployer] Started J2EE application: 
file:/tmp/jboss-4.0.4.GA/server/default/deploy/SimpleMessage.ear
            

If you look more closely at this, you will see warnings that the message queue specified in the deployment doesn’t exist. In this case JBoss will create a temporary one for the application and bind it under the supplied name. You can check it exists using the JNDIView MBean again. Look under the global JNDI namespace. We’ll look at how to explicitly create JMS destinations below.

Run the client with the run-mdb Ant target.

ant -f jboss-build.xml run-mdb

You should see output in both the client and server windows as they send and receive the messages respectively.

6.3. Managing JMS Destinations

As with most things in JBoss, JMS Topics and Queues are implemented using MBeans. There are two ways you can create them: you can add MBean declarations to the appropriate configuration file, or you can create them dynamically using the JMX Console. However, if you use the latter method, they won’t survive a server restart.

6.3.1. The jbossmq-destinations-service.xml File

You’ll find this file in the jms directory inside the deploy directory. It contains a list of JMS destinations and sets up a list of test topics and queues which illustrate the syntax used. To add the queue for our example, you would simply add the following MBean declaration to the file.

<mbean code="org.jboss.mq.server.jmx.Queue" 
      name="jboss.mq.destination:service=Queue,name=MyQueue"> 
</mbean> 

6.3.2. Using the DestinationManager from the JMX Console

With JBoss running, bring up the JMX Console in your browser and look for the section labelled jboss.mq in the main agent view. Click on the link which says service=DestinationManager. The DestinationManager MBean is the main JMS service in JBoss and you can use it to create and destroy queues and topics at runtime. Look for the operation called createQueue. There will be two operations by that name, both of which take a different number of arguments. Look for the one that takes only one argument. That argument is the name of the queue. This takes two parameters. Enter MyQueue and click the Invoke button. This will create a queue bound under the JNDI name queue/MyQueue, assuming it doesn't already exist.

6.3.3. Administering Destinations

You can access the attributes and operations that the MBeans representing a queue or topic exposes via JMX. Look at the main JMX Console view again and you’ll find a separate jboss.mq.destination section which should contain an entry for our Queue (no matter how it was created). Click on this and you’ll see the attributes for the queue. One of them is QueueDepth, which is the number of messages which are currently on the queue.

As an exercise, you can try temporarily stopping the delivery of messages to the MDB. Locate the section called jboss.j2ee in the JMX console and you should find an MBean listed there which is responsible for invoking your MDB. The name will be binding=message-driven-bean, jndiName=local/SimpleMessageEJB, plugin=invoker,service=EJB

You can start and stop the delivery of messages using the corresponding MBean operations which it supports. Invoke the stopDelivery() method, and then run the client a few times. You will see the QueueDepth increase as the messages accumulate. If you re-start message delivery, with the startDelivery() method, you should see all the messages arriving at once.