Database transactions between multiple camel routes - apache-camel

How transactions works in Camel routes with Spring DSL and one of the route throws Exception?
If routeB throws an exception, how exception will be propagated back to routeA.
If exception is thrown in routeB, I could see transactionalErrorHandler is handling the exception and rolling back the transaction.
Setting the errorHandlerRef="noErrorHandler" on routeB does not help.
How can we do this?
My Camel routes definition:
<route id="routeA">
<from uri="direct-vm:endpointA" />
<transacted />
<to uri="direct-vm:endPointB" />
<bean ref="beanA" method="save" />
<onException>
<exception>java.lang.Exception>
<handled><constant>true</constant></handled>
<bean ref="beanA" method="handleError" />
<rollback markRollbackOnly="true" />
</onException>
</route>
<route id="routeB">
<from uri="direct-vm:endPointB" />
<throwException ref="ex"/>
</route>

In camel the transacted command is simply a wrapper for the Spring TransactionTemplate, in that it will enlist the route in a transaction supplied by the PlatformTransactionManager. The only configuration option you get on the org.apache.camel.spring.spi.SpringTransactionPolicy is the propagation behaviour, so handling rollbacks etc must be done within the transacted route.
In this case you should catch the exception from route B, if it gets to the error handler then it is too late.
<route id="routeA">
<from uri="direct-vm:endpointA" />
<transacted/>
<doTry>
<to uri="direct-vm:endPointB" />
<doCatch>
<exception>java.lang.Exception</exception>
<bean ref="beanA" method="handleFail"/>
</doCatch>
<doFinally>
<bean ref="beanA" method="save" />
</doFinally>
</doTry>
</route>
<route id="routeB">
<from uri="direct-vm:endPointB" />
<throwException ref="ex"/>
</route>

Related

How to setBody in camelcontext route from the xml recieved to pojo class?

<from uri="direct:validating-route" />
<setBody>
<simple>${body}</simple>
</setBody>
<log message="Mapping request from source to destination"
loggingLevel="INFO" />
<to
uri="dozer:transformValidateWrapperType?mappingFile=mappings/validate-mapping.xml&targetModel=in.map.loc.elements.ValidateWrapperType" />
<log message="Completed MApping and sending request"
loggingLevel="INFO" />
<setBody>
<simple>${body}</simple>
</setBody>
<setHeader headerName="operationNamespace">
<constant>http://in.map.com/functions/tele/ap</constant>
</setHeader>
<to uri="cxf:bean:validateOutside" />
The body passed after the set body is null. This is the route for a SOAP request. How to get In the body of the exchange with the needed classes object in the camel route itself?

Send property to seda queue

I have a route from which I am trying to call a seda queue. I wanted to use a property which has been set in my current route to the seda queue. The below is the piece of code that I have been used, but it doesn't seems to be working as expected.
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route1">
<!-- Method initialize the JobDetails class with values jobName="jobTest" and jobMode="mode1" -->
<bean ref="jobDetails" method="createJobDetails"/>
<to uri="activemq:queue:myqueue?disableReplyTo=true" />
</route>
<route id="route2">
<from uri="activemq:queue:myqueue" />
<convertBodyTo type="my.package.JobDetails" />
<setProperty propertyName="JOB_DETAILS">
<simple>${body}</simple>
</setProperty>
<recipientList>
<simple>direct-vm:testDirect-${property.JOB_DETAILS.jobName}</simple>
</recipientList>
</route>
</camelContext>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route3">
<from uri="direct-vm:testDirect-jobTest" />
<!-- Some business logic based on the job mode-->
<setProperty propertyName="JOB_MODE">
<simple>mode1</simple>
</setProperty>
<to uri="seda:testSeda?blockWhenFull=true" />
</route>
<route id="sedaRoute">
<from uri="seda:testSeda?concurrentConsumers=5" />
<log message="Message from firstRoute: ${property.JOB_MODE}" />
<!-- Perform some business logic based on the job mode -->
</route>
</camelContext>
Appreciated help!!!

Is there a way in Apache Camel by which a lock can be obtained and released by a route on another route

I am looking out for a way by which a route can obtain and release a lock on another route, Below is my code snippet and I am looking for a solution where snmp-trap-route and snmp-timer-route can obtain an exclusive lock on business-logic-route and while one is processing other should wait till it completion.
<route id="snmp-trap-route">
<from uri="snmp:{{snmp.host}}:{{snmp.port}}?protocol=udp&type=TRAP" />
<to uri="direct:snmp-main-route"/>
<route id="snmp-timer-route">
<from uri="timer://pulse?fixedRate=true&period=1000" />
<to uri="direct:snmp-main-route"/>
<route id="snmp-main-route">
<from uri="direct:snmp-main-route" />
<choice>
<when>
<simple>${property[batch.ended]} == true </simple>
<to uri="direct:transacted-endpoint" />
</when>
<when>
<simple>${property[batch.started]} == true </simple>
<to uri="direct:business-logic-endpoint" />
</when>
<otherwise>
<to uri="direct:business-logic-endpoint" />
</otherwise>
</choice>
</route>
<route id="business-logic-route">
<from uri="direct:business-logic-endpoint"/>
<setProperty propertyName="route.name">
<constant>TestRoute</constant>
</setProperty>
<process ref="messageMultiplierProcessor" />
<process ref="calculatedFieldsProcessor" />
<process ref="tableProcessor" />
</route>
<route id="transacted-route">
<from uri="direct:transacted-endpoint"/>
<transacted/>
<to uri="direct:business-logic-endpoint"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<rollback markRollbackOnly="true"/>
</onException>
</route>
You could reach the same result by using a queue.
A queue processes the messages 1-by-1. You can use the Seda component to achieve this if your route is in the same camelcontext. Otherwise you can use activemq
<route id="snmp-trap-route">
<from uri="snmp:{{snmp.host}}:{{snmp.port}}?protocol=udp&type=TRAP" />
<to uri="seda:business-logic-route"/>
<route id="snmp-timer-route">
<from uri="timer://pulse?fixedRate=true&period=1000" />
<to uri="seda:business-logic-route"/>
<route id="business-logic-route">
<from uri="seda:business-logic-endpoint"/>
<setProperty propertyName="esq.route.name">
<constant>TestRoute</constant>
</setProperty>
<process ref="messageMultiplierProcessor" />
<process ref="calculatedFieldsProcessor" />
This way the next message in the business-logic-route will only be processed after the business-logic-route is finished. Maybe this is what you are looking for.

How to define ActiveMQ component in format of JMS Component in Apache Camel

I'm using Apache Camel 2.11.1. It seems that both xml definitions are not equivalent in Camel:
First definition:
<bean id="amq" class="org.apache.activemq.camel.component.ActiveMQComponent"
p:brokerURL="tcp://localhost:61616" p:transacted="true"
p:cacheLevelName="CACHE_CONSUMER" p:concurrentConsumers="20"
p:maxConcurrentConsumers="500" p:idleConsumerLimit="10" />
Second definition:
<bean id="amq" class="org.apache.camel.component.jms.JmsComponent"
p:configuration-ref="jmsConfig" p:transacted="true" p:cacheLevelName="CACHE_CONSUMER" />
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"
p:connectionFactory-ref="nakedConnectionFactory"
p:concurrentConsumers="20" p:maxConcurrentConsumers="500"
p:idleConsumerLimit="10" />
<bean id="nakedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
Since the first definition works well on the following route, but the second doesn't.
<route>
<from uri="amq:example.MyQueue" />
<setHeader headerName="myRoutingSlipHeader">
<constant>amq:one#amq:two#amq:three#amq:four</constant>
</setHeader>
<log message="Makan" />
<setExchangePattern pattern="InOut" />
<routingSlip uriDelimiter="#">
<header>myRoutingSlipHeader</header>
</routingSlip>
<setExchangePattern pattern="InOnly" />
<log message="End: ${body}" />
</route>
<route>
<from uri="amq:one" />
<to uri="bean:helloBean?method=stepOne" />
</route>
<route>
<from uri="amq:two" />
<to uri="bean:helloBean?method=stepTwo" />
</route>
<route>
<from uri="amq:three" />
<to uri="bean:helloBean?method=stepThree" />
</route>
<route>
<from uri="amq:four" />
<to uri="bean:helloBean?method=stepFour" />
</route>
The second component definition causes hang during execution.
Seems to work fine for me. I did have to override the spring version with the created archetype. But I used this and it worked fine.
Please find my example project here :
https://github.com/jimternet/camel-activemq
<broker xmlns="http://activemq.apache.org/schema/core" useJmx="true"
persistent="false">
<transportConnectors>
<transportConnector uri="tcp://localhost:61616" />
</transportConnectors>
</broker>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:src/data?noop=true" />
<to uri="activemq:personnel.records" />
</route>
<route>
<from uri="activemq:personnel.records" />
<log message="${body}" />
<choice>
<when>
<xpath>/person/city = 'London'</xpath>
<to uri="file:target/messages/uk" />
</when>
<otherwise>
<to uri="file:target/messages/others" />
</otherwise>
</choice>
</route>
</camelContext>
<bean id="activemq" class="org.apache.camel.component.jms.JmsComponent"
p:configuration-ref="jmsConfig" p:transacted="true" p:cacheLevelName="CACHE_CONSUMER" />
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"
p:connectionFactory-ref="nakedConnectionFactory"
p:concurrentConsumers="20" p:maxConcurrentConsumers="500"
p:idleConsumerLimit="10" />
<bean id="nakedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />

Camel XSLT message routing issue

I am routing a message from queue->converting it using xslt and forwarding it to another queue, log.
My Camel configuration is as follows:
<camelContext xmlns="http://camel.apache.org/schema/spring"
streamCache="true">
<route>
<from uri="jms:queue:TradeEventsToESBQueue" />
<multicast>
<to uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
</multicast>
</route>
<route>
<from uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="log:output?showAll=true" />
</route>
<route>
<from uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
<to uri="jms:queue:TradeValuationStartQueue1?jmsMessageType=Text" />
<to uri="log:output?showAll=true" />
</route>
</camelContext>
On running the program i get the following error:
Caused by: org.apache.camel.ExpectedBodyTypeException: Could not
extract IN message body as type: interface javax.xml.transform.Source
body is: null at
org.apache.camel.builder.xml.XsltBuilder.getSource(XsltBuilder.java:482)[64:org.apache.camel.camel-core:2.10.1]
at
org.apache.camel.builder.xml.XsltBuilder.process(XsltBuilder.java:125)[64:org.apache.camel.camel-core:2.10.1]
at
org.apache.camel.impl.ProcessorPollingConsumer.receive(ProcessorPollingConsumer.java:58)[64:org.apache.camel.camel-core:2.10.1]
Any ideas what is causing this issue?
You should not use the XSLT component in that manner.
You should particularly not try to use "from" with XSLT, but rather use it in combination with any internal transport component (directly for the instance). I think the following will do what you want.
<route>
<from uri="jms:queue:TradeEventsToESBQueue" />
<multicast>
<to uri="direct:confirmation"/>
<to uri="direct:valuation"/>
</multicast>
</route>
<route>
<from uri="direct:confirmation"/>
<to uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="log:output?showAll=true" />
</route>
<route>
<from uri="direct:valuation"/>
<to uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
<to uri="jms:queue:TradeValuationStartQueue1?jmsMessageType=Text" />
<to uri="log:output?showAll=true" />
</route>

Resources