This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 877dfd3  CAMEL-16861: Cleanup and update EIP docs
877dfd3 is described below

commit 877dfd30d7f321fd5ac8371b7a0c9141cc1e2327
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Oct 22 11:56:02 2021 +0200

    CAMEL-16861: Cleanup and update EIP docs
---
 .../modules/eips/pages/transactional-client.adoc   | 352 +++++++++------------
 1 file changed, 146 insertions(+), 206 deletions(-)

diff --git 
a/core/camel-core-engine/src/main/docs/modules/eips/pages/transactional-client.adoc
 
b/core/camel-core-engine/src/main/docs/modules/eips/pages/transactional-client.adoc
index e1f35c4..057493a 100644
--- 
a/core/camel-core-engine/src/main/docs/modules/eips/pages/transactional-client.adoc
+++ 
b/core/camel-core-engine/src/main/docs/modules/eips/pages/transactional-client.adoc
@@ -1,60 +1,101 @@
 = Transactional Client
 
-Camel recommends supporting the
+Camel supports the
 
http://www.enterpriseintegrationpatterns.com/TransactionalClient.html[Transactional
 Client] from the xref:enterprise-integration-patterns.adoc[EIP patterns]
-using spring transactions.
+using JTA transactions.
+
+How can a client control its transactions with the messaging system?
 
 image::eip/TransactionalClientSolution.gif[image]
 
-Transaction Oriented Endpoints like xref:components::jms-component.adoc[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.
+Use a Transactional Client—make the client’s session with the messaging system 
transactional so that the client can specify transaction boundaries.
 
-== Configuration of Redelivery
+Transactions are supported by Spring Transactions and also with a JTA 
Transaction Manager.
 
-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.
+Traditionally a JTA Transaction Manager are included in JEE application 
servers.
+However, when running microservice applications with Spring Boot, or Quarkus, 
then
+a 3rd-party JTA transaction manager can be embedded and used.
 
-You should use the
-https://www.javadoc.io/doc/org.apache.camel/camel-spring/current/org/apache/camel/spring/SpringRouteBuilder.html[SpringRouteBuilder]
-to setup the routes since you will need to setup the spring context with
-the TransactionTemplates that will define the transaction manager
-configuration and policies.
+In Camel transactions are supported by JMS messaging components:
 
-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.
+- xref:components::activemq-component.adoc[ActiveMQ]
+- xref:components::jms-component.adoc[JMS]
+- xref:components::sjms-component.adoc[Simple JMS]
+- xref:components::sjms2-component.adoc[Simple JMS 2.x]
 
-You first define needed object in the spring configuration.
+And all the SQL database components, such as:
 
-[source,xml]
-----
-<bean id="jmsTransactionManager" 
class="org.springframework.jms.connection.JmsTransactionManager">
-    <property name="connectionFactory" ref="jmsConnectionFactory" />
-</bean>
+- xref:components::elsql-component.adoc[ElSQL]
+- xref:components::jdbc-component.adoc[JDBC]
+- xref:components::jpa-component.adoc[JPA]
+- xref:components::sql-component.adoc[SQL]
+- xref:components::mybatis-component.adoc[MyBatis]
 
-<bean id="jmsConnectionFactory" 
class="org.apache.activemq.ActiveMQConnectionFactory">
-    <property name="brokerURL" value="tcp://localhost:61616"/>
-</bean>
-----
+== Understanding Transactions
+
+A transaction is a series of events. The start of a transaction is often named 
begin, and
+the end is commit (or rollback if the transaction isn’t successfully 
completed).
 
-Then you look them up and use them to create the JmsComponent.
+If you were to write in Java a locally managed transaction then it could be 
something like:
 
 [source,java]
 ----
-  PlatformTransactionManager transactionManager = (PlatformTransactionManager) 
spring.getBean("jmsTransactionManager");
-  ConnectionFactory connectionFactory = (ConnectionFactory) 
spring.getBean("jmsConnectionFactory");
-  JmsComponent component = 
JmsComponent.jmsComponentTransacted(connectionFactory, transactionManager);
-  component.getConfiguration().setConcurrentConsumers(1);
-  ctx.addComponent("activemq", component);
+TransactionManager tm = ...
+Transaction tx = tm.getTransaction();
+try {
+    tx.begin();
+    // code here under transaction
+    tx.commit();
+} catch (Exception e) {
+    tx.rollback();
+}
 ----
 
-[[TransactionalClient-TransactionPolicies]]
-== Transaction Policies
+You start the transaction using the `begin` method. Then you have a series of 
events to
+do whatever work needs to be done. At the end, you either `commit` or 
`rollback` the
+transaction, depending on whether an exception is thrown.
+
+You may already be familiar with this principle, and transactions in Camel use 
the
+same principle at a higher level of abstraction. In Camel transactions, you 
don’t invoke
+begin and commit methods from Java code; you use declarative transactions, 
which can
+be configured using Java code or in XML files. Camel doesn't reinvent the 
wheel and
+implement a transaction manager, which is a complicated piece of technology to 
build.
+Instead, Camel uses APIs from either `camel-spring` or `camel-jta`.
+
+=== Local vs Global Transactions
+
+TODO:
+
+=== About Spring Transactions
+
+Camel uses Spring Transaction to manage transactions via its 
`TransactionManager`
+API. Depending on the kinds of resources that are taking part in the 
transaction,
+an appropriate implementation of the transaction manager must be chosen. Spring
+offers a number of transaction managers out of the box that work for various 
local
+transactions such as JMS and JDBC. But for global transactions, you must use a 
third-party
+JTA transaction manager implementation; JTA transaction manager is provided
+by Java EE application servers. Spring doesn't offer that out of the box, only 
the necessary
+API abstract that Camel uses.
+
+=== About JTA Transactions
+
+TODO:
+
+== Using Transactions in Camel
+
+TODO:
+
+=== Transaction error handler
+
+When a route is marked as transacted using ``<transacted/>` Camel will
+automatically use `TransactionErrorHandler` as the
+xref:latest@manual:ROOT:error-handler.adoc[Error Handler].
+
+This error handler supports basically the same
+feature set as the 
xref:latest@manual:ROOT:defaulterrorhandler.adoc[DefaultErrorHandler].
+
+=== 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
@@ -105,55 +146,53 @@ from("activemq:queue:foo").policy(notsupported)
     .to("activemq:queue:bar");
 ----
 
-[[TransactionalClient-DatabaseSample]]
-== Database Sample
+== Transaction example with database
 
 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
-https://github.com/apache/camel/tree/main/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/TransactionalClientDataSourceMinimalConfigurationTest.java[unit
 test].
+https://github.com/apache/camel/tree/main/components/camel-spring-xml/src/test/java/org/apache/camel/spring/interceptor/TransactionalClientDataSourceMinimalConfigurationTest.java[unit
 test].
 
-First of all we setup the usual spring stuff in its configuration file.
+First we set up the usual spring stuff in its configuration file.
 Here we have defined a DataSource to the HSQLDB and a most
-importantly the Spring DataSource TransactionManager that is doing the
-heavy lifting of ensuring our transactional policies. You are of course
-free to use any of the Spring based TransactionManager, eg. if you are
-in a full blown J2EE container you could use JTA or the WebLogic or
-WebSphere specific managers.
+importantly the Spring `DataSourceTransactionManager` that is doing the
+heavy lifting of ensuring our transactional policies.
 
 As we use the new convention over configuration we do *not* need to
 configure a transaction policy 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.
+*standard* Spring beans only, there are no Camel specific configuration at all.
+
 [source,xml]
 ----
-    <!-- this example uses JDBC so we define a data source -->
-    <jdbc:embedded-database id="dataSource" type="DERBY">
-       <jdbc:script location="classpath:sql/init.sql" />
-    </jdbc:embedded-database>
-
-    <!-- spring transaction manager -->
-    <!-- this is the transaction manager Camel will use for transacted routes 
-->
-    <bean id="txManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
-        <property name="dataSource" ref="dataSource"/>
-    </bean>
-
-    <!-- bean for book business logic -->
-    <bean id="bookService" 
class="org.apache.camel.spring.interceptor.BookService">
-        <property name="dataSource" ref="dataSource"/>
-    </bean>
+<!-- this example uses JDBC so we define a data source -->
+<jdbc:embedded-database id="dataSource" type="DERBY">
+    <jdbc:script location="classpath:sql/init.sql" />
+</jdbc:embedded-database>
+
+<!-- spring transaction manager -->
+<!-- this is the transaction manager Camel will use for transacted routes -->
+<bean id="txManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+    <property name="dataSource" ref="dataSource"/>
+</bean>
+
+<!-- bean for book business logic -->
+<bean id="bookService" class="org.apache.camel.spring.interceptor.BookService">
+    <property name="dataSource" ref="dataSource"/>
+</bean>
 ----
 
 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.
+as transacted using the `<transacted/>` XML tag.
 
 [source,xml]
 ----
-    <camelContext xmlns="http://camel.apache.org/schema/spring";>
+<camelContext xmlns="http://camel.apache.org/schema/spring";>
+
     <route>
         <from uri="direct:okay"/>
         <!-- we mark this route as transacted. Camel will lookup the spring 
transaction manager
@@ -185,15 +224,15 @@ as transacted using the *transacted* tag.
         </setBody>
         <bean ref="bookService"/>
     </route>
-    </camelContext>
+
+</camelContext>
 ----
 
 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.
+Just remember to use `<transacted/>`. The rest is standard Spring
+XML to set up the transaction manager.
 
-[[TransactionalClient-JMSSample]]
-== JMS Sample
+== Transaction example with JMS
 
 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
@@ -207,148 +246,49 @@ use in our routing.
 
 [source,xml]
 ----
-    <!-- setup JMS connection factory -->
-    <bean id="poolConnectionFactory" 
class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" 
destroy-method="stop">
-        <property name="maxConnections" value="8"/>
-        <property name="connectionFactory" ref="jmsConnectionFactory"/>
-    </bean>
-
-    <bean id="jmsConnectionFactory" 
class="org.apache.activemq.ActiveMQConnectionFactory">
-        <property name="brokerURL" 
value="vm://localhost?broker.persistent=false&amp;broker.useJmx=false"/>
-    </bean>
-
-    <!-- setup spring jms TX manager -->
-    <bean id="jmsTransactionManager" 
class="org.springframework.jms.connection.JmsTransactionManager">
-        <property name="connectionFactory" ref="poolConnectionFactory"/>
-    </bean>
-
-    <!-- define our activemq component -->
-    <bean id="activemq" 
class="org.apache.activemq.camel.component.ActiveMQComponent">
-        <property name="connectionFactory" ref="poolConnectionFactory"/>
-        <!-- define the jms consumer/producer as transacted -->
-        <property name="transacted" value="true"/>
-        <!-- setup the transaction manager to use -->
-        <!-- if not provided then Camel will automatic use a 
JmsTransactionManager, however if you
-             for instance use a JTA transaction manager then you must 
configure it -->
-        <property name="transactionManager" ref="jmsTransactionManager"/>
-    </bean>
-----
-
-And then we configure our routes. Notice that all we have to do is mark the
-route as transacted using the *transacted* tag.
-
-[source,xml]
-----
-    <camelContext xmlns="http://camel.apache.org/schema/spring";>
-        <!-- disable JMX during testing -->
-        <jmxAgent id="agent" disabled="true"/>
-        <route>
-            <!-- 1: from the jms queue -->
-            <from uri="activemq:queue:okay"/>
-            <!-- 2: mark this route as transacted -->
-            <transacted/>
-            <!-- 3: call our business logic that is myProcessor -->
-            <process ref="myProcessor"/>
-            <!-- 4: if success then send it to the mock -->
-            <to uri="mock:result"/>
-        </route>
-    </camelContext>
-
-    <bean id="myProcessor" 
class="org.apache.camel.component.jms.tx.JMSTransactionalClientTest$MyProcessor"/>
-----
-
-=== Transaction error handler
-
-When a route is marked as transacted using *transacted* Camel will
-automatic use `TransactionErrorHandler` as the
-xref:latest@manual:ROOT:error-handler.adoc[Error Handler]. This error handler 
supports basically the same
-feature set as the 
xref:latest@manual:ROOT:defaulterrorhandler.adoc[DefaultErrorHandler],
-so you can for instance use 
xref:latest@manual:ROOT:exception-clause.adoc[Exception Clause]
-as well.
-
-[[TransactionalClient-IntegrationTestingwithSpring]]
-== 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 
https://github.com/rajivj2/example2/blob/master/src/test/java/com/example/NotificationRouterIT.java[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.
-
-[[TransactionalClient-Usingmultiplerouteswithdifferentpropagationbehaviors]]
-== Using multiple routes with different propagation behaviors
-
-*Since 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:
+<!-- setup JMS connection factory -->
+<bean id="poolConnectionFactory" 
class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" 
destroy-method="stop">
+    <property name="maxConnections" value="8"/>
+    <property name="connectionFactory" ref="jmsConnectionFactory"/>
+</bean>
 
-* The first route use `PROPAGATION_REQUIRED`
-* The second route use `PROPAGATION_REQUIRES_NEW`
+<bean id="jmsConnectionFactory" 
class="org.apache.activemq.ActiveMQConnectionFactory">
+    <property name="brokerURL" 
value="vm://localhost?broker.persistent=false&amp;broker.useJmx=false"/>
+</bean>
 
-This is configured in the Spring XML file:
+<!-- setup spring jms TX manager -->
+<bean id="jmsTransactionManager" 
class="org.springframework.jms.connection.JmsTransactionManager">
+    <property name="connectionFactory" ref="poolConnectionFactory"/>
+</bean>
 
-[source,xml]
-----
-    <bean id="PROPAGATION_REQUIRED" 
class="org.apache.camel.spring.spi.SpringTransactionPolicy">
-        <property name="transactionManager" ref="txManager"/>
-        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
-    </bean>
-
-    <bean id="PROPAGATION_REQUIRES_NEW" 
class="org.apache.camel.spring.spi.SpringTransactionPolicy">
-        <property name="transactionManager" ref="txManager"/>
-        <property name="propagationBehaviorName" 
value="PROPAGATION_REQUIRES_NEW"/>
-    </bean>
+<!-- define our activemq component -->
+<bean id="activemq" 
class="org.apache.activemq.camel.component.ActiveMQComponent">
+    <property name="connectionFactory" ref="poolConnectionFactory"/>
+    <!-- define the jms consumer/producer as transacted -->
+    <property name="transacted" value="true"/>
+    <!-- setup the transaction manager to use -->
+    <!-- if not provided then Camel will automatic use a 
JmsTransactionManager, however if you
+         for instance use a JTA transaction manager then you must configure it 
-->
+    <property name="transactionManager" ref="jmsTransactionManager"/>
+</bean>
 ----
 
-Then in the routes you use transacted DSL to indicate which of these two
-propagations it uses.
+And then we configure our routes. Notice that all we have to do is mark the
+route as transacted using the `<transacted/>` XML tag.
 
-[source,java]
+[source,xml]
 ----
-    from("direct:mixed")
-    // using required
-    .transacted("PROPAGATION_REQUIRED")
-    // all these steps will be okay
-    .setBody(constant("Tiger in Action")).bean("bookService")
-    .setBody(constant("Elephant in Action")).bean("bookService")
-    // continue on route 2
-    .to("direct:mixed2");
-
-    from("direct:mixed2")
-    // tell Camel that if this route fails then only rollback this last route
-    // by using (rollback only *last*)
-    .onException(Exception.class).markRollbackOnlyLast().end()
-    // using a different propagation which is requires new
-    .transacted("PROPAGATION_REQUIRES_NEW")
-    // this step will be okay
-    .setBody(constant("Lion in Action")).bean("bookService")
-    // this step will fail with donkey
-    .setBody(constant("Donkey in Action")).bean("bookService");
+<camelContext xmlns="http://camel.apache.org/schema/spring";>
+    <route>
+        <!-- 1: from the jms queue -->
+        <from uri="activemq:queue:okay"/>
+        <!-- 2: mark this route as transacted -->
+        <transacted/>
+        <!-- 3: call our business logic that is myProcessor -->
+        <process ref="myProcessor"/>
+        <!-- 4: if success then send it to the mock -->
+        <to uri="mock:result"/>
+    </route>
+</camelContext>
 ----
 
-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.
-

Reply via email to