It is also possible to use transactions in Apache Camel routes. Camel relies in the spring transaction abstraction so it is necessary to use the right wrapper class to make JTA transactions work.
A transactional route can look like this:
The transactional() DSl Element tells Karaf to start a transaction when the route enters the segment and commit once the route is completed successfully. In case of unhandled errors, it will roll back.
The above approach would not cover the part through where the message is received. So to make the whole route transactional, it is necessary to also configure the JMS component to do JTA transactions.
For this to work like in databases, you first need to provide a ConnectionFactory as an OSGi service that is correctly wrapped for XA and pooling.
The ConnectionFactory and the TransactionManager are referenced as OSGi services. They then need to be injected into the JMSComponent and the SpringTransactionPolicy.
<reference id="connectionFactory" interface="javax.jms.ConnectionFactory"/> <reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager"/> <bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory" ref="connectionFactory"/> <property name="transactionManager" ref="transactionManager"/> </bean> <bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="transactionManager"/> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/> </bean>
With this set-up, the JmsComponent will always receive messages inside a JTA transaction and will also participate in a JTA transaction when sending out messages.
Interestingly, the transaction manager is looked up as spring PlatformTransactionManager. This is possible as the default transaction manager in Karaf from Aries already implements this interface in addition to the plain JTA TransactionManager.