"Cannot rollback() inside an XASession" error on Fuse ESB 7.1.0 - apache-camel

Yesterday I tried to migrate my bundles from ServiceMix 4.4.1 to Fuse ESB Enterprise 7.1.0. Bundles with local transactions work fine, but other ones with XA transaction don't work well. They write continuously tracebacks with the following messages to the log file:
13:30:29,283 | WARN | cation-stageOne] | PooledSession | 139 - org.apache.activemq.activemq-spring - 5.7.0.fuse-71-047 | Caught exception trying rollback() when putting session back into the pool, will invalidate. javax.jms.TransactionInProgressException: Cannot rollback() inside an XASession
javax.jms.TransactionInProgressException: Cannot rollback() inside an XASession
at org.apache.activemq.ActiveMQXASession.rollback(ActiveMQXASession.java:76)279:org.apache.activemq.activemq-core:5.7.0.fuse-71-047
at org.apache.activemq.pool.PooledSession.close(PooledSession.java:120)139:org.apache.activemq.activemq-spring:5.7.0.fuse-71-047
at org.springframework.jms.connection.JmsResourceHolder.closeAll(JmsResourceHolder.java:193)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.jms.connection.ConnectionFactoryUtils$JmsResourceSynchronization.releaseResource(ConnectionFactoryUtils.java:412)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.jms.connection.ConnectionFactoryUtils$JmsResourceSynchronization.releaseResource(ConnectionFactoryUtils.java:1)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.transaction.support.ResourceHolderSynchronization.afterCompletion(ResourceHolderSynchronization.java:98)148:org.springframework.transaction:3.0.7.RELEASE
at org.springframework.transaction.support.TransactionSynchronizationUtils.invokeAfterCompletion(TransactionSynchronizationUtils.java:168)148:org.springframework.transaction:3.0.7.RELEASE
at org.springframework.transaction.support.AbstractPlatformTransactionManager.invokeAfterCompletion(AbstractPlatformTransactionManager.java:996)148:org.springframework.transaction:3.0.7.RELEASE
at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerAfterCompletion(AbstractPlatformTransactionManager.java:971)148:org.springframework.transaction:3.0.7.RELEASE
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:799)148:org.springframework.transaction:3.0.7.RELEASE
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)148:org.springframework.transaction:3.0.7.RELEASE
at org.apache.aries.transaction.GeronimoPlatformTransactionManager.commit(GeronimoPlatformTransactionManager.java:76)
at sun.reflect.GeneratedMethodAccessor243.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25):1.6.0_35
at java.lang.reflect.Method.invoke(Method.java:597):1.6.0_35
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58)114:org.springframework.osgi.core:1.2.1
at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62)114:org.springframework.osgi.core:1.2.1
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:56)114:org.springframework.osgi.core:1.2.1
at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:39)114:org.springframework.osgi.core:1.2.1
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59)114:org.springframework.osgi.core:1.2.1
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)110:org.springframework.aop:3.0.7.RELEASE
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)110:org.springframework.aop:3.0.7.RELEASE
at $Proxy178.commit(Unknown Source)[:]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)153:org.springframework.jms:3.0.7.RELEASE
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)153:org.springframework.jms:3.0.7.RELEASE
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886):1.6.0_35
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908):1.6.0_35
at java.lang.Thread.run(Thread.java:662):1.6.0_35
It happens with an empty queue.
My activemq endpoint configuration looks as following:
<osgi:reference id="osgiPlatformTransactionManager" interface="org.springframework.transaction.PlatformTransactionManager"/>
<osgi:reference id="osgiJtaTransactionManager" interface="javax.transaction.TransactionManager"/>
<bean id="jmstx" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsTxConfig" />
</bean>
<bean id="jmsTxConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsXaPoolConnectionFactory"/>
<property name="transactionManager" ref="osgiPlatformTransactionManager"/>
<property name="transacted" value="true"/>
<property name="cacheLevelName" value="CACHE_NONE"/>
<property name="concurrentConsumers" value="${jms.concurrentConsumers}" />
</bean>
<bean id="jmsXaPoolConnectionFactory" class="org.apache.activemq.pool.XaPooledConnectionFactory">
<property name="maxConnections" value="${jms.maxConnections}" />
<property name="connectionFactory" ref="jmsXaConnectionFactory" />
<property name="transactionManager" ref="osgiJtaTransactionManager" />
</bean>
<bean id="jmsXaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL" value="${jms.broker.url}"/>
<property name="redeliveryPolicy">
<bean class="org.apache.activemq.RedeliveryPolicy">
<property name="maximumRedeliveries" value="-1"/>
<property name="initialRedeliveryDelay" value="2000" />
<property name="redeliveryDelay" value="5000" />
</bean>
</property>
</bean>
This endpoint is used very easy in the camel context as:
<route id="route">
<from uri="jmstx:queue:somequeue" />
<!-- some logic here -->
</route>
I would be glad if someone can help me to solve this issue. I can provide more deatails if it necessary.
EDIT
It seems that the issue is connected to the JMS connection pool: when I change connection factory to a simple ActiveMQXAConnectionFactory, then the exception disappears.

This is a known problem in the activemq-pool of version 5.7.0 (and most likely earlier versions) and has been reported http://fusesource.com/issues/browse/ENTMQ-441.

Related

Azure Service Bus (ASB) with Camel, MessageProducer has been closed (amqp:link:detach-forced)

I am using Apache Camel and camel-amqp component in order to communicate with an ASB queue.
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<property name="remoteURI" value="amqps://${service.bus.uri}?amqp.idleTimeout=120000" />
<property name="username" value="${service.bus.username}" />
<property name="password" value="${service.bus.password}" />
<property name="receiveLocalOnly" value="true" />
</bean>
<bean id="jmsCachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsCachingConnectionFactory"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
</bean>
...
<route>
...
<to uri="amqp:queue:{{service.bus.queue}}?exchangePattern=InOnly"/>
</route>
The first time that my route is running a AmqpFixedProducer is created for the {{service.bus.queue}}. If i manage to re-run the route (after 10 minutes) then I am getting the following error:
Caused by: javax.jms.JMSException: The link 'G24:360891:qpid-jms:sender:ID:b60452dd-5a2e-4478-a462-7ca280ecd953:1:2:1:themis-test' is force detached by the broker due to errors occurred in publisher(link252). Detach origin: AmqpMessagePublisher.IdleTimerExpired: Idle timeout: 00:10:00. [condition = amqp:link:detach-forced]
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:164)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:117)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at org.apache.qpid.jms.provider.amqp.AmqpAbstractResource.processRemoteClose(AmqpAbstractResource.java:262)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at org.apache.qpid.jms.provider.amqp.AmqpProvider.processUpdates(AmqpProvider.java:903)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at org.apache.qpid.jms.provider.amqp.AmqpProvider.access$1800(AmqpProvider.java:101)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at org.apache.qpid.jms.provider.amqp.AmqpProvider$17.run(AmqpProvider.java:789)[149:org.apache.qpid.jms.client:0.26.0.redhat-1]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)[:1.8.0_111]
at java.util.concurrent.FutureTask.run(FutureTask.java:266)[:1.8.0_111]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)[:1.8.0_111]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)[:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)[:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)[:1.8.0_111]
at java.lang.Thread.run(Thread.java:745)[:1.8.0_111]
It seems that application uses the same producer for both calls bu the connection to the ASB is closed after 10 minutes.
My question is how can I manage this?
Is there a way to retrieve the producer that was automatically created by Camel, and an OnException part close it and retry again? How can I get the producer?
Thanks a lot!
Problem was solved by modifying cacheLevelName to CACHE_NONE instead of CACHE_CONSUMER.
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsCachingConnectionFactory"/>
<property name="cacheLevelName" value="CACHE_NONE"/>
</bean>

How to use transaction in Apache Camel with mybatis?

How to use transaction in mybatis? I have two inserts and I want to be sure that. Second insert won't be executed if first didn't. Sorry for my english.
<route>
<from uri="nomatterhere" />
<transacted/>
<to uri="mybatis:insertHeader?statementType=Insert"/>
<to uri="mybatis:insertBody?statementType=Insert"/>
</route>
My beans:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${database.driver_class_name}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="txManager"/>
<property name="propagationBehaviorName" value="PROPAGATION_NESTED"/>
</bean>
#Edit
I added beans and route.
this transacted isn't working. I mean when something will go wrong in insertBody (for example null value) then header is inserted anyway. I want to back transaction then. How can I achive this?

Came jmsComponent: what's the difference setting the exception Listener in different beans?

I set up a jms component with spring like this way:
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="sessionCacheSize" value="10"/>
<property name="exceptionListener" ref="exceptionListener"/>
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="cachedConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
I notice that all these 4 beans have exceptionListener property. So I wonder what's the difference setting exceptionListener in different beans.
During my test, only setting in CachingConnectionFactory can work, it can go into my ExceptionListener, while in other cases, the exception will be logged somewhere else, but can't go into my code, the exception is like below.
WARN CachingConnectionFactory.onException(322) - Encountered a JMSException - resetting the underlying JMS Connection
javax.jms.JMSException: java.io.EOFException
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:54)
at org.apache.activemq.ActiveMQConnection.onAsyncException(ActiveMQConnection.java:1983)
at org.apache.activemq.ActiveMQConnection.onException(ActiveMQConnection.java:2002)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.ResponseCorrelator.onException(ResponseCorrelator.java:126)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:101)
at org.apache.activemq.transport.WireFormatNegotiator.onException(WireFormatNegotiator.java:160)
at org.apache.activemq.transport.AbstractInactivityMonitor.onException(AbstractInactivityMonitor.java:314)
at org.apache.activemq.transport.TransportSupport.onException(TransportSupport.java:96)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:200)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:392)
at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:275)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:221)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:213)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:196)
... 1 more
I can't understand how this works, please give some explanation or hint.
org.springframework.jms.connection.CachingConnectionFactory.exceptionListener set the org.apache.activemq.ActiveMQConnectionFactory.exceptionListener , so this is the same.
org.apache.camel.component.jms.JmsConfiguration.exceptionListener set up the org.springframework.jms.listener.AbstractMessageListenerContainer.exceptionListener
Set the JMS ExceptionListener to notify in case of a JMSException
thrown by the registered message listener or the invocation infrastructure.
so it is nearly the same use of that listener at any level but it is better to set it at the org.apache.camel.component.jms.JmsConfiguration.exceptionListener level to be managed by the spring Container.

ActiveMQ Camel: Every other message sends with multicast

I am trying to route an XML packet from one ActiveMQ queue to another ActiveMQ queue on another box. I am using camel to achieve this. I intend to send it to other boxes later so I am using the multicast to duplicate the message.
I am sending and receiving the messages using the C-Stomp library on both ends.
ActiveMQ-5.9.0 and Camel-2.12.3
camel.xml
<camelContext>
<route>
<from uri="activemq:queue:out" />
<multicast>
<to uri="otheractivemq:queue:in" />
</multicast>
</route>
</camelContext>
<!-- ActiveMQs -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="${activemq.username}"/>
<property name="password" value="${activemq.password}"/>
</bean>
</property>
</bean>
<bean id="otheractivemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://[differentip]:61616"/>
<property name="userName" value="${activemq.username}"/>
<property name="password" value="${activemq.password}"/>
</bean>
</property>
</bean>
On my ActiveMQ broker, I can see that messages are being added into the queue on the local side the promptly dequeued; but, when I check the other ActiveMQ, only every other message gets enqueued.
I attempted to add a "clone" of the destination queue on the other box and added it to the multicast; so, my route liked like the following:
<route>
<from uri="activemq:queue:out" />
<multicast>
<to uri="otheractivemq:queue:in" />
<to uri="otheractivemq:queue:in_clone" />
</multicast>
</route>
But, then the "clone" only received every other message, while the other queue received them all.

Camel - using custom jmsOperations: cannot be cast to org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate

I want to use a custom jmsOperations, when I try that I get a class cast exception: cannot be cast to org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate
Config :
<bean id="jmsErf" class="org.apache.camel.component.jms.JmsComponent">
<property name="jmsOperations" ref="myJmsTemplate" />
<property name="preserveMessageQos" value="true"/>
<property name="explicitQosEnabled" value="false"/>
<property name="testConnectionOnStartup" value="true"/>
<!--property name="useMessageIDAsCorrelationID" value="true" / WARNING! Do not use this as we need to copy only in the beginning not everywhere -->
<property name="transactionManager" ref="jpaTransactionManager" />
<property name="transacted" value="true" />
</bean>
<bean name="myJmsTemplate" class="blabla.MyJmsTemplate">
<property name="connectionFactory">
<bean class="jms.MQConnectionFactory">
<property name="queueManagerName" value="${Queue.My.manager}" />
<property name="throwOnInvalidMessageProperty" value="false" />
</bean>
</property>
</bean>
Sample class I created
MyJmsTemplate extends org.springframework.jms.core.JmsTemplate implements
org.springframework.jms.core.JmsOperations { .. no code :)
Why I'm trying jmsOperations:
I just need to have original JMSPriority maintained. Yes I did try preserveQoS explicitQoS [various combinations of enablingetc.. it either sets all priority to 4; or priority remains zero despite setting eg=6 priority]. by creating my own jmsOperations and explictly transfering JMSPriority value.
Exception trace:
Caused by: org.apache.camel.FailedToCreateProducerException: Failed to
create Producer for endpoint:
Endpoint[jmsErf://queue:MQDEV.MYQ.ERROR]. Reason:
java.lang.ClassCastException: blabla.MyJmsTemplate cannot be cast to
org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate at
org.apache.camel.component.jms.JmsProducer.testConnectionOnStartup(JmsProducer.java:458)
at
org.apache.camel.component.jms.JmsProducer.doStart(JmsProducer.java:469)
at
org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:60)
at
org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:62)
at
org.apache.camel.impl.ProducerCache.doGetProducer(ProducerCache.java:387)
... 115 more Caused by: java.lang.ClassCastException:
bla.MyJmsTemplate cannot be cast to
org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate at
org.apache.camel.component.jms.JmsProducer.testConnectionOnStartup(JmsProducer.java:447)
... 119 more
Can anyone point me to jmsOptions usage in camel?
What Camel version do you use?
You should use a custom messageConverter if you want to map to/from JMS messages yourself.
And the JMSPriority ought to be preserved if you set preserveMessageQos=true.

Resources