Camel - using end() - java

Is it a best practice to use end() for every route?
The following works:
from("jms:some-queue")
.beanRef("bean1", "method1")
.beanRef("bean2", "method2")
and so is this,
from("jms:some-queue")
.beanRef("bean1", "method1")
.beanRef("bean2", "method2")
.end()

No! Calling end() to "end" a Camel route is not a best practice and won't yield any functional benefits.
For common ProcessorDefinition functions like to(), bean() or log() it simply leads to a call to the endParent() method, which as one can see from the Camel source code, does very little:
public ProcessorDefinition<?> endParent() {
return this;
}
The call to end() is required, once you have called processor definitions that start their own block and most prominently includes TryDefinitions aka doTry() and ChoiceDefinitions aka choice(), but also well know functions like split(), loadBalance(), onCompletion() or recipientList().

You must use the end() when you want to end specific route which is in action. It can be best explained in example of onCompletion
from("direct:start")
.onCompletion()
// this route is only invoked when the original route is complete as a kind
// of completion callback
.to("log:sync")
.to("mock:sync")
// must use end to denote the end of the onCompletion route
.end()
// here the original route contiues
.process(new MyProcessor())
.to("mock:result");
Here you must put end to indicate operation related to onCompletion is done and you are resuming operation on the original rote.
This becomes more lucid and easy to understand if you are using XML DSL instead of java. Because in this you don't have to use end tag. The closing tags of XML will take care of writing end(). Below is exactly same example written in XML DSL
<route>
<from uri="direct:start"/>
<!-- this onCompletion block will only be executed when the exchange is done being routed -->
<!-- this callback is always triggered even if the exchange failed -->
<onCompletion>
<!-- so this is a kinda like an after completion callback -->
<to uri="log:sync"/>
<to uri="mock:sync"/>
</onCompletion>
<process ref="myProcessor"/>
<to uri="mock:result"/>

Related

Execute #Handler method in multi-thread

Need to execute #Handler(import org.apache.camel.Handler) method in multi-threading environment. below is my current code and camelroute.xml file. Any Idea or suggestion would be appreciable.
#Component("messagehandler")
public class HandleMessages {
#Handler
public void handle(String body, Exchange exchange) throws Exception {
// do some business operation
}
}
<?xml version="1.0" encoding="UTF-8"?>
<routes xmlns="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<route id="IncomingRoute">
<from uri="someSourceURL" />
<to uri="bean:messagehandler" />
<log message="Message Body - ${body}" />
</route>
</routes>
In general terms, thread safety is all about execution – that's all. A given method / routine / piece of code is thread-safe if it guarantees the manipulation of shared data (data structures, etc.) safely in a way that multiple threads don't corrupt that data.
So it really depends on how you structure the execution of a given workflow; and that's the same for any other piece of code you can think of.
Since you are using Apache Camel, take a look at their threading model. If I remember correctly, you would have to define your routes / workflows in such a way they run concurrently by using parallelProcessing (CC EIP), a custom thread pool, or using staged event-driven architecture (SEDA); at that point you would need to take care about what you do in the handlers (or any other "processor(s)" that handle shared data), otherwise you should be OK.
Another thing you need to think about is how Camel uses its routing engine to route messages synchronously or asynchronously; be aware that synchronicity and MEP affects the threading model.

on-demand/trigger based camel route

I'm trying to implement the following JMS message flow using camel routes:
there is a topic published on external message broker. My program is listening for messages on this topic. Each incoming message triggers specific route to be executed - ONE TIME ONLY (some kind of ad-hoc, disposable route). This route is supposed to move messages between queues within my internal message broker based on some selector (get all messages from queue A matching given selector and move them to queue B). I'm only starting with camel and so far I figured out just the first part - listening for messages on topic:
<bean id="somebroker" class="org.apache.camel.component.jms.JmsComponent"
p:connectionFactory-ref="rmAdvisoriesConnectionFactory"/>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<endpoint id="jms" uri="somebroker:topic:sometopic"/>
<route id="routeAdvisories">
<from ref="jms"/>
<to>???</to>
</route>
</camelContext>
Can you suggest a destination for these advisory messages? I need to read some of their JMS properties and use these values to construct JMS selector that will be used for the "move messages" operation. But I have no idea how to declare and trigger this ad-hoc route. It would be ideal if I could define it within the same camelContext using only Spring DSL. Or alternatively, I could route advisories to some java method, which would be creating and executing this ad-hoc routes. But if this isn't possible, I'll be grateful for any suggestion.
Thanks.
As far as I understand, it will be useful to use the 'selector' option, in your JMS consumer route, for example:
from("activemq:queue:test?selector=key='value1'").to("mock:a");
from("activemq:queue:test?selector=key='value2'").to("mock:b");
Maybe, another option is to implement some routes based on 'Content Based Router Pattern" through "choice" option. You can find more info here: http://camel.apache.org/content-based-router.html
I hope it helps.
I couldn't get it working the way I intended, so I had to abandon my original approach. Instead of using camel routes to move messages between queues (now I'm not sure camel routes are even intended to be used this way) I ended up using ManagedRegionBroker - the way JMX operation "moveMatchingMessagesTo" is implemented - to move messages matching given selector.

How to use Camel route in separate XML file

I have two separate Camel routes defined in separate XML files. Call them route A and B.
I would like to direct route B to first call route A, before passing the result to route B.
How should I go about doing so? So far I am looking at the direct DSL.
Thank you.
The solution is to define the secondary route, and link both routes together using vm-direct.
When called, objects stored as variables in secondary route can be referenced by the earlier route, i.e. the routes are executed sequentially and pend on the secondary route's completion.
Like so:
Primary route:
<To uri="direct-vm:....>
<!-- variables if stored by secondary route available here -->
Secondary route:
<Route>
<From uri="direct-vm:.....>
</Route>

Using Time to live with Camel framework in Java

I am using doing integration work with Camel and using the HTTP endpoint as a proxy to route certain messages to an HTTP endpoint. I have my route configured to use my custom error handler which places failed messages in a queue that I specified (Dead Letter Channel pattern).
<route>
...
<to uri="direct:MessageTypeGuaranteed"/>
</route>
<route errorHandlerRef="MyCustomErrorHandler">
<from uri="direct:MessageTypeGuaranteed">
<to uri="http://dummyUri?throwExceptionOnFailure=true"/>
</route>
When anything fails to get delivered to my http endpoint, it's being added to my custom queue ("CustomFailedMessageQueue"), and I have a separate route that attempts to retry these messages:
<route>
<from uri="jms:queue:CustomFailedMessageQueue">
<to uri="direct:MessageTypeGuaranteed"/>
</route>
What I'd like to do is to be able to specify that I only want a message to live say for 10 seconds. So I am trying to set time to live on my http destination itself.
For example, I have a processor that does something like this:
exchange.getIn().setHeader(Exchange.HTTP_URI, "http://localhost/nodeserver?timeToLive=10000");
However, I think I have misunderstood the documentation. The timeToLive option is only valid when passing it to the jms component, correct? In other words, if I want to make use of time to live with this end point, I will need to do that handling myself in a processor, correct?
Yes TimeToLive is an option from the JMS spec that the Camel JMS components support. That options has no meaning for other components such as HTTP.
It seems like you may want to use a filter EIP and discard the message if its to old, and you can use a java method etc to implement some code that figures out if its to old or not, and return a boolean
public boolean isNotToOld(Exchange exchange) {
...
return true // to accept and process the message
}
See more about the filter eip here
http://camel.apache.org/message-filter
And you can use it in a route something a like
<from uri="direct:MessageTypeGuaranteed">
<filter>
<method ref="myBean" method="isNotToOld"/>
<to uri="http://dummyUri?throwExceptionOnFailure=true"/>
</filter>

How can I merge the response from an external service call with the original message in camel

From a logical perspective this is the kind of routing behaviour I wish to implement:
I want to be able to merge the response of an external service with the original request.
I have been able to implement this using multicasting, an aggregator, and a mock endpoint but I was wondering if there is a cleaner way. My current implementation looks like this:
<multicast strategyRef="serviceAggregator" stopOnException="false">
<to uri="mock:foo" />
<to uri="http://0.0.0.0:9999/service/?throwExceptionOnFailure=false" />
</multicast>
<camel:to uri="log:uk.co.company.aggregated?showAll=true" />
<to uri="http://0.0.0.0:9999/anotherService/
The part I particularly don't like is using a mock endpoint but I also don't think that this is a very readable way to express the above diagram. So I was wondering if there was a more elegant way of doing this?
I suggest to read about the EIP patterns, for example the content enricher
http://camel.apache.org/content-enricher.html
Where you can merge the reply message with the request message.
Mind the Content Enricher has 2 modes
- enrich
- pollEnrich
Make sure to notice the difference, from the docs in the link above.
<route>
<from uri="...">
<enrich uri="http://0.0.0.0:9999/service/?throwExceptionOnFailure=false" strategyRef="serviceAggregator"/>
<to uri="log:uk.co.company.aggregated?showAll=true" />
<to uri="http://0.0.0.0:9999/anotherService/>
...
</route>
And yes you diagram is showing splitter, but the sample code is using multicast EIP.
You could simply store the original message in a header or property and later do some merge in a bean. Using the header and the current body.
.setHeader("orig", body())
.to("externalService")
.bean(new MyMergeBean())

Categories