Camel: route messages based on the contents of a map - java

Currently, my code for routing messages in Camel according to a JMS message header field looks like this:
// MyRouteBuilder.java
#Override
public void configure() {
from(...)
.choice()
.when(header("type").isEqualTo("A"))
.to("proc_a:1")
.when(header("type").isEqualTo("B"))
.to("proc_b:1", "proc_b:2", "proc_b:3")
.when(header("type").isEqualTo("C"))
.to("proc_c:1", "proc_c:2")
.when(...)
.to(...) // ~15 more branches to follow
.otherwise()
.to("proc_default");
}
Dependend on the value of the type header field, there is a specific pipeline of processors that should be used in each case. As you can see, the code is not only repetitive, but also cumbersome to maintain.
There already is a dynamically created Map<String, String[]> which maps types to processors, e.g. the key B returns ["proc_b:1", "proc_b:2", "proc_b:3"]. However, I don't know how to make use of it in the scenario shown above.
I also read about the dynamic router. However, the given example didn't really help me and I don't want to add more complexitiy by having to manage the state of my routing logic or to ensure thread safety.
I'm grateful for any solution. The only requirements are that I'm stuck with Camel 2.15 and that I'm not allowed to adapt the existing processors (this especially means that the routing logic should not remove any header fields since they are needed later on).

Use dynamic to (eg toD), where you use some java method to compute the url to route to: http://camel.apache.org/how-to-use-a-dynamic-uri-in-to.html and here as well about dynamic to: http://camel.apache.org/message-endpoint.html

Related

Execute a camel route directly

I recently took over some Java code and there was a method that took in an object and based on some properties of that object, performed some processing on that object.
I was playing around with Apache Camel and was able to define a route that accomplished the same task. Where I am struggling is, how can I find the easiest way to pass an object to the route and execute the logic? What I have right now is a
producerTemplate.sendBody("direct:blah", myObject)
and the route itself defines a
from("direct:blah").process(...)
The above is working fine, albeit a little slower than before.
Is this the simplest way to replace the logic of a method? I was hoping to just be able to grab the route itself and pass an object to it for execution, but I don't see any ways to do this.
You don't necessarily need a from().process(). You can also inject an endpoint to your method. For example:
#Consume(uri = "direct:blah")
public void onFileSendToQueue(String body, #Header("CamelFileName") String name) {
LOG.info("Incoming file: {}", name);
producer.sendBody(body);
}
You can do the same for producers as well. See the Camel pojo messaging for more details.
http://camel.apache.org/pojo-messaging-example.html

Producing multiple outputs from a Camel Processor/Component

I am trying to implement a Camel Component/Processor that takes one input and produces multiple output messages, similar to a Splitter. Like Splitter, the output should go to the next processor/endpoint in the route.
I have looked at Splitter & MulticastProcessor classes in the hope that I can reuse them or use similar logic. The idea, as I understood, is to create an new Exchange for each output and emit them. To do this, I need to provide the endpoint to which output is written to. This works, if I dynamically create the end point within the Processor class; my requirement is to send the output to the end point configured in the route. That is in the route below, mycomponent needs to write (multiple times) to file:output.
<route>
<from uri="file:input"/>
<to uri="mycomponent:OrderFlow?multi.output=true"/>
<to uri="file:output" />
</route>
In case of Splitter, it is instantiated by SplitDefinition class which has access to the output Processor/Endpoint.
a) From within a Processor is it possible to access the configured Output Processor/Endpoint?
b) If not, should I be writing a ProcessorDefinition class for my processor? Any pointers on this would help.
Two solutions suggested below by Petter are,
a) Inject a Producer template
b) Use Splitter component with a method call instead of writing a new component.
I assume you have read this page.
Yes, you can send multiple exchanges from a custom processor, but not really to the next processor in the flow. As in the link above, you can decouple the component implementation by injecting a producer template with a specific destination. You can cut your route into several parts using the direct or seda transport and make your component send the messages there. This way, you can reuse the code in several routes.
This is, as you point out, done in the splitter component (among others) in Camel core. Take a look at the multicastprocessor baseclass for example. However, there processors are aware of the following processors in the route, thanks to the route builder. You custom processor is not that lucky.
You can, non the less, extract that information from the CamelContext. Get hold of your route and there you can find the processors in the route. However, that seems like overcomplicating things.
UPDATE:
Instead of trying to alter the DSL, make use of the already existing DSL and components.
.split().method("mycomponent", "OrderFlow")
Instead of emitting new exchanges, your OrderFlow method just needs to create a List<..> with the resulting messages.

How to send a message using Apache Camel?

I am trying to create a sample application hosted at "mina:tcp://localhost:9991" that sends a very simple message to a server hosted at "mina:tcp://localhost:9990".
Now admittedly I have some problems understanding how to do this. My first approach was to create a class called Message, that has two fields: String order and String host. However, I am terribly confused on how to do this.
First I tried to follow the loadbalancer-example basing myself on the ReportGenerator and create a MessageGenerator class that could create a message and return it:
http://camel.apache.org/loadbalancing-mina-example.html
However, there is a problem, I need parameters to create my Message, something that doesn't happen when creating the Report from the example:
//Message constructor
public Message(String order, String host){
//constructor stuff
}
By reading Camel in Action I know how to use beans to call methods that have no parameters, however I still do not understand how I should use them to call a method that has several parameters (Am I forced to use processors?)
Then i realized that perhaps I am complicating things a little bit and there is an easier way to send messages. So I tried another approach that resulted in a small sample of code that does not work as well. I have created a separate question for that matter:
Apache camel send a simple message
Obviously I am doing something wrong and I don't get what. So, I have 2 questions:
Manning's Camel in Action defines an Easy way and a Hard way to use beans, but I did not understand the easy way of using beans with parameters. Can someone provide an example of it?
Is there a way to send a message composed of several fields in Camel (an easy way, without processors) that does not involve using beans? If so, how?
There are several ways to sends Messages in Camel. According to the help provided in the Camel forums, the two best are:
Using beans linked to POJOS and routes (example: http://camel.apache.org/loadbalancing-mina-example.html)
Using the Producer Template (docs: http://camel.apache.org/producertemplate.html)
Hope it helps someone one day.

Apache Camel terminology subtleties

I'm trying to wrap my head around Apache Camel, and after spending some time this morning reading both the online Camel docs as well as the Javadocs, I have some questions that I can't seem to find answers for.
Is it true that all endpoints are either consumers or producers (or both)? Is it true that all processors are endpoints? Are there
any endpoints that are not processors?
What's the difference between a Message header and an Exchange? An exchange is considered to be a "message container", but how is that different from the metadata that a header would contain?
Is it typical to implement your own Message/Exchange? If so, what would be an example of doing so, and "straying" from the typical DefaultMessage and DefaultExchange?
Thanks in advance.
First things first: A good suggestion is to read the book Camel in Action, it explains most of the basic concepts. There is a free first chapter available online which explains the kind of questions you ask http://manning.com/ibsen/
An endpoint references a component and some component specific options, such as addresses etc. The endpoint can then (depending on the component) function as either consumer (ex. "servlet:path/to/web/service") or producer (ex. "http://localhost/path/to/web/service") or both of them (ex. "jms:queue:orderQueue").
There are headers in Camel messages as well. An exchange outlives an entire route, and exchange properties will also stay for the entire route. Message headers in Camel are a bit different concept. They are often closely mapped to the component used - i.e. a HTTP endpoint might set/change headers (for instance COOKIES etc.) while HTTP headers has no influence on exchange properties as these are for use within the camel route and camel logic only. The exchange also wrapps other non message specific things, such as exceptions.
It is quite uncommon to develop new message implementations. There could be a point in extending DefaultMessage when you have implemented your own component/protocol and need to keep instances of helper objects around in the message or whatnot. It's typically not done even when developing components. I have never heard of any custom implementation of an Exchange, and you should typically not do so without good reasons.
#DirtyMikeAndTheBoys you wrote:
Is it true that all processors are endpoints? Are there any endpoints
that are not processors?
This is not true. 'Processors' in Camel terminology are callbacks which are part of some pattern (like Aggregator, Message Channel or RoutingSlip). Processors receive the messages when they are flowing within a route and do something on messages. Messages are wrapped within Exchanges.
An Endpoint is where a route will receive messages (consumer endpoint) and where it will send the processed messages (To endpoint). So when you see the 'from' clause in a route, Camel engine is using a 'Consumer' instance associated with the endpoint instance defined in 'from' clause. It really depends on the endpoint implementation whether a new consumer instance is created/reused every where that given endpoint appears in a 'from' clause in your camel context.
Similarly when the same endpoint is mentioned in a 'To' clause, a Producer instance will be used (either created/reused) and will remain associated with the endpoint instance.

Does onCompletion() order matter in camel DSL?

I am trying to set some headers on a message that is manipulated as it passes through the processors references in my camel DSL. The very first thing I have, however, is a processor for .onCompletion, which is supposed to read the message from the exchange, get the headers and log them.
Does that have to come last in my DSL? It appears that my finaly .process() processor can see all of the new header values I added through the rest of the code, but when I go to log them all at .onCompletion, the values for those headers is null. it's almost like it has a stale version of the message or exchange or something. Why else would this be happening?
Yes you should configure things like
onCompletion
onException
intercept
errorHandler
transacted
policy
etc
In the start of your route. However the DSL is Camel 2.x is very open, and thus you can in some places configure this elsewhere (eg not in the start). But the rule of thumb is to do this first. And then after that, you regular route.
Side note: Mind that Camel also allows you to configure these kind on global level (aka context scope) instead of route. Eg you can have
a context scoped error handler. And then only in a special route
override and have a route special error handler.
In Camel 3.0 onwards we will make the DSL more strict, so we enforce configuration in the start. This also reduces the number of methods you would see in the code assistance list (eg pressing ctrl + space) in the regular routes. As those configurations would then no longer be listed.
The reason why they show up, is that they inheirt the same base class which is the corner stone in the DSL. And we don't wanna break this in the current 2.x line as then some people may get affected.
the order shouldn't matter...it should be using a copy of the Exchange when the route has completed regardless...post your route and we can perhaps help more

Categories

Resources