I am new to Apache Camel. I have setup my application to use Apache Camel using XML based configuration. My configuration contains multiple routes which have similar set of steps. I was trying to find if there a way to place common or repeating parts of these different routes in one place and refer them from routes instead of repeating them again and again ?
for e.g. in my below camel route configuration, route 2 is repeating few steps from route 1. So is there a way to extract the common steps of the route 1 and route 2 and then refer extracted part from route 1 and 2?
<context:property-placeholder location="classpath:quartz.properties" />
<context:component-scan base-package="com"></context:component-scan>
<camel:route>
<camel:from uri="quartz://deadlines/SDGWD?cron=15+34+14+?+*+MON-SUN+*" />
<camel:onCompletion>
<camel:to uri="seda:checkAnyPendingDeadlines"/>
</camel:onCompletion>
<camel:to uri="bean:sdgwdNotifier" />
<camel:choice>
<camel:when>
<camel:method ref="deadlineHandler" method="canProcessDeadline" />
<camel:bean ref="deadlineHandler" method="prepareDeadline" />
<camel:bean ref="sdgwdProcessor" method="initiateMessageProcessing" />
<camel:bean ref="schedulerXdrTransformer" method="marshall" />
<camel:to uri="wmq:SU.SES" />
<camel:bean ref="sdgwdProcessor" method="waitForAcknowledgment" />
<camel:bean ref="sdgwdProcessor" method="afterMessageProcessed" />
<camel:bean ref="deadlineHandler" method="onDeadlineProcessingCompletion" />
</camel:when>
<camel:otherwise>
<camel:bean ref="deadlineHandler" method="enqueDeadline" />
</camel:otherwise>
</camel:choice>
</camel:route>
<camel:route>
<camel:from uri ="seda:checkAnyPendingDeadlines"/>
<camel:onCompletion>
<camel:to uri ="seda:checkAnyPendingDeadlines"/>
</camel:onCompletion>
<camel:to uri="bean:deadlineHandler?method=getNextProcessableDeadline" />
<camel:choice>
<camel:when>
<camel:method ref="deadlineHandler" method="canProcessDeadline" />
<camel:bean ref="deadlineHandler" method="prepareDeadline" />
<camel:choice>
<camel:when>
<camel:simple>${body.deadline} == ${type:settlementcontrol.scheduler.model.Deadline.SDGW} </camel:simple>
<camel:bean ref="sdgwdProcessor" method="initiateMessageProcessing" />
<camel:bean ref="schedulerXdrTransformer" method="marshall" />
<camel:to uri="wmq:SU.SES" />
<camel:bean ref="sdgwdProcessor" method="waitForAcknowledgment" />
<camel:bean ref="sdgwdProcessor" method="afterMessageProcessed" />
<camel:bean ref="deadlineHandler" method="onDeadlineProcessingCompletion" />
</camel:when>
</camel:choice>
</camel:when>
<camel:otherwise>
<camel:bean ref="deadlineHandler" method="enqueDeadline" />
</camel:otherwise>
</camel:choice>
</camel:route>
Thanks,
Vaibhav
Is common route, which contains repeating part of your flow, sufficient? If so, then create something like this:
<camel:route id="myCommonPartOfFlow">
<camel:from uri="direct-vm:common-in"/>
[common part]
</camel:route>
You can invoke your sub (myCommonPartOfFlow) route from your main routes now:
<camel:to uri="direct-vm:common-in/>
You can either use a direct component to create subroutes that factor out common parts or split your routes so that the common routes have their own route and then other routes can send messages to the common route. For example, if you have two routes that do the following processes "Process A" -> "Process B" -> "Process C" and "Process D" -> "Process B" -> "Process E" then you can separate Process B into its own route and do the following:
from("jms:queue:processB") - "Process C" -> end()
Process A -> set Header "JMSReplyTo", jms:queue:processC -> to("jms:queue:processB")
Process C -> set Header "JMSReplyTo", jms:queue:processE -> to("jms:queue:processB")
The for the sake of brevity I used Java DSL but the same can be done with XML DSL. I also used "process A" and the like to abstract what could be multiple steps in the route. The concepts of linking the routes is the same no matter what the process is. The advantage to this approach is that it allows federation of "process B" to handle the extra load and distribute processing around your infrastructure. Once you go to Asynchrounous programming, your capabilities rise quite a bit.
Related
I have a camel route that goes through a series of processors which each call some service. If processor 1 fails gracefully, I no longer want to call processors 2-5, but I do want to call consolidateResponse. The same for all the other processors. Is there a best practices way of achieving this without throwing an exception on failures?
<camel:routeContext id="myRouteRouteContext">
<camel:route id="my-route-route">
<camel:from uri="{{camel.uri.myRoute}}" />
<camel:process ref="{{bean.processor.processor1}}" />
<camel:process ref="{{bean.processor.processor21}}" />
<camel:process ref="{{bean.processor.processor3}}" />
<camel:process ref="{{bean.processor.processor4}}" />
<camel:process ref="{{bean.processor.processor5}}" />
<!-- Stringfy response object into a JSon text response -->
<camel:process ref="{{bean.processor.consolidateResponse}}" />
<!-- All catch exception handler -->
<camel:onException>
<camel:exception>java.lang.Exception</camel:exception>
<camel:handled>
<camel:constant>true</camel:constant>
</camel:handled>
<camel:to uri="{{camel.uri.error}}" />
</camel:onException>
</camel:route>
</camel:routeContext>
I think try catch is best solution also it is common programming solution also camel also has stop
https://camel.apache.org/manual/try-catch-finally.html
from("direct:start")
.choice()
.when(body().contains("Hello")).to("mock:hello")
.when(body().contains("Bye")).to("mock:bye").stop()
.otherwise().to("mock:other")
.end()
.to("mock:result");
I need to fetch multiple files from a directory using camel pollEnrich. When I searched for this implementation, I found out that camel pollEnrich will pick up only one file at a time. But it was given that we can fetch multiple files by repeating pollEnrich by loop. How can this be correctly implemented?
Sample code for current implementation below:
<camel:route id="fileRoute">
<camel:from uri="jetty:{{file.api.endpoint}}" />
<camel:convertBodyTo type="java.lang.String"/>
<camel:unmarshal ref="json" />
<camel:choice>
<camel:when>
<camel:simple>Condition check for validating the request</camel:simple>
<camel:pollEnrich timeout="5000">
<camel:simple>file:{{file.input.dir}}?preMove={{file.inprogress.dir}}&move={{file.processed.dir}}&filter=#fileFilter</camel:simple>
</camel:pollEnrich>
<!-- Logic -->
</camel:when>
<camel:otherwise>
<!-- Invalid request -->
</camel:otherwise>
</camel:choice>
</camel:route>
I also tried loop doWhile aproach, but it didn't work out for me. My requirement is to get all the files from a directory using camel pollEnrich.
Sample code for loop doWhile approach:
<camel:route id="fileRoute">
<camel:from uri="jetty:{{file.api.endpoint}}" />
<camel:convertBodyTo type="java.lang.String"/>
<camel:unmarshal ref="json" />
<camel:loop doWhile="true">
<camel:simple>Condition check for validating the request</camel:simple>
<camel:pollEnrich timeout="5000">
<camel:simple>file:{{file.input.dir}}?preMove={{file.inprogress.dir}}&move={{file.processed.dir}}&filter=#fileFilter</camel:simple>
</camel:pollEnrich>
<!-- Logic -->
</camel:loop>
</camel:route>
Is it possible to set a header in one route and then use it again later in another route in the same context?
For example, I have a route that sets a header as so:
<setHeader headerName="clientId">
<xpath>/Alarm/clientid/text()</xpath>
</setHeader>
The route uses Dead Letter Channel to send the message to an error route in the same context when delivery fails and I would like to use the clientId header I defined above in the message the error route sends, but currently calling the header returns nothing (an empty string I assume).
It should work , I am using camel 2.15.1 ,check the code below , if you run it you should see the header
<bean id="mybean" class="java.lang.Exception" />
<camel:camelContext xmlns="http://camel.apache.org/schema/spring"
trace="false">
<camel:errorHandler id="deadLetterErrorHandler"
type="DeadLetterChannel" deadLetterUri="direct:b">
</camel:errorHandler>
<camel:route>
<camel:from uri="timer:foo?repeatCount=1" />
<camel:setHeader headerName="myheader">
<camel:simple>Sundar</camel:simple>
</camel:setHeader>
<camel:to uri="direct:a" />
</camel:route>
<camel:route errorHandlerRef="deadLetterErrorHandler">
<camel:from uri="direct:a" />
<camel:throwException ref="mybean"></camel:throwException>
</camel:route>
<camel:route>
<camel:from uri="direct:b" />
<camel:log message="${in.header.myheader}"/>
</camel:route>
</camel:camelContext>
It should print a log like below
24 Feb 2016 19:09:47,707 route3 INFO Sundar
Could you please help me to resolve the problem I am facing?
When forwarding message from one queue to another ( no message seems to be published ) ,
steps:
timer publish current date to queue 'inbox'- this part working
from 'inbox' to 'outbox' - this is not working
from 'outbox' to print console
Follows the spring xml.
<route>
<camel:from
uri="rabbitmq://localhost:5672/outBox?sername=guest&password=guest" />
<camel:to uri="stream:out" />
</route>
<route>
<camel:from
uri="rabbitmq://localhost:5672/inbox?username=guest&password=guest" />
<camel:to
uri="rabbitmq://localhost:5672/outBox?username=guest&password=guest" />
</route>
<route>
<camel:from uri="timer:foo?period=10" />
<setBody>
<simple>${body}Message at ${date:now:yyyy-MM-dd HH:mm:ss}</simple>
</setBody>
<to
uri="rabbitmq://localhost:5672/inbox?username=guest&password=guest" />
</route>
According to http://camel.apache.org/rabbitmq.html the URI format is
rabbitmq://hostname[:port]/exchangeName?[options]
Thus inbox in your code is not queue name but exchange.
Use queue= option to specify the queue
I have written a camel route that polls a file folder, picks up request, checks for memory consumption on server (in a java file). If its below threshold it drops the request on a JMS queue otherwise it throws an exception and picks it again for processing.
What i need to do is that when exception is thrown i need to delay processing for a configurable amount of time say 15 mins. This will give some time for server to stabilize instead of keeping it polling unnecessarily.
I am using errorHandler mechanism of camel however it doesnt seem to work. Camle keeps on picking up the request without any delay. Please help with this issue.
Below is the bundle context snapshot:
<camel:onException>
<camel:exception>java.lang.Exception</camel:exception>
<camel:redeliveryPolicy backOffMultiplier="500" />
<camel:log message="Default error handler was called"></camel:log>
</camel:onException>
<camel:route>
<!-- Reading from REST url -->
<camel:from uri="<my url>" />
<!-- If else loop -->
<camel:choice>
<camel:when>
<camel:xpath>Some path</camel:xpath>
<!-- Parsing OrderNumber and OrderVersion-->
<camel:log message="Recieved request ${headers.OrderNumber}-${headers.OrderVersion}.xml"/>
<camel:setHeader headerName="OrderNumber">
<xpath>Some path</xpath>
</camel:setHeader>
<camel:setHeader headerName="OrderVersion">
<camel:xpath>Some path</camel:xpath>
</camel:setHeader>
<!-- Request being put in file folder -->
<to
uri="file:data/inbox?fileName=${header.OrderNumber}-${header.OrderVersion}.xml"
pattern="InOut" />
</camel:when>
<!-- For all other requests put on queue -->
<camel:otherwise>
<camel:log message="Request ${headers.OrderNumber}-${headers.OrderVersion}.xml directly sent to queue"/>
<to uri="my queue"
pattern="InOut" />
</camel:otherwise>
</camel:choice>
</camel:route>
<camel:route errorHandlerRef="errorHandler">
<!-- Route to put message from folder to JMS queue if memory consumption is below limit-->
<camel:from uri="file:data/inbox"/>
<camel:process ref="checkMemoryConsumption"/>
<camel:convertBodyTo type="String" />
<camel:log message="Sucessfully processing service order ${headers.OrderNumber}-${headers.OrderVersion}.xml"/>
<to uri="my queue"
pattern="InOut" />
</camel:route>
Did you try redeliveryDelay of redeliveryPolicyProfile?
Below policy profile will retry 3 times with the delay of 1000mS between each try.
<redeliveryPolicyProfile id="myRedeliveryProfile"
maximumRedeliveries="3"
redeliveryDelay="1000" allowRedeliveryWhileStopping="false"
retryAttemptedLogLevel="INFO" />
Read more on here
By making below modification in my bundle context (bundle context displayed above), re-delivery policy kicked in and seems to do the trick.