Making java call to determine Apache Camel conditional routing - java

Here is my scenario. I have an existing processing application that currently is using camel to route ActiveMQ messages from a queue to a java application for processing, there are usually multiple instances of the app running on different nodes.
I need to be able to only route the messages to an app instance when that instance has capacity to handle it. The app bean itself is aware of its capacity state. The method "testCapacity" returns a boolean denoting available capacity.
I have searched as far as I can trying to find a way where I an use a call to the bean itself as the decision point for a "when" conditional.
Is this even possible, and if it is possible how can this be achieved.
<route>
<from uri="activemq:queue:myQueue" />
<when>
<xpath>idontknowwhattoputhere("bean:javaBean?method=testCapacity")</xpath>
<to uri="bean:javaBean?method=doThings" />
</when>
</route>

<route>
<from uri="activemq:queue:myQueue" />
<when>
<simple>${bean:javaBean?method=testCapacity}</simple>
<to uri="bean:javaBean?method=doThings" />
</when>
</route>

Related

Camel retry processing in a inner route

I was trying to implement a retry mechanism with inner routes in camel DSL with spring.
For example I have the following two routes:
<route>
<from uri="direct:start"/>
<to uri="procA"/>
<to uri="direct:sub"/>
<to uri="procB"/>
</route>
<route >
<from uri="direct:sub"/>
<to uri="procD"/>
<process ref="myProcessor"/>
</route>
and I want to achieve the following behaviour: when there is an error in the first route or in the second route I want that the operation with the error (and not the entire route) is retried, in addition the sub-route could be called also by others routes in which the retried mechanism is not allowed. In other words the retry mechanism shoud be controlled by the main route.
Is there a way to achieve this behaviour?
Thanks

Conditionally Exit Camel Loop

I'll start off by saying that I'm using Camel 2.14, upgrading is simply not in the cards at the moment. So I miss out on the doWhile option which came in 2.17.
I have a scenario in which I need to be able to have the routing repetitively attempt to deliver to a service instance when it is ready. Once this succeeds then I need to exit the loop. So far I have been able to look a specified number of times. However, that loop continues even after success.
I've searched through and it appears I don't have many options. Or I'm still too new at the Camel realm to recognize my options.
<route>
<from uri="activemq:queue:myQueue" />
<loop>
<simple>100</simple>
<when>
<simple>${bean:myService?method=isReady}</simple>
<to uri="bean:myService?method=doWork" />
</when>
</loop>
</route>
You can write that in a java bean where you combine isReady and doWork method, instead of the Camel loop. Also mind about looping is not a good idea if you need to loop for a very long time. If you are not ready its better to not consume from the AMQ queue but leave the messages in the store.
So you can instead use a route policy that is controlling the route to suspend/resume depending on the ready status.
You can then from the route policy periodically check the isReady and then either suspend/resume the route accordingly.
http://camel.apache.org/routepolicy.html
I was facing a similar situation, and addressed it by a self recursive route. I don't know whether there are some down sides for this approach.
<route>
<from uri="activemq:queue:myQueue" />
<to uri="direct:loopingRoute"/>
</route>
<route>
<from uri="direct:loopingRoute"/>
<choice>
<when>
<method ref="myService" method="isReady"/>
<bean ref="myService" method="doWork"/>
</when>
<otherwise>
<to uri="direct:loopingRoute"/>
</otherwise>
</choice>
</route>
This was the apporach used by me. While answering the question, one point came into my mind. Does it cause stack overflow if recursion is beyond a limit?

Using controlBus from spring DSL with parameters

I need to control my routes and I am using spring DSL for Camel.
I need to exposed a service which will perform thoses actions to the routeId given in paramaters.
The following code does not work (the body contain the routeId)
<route id="stopRoute">
<from uri="direct:stopRoute"/>
<log message="about to stop a route"/>
<to uri="controlbus:route?routeId=${body}&action=stop"/>
<to uri="controlbus:route?routeId=${body}&action=status"/>
</route>
I also tried with simple language but I can't figure out the correct syntax
See this FAQ
http://camel.apache.org/how-to-use-a-dynamic-uri-in-to.html
Use <toD> to make the to dynamic.

Camel : direct connection the next route, can it be transacted?

I have two camel routes that are connected via a direct: link, not linked via JMS-Queue in this case.
Can I have a transaction between these two routes?
e.g.
<route id="fileRoute">
..
<to uri="direct:start">
</route>
<route id="directStartRoute">
<from uri="direct:start">
<to uri="http://myhost/mypath">
</route>
Yes if the first route starts with a transaction and you use direct between routes then the transaction still apply. The transaction manager requires the work that happens in the transaction happens on the same thread and therefore needs to be synchronous routing, which is what direct do.

Camel not publishing to RabbitMQ queue

I have a simple route defined in a routeContext in Camel (this route will be used in multiple routes).
<route id="sendToRabbitQueue">
<from uri="direct:sendToQueue" />
<convertBodyTo type="java.lang.String"/>
<setHeader headerName="rabbitmq.ROUTING_KEY">
<constant>my.routing.key</constant>
</setHeader>
<to uri="ref:genericRabbitEndpoint"/>
</route>
And I have an endpoint (defined in an endpoints file)
<endpoint id="genericRabbitEndpoint" uri="rabbitmq://${rabbitmq.host}:${rabbitmq.port}/${rabbitmq.exchange.name}">
<camel:property key="autoDelete" value="false" />
<camel:property key="connectionFactory" value="#rabbitConnectionFactory" />
</endpoint>
Yes - I have seen the http://camel.apache.org/rabbitmq.html page - that's where I got the idea to set the header on the exchange. However no message is being published on the queue. I'm clearly overlooking something and any help would be appreciated.
So this seems like a bit of a gotcha and the answer relates to part of the route I didn't include in the question because I didn't think it was relevant.
The route starts at a RabbitMQ endpoint (not included above). As a result the exchange has some RabbitMQ headers set when it arrives:
rabbitmq.ROUTING_KEY
rabbitmq.EXCHANGE_NAME
rabbitmq.DELIVERY_TAG
These headers are used across the life of the route and appear to override the values when I try to publish at a different RabbitMQ endpoint. The way I've fixed is by introducing a bean which strips the headers out. Not ideal behaviour in my opinion...
public void stripRabbitHeaders(#Headers Map headers)
{
headers.remove("rabbitmq.ROUTING_KEY");
headers.remove("rabbitmq.DELIVERY_TAG");
headers.remove("rabbitmq.EXCHANGE_NAME");
}

Categories

Resources