15.2. IBM WebSphere MQ Integration

Apart from the default messaging options listed above, it is also possible to connect JBoss Enterprise Application Platform to a WebSphere MQ messaging system. WebSphere MQ is IBM's Messaging Oriented Middleware (MOM) software that allows applications on distributed systems to communicate with each other. This is accomplished through the use of messages and message queues. WebSphere MQ is responsible for delivering messages to the message queues and for transferring data to other queue managers using message channels. For more information about IBM WebSphere MQ, please refer to its documentation accessible at http://www.ibm.com.
Within the scope of the integration with JBoss Enterprise Application Platform, WebSphere MQ does not act as a default messaging provider equivalent to JBoss Messaging or Hornet Q. Instead, it runs as a standalone messaging system connected to JBoss Enterprise Application Platform through a resource adapter. While connected to WebSphere MQ, the platform still uses either JBoss Messaging or HornetQ as its default JMS messaging provider. This is typically useful when an application based on JBoss Enterprise Application Platform needs to be integrated with an existing infrastructure that uses WebSphere MQ.

15.2.1. Configuring WebSphere MQ Integration

This section covers the general steps that need to be performed to deploy and configure the WebSphere MQ Resource Adapter in JBoss Enterprise Application Platform 5.
Prerequisites

The following is required before you get started configuring your instance of JBoss Enterprise Application Platform for integration with WebSphere MQ.

  • A running instance of WebSphere MQ version 7.5.
  • A WebSphere MQ JMS resource adapter. It is supplied with your distribution of WebSphere MQ as a Resource Archive (RAR) file called wmq.jmsra.rar. You can find it in the MQ.HOME/java/lib/jca directory.
  • To configure the connection properly, you also need to know the values listed below. The names shown in capital letters are used in the code samples further in this chapter. When reusing the code, make sure that you replace these names with the actual values relevant for your WebSphere MQ instance.
    MQ.HOST.NAME
    The host name of the machine where the WebSphere MQ instance is running. It is also possible to specify the machine's IP address instead of the hostname.
    MQ.PORT
    The port used to connect to the WebSphere MQ queue manager. The default value is 1414.
    MQ.CHANNEL.NAME
    The server channel used to connect to the WebSphere MQ queue manager. The default value is SYSTEM.DEF.SVRCONN.
    MQ.TRANSPORT.TYPE
    The transport type used for the connection to WebSphere MQ. The default value is CLIENT.
    MQ.HOME
    The path to the WebSphere MQ instance's base directory. The default is /opt/mqm/ on Linux or Unix, /usr/mqm/ on AIX and C:\ProgramFiles\IBM\WebSphere MQ on Windows.
    MQ.USER
    The user name of a user account with permissions to connect to the WebSphere MQ server by the broker.
    MQ.PASSWORD
    The password of the MQ.USER user account.
  • Within the WebSphere MQ instance, you need to have objects like queue managers, queues, topics and channels defined according to the needs of your specific system. The list below contains WebSphere MQ objects that are used to demonstrate the configuration in the code samples further in this chapter. Similarly as above, when reusing the code samples, make sure that you replace the capitalized names with the names of the actual objects defined in your WebSphere MQ instance.
    MQ.QUEUE.MANAGER
    The name of the WebSphere MQ queue manager with which the connection will be established.
    MQ.QUEUE.REQUESTS
    The name of the destination message queue in WebSphere MQ to which request messages will be sent.
    MQ.QUEUE.RESPONSES
    The name of the source message queue in WebSphere MQ from which response messages will be received.
    MQ.TOPIC1
    The name of a topic defined in WebSphere MQ.
    MQ.TOPIC2
    The name of another topic defined in WebSphere MQ.

Procedure 15.1. Deploying the WebSphere MQ Resource Adapter

  1. Copy the wmq.jmsra.rar file to the JBOSS_HOME/server/PROFILE/deploy/ directory.
    cp MQ.HOME/java/lib/jca/wmq.jmsra.rar JBOSS_HOME/server/PROFILE/deploy/
  2. Create a file named jboss_jmsra_ds.xml in the JBOSS_HOME/server/PROFILE/deploy/ directory.
    Below, you can find a code sample showing the expected content of the file. The first part of the XML file defines a connection factory used to establish the connection with the WebSphere MQ instance. The second part of the file defines JNDI bindings of objects defined in WebSphere MQ to JMS administered objects.
    <?xml version="1.0" encoding="UTF-8"?> 
    <connection-factories>
      <!-- connection factory definition -->
      <tx-connection-factory> 
        <jndi-name>jms/CF</jndi-name>
        <xa-transaction />
        <rar-name>wmq.jmsra.rar</rar-name>
        <connection-definition>javax.jms.ConnectionFactory</connection-definition>
        <config-property name="channel" type="java.lang.String">MQ.CHANNEL.NAME</config-property>
        <config-property name="hostName" type="java.lang.String">MQ.HOST.NAME</config-property>
        <config-property name="port" type="java.lang.String">MQ.PORT</config-property>
        <config-property name="username" type="java.lang.String">MQ.USER</config-property>
        <config-property name="password" type="java.lang.String">MQ.PASSWORD</config-property>
        <config-property name="queueManager" type="java.lang.String">MQ.QUEUE.MANAGER</config-property>
        <config-property name="transportType" type="java.lang.String">MQ.TRANSPORT.TYPE</config-property> 
        <security-domain-and-application>JmsXARealm</security-domain-and-application>
      </tx-connection-factory>
    
      <!-- admin object definitions -->
      <mbean code="org.jboss.resource.deployment.AdminObject" name="jca.wmq:name=queue1">
        <attribute name="JNDIName">
          jms/queue/MQ.QUEUE.REQUESTS
        </attribute>
        <depends optional-attribute-name="RARName">
          jboss.jca:service=RARDeployment,name='wmq.jmsra.rar'
        </depends>
        <attribute name="Type">javax.jms.Queue</attribute> 
        <attribute name="Properties">
          baseQueueManagerName=MQ.QUEUE.MANAGER
          baseQueueName=MQ.QUEUE.REQUESTS
        </attribute>
      </mbean>
    
      <mbean code="org.jboss.resource.deployment.AdminObject" name="jca.wmq:name=topic1"> 
        <attribute name="JNDIName">
          jms/topic/MQ.TOPIC1
        </attribute>
        <depends optional-attribute-name="RARName">
          jboss.jca:service=RARDeployment,name='wmq.jmsra.rar'
        </depends>
        <attribute name="Type">javax.jms.Topic</attribute> 
        <attribute name="Properties">
          brokerPubQueueManager=MQ.QUEUE.MANAGER
          baseTopicName=MQ.TOPIC1
        </attribute>
      </mbean>
    
      <mbean code="org.jboss.resource.deployment.AdminObject" name="jca.wmq:name=queue2"> 
        <attribute name="JNDIName">
          jms/queue/MQ.QUEUE.RESPONSES
        </attribute>
        <depends optional-attribute-name="RARName">
          jboss.jca:service=RARDeployment,name='wmq.jmsra.rar'
        </depends>
        <attribute name="Type">javax.jms.Queue</attribute> 
        <attribute name="Properties">
          baseQueueManagerName=MQ.QUEUE.MANAGER
          baseQueueName=MQ.QUEUE.RESPONSES
        </attribute>
      </mbean>
    
      <mbean code="org.jboss.resource.deployment.AdminObject" name="jca.wmq:name=topic2">
        <attribute name="JNDIName">
          jms/topic/MQ.TOPIC2
        </attribute>
        <depends optional-attribute-name="RARName">
          jboss.jca:service=RARDeployment,name='wmq.jmsra.rar'
        </depends>
        <attribute name="Type">javax.jms.Topic</attribute> 
        <attribute name="Properties">
          brokerPubQueueManager=MQ.QUEUE.MANAGER
          baseTopicName=MQ.TOPIC2
        </attribute>
      </mbean>
    </connection-factories>
    
    

15.2.1.1. Using the WebSphere MQ resource adapter in an MDB

Once you have performed the configuration described above, you can access a message queue from the code of an MDB by specifying the ActivationConfigProperty and ResourceAdapter annotations as in the following code sample:
@MessageDriven(name="WebSphereMQMDB". 
 activationConfig =
   {
   @ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"),
   @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false"),
   @ActivationConfigProperty(propertyName = "hostName", propertyValue = "MQ.HOST.NAME"),
   @ActivationConfigProperty(propertyName = "port", propertyValue = "MQ.PORT"),
   @ActivationConfigProperty(propertyName = "channel", propertyValue = "MQ.CHANNEL.NAME"),
   @ActivationConfigProperty(propertyName = "queueManager", propertyValue = "MQ.QUEUE.MANAGER"),
   @ActivationConfigProperty(propertyName = "destination", propertyValue = "MQ.QUEUE.REQUESTS"),
   @ActivationConfigProperty(propertyName = "transportType", propertyValue = "MQ.TRANSPORT.TYPE"),
   @ActivationConfigProperty(propertyName = "username", propertyValue = "MQ.USER"),
   @ActivationConfigProperty(propertyName = "password", propertyValue = "MQ.PASSWORD")
   })
@ResourceAdapter(value = "wmq.jmsra.rar")
public class WebSphereMQMDB implements MessageListener {
}

15.2.1.2. Configuration for XA Transaction Recovery

If unfinished two-phase commit transactions are not recovered after a system crash, they can use storage space in the WebSphere MQ instance and cause performance problems. To prevent this, JBoss Enterprise Application Server's Transaction service can recover such transactions if a recovery module is configured for each resource. This section explains how to configure the XARecovery module for the sample WebSphere MQ instance configured previously in this chapter.
Prerequisites

Before you begin the configuration for XA transaction recovery, you need:

  • JBoss Enterprise Application Platform and WebSphere MQ configured as described previously in this chapter.
  • The mqcontext.jar library. It is available as part of IBM Support Pac: ME01, which can be downloaded from the IBM website. Installation of the pack adds the library to the MQ.HOME/java/lib/ directory.
  • An additional message queue created in WebSphere MQ for transaction recovery purposes. In the following code samples, it is referred to as MQ.RECOVERY.QUEUE.

Procedure 15.2. Configuring WebSphere MQ Integration for XA Transaction Recovery

  1. In a directory of your choice on the WebSphere MQ server, create a JMSAdmin.config file with the following content:
    INITIAL_CONTEXT_FACTORY=com.ibm.mq.jms.context.WMQInitialContextFactory
    PROVIDER_URL=MQ.HOST.NAME:MQ.PORT/MQ.CHANNEL.NAME
    
  2. In the same directory, create a file called xaqcf_def.scp. In the file, define an XA queue connection factory as follows:
    def xaqcf(WNPMQMXACF) qmgr(MQ.QUEUE.MANAGER) tran(MQ.TRANSPORT.TYPE) chan(MQ.CHANNEL.NAME) host(MQ.HOST.NAME) port(MQ.PORT)
    
  3. Still in the same directory, create a JMSAdmin.sh script as follows:
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/jms.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/com.ibm.mq.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/com.ibm.mqjms.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/jta.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/connector.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/jndi.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/providerutil.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/fscontext.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/com.ibm.mqjms.jar
    CLASSPATH=$CLASSPATH:/opt/mqm/java/lib/mqcontext.jar
    export CLASSPATH
    /opt/mqm/java/bin/JMSAdmin -v -cfg $PWD/JMSAdmin.config < xaqcf_def.scp
    
    All libraries necessary for JMSAdmin tools are linked from the default WebSphere MQ installation directory, which is /opt/mqm. Please modify the paths in the script accordingly if your WebSphere MQ installation is located elsewhere.
  4. Launch the script created in the previous step. The script will append the required paths to the CLASSPATH variable and create the XA queue connection factory.
  5. Copy the following libraries from MQ.HOME/java/lib/ to the JBOSS_HOME/server/PROFILE/lib/ directory:
    • dhbcore.jar
    • mqcontext.jar
    • com.ibm.mq.jar
    • com.ibm.mqjms.jar
    • com.ibm.mq.pcf.jar
    • com.ibm.mq.jmqi.jar
    • com.ibm.mq.headers.jar
    • com.ibm.mq.commonservices.jar
  6. Create an external JNDI context by adding the following code to the JBOSS_HOME/server/PROFILE/conf/jboss-service.xml file:
    <mbean code="org.jboss.naming.ExternalContext" 
        name="jboss.jndi:service=ExternalContext,jndiName=IBMMQInitialContext">
      <attribute name="JndiName">IBMMQInitialContext</attribute>
      <attribute name="InitialContext">javax.naming.InitialContext</attribute>
      <attribute name="Properties">
        java.naming.factory.initial=com.ibm.mq.jms.context.WMQInitialContextFactory
        java.naming.factory.url.pkgs=com.ibm.mq.jms.naming
        java.naming.provider.url=MQ.HOST.NAME:MQ.PORT/MQ.CHANNEL.NAME
      </attribute>
    </mbean>
    
    Alternatively, it is possible to define the external JNDI context as a remote one by adding the RemoteAccess attribute to the MBean definition. In this case, the IBMMQInitialContext/WNPMQMXACF JNDI name used in the following step points to a remote connection factory in the WebSphere MQ broker.
    <mbean code="org.jboss.naming.ExternalContext" name="jboss.jndi:service=ExternalContext,jndiName=IBMMQIntialContext">
      <attribute name="JndiName">IBMMQIntialContext</attribute>
      <attribute name="InitialContext">javax.naming.InitialContext</attribute>
      <!-- Indicates that the external context is remote -->
      <attribute name="RemoteAccess">true</attribute>
      <attribute name="Properties">
        java.naming.factory.initial=com.ibm.mq.jms.context.WMQInitialContextFactory
        java.naming.factory.url.pkgs=com.ibm.mq.jms.naming
        java.naming.provider.url=MQ.HOST.NAME:MQ.PORT/MQ.CHANNEL.NAME
      </attribute>
    </mbean>
    
  7. Create a file called wsmq-jmsprovider-ds.xml in the JBOSS_HOME/server/PROFILE/conf/ directory.
    Below, you can find a code sample showing the expected content of the file. The first part of the XML file defines a connection factory that supports XA transactions. The second part of the file defines JNDI bindings of the recovery queue defined in WebSphere MQ and of the XA connection factory. See the comments inside the code sample for more information.
    <?xml version="1.0" encoding="UTF-8"?>
    <connection-factories>
      <!-- connection factory definition -->
      <tx-connection-factory>
        <!-- Bind this ConnectionFactory with the JNDI -->
        <jndi-name>IbmMQJMSXA</jndi-name>
        <!-- Indicate that the connection factory supports XA transactions -->
        <xa-transaction/>
        <!-- rar-name is the actual RAR file name, in this case wmq.jmsra.rar -->
        <rar-name>wmq.jmsra.rar</rar-name>
        <!-- Do not prefix the JNDI name of the connection factory with the java: context and thus allow it to be looked up externally -->
        <use-java-context>true</use-java-context>
        <!-- connection-definition is the ConnectionFactory interface defined in the jboss_jmsra_ds.xml file -->
        <connection-definition>
          javax.jms.ConnectionFactory
        </connection-definition>
        <config-property name="hostName" type="java.lang.String">MQ.HOST.NAME:</config-property>
        <config-property name="username" type="java.lang.String">MQ.USER</config-property>
        <config-property name="password" type="java.lang.String">MQ.PASSWORD</config-property>
        <config-property name="port" type="java.lang.String">MQ.PORT</config-property>
        <config-property name="queueManager" type="java.lang.String">MQ.QUEUE.MANAGER</config-property>
        <config-property name="channel" type="java.lang.String">MQ.CHANNEL.NAME</config-property>
        <config-property name="transportType" type="java.lang.String">MQ.TRANSPORT.TYPE</config-property>
        <!-- define the security domain -->
        <security-domain-and-application>JmsXARealm</security-domain-and-application>
      </tx-connection-factory>
      
      <!-- admin object definitions -->
    
      <!-- Binding of the crash recovery queue in WebSphere MQ -->
      <mbean code="org.jboss.resource.deployment.AdminObject" name="jca.wmq:name=crashRecovery">
        <attribute name="JNDIName">
          queue/crashRecoveryQueue
        </attribute>
        <depends optional-attribute-name="RARName">
          jboss.jca:service=RARDeployment,name='wmq.jmsra.rar'
        </depends>
        <attribute name="Type">javax.jms.Queue</attribute>
        <attribute name="Properties">
          baseQueueManagerName=MQ.QUEUE.MANAGER
          baseQueueName=MQ.RECOVERY.QUEUE
        </attribute>
      </mbean>
      
      <!-- Binding of the XA Connection factory to the JMSProvider that is used by the transaction module -->
      <!-- The properties must match the Websphere MQ JNDI entry and the FactoryRef must match the xaqcf name -->
      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
          name="jboss.jms:service=JMSProviderLoader,name=WSMQJmsWNPMQMProvider">
        <!-- this will be bound to java:/... and you will need to use it in conf/jbossts-properties.xml -->
        <attribute name="ProviderName">WSMQJmsWNPMQMProvider</attribute> 
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="FactoryRef">IBMMQInitialContext/WNPMQMXACF</attribute>
        <attribute name="QueueFactoryRef">IBMMQInitialContext/WNPMQMXACF</attribute>
        <attribute name="TopicFactoryRef">IBMMQInitialContext/WNPMQMXACF</attribute>
        <!-- external context defined in conf/jboss-service.xml -->
        <depends>jboss.jndi:service=ExternalContext,jndiName=IBMMQInitialContext</depends>
      </mbean>
    </connection-factories>
    
    
  8. Add the the JMSProviderLoader reference to the <properties depends="arjuna" name="jta"> section of the JBOSS_HOME/server/PROFILE/conf/jbossts-properties.xml file. The WSMQJmsWNPMQMProvider value must match the name in the JMSProviderLoader definition in the wsmq-jmsprovider-ds.xml file.
    <!-- the value has to correspond with property com.arjuna.ats.arjuna.xa.nodeIdentifier -->
    <property name="com.arjuna.ats.jta.xaRecoveryNode" value="1" />
    <!-- IBM MQ settings -->
    <!-- the WSMQJmsWNPMQMProvider must match the name in the JMSProviderLoader definition in the *-ds.xml file. -->
    <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.WSMQWNPMQM" value="org.jboss.jms.server.recovery.MessagingXAResourceRecovery;java:/WSMQJmsWNPMQMProvider"/>
    
    
  9. Restart the JBoss Enterprise Application Server instance. After the restart, the connection will be established. The connection factory will be available under the IbmMQJMSXA JNDI name (bound by JCA). The XA connection factory will be available under the IBMMQInitialContext/WNPMQMXACF JNDI name (bound as external context).
    If the connection is not established successfully, the following WARN message will be periodically logged:
    2011-06-10 10:44:08,707 WARN  [loggerI18N] [com.arjuna.ats.internal.jta.recovery.xarecovery1] 
    Local XARecoveryModule.xaRecovery  got XA exception javax.transaction.xa.XAException: 
     Error trying to connect to provider java:/WSMQJmsWNPMQMProvider, XAException.XAER_RMERR