Ejb3 Basics: Deploying Message Driven Beans

Farewell to lazy auto queue generation in JBoss 5

MDB’s were never so easy to deploy and manage when ejb3 first came out. In Jboss 4, all you have to do was annotate a class with @MessageDriven, sprinkle some meta data here and there, stick it in the oven and wham! Instant “I cant believe I made an MDB!?!” In Jboss AS 5 however, MDB queues are no longer automatically created for your application anymore on boot. An inspection of the MDB llifecycle illustrates why:

  1. MDB deploys
  2. No existing Topic/Queue
  3. Topic/Queue is automatically created
  4. MDB is undeployed
  5. There’s no callback/hook to remove the created Topic/Queue. And if there was, should undeploying the MDB even be allowed to trigger this action?

blatantly stolen from JBAS-5114, 5th comment down – thanks Andy, and DeCoste by proxy

SO to reiterate… whereas JBoss AS 4.0 would have auto-created and MDB queues for you on boot, in 5.0 this no longer holds true. Consider the following MDB:

package com.examples.mdb;

import javax.ejb.*;
import javax.jms.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@MessageDriven(name = "MyQueue", activationConfig = {
        @ActivationConfigProperty(
        		propertyName = "destinationType", 
        		propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(
        		propertyName = "destination", 
        		propertyValue = "queue/MyQueue"),
        @ActivationConfigProperty(
        		propertyName="DLQMaxResent", 
        		propertyValue="1")
})
public class MyQueue implements MessageListener {
	
	private static final Log log = LogFactory.getLog(MyQueue.class);
	
	public void onMessage (Message msg) {
		try {
			
			log.debug("Processing MyQueue queue...");
			ObjectMessage oMsg = (ObjectMessage) msg;
			
			SomeObject result = (SomeObject ) oMsg.getObject();

			/**
			 * do stuff with the object
			 */

		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}

In jboss 4 you could leave your MDB class like this, and the app server would automatically handle everything for you. If you plan on using jboss 5.+ however, you will have to choose one of the following..

Wire it yourself in destinations-service.xml

In /deploy/messaging/destinations-service.xml, you can add the MDB destination yourself, letting jboss know to create your queue on boot. Here’s an example configuration:

<?xml version="1.0" encoding="UTF-8"?>
<!--
	Messaging Destinations deployment descriptor.
 -->
<server>

	<mbean 
		code="org.jboss.jms.server.destination.QueueService"
		name="jboss.messaging.destination:service=Queue,name=MyQueue"
		xmbean-dd="xmdesc/Queue-xmbean.xml">
		<depends optional-attribute-name="ServerPeer">
			jboss.messaging:service=ServerPeer
		</depends>
		<depends>
			jboss.messaging:service=PostOffice
		</depends>      
	</mbean>

</server>

The only thing this configuration needs to change is the queue name – make sure it matches the name of the queue annotated in your MDB class. This by itself is the closest you can get to being lazy. You will need to make sure however that you add one destination for each of the MDB queues your application uses. Option two requires a little bit more work but you don’t have to muck around with the jboss environment…

Add deployment descriptors to auto create the queue via jboss.xml

You can instead deploy the optional jboss.xml file in your ejb jar file’s META-INF folder (in addition to your persistence.xml file if you’re using entities). Your ejb jar structure should then look like this:

ejb-jar.jar
	- / ejb classes and cool stuff here
	- / META-INF
		- MANIFEST.MF
		- persistence.xml
		- jboss.xml

And this is what jboss.xml would look like:

<?xml version="1.0" encoding="UTF-8"?>
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee 
                           http://www.jboss.org/j2ee/schema/jboss_5_0.xsd" 
       version="3.0"> 
	<enterprise-beans>
		<message-driven>
			<ejb-name>MyQueue</ejb-name>
			<destination-jndi-name>queue/MyQueue</destination-jndi-name>
			<create-destination>true</create-destination>
		</message-driven>
	</enterprise-beans>
</jboss>

The key command in this file here being: <create-destination>true</create-destination>. This will flag jboss to create the queue for you if it doesn’t already exist. This approach would probably be better suited for jboss only deployments since the flag to auto create the queue is configured within a jboss exclusive deployment descriptor – jboss.xml.

Once either of these has been implemented, your MDB should be deployed, initialized and ready to fire up. Oh, and fist pumps to ALR for pointing me in the right direction – cheers buddy!

Comments (2)

  1. 5:55 PM, September 20, 2010Tuan Nguyen  / Reply

    Hello,

    I kept getting the following error:

    The import javax.ejb.MessageDriven cannot be resolved
    The import javax.ejb.ActivationConfigProperty cannot be resolved.

    Which j2se package should I download from Sun?

    • 6:24 PM, September 20, 2010Ant  / Reply

      These files are actually container dependent – they’re implemented by the particular container used. If you’re using Jboss 5.x you’ll want to add the jars in jboss-5.1.0.GAclient to your classpath, specifically jboss-javaee.jar. The jars in this folder provide implementation classes for any Jboss client applications, of which your app could be considered one. I use eclipse so usually just define 2 custom user classpath libraries, one mapping to this client folder and another one mapping to jboss-5.1.0.GAcommonlib.

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pingbacks (0)

› No pingbacks yet.