JBoss JMS provider for WebSphere MQ

This readme explains how to configure WebSphere MQ (a.k.a. WSMQ) as a JMS provider in JBoss.

If you just need to send some JMS messages to WSMQ from a bean deployed in JBoss, and you do not need any kind of XA transaction support, then you do not need to go through this readme. Use the WSMQ JMS interface in your bean code as any other Java API and you are done.

But if you need any XA transaction support or if you need to deploy, in JBoss, a Message Driven Bean listening to a WSMQ destination, then you might find this readme useful.

Thank you to everyone's help in the JBoss forum (http://www.jboss.org) as well as in the JBoss mailing lists (http://sourceforge.net/projects/jboss).
A special thank to Hiram from Core Developers Network for the details on XA and the JBoss MDB.

Beside JBoss and WebSphere MQ, you will also need a JDK (http://www.javasoft.com) and Ant (http://www.apache.org) installed and properly configured in order to build and run the sample code. The sample was developed using Ant 1.5.3 and SUN JDK 1.4.1.

The current status of this sample is as follow:

WebSphere MQ prerequisite

This sample was developed using WebSphere MQ 5.3.0.2 with CSD03 (also called WebSphere MQ 5.3.0.3) and the WebSphere MQ Extended Transactional Clients (which requires CSD03).

The Extended Transactional Clients enables XA support through the JMS interface using the "client protocol".
Internally, WSMQ has multiple protocols. The client protocol allows you to access a remote WSMQ server (also called queue manager) through regular TCP/IP. In this case, the WSMQ client is 100% java code.
Before the Extended Transactional Clients, in order to enable XA support through the JMS interface, the "binding" protocol was required. WSMQ documentation specifies that this is the prefered connection mode (and the best for performance), but it has two drawbacks from my point of view:

This is out of the scope of this readme to configure the WSMQ JMS provider using the binding protocol, but everything applies to this case as well. The only changes are in the way the WSMQ connection factory object are created (binding protocol used instead of client).
What is not covered by this readme is the setting of the JBoss path to get all the WSMQ dlls.

If you do need any kind of XA support, you also do not need to worry about all that. Regular WSMQ 5.3.0 or 5.2.0 with the Java JMS interface is enough.

Configuration for JBoss 3.2.1

Here are the different steps to follow to configure WSMQ as a JMS provider in JBoss 3.2.1.
Those steps are not addressing the XA requirements. This is done separately, later on in this readme.
Going through those steps first is a requirement. It is also strongly advised not to change any of the proposed names until your are familiar with the overall configuration.

JBoss standard configuration changes

JBOSS_HOME refers to the directory where you installed the jboss-3.2.1 distribution.

  1. Edit JBOSS_HOME/server/default/conf/jboss-service.xml, make sure that the RecursiveSearch is set to True:

    <attribute name="RecursiveSearch">True</attribute>

    This will make sure that all the JMS related services are deployed before any of your custom services and beans.


  2. From the Java\lib directory of the WebSphere MQ installation, copy the following jar files in the JBOSS_HOME/server/default/lib directory:

    com.ibm.mq.jar
    com.ibm.mqetclient.jar
    com.ibm.mqjms.jar
    com.ibm.mqbind.jar

    The com.ibm.mqetclient.jar is a jar installed as part of the WebSphere MQ Extended Transactional Clients. It is only required for WSMQ XA support.


  3. Create the WSMQ JMS provider. Edit JBOSS_HOME/server/default/deploy/jms/jms-ds.xml, add the following lines (copy/paste the default JMS provider and update mbean element name attibute, the ProviderName and the QueueFactoryRef and TopicFactoryRef):

    <!-- The WSMQ JMS provider loader -->
    <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
        name="jboss.mq:service=JMSProviderLoader,name=WSMQJMSProvider">
      <attribute name="ProviderName">WSMQJMSProvider</attribute>
      <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
      <attribute name="QueueFactoryRef">WSMQQueueConnectionFactory</attribute>
      <attribute name="TopicFactoryRef">WSMQTopicConnectionFactory</attribute>
    </mbean>

    The ProviderName attribute is important as this is the way the MDB configuration will specify this JMS provider.
    The QueueFactoryRef and TopicFactoryRef are also important and must match the JNDI names of the WSMQ connection factory object that you create and register in JNDI (see below).


  4. Create the WSMQ Message Driven Bean configuration. It will allow the deployment of MDBs listening to WSMQ destinations.
    Edit the JBOSS_HOME/server/default/conf/standardjboss.xml, add the following lines in the container-configurations (copy/paste the Standard Message Driven Bean configuration and update the container-name and invoker-proxy-binding-name):

    <container-configuration>
      <container-name>WSMQ Message Driven Bean</container-name>
      <call-logging>false</call-logging>
      <invoker-proxy-binding-name>wsmq-message-driven-bean</invoker-proxy-binding-name>
      <container-interceptors>
        <interceptor>org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor</interceptor>
        <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
        <interceptor>org.jboss.ejb.plugins.RunAsSecurityInterceptor</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>
        <interceptor>org.jboss.resource.connectionmanager.CachedConnectionInterceptor</interceptor>
      </container-interceptors>
      <instance-pool>org.jboss.ejb.plugins.MessageDrivenInstancePool</instance-pool>
      <instance-cache></instance-cache>
      <persistence-manager></persistence-manager>
      <container-pool-conf>
        <MaximumSize>100</MaximumSize>
      </container-pool-conf>
    </container-configuration>

    The container-name is the name that will be used in the MDB deployment descriptor.
    You also need to add the following lines in the invoker-proxy-bindings (copy/paste the message-driven-bean invoker-proxy-binding and update the name and JMSProviderAdapterJNDI):

    <invoker-proxy-binding>
      <name>wsmq-message-driven-bean</name>
      <invoker-mbean>default</invoker-mbean>
      <proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
      <proxy-factory-config>
        <JMSProviderAdapterJNDI>WSMQJMSProvider</JMSProviderAdapterJNDI>
        <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
        <MaximumSize>15</MaximumSize>
        <MaxMessages>1</MaxMessages>
        <MDBConfig>
          <ReconnectIntervalSec>10</ReconnectIntervalSec>
          <DLQConfig>
            <DestinationQueue>queue/DLQ</DestinationQueue>
            <MaxTimesRedelivered>10</MaxTimesRedelivered>
            <TimeToLive>0</TimeToLive>
          </DLQConfig>
        </MDBConfig>
      </proxy-factory-config>
    </invoker-proxy-binding>

    The name must match the invoker-proxy-binding-name of the WSMQ Message Driven Bean configuration created previously.
    The JMSProviderAdapterJNDI must match the ProviderName created previously in the JBOSS_HOME/server/default/deploy/jms/jms-ds.xml file.
You are now done with the JBoss standard configuration changes.

WSMQ JMS administered objects

The next step is to create the WSMQ JMS administered objects (destinations - queue/topic - and connection factories) in the JBoss JNDI namespace.
Multiple options are possible, such as using the JMSAdmin tool provided by WSMQ to create those objects by hand in the JBoss JNDI space or in another JNDI space and bind it into JBoss. Search through the JBoss JMS forum at http://www.jboss.org for more details on those options.

For this sample, we will create some custom MBeans that, once deployed in JBoss, will create the WSMQ JMS objects and add them to JBoss JNDI space automatically.
With this option, it is very easy to add new objects (just adding a couple of lines to an xml file and redeploy), and each time JBoss is started those objects are created and available.
The custom MBean code is under the jmx package in the sources (src directory) of this sample. It will be packaged in a sar file and deployed in JBoss. The jboss-service.xml file containing the WSMQ JMS object definitions is in the resources folder.
To build and deploy the custom MBeans, perform the following steps:

  1. Edit the resources/jboss-service.xml and update the different WSMQ specific settings according to your environement:


  2. Edit build.xml and update the jboss.dist property to point to your JBOSS_HOME.


  3. Open a shell and run the following commands from the directory where build.xml is located:

    ant mb-build
    ant mb-deploy

    The first command builds and packages the custom MBeans.
    The second one will deploy them in JBoss.
    Make sure that there is no compilation errors and no deployment errors (no exceptions in the JBoss console/log).
    If the JMX console is available in your JBoss configuration (http://localhost:8080/jmx-console/), you can check the availibility of the WSMQ JMS objects by using the service=JNDIView service and invoking the list or listXML MBean operation. In the returned list, you should see the WSMQ objects you just deployed.


  4. Compile the client sample code:

    ant client-build


  5. You can now use the wsmq-tests target to check that the custom MBeans are correctly deployed and configured.
    Make sure that the following properties near the top of the build.xml are properly configured according to the resources/jboss-service.xml:

    <property name="wsmq.factory" value="WSMQQueueConnectionFactory"/>
    <property name="wsmq.request.destination" value="wsmq/RequestQueue"/>
    <property name="wsmq.response.destination" value="wsmq/ResponseQueue"/>

    Then run the following command:

    ant wsmq-tests

    This target will run some standard JMS clients sending and receiving messages to WSMQ.
    JBoss is used only as a JNDI server for the WSMQ JMS objects but it will make sure that those objects, as well as WSMQ, are properly configured.

Message Driven Bean listening to a WSMQ Queue, responding to a WSMQ Queue

Let's try now an MDB (Message Driven Bean) listening to a WSMQ queue and sending a response to another WSMQ Queue.
The default configuration of the sample MDB is as follow: Check resources/ejb-jar.xml for more details on the behaviour of the MDB.
To build and deploy the sample MDB, perform the following steps:
  1. Make sure that everything is defined correctly across the different configuration files as specified above.


  2. Open a shell and run the following commands:

    ant mdb-build
    ant mdb-deploy

    The first command builds and packages the MDB. The second one will deploy it in JBoss. Make sure that there is no compilation errors and no deployment errors (no exceptions in the JBoss console/log).


  3. Make sure that the following properties near the top of the build.xml are properly configured according to the resources/jboss-service.xml:

    <property name="wsmq.factory" value="WSMQQueueConnectionFactory"/>
    <property name="wsmq.request.destination" value="wsmq/RequestQueue"/>
    <property name="wsmq.response.destination" value="wsmq/ResponseQueue"/>

    Then run the following command:

    ant wsmq2wsmq

    Check the JBoss console/log. It will show you the received messages and when an abort is generated. For each generated abort, the JMS message will be received again meaning that you should see some duplicated messages on the output of the wsmq2wsmq.

Message Driven Bean listening to a WSMQ Queue, responding to a JBoss Queue

Let's try now an MDB (Message Driven Bean) listening to a WSMQ queue and sending a response to a JBoss queue.
Changing the response queue is actually quite easy to do. Everyting is configurable from the ejb-jar.xml of the MDB.
  1. Create a JBoss queue called ResponseQueue used for the response message.
    Edit the JBOSS_HOME/server/default/deploy/jms/jbossmq-destinations-service.xml and add the following lines at the end of the file (just before the closing <server> element):

    <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=ResponseQueue">
      <depends optional-attribute-name="DestinationManager"> jboss.mq:service=DestinationManager</depends>
    </mbean>


  2. Edit the resources/ejb-jar.xml.
    Change the env-entry-value for the mdb/responseFactory to ConnectionFactory which is the default JBoss MQ connection factory.
    Change the env-entry-value for the mdb/responseDestination to queue/ResponseQueue which is the JBoss queue you created in the previous step.


  3. Open a shell and rebuild, redeploy the MDB:

    ant mdb-build
    ant mdb-deploy


  4. Edit the build.xml file and make sure that the follwing properties are correctly setup:

    <property name="jboss.factory" value="ConnectionFactory"/>
    <property name="jboss.response.destination" value="queue/ResponseQueue"/>

    Then run the following command:

    ant wsmq2jboss

    Check the JBoss console/log. It will show you the received messages and when an abort is generated. For each generated abort, the JMS message will be received again meaning that you should see some duplicated messages on the output of the wsmq2jboss.
The JBoss MDB container was created knowing that it would not always be able to work with an XA connection to get it's messages. If the MDB does not have XA JMS provider, it will manually commit/rollback the JMS transaction (using Session.commit()/Session.rollback()). In the case the MDB is accessing XA resources the XA transaction will although be committed/rollbacked. This is not complete transaction integrity (both transactions are handled separately) but this is an interesting feature of JBoss.
Edit the resources/ejb-jar.xml, change the env-entry-value for the mdb/responseFactory to java:/JmsXA (the JBoss JMS XA connection factory), change the env-entry-value for the mdb/responseTransacted to true, rebuild (ant mdb-build), redeploy (ant mdb-deploy) and run the wsmq2jboss client again. You will see that the output does not contain any message duplicates anymore, even if some aborts are generated on the MDB side.
The client application is waiting for a fixed amount of seconds for messages to be delivered. It might exit before all messages have been redelivered by the MDB in case multiple aborts are generated. If you re-run the command, you should see the missing messages of the previous run right away and then the new messages sent.

The details of the JBoss MDB XA internals came from Hiram from Core Developers Network (through the JBoss mailing list). Hiram, thanks again for those details.
Hiram also provided some information on why a WSMQ MDB is not working with XA. Here are the details from his email:

The JMS ASF spec is a little weak in describing who/how the inbound XA transaction gets started.
The only way JBossMQ was able to implement the ASF spec was by starting the transaction without an associated XID. Once the message gets delivered to the container, JBossMQ allows the container to associate an XID with the session. The session then assigns the XID to the TX that delivered the message. JBossMQ had to kind of jump through hoops to get this to work.

It would have been much easier to allow JBossMQ to assign an XID to the transaction to begin with. WebSphere MQ might be trying to do something like that. But since it's not in the JMS ASF spec, IBM would need to tell us what MQ is expecting (outside the spec) to get the asynch message delivery to work.

Other ways to skin this cat:

Message Driven Bean listening to a JBoss Queue, responding to a WSMQ Queue

Let's try now an MDB (Message Driven Bean) listening to a JBoss queue and sending a response to a WSMQ queue.
We will also configure the WSMQ Queue for XA to insure full transaction integrity between the JBoss and the WSMQ queue
  1. Create a JBoss queue called RequestQueue used for the response message.
    Edit the JBOSS_HOME/server/default/deploy/jms/jbossmq-destinations-service.xml and add the following lines at the end of the file (just before the closing <server> element):

    <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=RequestQueue">
      <depends optional-attribute-name="DestinationManager"> jboss.mq:service=DestinationManager</depends>
    </mbean>


  2. Edit the resources/ejb-jar.xml.
    Change the env-entry-value for the mdb/responseFactory to WSMQQueueConnectionFactory (matching the non-XA WSMQ connection factory defined in the resources/jboss-service.xml.
    Change the env-entry-value for the mdb/responseDestination to wsmq/ResponseQueue (matching the response queue defined in the resources/jboss-service.xml.
    Change the env-entry-value for the mdb/responseTransacted to false.


  3. Edit the resources/jboss.xml.
    Change the configuration-name to Standard Message Driven Bean in order to have the MDB using the JBoss JMS provider.
    Change the destination-jndi-name to queue/RequestQueue (matching the queue you created in the first step).
    Set the xa-connection to true (or comment the line out) as the JBoss connection factory associated with the Standard Message Driven Bean coonfiguration is an XA one.


  4. Open a shell and rebuild, redeploy the MDB:

    ant mdb-build
    ant mdb-deploy


  5. Edit the build.xml file and make sure that the follwing properties are correctly setup:

    <property name="jboss.factory" value="ConnectionFactory"/>
    <property name="jboss.request.destination" value="queue/RequestQueue"/>

    Then run the following command:

    ant jboss2wsmq

    Check the JBoss console/log. It will show you the received messages and when an abort is generated. For each generated abort, the JMS message will be received again meaning that you should see some duplicated messages on the output of the jboss2wsmq.
Let's now go one step further and configure the appropriate XA connection factory for WSMQ in JBoss. It will allow full XA transaction integrity between the JBoss MDB and the WSMQ queue (doing the reading of the message by the JBoss MDB and the sending of a response to WSMQ within the same XA transaction).
  1. The first step is to configure the WSMQ JMS provider to use the WSMQ XA connection factory.
    Edit JBOSS_HOME/server/default/deploy/jms/jms-ds.xml and modify the QueueFactoryRef to be the name of the XA connection factory configured in the resources/jboss-service.xml (a connection factory for which IsXA is set to true):

    <!-- The WSMQ JMS provider loader -->
    <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
        name="jboss.mq:service=JMSProviderLoader,name=WSMQJMSProvider">
      <attribute name="ProviderName">WSMQJMSProvider</attribute>
      <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
      <attribute name="QueueFactoryRef">WSMQXAQueueConnectionFactory</attribute>
      <attribute name="TopicFactoryRef">WSMQXATopicConnectionFactory</attribute>
    </mbean>


  2. Still in the JBOSS_HOME/server/default/deploy/jms/jms-ds.xml you need to wrap the WSMQ JMS provider within a JBoss "transaction connection factory". Such factory will make sure that the resources created by the wrapped JMS provider will be enlisted as XA resources when used in an XA transaction context.
    Insert the following lines just before the closing connection-factories element:

    <tx-connection-factory>
      <jndi-name>WSMQJmsXA</jndi-name>
      <xa-transaction/>
      <adapter-display-name>JMS Adapter</adapter-display-name>
      <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:WSMQJMSProvider</config-property>
      <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
    </tx-connection-factory>


  3. Edit the resources/ejb-jar.xml.
    Change the env-entry-value for the mdb/responseFactory to java:/WSMQJmsXA (matching the transaction connection factory created in the previous step).
    Make sure that the env-entry-value for the mdb/responseDestination is set to wsmq/ResponseQueue (matching the response queue defined in the resources/jboss-service.xml.
    Change the env-entry-value for the mdb/responseTransacted to true.


  4. Open a shell and rebuild, redeploy the MDB:

    ant mdb-build
    ant mdb-deploy


  5. Then run the following command:

    ant jboss2wsmq

    Check the JBoss console/log. It will show you the received messages and when an abort is generated. For each generated abort, the JMS message will be received again but since the sending of the response is done within the same transaction as the message receipt, no duplicated messages are received by jboss2wsmq.

Configuration for JBoss 3.0.7

The steps to configure WSMQ as a JMS provider in JBoss 3.0.7 are the same as the ones used for JBoss 3.2.1. except the following "minor differences":
Not a lot of details in the JBoss 3.0.7 configuration, but it has been tested and it is possible to make it work like for JBoss 3.2.1.

That's it !!!! Hope you found all that useful.