I'd like configure a Camel route where the to(uri) can be specified at runtime.
I tried the following:
public class Foo extends RouteBuilder {
#Override
public void configure() {
// the URI can point to different hosts
from("direct:start").to(${someUri}");
}
}
and then
ProducerTemplate pt = camelContext.createProducerTemplate();
pt.requestBodyAndHeader("direct:start", "someUri", "http://example.com");
However the above doesn't work (Camel complains about not having a default Endpoint).
What's the best way to go about this?
Although this question has already been answered, I wanted to share this other option to achieve what you're looking for, in case someone else still wonders how to do it:
There is a new method since Camel 2.16 called "toD" wich basically means a "dynamic to". Here is the official reference documentation.
from("direct:start")
.toD("${someUri}");
In this case, the toD method resolves the argument using the Simple language wich means you can use any property that the language supports.
You can also take a look at this other StackOverflow answer, about that same topic.
see these links for reference:
http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
http://camel.apache.org/recipient-list.html
for an example, see this unit test
https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/RecipientListTest.java
I simply used curly braces without the '$' before it. Here is what I did:
{headers.reQueueName} instead of ${headers.reQueueName} for the uri and it worked :
<to id="requeue" uri="jmsamq:queue:{headers.reQueueName}"/> here is my implementation :
<route id="_throttleRoute">
<from id="throttleRouteStarter" uri="direct:throttleRouteService"/>
<log id="_Step_5" message="Camel throttle Route Started"/>
<log id="_Step_5_1" message="Camel throttle Route is ${headers.next}"/>
<to id="restThrottleCall" uri="restlet:http://host:port/path"/>
<process id="throttleRouteProcess" ref="throttleServiceProcessor"/>
<choice id="_choice2">`enter code here`
<when id="_when3">
<simple>${headers.next} == 'requeue'</simple>
<to id="requeue" uri="jmsamq:queue:{headers.reQueueName}"/>
<log id="_Step_wait1" message="ReQueue sending to ${headers.reQueueName}"/>
</when>
<when id="_when4">
<simple>${headers.next} == 'process'</simple>
<log id="_logNext" message="Invoking Next Work Unit ${headers.next}"/>
<process id="jBPMRouteProcess" ref="jBPMRouteProcessor"/>
</when>
<otherwise id="_otherwise2">
<log id="_log5" loggingLevel="WARN" message="Next for orderId: ${headers.orderid} not found"/>
</otherwise>
</choice>
</route>
Related
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?
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>
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.
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");
}
If I have a String Java constant com.example.Constants.MY_URI, can I somehow use it to assign the value of a uri attribute in a Camel XML file?
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="aaa" /> <-- how to use MY_URI here?
<to uri="bbb"/>
</route>
</camelContext>
In particular, is there a way to use one of the Camel languages for this?
Many thanks!
edit
After more work with camel and better know. It is possible to use one of the camel languages to define where message shold go, using recipient-list. But you can't use it as a replacement of from - it must be hardcoded or taken from properties file as I described below.
end edit
I don't know if that is possible, but there is another option:
you can use propertyPlaceholder:
<camelContext ...>
<propertyPlaceholder id="properties" location="com/mycompany/myprop.properties"/>
</camelContext>
and you need to put your constans into myprop.properties files:
example.from.property.name=direct:start
then you can use that property inside from:
<from uri="{{example.from.property.name}}" />