0

I'm trying to integrate Atomikos transaction manager into a Spring Integration program that forwards JMS from ActiveMQ to a WebMethods ESB.

The spring integration part only retrieves JMs from local ActiveMQ broker and sends them to a distant ESB broker.

When I test the nominal case, JMS is sent well and passes through the ESB and is dispatched to the subscribers then.

When I test the case where ESB sending fails, I have an issue : the JMS is never published back. I suppose it's a transaction issue because the transaction should have been rolled back when program tried to publish on ESB broker but it seems not.

Here's my spring config :

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

<!-- Atomikos Transaction Manager Defintion (JTA) -->
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
    init-method="init" destroy-method="close" depends-on="atomikosConnectionFactorySource,connectionFactoryDestination">
    <property name="transactionTimeout" value="300" />
    <property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    <property name="transactionTimeout" value="300" />
</bean>

<bean id="jmsXaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
    <property name="brokerURL" value="${source.java.naming.provider.url}" />
    <property name="userName" value="${source.username}" />
    <property name="password" value="${source.passwd}" />
</bean>

<bean id="atomikosConnectionFactorySource" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
    init-method="init" destroy-method="close">
    <property name="poolSize" value="1" />
    <property name="uniqueResourceName" value="activemq" />
    <property name="xaConnectionFactory" ref="jmsXaConnectionFactory" />

</bean>

<bean id="connectionFactorySource"
    class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="jmsXaConnectionFactory" />
    <property name="clientId" value="CustomerOrderForwarderID" />
    <property name="reconnectOnException" value="true" />
</bean>



<!-- Destination JNDI Context -->
<bean id="jndiTemplateDestination" class="org.springframework.jndi.JndiTemplate"
    lazy-init="true">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">${destination.java.naming.factory.initial}</prop>
            <prop key="java.naming.provider.url">${destination.java.naming.provider.url}</prop>
            <prop key="java.naming.factory.url.pkgs">${destination.java.naming.factory.url.pkgs}</prop>
        </props>
    </property>
</bean>


<!-- Destination Connection factory -->
<bean id="customerOrderXAConnectionFactoryDestination" class="org.springframework.jndi.JndiObjectFactoryBean"
    lazy-init="true">
    <property name="jndiTemplate" ref="jndiTemplateDestination" />
    <property name="jndiName"
        value="${destination.java.naming.factory.connection}" />
    <property name="lookupOnStartup" value="false" />
    <property name="proxyInterface" value="javax.jms.XAConnectionFactory" />
</bean>

<bean id="connectionFactoryDestination" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
    init-method="init" destroy-method="close">
    <property name="poolSize" value="100" />
    <property name="uniqueResourceName" value="esb" />
    <property name="xaConnectionFactory" ref="customerOrderXAConnectionFactoryDestination" />
    <property name="localTransactionMode" value="true" />
</bean>



<bean id="ddr" class="com.adeo.transverse.jms.forwarder.customerorder.DynamicDestinationResolver" />

<bean id="userCredentialsConnectionFactoryDestination"
    class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter" lazy-init="true">
    <property name="targetConnectionFactory">
        <ref bean="connectionFactoryDestination" />
    </property>
    <property name="username" value="${destination.username}" />
    <property name="password" value="${destination.passwd}" />
</bean>

Here's the integration part :

<!--  In bridge -->
<jms:message-driven-channel-adapter
    id="StoreStockMotionSourceJmsAdapter" channel="bridgeChannelStoreStockMotionEnricher"
    container="jmsContainerSourceStoreStockMotion" />

<!--  Channel -->
<si:channel id="bridgeChannelStoreStockMotionEnricher" />

<jms:outbound-channel-adapter id="StoreStockMotionDestinationJmsAdapter"
    channel="bridgeChannelStoreStockMotionEnricher" jms-template="jmsTemplateStoreStockMotionDestination" />
<bean id="jmsTemplateStoreStockMotionDestination" class="org.springframework.jms.core.JmsTemplate">
    <property name="transactionManager" ref ="transactionManager"/>
    <property name="connectionFactory" ref="userCredentialsConnectionFactoryDestination" />
    <property name="defaultDestinationName" value="${StoreStockMotion.destination.topic}" />
    <property name="defaultDestination" ref="StoreStockMotionDestinationTopic" />
    <property name="pubSubDomain" value="true"/>
</bean>


<!-- Topic JMS for published message -->
<bean id="StoreStockMotionDestinationTopic" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
    <property name="jndiTemplate">
        <ref bean="jndiTemplateDestination" />
    </property>
    <property name="jndiName">
        <value>${StoreStockMotion.destination.topic}</value>
    </property>
</bean>

<!-- Topic JMS for Subscribing Message -->
<bean id="jmsContainerSourceStoreStockMotion"
    class="org.springframework.jms.listener.DefaultMessageListenerContainer"
    lazy-init="true">
    <property name="connectionFactory" ref="connectionFactorySource" />
    <property name="destinationName" value="${StoreStockMotion.source.topic}" />
    <property name="subscriptionDurable" value="true" />
    <!--  2 is client acknowledge -->
    <property name="sessionAcknowledgeMode" value="2" />
    <property name="durableSubscriptionName" value="${StoreStockMotion.source.subname}" />
    <property name="sessionTransacted" value="false" />
    <property name="pubSubDomain" value="true"/>

</bean>

Source and Destination are both encapsulated in XA connection factories and transactionManager handles the two transactions. Any idea what's missing ?

Biologeek
  • 541
  • 2
  • 6
  • 18
  • Show, please, the Integration part. How do you really consume and produce? – Artem Bilan Jun 16 '17 at 13:24
  • Added it to original question – Biologeek Jun 20 '17 at 09:58
  • ??? I don't see how you use `transactionManager`. The `jmsContainerSourceStoreStockMotion` should use that one. Also `jmsTemplateStoreStockMotionDestination` should be configured for its `sessionTransacted = true` – Artem Bilan Jun 20 '17 at 11:47
  • Added it but still not working ... As org.springframework.jms.listener.AbstractMessageListenerContainer javadoc specifies, when using an external transaction manager, sessionTransacted should be set to false. Anything I am missing ? – Biologeek Jun 21 '17 at 06:25

0 Answers0