Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

Transaction Oriented Endpoints (Camel Toes) like JMS support using a transaction for both inbound and outbound message exchanges. Endpoints that support transactions will participate in the current transaction context that they are called from.

...

The redelivery in transacted mode is not handled by Camel but by the backing system (the transaction manager). In such cases you should resort to the backing system how to configure the redelivery.

You should use the SpringRouteBuilder to setup the routes since you will need to setup the spring context with the TransactionTemplates TransactionTemplates that will define the transaction manager configuration and policies.

For inbound endpoint to be transacted, they normally need to be configured to use a Spring PlatformTransactionManager. In the case of the JMS component, this can be done by looking it up in the spring context.

You first define needed object in the spring configuration.

...

Then you look them up and use them to create the JmsComponent.

...

...

Transaction Policies

Outbound endpoints will automatically enlist in the current transaction context. But what if you do not want your outbound endpoint to enlist in the same transaction as your inbound endpoint? The solution is to add a Transaction Policy to the processing route. You first have to define transaction policies that you will be using. The policies use a spring TransactionTemplate to declare under the covers for declaring the transaction demarcation to use. So you will need to add something like the following to your spring xml:

...

...

Then in your SpringRouteBuilder, you just need to create new SpringTransactionPolicy objects for each of the templates.

...

...

Once created, you can use the Policy objects in your processing routes:

...

OSGi Blueprint

If you are using OSGi Blueprint then you most likely have to explicit declare a policy and refer to the policy from the transacted in the route.

...

Transaction Policies improvements in Camel 1.4

In Camel 1.4 we have eased the syntax to setup the transaction polices directly on the SpringTransactionPolicy object:

...

And the Java DSL is a bit simpler now:

...

then refer to "required" from the route:

...

Database Sample

In this sample we want to ensure that two endpoints is under transaction control. These two endpoints inserts data into a database.
The sample is in its full as a unit test.

First of all we setup the usual spring stuff in its configuration file. Here we have defined a DataSource to the HSQLDB and a most importantly
the importantly the Spring DataSoruce DataSource TransactionManager that is doing the heavy lifting of ensuring our transactional policies. You are of course free to use any
of any of the Spring based TransactionManangerTransactionManager, eg. if you are in a full blown J2EE container you could use JTA or the WebLogic or WebSphere specific managers.We

As we use the required new convention over configuration we do not need to configure a transaction policy that we define as the PROPOGATION_REQUIRED spring bean. And as last we have our book service bean that does the business logic
and inserts data in the database as our core business logic.

...

bean, so we do not have any PROPAGATION_REQUIRED beans. All the beans needed to be configured is standard Spring beans only, eg. there are no Camel specific configuration at all.{snippet:id=e1|lang=xml|url=

...

camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/

...

In our Camel route that is Java DSL based we setup the transactional policy, wrapped as a Policy.

Wiki Markup
{snippet:id=e1|lang=java|url=activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/TransactionalClientDataSourceTest.java}

springTransactionalClientDataSourceMinimalConfiguration.xml}Then we are ready to define our Camel routes. We have two routes: 1 for success conditions, and 1 for a forced rollback condition.
This is after all based on a unit test.

...

Notice that we mark each route as transacted using the transacted tag.{snippet:id=e2|lang=

...

xml|url=

...

camel/trunk/components/camel-spring/src/test/

...

resources/org/apache/camel/spring/interceptor/

...

springTransactionalClientDataSourceMinimalConfiguration.

...

As its a unit test we need to setup the database and this is easily done with Spring JdbcTemplate

Wiki Markup
{snippet:id=e5|lang=java|url=activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/TransactionalClientDataSourceTest.java}

And our core business service, the book service, will accept any books except the Donkeys.

Wiki Markup
{snippet:id=e1|lang=java|url=activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/BookService.java}

Then we are ready to fire the tests. First to commit condition:

Wiki Markup
{snippet:id=e3|lang=java|url=activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/TransactionalClientDataSourceTest.java}

And lastly the rollback condition since the 2nd book is a Donkey book:

...

xml}That is all that is needed to configure a Camel route as being transacted. Just remember to use the transacted DSL. The rest is standard Spring XML to setup the transaction manager.

JMS Sample

In this sample we want to listen for messages on a queue and process the messages with our business logic java code and send them along. Since its based on a unit test the destination is a mock endpoint.

This time we want to setup the camel context and routes using the Spring XML syntax.
Wiki MarkupFirst we configure the standard Spring XML to declare a JMS connection factory, a JMS transaction manager and our ActiveMQ component that we use in our routing.{snippet:id=e1|lang=xml|url=activemq/camel/trunk/components/camel-jms/src/test/resources/org/apache/camel/component/jms/tx/JMSTransactionalClientTestTransactionMinimalConfigurationTest.xml}.Since the rest is standard XML stuff its nothing fancy now for the reader:
Wiki MarkupAnd then we configure our routes. Notice that all we have to do is mark the route as transacted using the transacted tag.{snippet:id=e2|lang=xml|url=activemq/camel/trunk/components/camel-jms/src/test/resources/org/apache/camel/component/jms/tx/JMSTransactionalClientTestTransactionMinimalConfigurationTest.xml}

...

When a route is marked as transacted using transacted Camel will automatic use the TransactionErrorHandler as Error Handler. It supports basically the same feature set as the DefaultErrorHandler, so you can for instance use Exception Clause as well.

Integration Testing with Spring

...

An Integration Test here means a test runner class annotated @RunWith(SpringJUnit4ClassRunner.class).

When following the Spring Transactions documentation it is tempting to annotate your integration test with @Transactional then seed your database before firing up the route to be tested and sending a message in. This is incorrect as Spring will have an in-progress transaction, and Camel will wait on this before proceeding, leading to the route timing out.

Instead, remove the @Transactional annotation from the test method and seed the test data within a TransactionTemplate execution which will ensure the data is committed to the database before Camel attempts to pick up and use the transaction manager. A simple example can be found on GitHub.

Spring's transactional model ensures each transaction is bound to one thread. A Camel route may invoke additional threads which is where the blockage may occur. This is not a fault of Camel but as the programmer you must be aware of the consequences of beginning a transaction in a test thread and expecting a separate thread created by your Camel route to be participate, which it cannot. You can, in your test, mock the parts that cause separate threads to avoid this issue.

Using multiple routes with different propagation behaviors

Available as of Camel 2.2
Suppose you want to route a message through two routes and by which the 2nd route should run in its own transaction. How do you do that? You use propagation behaviors for that where you configure it as follows:

  • The first route use PROPAGATION_REQUIRED
  • The second route use PROPAGATION_REQUIRES_NEW

This is configured in the Spring XML file:{snippet:id=e1|lang=xml|url=Our business logic is set to handle the incomming messages and fail the first two times. When its a success it responds with a Bye World message.
Wiki Markup{snippet:id=e2|lang=java|url=activemq/camel/trunk/components/camel-jmsspring/src/test/javaresources/org/apache/camel/componentspring/jmsinterceptor/tx/JMSTransactionalClientTestMixedTransactionPropagationTest.java}.And our unit test is tested with this java code. Notice that we expect the Bye World message to be delivered at the 3rd attempt.
Wiki Markupxml}Then in the routes you use transacted DSL to indicate which of these two propagations it uses.{snippet:id=e1|lang=java|url=activemq/camel/trunk/components/camel-jmsspring/src/test/java/org/apache/camel/componentspring/jmsinterceptor/tx/JMSTransactionalClientTestMixedTransactionPropagationTest.java}Notice how we have configured the onException in the 2nd route to indicate in case of any exceptions we should handle it and just rollback this transaction. This is done using the markRollbackOnlyLast which tells Camel to only do it for the current transaction and not globally.

See Also

...

...

Using This Pattern