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 theMQ.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 andC:\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
- Copy the
wmq.jmsra.rar
file to theJBOSS_HOME/server/PROFILE/deploy/
directory.cp MQ.HOME/java/lib/jca/wmq.jmsra.rar JBOSS_HOME/server/PROFILE/deploy/
- Create a file named
jboss_jmsra_ds.xml
in theJBOSS_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 theMQ.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
- 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
- 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)
- 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. - 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.
- Copy the following libraries from
MQ.HOME/java/lib/
to theJBOSS_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
- 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 theRemoteAccess
attribute to the MBean definition. In this case, theIBMMQInitialContext/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>
- Create a file called
wsmq-jmsprovider-ds.xml
in theJBOSS_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>
- Add the the
JMSProviderLoader
reference to the<properties depends="arjuna" name="jta">
section of theJBOSS_HOME/server/PROFILE/conf/jbossts-properties.xml
file. TheWSMQJmsWNPMQMProvider
value must match the name in the JMSProviderLoader definition in thewsmq-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"/>
- 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 theIBMMQInitialContext/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