0
votes

I am trying to use Atomikos for distributed transaction management with spring integration project. I am getting problem If I try to use AtomikosConnectionFactoryBean as connection-factory in message driven channel adapter.

I'm getting below error:

Caused by: com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ0018: Failed to connect to queue manager 'NYHUB6S' with connection mode 'Client' and host name 'nyhub6s.us.ml.com'.
    at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:608) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:236) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:430) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.internal.WMQXAConnection.<init>(WMQXAConnection.java:70) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.factories.WMQXAConnectionFactory.createV7ProviderConnection(WMQXAConnectionFactory.java:190) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:6210) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.wmq.factories.WMQXAConnectionFactory.createProviderXAConnection(WMQXAConnectionFactory.java:102) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createXAConnectionInternal(JmsConnectionFactoryImpl.java:371) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.mq.jms.MQXAQueueConnectionFactory.createXAQueueConnection(MQXAQueueConnectionFactory.java:144) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.mq.jms.MQXAQueueConnectionFactory.createXAConnection(MQXAQueueConnectionFactory.java:98) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.atomikos.datasource.xa.jms.JmsTransactionalResource.refreshXAConnection(JmsTransactionalResource.java:73) ~[transactions-jta-4.0.4.jar:na]
    ... 17 common frames omitted
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
    at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:223) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    ... 26 common frames omitted
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009;AMQ9204: Connection to host 'nyhub6s.us.ml.com(1467)' rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2009],3=nyhub6s.us.ml.com(1467),5=RemoteRcvThread.run]
    at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:2072) ~[com.ibm.mq.jmqi-7.0.1.8.jar:7.0.1.8 - k701-108-120201]
    at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:1286) ~[com.ibm.mq.jmqi-7.0.1.8.jar:7.0.1.8 - k701-108-120201]
    at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:345) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    ... 25 common frames omitted
com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009
    at com.ibm.mq.jmqi.remote.internal.RemoteRcvThread.run(RemoteRcvThread.java:362) ~[com.ibm.mq.jmqi-7.0.1.8.jar:7.0.1.8 - k701-108-120201]
    at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.runTask(WorkQueueItem.java:209) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.commonservices.workqueue.SimpleWorkQueueItem.runItem(SimpleWorkQueueItem.java:100) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.run(WorkQueueItem.java:224) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.runWorkQueueItem(WorkQueueManager.java:298) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]
    at com.ibm.msg.client.commonservices.j2se.workqueue.WorkQueueManagerImplementation$ThreadPoolWorker.run(WorkQueueManagerImplementation.java:1220) ~[com.ibm.mqjms-7.0.1.1.jar:7.0.1.1 - k701-101-091116]

My spring integration and Atomikos config are as below:

<bean id="xaConnectionFactory" class="com.ibm.mq.jms.MQXAQueueConnectionFactory">               
        <property name="hostName">
            <value>${receiving.queue.hostname}</value>
        </property>
        <property name="port">
            <value>${receiving.queue.port}</value>
        </property>
        <property name="queueManager">
            <value>${receiving.queue.manager}</value>
        </property>
        <property name="channel">
            <value>${receiving.queue.channel}</value>
        </property>
        <property name="transportType">
            <value>1</value>
        </property>
    </bean> 

    <bean id="jmsQueueConnectionFactory"
        class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
        <property name="targetConnectionFactory" ref="xaConnectionFactory" />       
        <property name="username" value="${mqSeriesUserName}" />
        <property name="password" value="${mqSeriesPassword}" />
    </bean> 

    <!-- lets wrap in a pool to avoid creating a connection per send -->
    <bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
        <property name="targetConnectionFactory" ref="jmsQueueConnectionFactory"/>
        <property name="sessionCacheSize" value="5"/>
        <property name="reconnectOnException" value="true"/>
    </bean>

    <!-- 
    <bean id="requestQueue1" class="com.ibm.mq.jms.MQQueue">
        <property name="baseQueueName" value="${receiving.queue1}" />   
        JMSC.MQJMS_CLIENT_NONJMS_MQ is one
        <property name="targetClient" value="1" />  
    </bean>

    <bean id="requestQueue2" class="com.ibm.mq.jms.MQQueue">
        <property name="baseQueueName" value="${receiving.queue2}" />   
        JMSC.MQJMS_CLIENT_NONJMS_MQ is one
        <property name="targetClient" value="1" />  
    </bean>

    <bean id="requestQueue3" class="com.ibm.mq.jms.MQQueue">
        <property name="baseQueueName" value="${receiving.queue3}" />   
        JMSC.MQJMS_CLIENT_NONJMS_MQ is one
        <property name="targetClient" value="1" />  
    </bean> -->

    <!--  XA related changes -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
        <property name="transactionTimeout" value="120"/> 
        <property name="forceShutdown">
            <value>false</value>
        </property>
    </bean>

    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" >
    </bean>

    <bean id="atomikos_ConnectionFactory" class="com.atomikos.jms.AtomikosConnectionFactoryBean"> 
        <property name="xaConnectionFactory" ref="xaConnectionFactory"/> 
        <property name="uniqueResourceName" value="MQSeries_XA_RMI"/>
        <property name="poolSize" value="2" />
        <property name="maxPoolSize" value="10" />
        <property name="maxIdleTime" value="15" />      
    </bean>

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
        <property name="transactionManager"> <ref bean ="atomikosTransactionManager"/></property>
        <property name="userTransaction"> <ref bean="atomikosUserTransaction" /></property>
    </bean>

<beans profile="SINGLE_REQUEST_Q">
        <jms:message-driven-channel-adapter id="exch" destination="requestQueue"    channel="jmsInChannel" 
                        transaction-manager="transactionManager" acknowledge="transacted" connection-factory="atomikos_ConnectionFactory" />
        <bean id="requestQueue" class="com.ibm.mq.jms.MQQueue">
                <property name="baseQueueName" value="${receiving.queue.${exch}}" />    
                <property name="targetClient" value="1" />
        </bean>             
    </beans>

I need to pass caching factory reference with user id and password to AtomikosConnectionFactoryBean but it does not take anything except MQXAQueueConnectionFactory. Please let me know your comments or pointers to pass either UserCredentialsConnectionFactoryAdapter or CachingConnectionFactory to AtomikosConnectionFactoryBean bean.

2

2 Answers

0
votes

Try to use atomikos_ConnectionFactory in the UserCredentialsConnectionFactoryAdapter and CachingConnectionFactory for the <jms:message-driven-channel-adapter>. Something like this:

 <bean id="jmsQueueConnectionFactory"
        class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
        <property name="targetConnectionFactory" ref="atomikos_ConnectionFactory" />       
        <property name="username" value="${mqSeriesUserName}" />
        <property name="password" value="${mqSeriesPassword}" />
    </bean> 

...

 <jms:message-driven-channel-adapter 
       transaction-manager="transactionManager" connection-factory="connectionFactory" />
0
votes

A solution is to create a class that extends com.ibm.mq.jms.MQXAQueueConnectionFactory and use this class instead com.ibm.mq.jms.MQXAQueueConnectionFactory

When you extends MQXAConnectionFactory, define attributes username and password (and the setter) and Override the method createXAConnection() and create a context like this

public class MyMQXAConnectionFactory extends MQXAConnectionFactory {

private String username;
private String password;

public void setUsername(String username) {
    this.username = username;
}

public void setPassword(String password) {
    this.password = password;
}

/**
 * create a connection with a context user/password if username is present
 * @return
 * @throws JMSException
 */
@Override
public XAConnection createXAConnection() throws JMSException {
    if(username != null) {
        createXAContext(this.username, this.password);
    }
    return super.createXAConnection(this.username, this.password);
}}

After you can reference the new class in your xml config file like this

<bean id="xaConnectionFactory" class="my.package.MyMQXAConnectionFactory">               
    <property name="hostName">
        <value>${receiving.queue.hostname}</value>
    </property>
    <property name="port">
        <value>${receiving.queue.port}</value>
    </property>
    <property name="queueManager">
        <value>${receiving.queue.manager}</value>
    </property>
    <property name="channel">
        <value>${receiving.queue.channel}</value>
    </property>
    <property name="transportType">
        <value>1</value>
    </property>
    <property name="username" >
        <value>${usernmame}/<value
    </property>
    <property name="password" >
        <value>${password}</value>
    </password>
</bean> 

Afterward, you don't need UserCredentialsConnectionFactoryAdapter or CachingConnectionFactory and you can pass immediately your XA bean