If X is false I want to route to A, if X is true I want to route to A and B
I tried to write something like
from(?)
.choice()
.when( X )
.multicast().to(A,B).end()
.otherwise() // I get a (compile) error underlined here saying 'otherwise() is not on type ProcessorDefinition
.to( A )
it doesn't like it
I suspect this isn't the best way of phrasing this
basically I always want to route to (A) and if that condition is there I also want to route to (B)
what is the best way of expressing this in Camel?
use endChoice() at the end of your when() clause and it'll work...
see http://camel.apache.org/why-can-i-not-use-when-or-otherwise-in-a-java-camel-route.html
See this FAQ about the choice: https://camel.apache.org/why-can-i-not-use-when-or-otherwise-in-a-java-camel-route.html
You can also use dynamic recipient list and compute the endpoints to route to. Then you can return 1 or 2 depending on the conditions: http://camel.apache.org/recipient-list.html
If you always want your message to go to route A, then do not include it in the choice clause
from(?)
.to( A )
.choice()
.when( X )
to(B).end()
Something like above should suffice your case. Also read the articles that Claus has given in his answer.
Regarding your compilation error, remove the end() after the when clause. end() causes the choice() clause to be finished but you then use otherwise() clause while choice has already been closed.
I have found that expressing your routes using the XML notation is a lot more concise in meaning.
For instance with the Java DSL people often make the mistake of not calling, or even adding 'endChoice()' and 'end()' like you have in your example; Sometimes you will also face an issue with Camel's Route Builder which is currently a limitation due to Java's Generics.
Unfortunately using XML comes with the cost of using XML :)
Related
My question is very similar to this one but the solution there does not work for me here - I am trying to use the filter EIP to discard selected exchanges. My routes look like (edited down for clarity):
from("{{fromSource}}")
.convertBodyTo(RequestInterface.class)
.enrich(INVOKE_BACKEND_URI, combiner)
.to("{{toDestination}}");
from(INVOKE_BACKEND_URI)
.to(backendUri)
.filter().method(DiscardResponse.class).log(LoggingLevel.INFO, "Discarding undesired response").stop().end()
.convertBodyTo(BodyInterface.class);
When the filter does NOT select the message, all is well - the log() is not displayed and the message goes to the convertBodyTo() and then back to the main route.
However, when the filter DOES select the message, the log() text is displayed but the exchange still continues on to the convertBodyTo() where it throws an exception because it's a message that shouldn't be there. The stop() appears to either not be executed or has no affect.
Can anyone suggest a solution to this?
It is possible from within a Processor to do this in order to stop the exchange:
exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
Since I'm not used to writing my routes using Java DSL I don't know if that option is available directly on the exchange within the route, but it probably is.
I guess one way could be:
from(INVOKE_BACKEND_URI)
.to(backendUri)
.filter().method(DiscardResponse.class).log(LoggingLevel.INFO, "Discarding undesired response")
.choice()
.when(simple("${property.Exchange.FILTER_MATCHED}=true")
.stop()
.end()
.convertBodyTo(BodyInterface.class);
Take a look at the bottom of the doc here:
http://camel.apache.org/message-filter.html
I have a message with a certain value (e.g. 100, 101) in header and I need to take a specific action depending on that value.
I know I can write a route with when / otherwise branches for content-based routing.
My question is: what if I have about 400 different cases? Is there a best practice in these cases to manage the routing?
Yes use recipient list instead which can compute the endpoint dynamically - eg its a dynamic to. See this FAQ link for further details: http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
another option is to use a ProducerTemplate to send messages to any endpoint from a POJO class, just need to inject/pass in a handle to the CamelContext, etc.
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.
I am using cakephp 1.3. here's my problem:
I have a controller named "learns" and a method named "classroom".
To access the classroom method, I use this link: http://www.url.com/learns/classroom/15
I wanted it to be like this: http://www.url.com/class/15
And this is how I setup the routes:
Router::connect('/:class/:id', array('controller' => 'learns', 'action' => 'classroom'), array('id' => '[0-9]+'));
I don't really know why its not working though. I read through the documentation and I just copied this solution from the cookbook..
Thanks for the help in advance.
I don't see anything wrong with your Router statement. Though I am not sure if you actually wanted /:class/:id instead of "/class/:id". See the difference? A Colon is missing in the 2nd version.
This tells the Router that any request that begins with /class/[an-id] should be mapped to whatever your rule is. Where as having it as /:class means you are passing an argument to the router. It can be anything /foo/15 or /bar/15 and these arguments will be available in your $this->params['class'] and $this->params['id']., assuming this rule -> /:class/:id
In your question you state that "I don't really know why its not working". Please avoid these kind of statements as it does not say any thing about the actual problem.
Instead tell us what were you expecting? And what did you see instead? Was it an error? Or a Warning? If you see something else entirely, for example a different action got executed, it is probably due to the fact how routers actually work. If you had a greedy route and a normal route like this:
/users/* and
/users/:id
The second url will not be matched for any request as /users/* is greedy and will hog all the requests to itself, unless the first routing rule returns false.
If this is your situation I would suggest you read up on how to write custom route classes. In summary custom route classes try to make a greedy route less greedy. For a better explanation here is an excellent article by mark story: http://mark-story.com/posts/view/using-custom-route-classes-in-cakephp
Routing in cakephp is one of the most confusing topics and might take a while before you get your head around it. Cookbook is your best friend. Read and Re-read everything until you are sure what each routing element does in a routing rule.
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