Advanced MDB configuration

The MDB implementation for JBoss have been written such that a user should not have to know a lot about the internals of JBoss. A part from the feew necessary lines in jboss.xml nothing else than standard knowledge of Message Driven Beans should suffice.

Following the design of JBoss, the MDB implementation is also extremely configurable, if one want to tune or totally change the default configuration and implementation! Here follows some short notes on howto configure MDB for JBoss

EJB deployment descriptor

All MDB:s are quite configurable, apart from them being deployed in JBoss. Here are the basic choices that can be made:

  • A bean may be either a javax.jms.Topic or a javax.jms.Queue bean, which is decided in the stanza "destination-type", eg.

         <message-driven-destination>
           <destination-type>javax.jms.Queue</destination-type>
           <subscription-durability>NonDurable</subscription-durability>
         </message-driven-destination>
    
    
  • If a bean is a Topic it may be either NonDurable or Durable, wich is described in the stanza "subscription-durability".

         <message-driven-destination>
           <destination-type>javax.jms.Topic</destination-type>
           <subscription-durability>Durable</subscription-durability>
         </message-driven-destination>
    
  • A bean may be have transaction either as bean managed or container managed, which is described in the stanza "transaction-type", eg.

         <transaction-type>Container</transaction-type>
    
  • A bean managed bean may have an acknowledge type of either Auto-acknowledge or Dups-ok-acknowledge. This is currently not supported in JBoss since the container always are receiving messages under a transaction. But it is described in the stanza "acknowledge-mode".

         <transaction-type>Bean</transaction-type>
         <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
    
  • A container managed bean may either specify transactions as Required or NotSupported, which is done in the container-transaction transaction part.

         <container-transaction>
           <method>
             <ejb-name>DurableTopicBean</ejb-name>
             <method-name>*</method-name>
           </method>
         <!-- May also be NotSupported -->
           <trans-attribute>Required</trans-attribute>
         </container-transaction>
    
  • An MDB may also specify a selector which follows the JMS syntax for a selector. Which is specified in the stanza "message-selector".

         <message-selector>JMSType='activityCompletion'</message-selector>
    

In a message-driven stanza one may also have the normal stuff that may be in a ejb deployment descriptor, such as "ejb-ref" and "resource-ref".

JBoss configuration

The meat of the configuration options are in the jboss.xml deployment descriptor. This may be divided into two part. The necessary one that configures a particular bean. And the optional one (that will be taken from standardjboss.xml if not found and which configures the container. We will describe both here, but the container configuration will be broken into several parts since it involves stuff outside the jboss.xml file.

In the bean part one always have to specify the JNDI for the JMS destination. In JBossMQ this always begins with either "topic/" or "queue/" followed by the name of the destination.

<destination-jndi-name>queue/testObjectMessage</destination-jndi-name>

You also have to tell the beans name and the name of the container configuration. To use the one in standardjboss.xml you should give the name "Standard Message Driven Bean".

     <message-driven>
       <ejb-name>QueueBean</ejb-name>
       <configuration-name>Standard Message Driven Bean</configuration-name>
       <destination-jndi-name>queue/testQueue</destination-jndi-name>
     </message-driven>

It is also possible to use a name and a password to log in to JBossMQ. These may be used by them self. If you have specified a Durable Topic they are however required. Then one also have to specify a client-id. All these stuff are configurable in conf/default/jbossmq.xml. Using one of the default in that file we could have a deployment descriptor looking like this:

     <message-driven>
       <ejb-name>DurableTopicBean</ejb-name>
       <configuration-name>Standard Message Driven Bean</configuration-name>
       <destination-jndi-name>topic/testDurableTopic</destination-jndi-name>
       <mdb-user>john</mdb-user>
       <mdb-passwd>needle</mdb-passwd>
       <mdb-client-id>DurableSubscriberExample</mdb-client-id>
     </message-driven>

The container stuff for MDB are in standardjboss.xml. It is however possible to override this configuration by including it in the jboss.xml deployment descriptor. I will first give you the complete look if doing like this, and then go through the individual entries.

     <?xml version="1.0" encoding="Cp1252"?>
     <jboss>
       <enterprise-beans>
         <message-driven>
           <ejb-name>ObjectMessageBean</ejb-name>
           <configuration-name>My Config</configuration-name>
           <destination-jndi-name>queue/testObjectMessage</destination-jndi-name>
         </message-driven>
         <secure>false</secure>
       </enterprise-beans>
       <container-configurations>
         <container-configuration>
           <container-name>My Config</container-name>
           <call-logging>false</call-logging>
           <container-invoker>org.jboss.ejb.plugins.jms.JMSContainerInvoker</container-invoker>
           <container-interceptors>
             <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
             <interceptor>org.jboss.ejb.plugins.SecurityInterceptor</interceptor>
             <!-- CMT -->
             <interceptor transaction="Container">org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>
             <interceptor transaction="Container" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
             <interceptor transaction="Container">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
             <!-- BMT -->
             <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
             <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenTxInterceptorBMT</interceptor>
             <interceptor transaction="Bean" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
           </container-interceptors>
           <instance-pool>org.jboss.ejb.plugins.MessageDrivenInstancePool</instance-pool>
           <instance-cache></instance-cache>
           <persistence-manager></persistence-manager>
           <transaction-manager>org.jboss.tm.TxManager</transaction-manager>
           <container-invoker-conf>
             <JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>
             <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
             <MaximumSize>15</MaximumSize>
             <MaxMessages>1</MaxMessages>
             <Optimized>True</Optimized>
           </container-invoker-conf>
           <container-pool-conf>
             <MaximumSize>100</MaximumSize>
             <MinimumSize>10</MinimumSize>
           </container-pool-conf>
         </container-configuration>

       </container-configurations>
       <resource-managers />
     </jboss>

Here we go through some ways to configure the MDB container

Container invoker

The container invoker is what sends messages into the container system. It is this that is responsible for handling everything that has to do with JMS. The rest of the MDB container parts are basically agnostic to what kind of message system that the container invoker uses. It is therefore possible to write a new container invoker for other types of message system. Currently there are one limitation to this. The bean class still has to implement the MessageListener interface and the invoker therefore have to adopt to this interface. This will be made pluggable in a later release of MDB.

Container interceptor

The container interceptor are an integral part of the container system and each does something particular to fulfill the EJB container contract. All of them are pluggable, meaning that it is possible to write new implementations of the and plug them in for a bean with a particular need. This should be considered a very advanced task.

Container invoker configuration

This is probably the most interesting part to understand. Lets look at it in smaller pieces. First it defines a "JMSProviderAdapterJNDI":

     <JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>

There should be a JNDI name to a JMX bean where one might lookup a provider adapter class. This class is then used by the invoker to find the names of the connection factories, all IntitialContext lookups are done through this class, to make it possible to get access to a JMS provider outside of JBoss.

The name is by default bound to the JbossMQProvider in jboss.jcml

     <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name=":service=JMSProviderLoader,name=JBossMQProvider">
       <attribute name="ProviderName">DefaultJMSProvider</attribute>
       <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider       </attribute>
     </mbean>

It is however possible to add more JMSProviders to the jboss.jcml and use them in the container configuration. On possible reason to do this is if one want to listen to a queue or topic in another JBoss server. The one could define another provider and configure its context. Say we have a JBoss server on a machine remote.com. We might then ad this to jboss.jcml:

     <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name=":service=JMSProviderLoader,name=RemoteJMSProvider">
       <attribute name="ProviderName">RemoteJMSProvider</attribute>
       <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
       <attribute name="ProviderUrl">remote.com:1099</attribute>
     </mbean>

Note how we added a "ProviderUrl" attribute. In jboss.xml we would write this in the JMSProviderAdapterJNDI element:

     <JMSProviderAdapterJNDI>RemoteJMSProvider</JMSProviderAdapterJNDI>

OBSERVE. I have this working for non transacted connections. It has not bean fully verified to work with the current JBossMQProvider.

Another way to use this configuration option is to integrate another JMS provider into JBoss. This was actually how MDB was first implemented in JBoss through the OpenJMS implementation. To do this one have to implement the interface org.jboss.jms.jndi.JMSProviderAdapter. Be aware though that if the JMS provider does not support the full JMS ASF (chapter 8 in the JMS spec) you will have to write a full implementation of both the ProvuderAdapter and the ServerSession stuff.

Next we have the "ServerSessionPoolFactoryJNDI" element

     <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>

This also points to a class loaded through jboss.jcml. It is the entry point to the ServerSessionPool. If one needs to write a provider specific pool or do some customization of the existing one, it would be possible to load that for a particular bean. The existing one is defined this way in jboss.jcml:

     <mbean code="org.jboss.jms.asf.ServerSessionPoolLoader" name=":service=ServerSessionPoolMBean,name=StdJMSPool">
       <attribute name="PoolName">StdJMSPool</attribute>
       <attribute name="PoolFactoryClass">org.jboss.jms.asf.StdServerSessionPoolFactory</attribute>
     </mbean>

The first implementation of MDB for JBoss was based on another ServerSessionPoolFactory, specially written for OpenJMS. This is currently not verified to work. What do work is the pluggability of ServerSessionPool factories.

The last two entries looks like this:

     <MaximumSize>15</MaximumSize>
     <MaxMessages>1</MaxMessages>

The first of these - "MaximumSize" - defines how large the pool will be, i.e how many session it will have ready to serve incoming messages. The second one is used to configure the maximum number of messages a session is allowed to handle at once. I have never tweaked that one, and do not know if JBossMQ actually support that option. It might enhance performance if used.