If route threw exception and handled is set to true, only first processor in doFinally is executed - apache-camel

I've got a Camel Blueprint definition with two Camel contexts containing one route each.
First contexts route is invoked and in turn calls the route of the second context. Now if in the second route an Exception is thrown and the onException sets handled=true, in the first routes doFinally block only the first processor is invoked.
Here is my Blueprint definition:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<bean id="myException" class="java.lang.RuntimeException">
<argument value="Booom" />
</bean>
<camelContext id="firstContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="firstRoute">
<from uri="direct-vm:start"/>
<doTry>
<to uri="log:FIRST_TRY"/>
<to uri="direct-vm:generateException"/>
<to uri="log:SECOND_TRY"/>
<doFinally>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</doFinally>
</doTry>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
<camelContext id="secondContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
<route id="secondRoute">
<from uri="direct-vm:generateException"/>
<throwException ref="myException"/>
</route>
</camelContext>
</blueprint>
Only the <to uri="log:FIRST_FINALLY"/> gets printed out. I cannot see the <to uri="log:SECOND_FINALLY"/>. Am I missing something here? Any help is appreciated.
I am using Camel 2.10.6 inside Apache Servicemix 4.5.2.
Regards
Dominik

You can consider using multicast [1] as a workaround for this issue.
<doFinally>
<multicast>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</multicast>
</doFinally>
This is not the same as pipeline processing of course, but in some cases doFinally block can just send two messages independently.
[1] http://camel.apache.org/multicast

Related

How to make Camel pattern="InOut" work with IBM MQ

As described here:
setting ReplyToQ attribute of MQMD of IBM MQ request message with Camel
I managed to set ReplyToQ in MQMD of request properly in Camel Route, but I can't get the response in the same Route, with the IBM MQ Endpoint ("to") that I would like to use both for output (of request) and for input (of response), because it is matching wrong Correlation ID, like this:
The OUT message was not received within: 20000 millis due reply message with correlationID: Camel-ID-MYPC-62418-1518179436629-0-5 not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-62418-1518179436629-0-4]
Namely, responding application sets CorrelationID (in MQMD) to the MessageID (from MQMD of the received request). How to make this scenario work?
I tried with useMessageIDAsCorrelationID, but this doesn't change much the result (responses are not consumed). Another try was to set MessageID of request to some fixed value (that would not be final solution), but I can't even do that. I added this:
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
but this only sets CorrelationID, and I still get such things:
The OUT message was not received within: 20000 millis due reply message with correlationID: abcdefg not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-65151-1518190285422-0-3]
Complete route definition:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean class="org.apache.camel.component.jms.JmsComponent" id="websphere">
<property name="connectionFactory">
<bean class="com.ibm.mq.jms.MQConnectionFactory">
<property name="transportType" value="1"/>
<property name="hostName" value="hostname"/>
<property name="port" value="port"/>
<property name="queueManager" value="qmgr_name"/>
<property name="channel" value="channel_name"/>
</bean>
</property>
</bean>
<!-- Define a traditional camel context here -->
<camelContext id="camel" useBreadcrumb="false" xmlns="http://camel.apache.org/schema/spring">
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request.txt"/>
<log id="route-log" message=">>> ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1&mdWriteEnabled=true&mdReadEnabled=true</constant>
</setHeader>
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?replyTo=REPLYQ"/>
</route>
</camelContext>
</beans>
OK, this simple code actually works as explained here:
http://camel.apache.org/correlation-identifier.html
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request464.txt"/>
<log id="route-log-request" message="request: ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?useMessageIDAsCorrelationID=true&replyTo=REPLYQ"/>
<log id="route-log-response" message="response: ${body}"/>
</route>
It prints out neatly response body to console output.
I don't know why I was under impression that it doesn't work when I first tried it. So, to summarize both questions, the catch is in using useMessageIDAsCorrelationID and replyTo parameters in uri of a queue, as well as pattern="InOut" parameter of <to> endpoint.

Retrieve/Preserve the file - if there is an exception caught by catch block when using "try.. catch" with onexception in Apache Camel

In below route , i am using both "try..catch" and onexception features .
If there is any exception in my bean or the lines outside try block..file is moved to ".error" since i used moveFailed option but during exception which are caught by catch block generated by lines of try block,file is lost..
1.when server is down
2.when connection timeout
Please suggest the ways to preserve the file during such failures/exceptions
<camelContext streamCache="false" useMDCLogging="true" id="XXX" xmlns="http://camel.apache.org/schema/spring">
<streamCaching spoolDirectory="/tmp/cachedir/#camelId#/#uuid#" spoolUsedHeapMemoryThreshold="70" bufferSize="65536" anySpoolRules="true" id="myCacheConfig"/>
<onException >
<description>An exception was encountered.</description>
<exception>java.lang.Exception</exception>
<log message="somemessage" loggingLevel="INFO"/>
</onException>
<route >
<from uri="file:D:/Users/Desktop/src?moveFailed=.error" />
<transform>
<method ref="somebean" method="somemethod"/>
</transform>
<doTry>
<to uri="file:D:/Users/Desktop/src" />
<log message="transfered successfully" />
<doCatch>
<exception>java.lang.Exception</exception>
<log message="Exception occurred and Stopping the Route"/>
<to uri="controlbus:route?routeId=XXXX&action=stop"/>
<log message="Stopped the Route:XXX"/>
</doCatch>
</doTry>
</route>
Please suggest the ways to preserve the file during such failures/exceptions
Rethrow the exception in your docatch-block to reach the onException block.
<doCatch>
<exception>java.lang.Exception</exception>
<log message="Exception occurred and Stopping the Route"/>
<to uri="controlbus:route?routeId=XXXX&action=stop&async=true"/> // async=true to resume/finish this route
<log message="Stopped the Route:XXX"/>
<throwException exception="java.lang.Exception"/> // dont know the exact syntax in xml dsl
</doCatch>

How to create a timer based camel polling route?

i created a route that is supposed to read from an OPC-UA endpoint. The read operation should be performed every second, based on a timer. Every example i found shows that the route can only have one from item. My route looks like this:
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<to uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>
When i deploy the route, it gets called every second, but it writes to the endpoint, since the call is declared in a to element. How can i turn this into a read? I could not find a solution so far. Thanks!
Use the .enrich() to turn it into a read when you want to read in the middle of a route.
http://camel.apache.org/content-enricher.html
For your example something similar to (not tested):
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<enrich uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>

Can we use multiple mutlicast in apache camel?

I have a requirement where i want to use mutlicast in Apache Camel for than single time in a single route. i.e Multicast within a multicast.
<routeContext id="myRoute" xmlns="http://camel.apache.org/schema/spring">
<route id="myRouteId">
<from uri="activemq:queue:{{XXXX.queue}}" />
....
<multicast parallelProcessing="true">
<pipeline>
##everything working fine here
</pipeline>
<pipeline>
<multicast>
<pipeline>
<log message="Inserting in database now"></log>
<transform>
<method ref="insertBean" method="myBatchInsertion"></method>
</transform>
<choice>
<when>
<simple>${in.header.myCount} == ${properties:batch.size} </simple>
<to uri="sql:{{sql.core.insertMyQuery}}?batch=true"></to>
<log message="Inserted rows ${body}"></log>
</when>
</choice>
</pipeline>
</multicast>
</pipeline>
</multicast>
</route>
</routeContext>
Is it possible to do that?
When i am trying to do that, my program is not getting executed successfully.
Is the unsuccessful execution is a result of mulitple multicast?
Can anybody help?
I got the reference from following link:
http://camel.apache.org/multicast.html
Why do you use pipeline? It "is" pipeline by default.
Also all the log and transform and choice statements can be put outside of the multicast. And since you are generating your endpoints dynamically, put the values in a header and use recipientlist for dynamic endpoints. Multicast is for hard-coded endpoints. Here is an example:
<route>
<from uri="direct:a" />
<!-- use comma as a delimiter for String based values -->
<recipientList delimiter=",">
<header>myHeader</header>
</recipientList>
</route>
http://camel.apache.org/recipient-list.html

Apache Camel Java dsl tool

Is there any tool available that can convert java DSL to XML route or vice versa.
I want to convert the following XML route into Java DSL
<route id="test">
<from uri="file://{{VAR_DATA_PATH}}/test/xml"/>
<multicast>
<choice>
<when>
<xpath>/bookinfo</xpath>
<doTry>
<to uri="downloadBook"/>
<marshal ref="xstream-utf8"/>
<to uri="another URI"/>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>false</constant>
</handled>
<to uri="3rd URI"/>
</doCatch>
</doTry>
</when>
<when>
<xpath>somePath</xpath>
<to uri="4th URI" />
<to uri="5th URI"/>
</when>
</choice>
<to uri="6th URI" />
</multicast>
</route>
From Java DSL to XML, it's fairly easy. You can use Hawtio or karaf's "route-info" command. Even though the routes are in Java DSL, when you view them it would be XML.
I'm not aware of the other way around (from XML to Java) but it's not difficult at all to do it yourself.

Resources