What's the difference between "direct:" and to() in Apache Camel? - apache-camel

The DirectComponent documentation gives the following example:
from("activemq:queue:order.in")
.to("bean:orderServer?method=validate")
.to("direct:processOrder");
from("direct:processOrder")
.to("bean:orderService?method=process")
.to("activemq:queue:order.out");
Is there any difference between that and the following?
from("activemq:queue:order.in")
.to("bean:orderServer?method=validate")
.to("bean:orderService?method=process")
.to("activemq:queue:order.out");
I've tried to find documentation on what the behaviour of the to() method is on the Java DSL, but beyond the RouteDefinition javadoc (which gives the very curt "Sends the exchange to the given endpoint") I've come up blank :(

In the very case above, you will not notice much difference. The "direct" component is much like a method call.
Once you start build a bit more complex routes, you will want to segment them in several different parts for multiple reasons.
You can, for instance, create "sub routes" that could be reused among multiple routes in your Camel context. Much like you segment out methods in regular programming to allow reusability and make code more clear. The same goes for sub routes using, for instance the direct component.
The same approach can be extended. Say you want multiple protocols to be used as endpoints to your route. You can use the direct endpoint to create the main route, something like this:
// Three endpoints to one "main" route.
from("activemq:queue:order.in")
.to("direct:processOrder");
from("file:some/file/path")
.to("direct:processOrder");
from("jetty:http://0.0.0.0/order/in")
.to("direct:processOrder");
from("direct:processOrder")
.to("bean:orderService?method=process")
.to("activemq:queue:order.out");
Another thing is that one route is created for each "from()" clause in DSL. A route is an artifact in Camel, and you could do certain administrative tasks towards it with the Camel API, such as start, stop, add, remove routes dynamically. The "to" clause is just an endpoint call.
Once starting to do some real cases with somewhat complexity in Camel, you will note that you cannot get too many "direct" routes.

Direct Component is used to name the logical segment of the route. This is similar process to naming procedures in structural programming.
In your example there is no difference in message flow. In the terms of structural programming, we could say that you make a kind of inline expansion to your route.

Another difference is Direct component doesn't has any thread pool, the direct consumer process method is invoked by the calling thread of direct producer.

Mainly its used for break the complex route configuration like in java we used to have method for reusability. And also by configuring threads at direct route we can reduce the work for calling thread .

from(A).to(B).to(OUT)
is chaining
A --- B --- OUT
But
from(A ).to( X)
from(B ).to( X)
from( X).to( OUT )
where X is a direct:?
is basically like a join
A
\____ OUT
/
B
obviously these are different behaviours, and with the second you could implement anylogic you wanted, not just a serial chain

Related

How to perform Camel routes with different exchanges synchronously?

I have some synchronous Camel routes with:
from("file:...")
...
.to("direct:next1")
from("direct:next1")
...
Now I'd like to run another route with a different exchange synchronously:
from("file:local/A")
...
.to("file:remote/A")
.to("direct:next2")
from("file:remote/A") // direct:next2 ?
...
How can I achieve this?
First off - the elephant in the room. Both of your file routes are going to start and run asynchronously by default because there is no dependency between those two routes at an EIP level to tell one to fire after the other.
There are two ways to solve this (e.g. to force an interdependency between the routes):
Require local/A to start the remote/A route (and to not attempt to restart the route if it's running.
Allow remote/A to poll for the file at given intervals.
Chain-starting the routes is a more sophisticated function of Camel and it allows you to precisely define the lifecycle of routes at your leisure. In this case, after your local/A file route finishes consuming, it would start up the remote/A route.
For that we can leverage the Control Bus EIP which allows us to control the lifecycle of routes directly.
from("file:local/A")
.routeId("localA")
.process(aProcessor)
.to("controlbus:route?routeId=remoteA&action=start");
from("file:remote/A")
.routeId("remoteA")
.autoStartup(false)
.process(aDifferentProcessor)
.to("controlbus:route?routeId=remoteA&action=suspend&async=true");
Polling is probably the most straightforward approach and it doesn't require much in the way of finickiness. Either the file exists or it doesn't when you go to process it, and you can choose to wait for a specific period of time when that file appears again.
from("file:local/A")
.routeId("localA")
.process(aProcessor);
from("file:remote/A?delay=2m")
.routeId("remoteA")
.process(aDifferentProcessor);
}
My preference would be to poll at a fixed interval or on a cron schedule, simply because it doesn't feel like you'd be gaining true synchronicity with either approach. You get the power to decide what fires when, but it's not 100% synchronous like direct routes.

Camel aggregation from two queues in Java DSL

I have two queues which having same type of objects in them. I want to aggregate them into a single queue through java DSL. Could anyone tell me if this is possible? If so, any code references?
If I understand your question correctly, it is possible to do such a thing.
If you need just to drive them into a single route (without any aggregations, enrichments, etc.) you can just proceed with this piece of code:
from('direct:queue1')
.to('direct:start');
from('direct:queue2')
.to('direct:start');
from('direct:start')
//there goes your processing
If you need to aggregate them later on, use Aggregator. Or you can use example from java-addict301's answer if it solves your case.
I believe this may be doable in Camel using the Content Enricher pattern.
Specifically, the following paradigm can be used to retrieve a message from one queue (where direct:start is) and enrich it with a message from the second queue (where direct:resource is). The combined message can then be built in your AggregationStrategy implementation class.
AggregationStrategy aggregationStrategy = ...
from("direct:start")
.enrich("direct:resource", aggregationStrategy)
.to("direct:result");
from("direct:resource")

Camel route with two MQs in it

I have a flow that I've defined using camel but I ended up using 6+ routes to accomplish what I wanted. Is there a way to do this with one or fewer than 4 routes?
I've outlined the routes below. The first one reads a message (containing an ID) from MQ1 and produces N-messages (expected to be in thousands) in MQ2 based on what it finds in a database for that one ID (db is not shown here). The messages produced in MQ2 have a type field defined, and based on that the choice element filters the messages to put them in the right MQ. Then each MQ(3,4,5) is processed by it's own processor (ProcessorMQ3,4,5). Once that's done, they output the result of the processing to MQ6 and ProcessorMQ6 reads the result and updates the database (also not shown).
Route 1: [Start]--->[MQ1]--->[ProcessorMQ1]--->[MQ2]
Route 2: [MQ2]--->[Choice]--->[MQ3,MQ4,MQ5 based on header value]
Route 3: [MQ3]--->[ProcessorMQ3]--->[MQ6]
Route 4: [MQ4]--->[ProcessorMQ4]--->[MQ6]
Route 5: [MQ5]--->[ProcessorMQ5]--->[MQ6]
Route 6: [MQ6]--->[ProcessorMQ6]--->[End]
Is there a way to do this using one route or am I doing this correctly? I will need to introduce 10 more "types" so the range MQ3-5 will increase by 10.
As far as I can see, your route design looks better now. Why do you want to minimise ? It will complicate your exception handling at the least.
I would always prefer to create micro routes which are functionally independent to each other, that way its makes life easier to write exception handling & unit test cases in a better way. (Even it is very good for refactoring, in the future if you want to move these routes to its own unit of deployment)
Yes, you are doing it in a correct way !
Cheers

Best approach to extend a Camel Route

We have lots of routes which do common stuff. I would like to move that stuff into a Base Route and add/overwrite functionality (e.g. adding system dependent headers, doing system dependent enrichments, etc) in the extension.
What is a good approach for that? Would it make sense to use the AdviceWithRouteBuilder since I saw only examples where it is used in unit tests?
Are there other ideas?
Thanks
Yusuf
You can do "sub routes". I have found them very useful for doing common tasks.
Create something like this inside a "CommonRoutes" route builder:
// Example
from("direct:extractCommonMetadata")
.setHeader("orderid").xpath("/data/orderid")
.setHeader("customer").xpath("/data/customer")
from("direct:enrichWithCommonStuff")
.enrich("foo:baz")
Then you can simply do this in your various routes:
from("foo:bar")
.inOut("direct:extractCommonMetadata")
.inOut("direct:enrichWithCommonStuff
.foo("bar")
from("bar:foo")
.inOut("direct:extractCommonMetadata")
.to("the little house on the hill");
The overhead of using the direct protocol is very low and a good way to break out common functionality.
If you use Java then its just java, and you can create a base RouteBuilder class, and do some shared stuff in the configure method, and call super.configure() from extended classes.

Camel # route steps vs memory/performance

It might be a silly question, but say I have a hughe message that I want to process with Camel. How will the number of steps in my route affect the memory usage? Does camel deep copy my message payload for every step in the route, even if the DSL-step only reads from the message or does it do something smart here?
Is it better to keep the route down and do things in a "hughe" bean for large messages or not?
This is an example route that does various things, but not changing the payload.
from("foo:bar")
.log(..)
.setProperty(..)
.setHeader(..)
.log(..)
.choice()
.when(simple(... ) )
.log(..)
.to(..)
.when(simple(..))
.log(..)
.to(..)
.end()
from my understanding, for a simple pipelined route like this, an Exchange is created containing the body once and passed along each step in the route. Other EIPs do cause the Exchange to be copied though (like multicast, wiretap, etc)...
as well, if you have steps along the route which interface with external resources which could result in any type of copy/clone/conversion/serialization of the body unnecessarily, then you might use something like the claim check pattern to reduce this.
The camel exchange is the same through the route the message objects are copied or recereated in the steps. The body is just referenced though. So normally you should not have a problem.
This is handled by each camel processor individually though. So some of the processors may copy the body. Typically this is the case when the processor really works on the body. So in this case it can not be avoided.

Resources