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 01717cb CAMEL-16861: Cleanup and update EIP docs 01717cb is described below commit 01717cbeedcc8caa6691a05c711965c48b6f50fa Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Oct 12 15:06:52 2021 +0200 CAMEL-16861: Cleanup and update EIP docs --- .../docs/modules/eips/pages/return-address.adoc | 63 +++--- .../main/docs/modules/eips/pages/rollback-eip.adoc | 235 ++++++--------------- 2 files changed, 96 insertions(+), 202 deletions(-) diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/return-address.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/return-address.adoc index fa35d98..a25f784 100644 --- a/core/camel-core-engine/src/main/docs/modules/eips/pages/return-address.adoc +++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/return-address.adoc @@ -3,56 +3,59 @@ Camel supports the http://www.enterpriseintegrationpatterns.com/ReturnAddress.html[Return Address] from the xref:enterprise-integration-patterns.adoc[EIP -patterns] by using the `JMSReplyTo` header. +patterns]. + +How does a replier know where to send the reply? image::eip/ReturnAddressSolution.gif[image] -For example when using xref:components::jms-component.adoc[JMS] with InOut the component will -by default return to the address given in `JMSReplyTo`. +The request message should contain a Return Address that indicates where to send the reply message. -*Requestor Code* +Camel supports Return Address by messaging xref:components::index.adoc[Components] +that provides this functionality such as the xref:components::jms-component.adoc[JMS] +component via the `JMSReplyTo` header. -[source,java] ----- -getMockEndpoint("queue:bar").expectedBodiesReceived("Bye World"); - -template.sendBodyAndHeader("direct:start", "World", "JMSReplyTo", "queue:bar"); ----- +== Example -*Route Using the Fluent Builders* +In the example below we send a message to the JMS cheese queue using `InOut` mode, this means +that Camel will automatically configure the `JMSReplyTo` header with a temporary queue as the Return Address. [source,java] ---- -from("direct:start").to("activemq:queue:foo?preserveMessageQos=true"); - -from("activemq:queue:foo").transform(body().prepend("Bye ")); - -from("activemq:queue:bar?disableReplyTo=true").to("mock:bar"); +from("direct:foo") + .to(ExchangePattern.InOut, "jms:queue:cheese"); ---- -*Route Using the Spring XML Extensions* +And in XML [source,xml] ---- <route> - <from uri="direct:start"/> - <to uri="activemq:queue:foo?preserveMessageQos=true"/> + <from uri="direct:foo"/> + <to pattern="InOut" uri="jms:queue:cheese"/> </route> +---- -<route> - <from uri="activemq:queue:foo"/> - <transform> - <simple>Bye ${in.body}</simple> - </transform> -</route> +You can also specify a named reply queue with the `replyTo` option (instead of a temporary queue). +When doing so then `InOut` mode is implied: + +[source,java] +---- +from("direct:foo") + .to("jms:queue:cheese?replyTo=myReplyQueue"); +---- +And in XML + +[source,xml] +---- <route> - <from uri="activemq:queue:bar?disableReplyTo=true"/> - <to uri="mock:bar"/> + <from uri="direct:foo"/> + <to uri="jms:queue:cheese?replyTo=myReplyQueue"/> </route> ---- -For a complete example of this pattern, see this -https://github.com/apache/camel/blob/main/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsInOnlyWithReplyToAsHeaderTest.java[junit -test case] +== See Also + +See the related xref:requestReply-eip.adoc[Request Reply] EIP. diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/rollback-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/rollback-eip.adoc index 25a70dd..a433da2 100644 --- a/core/camel-core-engine/src/main/docs/modules/eips/pages/rollback-eip.adoc +++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/rollback-eip.adoc @@ -2,199 +2,90 @@ :doctitle: Rollback :shortname: rollback :description: Forces a rollback by stopping routing the message -:since: +:since: :supportlevel: Stable -Camel recommends supporting the -http://www.enterpriseintegrationpatterns.com/TransactionalClient.html[Transactional -Client] from the xref:enterprise-integration-patterns.adoc[EIP patterns] -using spring transactions. +The Rollback EIP is used for marking an xref:latest@manual:ROOT:exchange.adoc[Exchange] +to rollback and stop continue routing the message. -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. +== Options +// eip options: START +include::partial$eip-options.adoc[] +// eip options: END -Configuration of Redelivery +== Using Rollback -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. +We want test message for some conditions and force a rollback if a message may be faulty. -You should use the -http://camel.apache.org/maven/current/camel-spring/apidocs/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 Java DSL we can do: -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. +[source,java] +---- +from("direct:start") + .choice().when(body().contains("error")) + .rollback("That do not work") + .otherwise() + .to("direct:continue"); +---- -You first define needed object in the spring configuration. +And in XML DSL: [source,xml] --------------------------------------------------------- -<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager"> - <property name="connectionFactory" ref="jmsConnectionFactory" /> -</bean> -<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> - <property name="brokerURL" value="tcp://localhost:61616"/> -</bean> --------------------------------------------------------- - -Then you look them up and use them to create the JmsComponent. - -[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); +<route> + <from uri="direct:start"/> + <choice> + <when> + <simple>${body} contains 'error'</simple> + <rollback message="That do not work"/> + </when> + <otherwise> + <to uri="direct:continue"/> + </otherwise> + </choice> +</route> ---- -== Options -// eip options: START -include::partial$eip-options.adoc[] -// eip options: END +When Camel is rolling back, then a `RollbackExchangeException` is thrown with the caused message "That do not work". -=== Transaction Policies +=== Marking for Rollback only -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 under the covers for declaring the transaction -demarcation to use. So you will need to add something like the following -to your spring xml: +When a message is rolled back, then Camel will by default throw a `RollbackExchangeException` +to cause the message to fail and rollback. -[source,xml] --------------------------------------------------------- -<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> - <property name="transactionManager" ref="jmsTransactionManager"/> -</bean> -<bean id="PROPAGATION_REQUIRES_NEW" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> - <property name="transactionManager" ref="jmsTransactionManager"/> - <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/> -</bean> --------------------------------------------------------- - -Then in your -http://camel.apache.org/maven/current/camel-spring/apidocs/org/apache/camel/spring/SpringRouteBuilder.html[SpringRouteBuilder], -you just need to create new SpringTransactionPolicy objects for each of -the templates. +This behavior can be modified to only mark for rollback, and not throw the exception. [source,java] ---- -public void configure() { - ... - Policy required = bean(SpringTransactionPolicy.class, "PROPAGATION_REQUIRED")); - Policy requirenew = bean(SpringTransactionPolicy.class, "PROPAGATION_REQUIRES_NEW")); - ... -} +from("direct:start") + .choice().when(body().contains("error")) + .markRollbackOnly() + .otherwise() + .to("direct:continue"); ---- -Once created, you can use the Policy objects in your processing routes: -[source,java] +And in XML DSL: + +[source,xml] ---- - // Send to bar in a new transaction -from("activemq:queue:foo").policy(requirenew).to("activemq:queue:bar"); -// Send to bar without a transaction. -from("activemq:queue:foo").policy(notsupported).to("activemq:queue:bar"); +<route> + <from uri="direct:start"/> + <choice> + <when> + <simple>${body} contains 'error'</simple> + <rollback markRollbackOnly="true"/> + </when> + <otherwise> + <to uri="direct:continue"/> + </otherwise> + </choice> +</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 -https://github.com/apache/camel/blob/main/components/camel-spring/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. -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. - -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.https://github.com/apache/camel/blob/main/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/springTransactionalClientDataSourceMinimalConfiguration.xml[springTransactionalClientDataSourceMinimalConfiguration]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.https://github.com/apache/camel/blob/main/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/springTransactionalClientDataSourceMinimalConfiguration.xml[springTransactionalClientDataSourceMinimalConfiguration]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 https://github.com/apache/camel/blob/main/components/camel-jms/src/test/java/org/apache/camel/component/jms/tx/TransactionMinimalConfigurationTest.java[TransactionMinimalConfigurationTest.java] the destination is a mock endpoint. - -First 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.https://github.com/apache/camel/blob/main/components/camel-jms/src/test/resources/org/apache/camel/component/jms/tx/TransactionMinimalConfigurationTest.xml[TransactionMinimalConfigurationTest.xml]And -then we configure our routes. Notice that all we have to do is mark the -route as transacted using the *transacted* -tag.https://github.com/apache/camel/blob/main/components/camel-jms/src/test/resources/org/apache/camel/component/jms/tx/TransactionMinimalConfigurationTest.xml[TransactionMinimalConfigurationTest.xml] - -== 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. - -== Using multiple routes with different propagation behaviors - -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.https://github.com/apache/camel/blob/main/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/MixedTransactionPropagationTest.xml[MixedTransactionPropagationTest.xml]Then -in the routes you use transacted DSL to indicate which of these two -propagations it -uses.https://github.com/apache/camel/blob/main/components/camel-spring/src/test/java/org/apache/camel/spring/interceptor/MixedTransactionPropagationTest.java[MixedTransactionPropagationTest.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. +Then no exception is thrown, but the message is marked to rollback and stopped continue routing. + +=== Using Rollback with Transactions + +Rollback can be used together with xref:transactional-client.adoc[transactions]. +For more details see xref:transactional-client.adoc[Transaction Client] EIP. +