Camel - Why the setProperty changes the header as well? - apache-camel

I've imagined, that setProperty change the header as well, and I don't know why.
<setProperty propertyName="A"><constant>AAA</constant></setProperty>
<log message="HA: ${headers.A}" />
<log message="PA: ${exchangeProperty[A]}" />
Both logs print AAA. Camel version 2.17.3, Spring version 4.3.2.RELEASE.
How should I use the setProperty?

As answered by Claus Ibsen:
This is working as Camel was designed with the header/property
expressions in the DSL.
A header lookup will fallback as property.
Source: Simple message header.XXX and exchange property.XXX the same?

Related

How to use properties with the SimpleRegistry in Apache Camel (Spring XML)

I want to use a SimpleRegistry to store properties (as global variables). The property is changed with setProperty in a route with a jms endpoint. The camel documentation changed last week and has many dead links, also the Registry page. I did not found any samples that describe the use of the simpleRegistry.
I used the camel-example-servlet-tomcat as base. I do not use Fuse or the patched camel wildfly, because is to huge for our simple module.
<beans .... >
.
.
.
<bean id="simpleRegistry" class="org.apache.camel.support.SimpleRegistry" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="ref:simpleRegistry" />
<route id="storeConfig">
<from id="myTopic" uri="jms:topic:myTopic?selector=Configuration %3D 'xyz'" />
<log id="printHeader2" message="Received header: ${headers}" />
<log id="logToken" message="Received token: ${headers[myToken]}" />
<setProperty id="setMyToken" name="myProperty">
<simple>${headers[myToken]}</simple>
</setProperty>
</route>
<route id="externalIncomingDataRoute">
<from uri="servlet:hello" />
<transform>
<simple>The Token is: {{myProperty}}</simple>
</transform>
</route>
</camelContext>
</beans>
With the camel context deined like above, I got a java.io.FileNotFoundException Properties simpleRegistry not found in registry.
When I use <propertyPlaceholder id="properties" location="classpath:test.properties" /> and create a test.properties file, everything works fine but I cannot change the property. The operation in the setProperty tag is ignored.
The reason why I need a global variable is, I send a dynamic configuration (the myToken) via a jms topic to the camel context. A single route should store this configuration globaly. If an other route is called via an rest component, this route need the token to make a choice.
Alternatively you can achieve the same result following the below approach which uses the PropertiesComponent
<bean id="applicationProperties" class="java.util.Properties"/>
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:application.properties"/>
<property name="overrideProperties" ref="applicationProperties" />
</bean>
Define the property place holder in the camel context:
<propertyPlaceholder id="propertiesRef" location="ref:applicationProperties" />
Set a property as shown below :
<bean ref="applicationProperties" method="setProperty(token, 'Test'})" />
And to fetch the property : ${properties:token}
OK, there are multiple subjects in your question.
You write you want to use Camel SimpleRegistry, but you obviously have a Spring application.
If you got Spring available, the Camel Registry automatically uses the Spring bean registry. The Camel Registry is just a thin wrapper or provider interface that uses whenever possible an available registry of another framework.
The Camel SimpleRegistry is only used when nothing else is available. This is basically an in-memory registry based on a Map.
You want to set an application property with <setProperty>.
<setProperty> sets an Exchange property, NOT an application property. With this you can save values in the Exchange of a message.
You want to use "global variables".
You could perhaps use a Spring singleton bean that is a Map. You could then autowire it where you need it, it would be like an application wide available map.
However, think twice why you need this kind of variable. This could also be a symptom of a design problem.

Camel-http httpclient timeout from exchange headers

I have a http component in my route in which I want to pass timeout value from exchange header's.
http://foo.com?httpClient.soTimeout=5000
How can we do this in Spring DSL.
Is is possible to do something like:
<to uri="http://foo.com?httpClient.soTimeout=${in.headers.timeout}"/>
Unfortunately, no, <to> DSL will create the endpoint and the producer before any exchange is received and for HTTP component SO_TIMEOUT is not a parameter that you can change in runtime (here's a list of what you can change).
That being said, if you are using Camel 2.16+ you can easily do it with Dynamic To endpoint. In your case that would be:
<toD uri="http://foo.com?httpClient.soTimeout=${in.headers.timeout}"/>
Otherwise, you'll have to use the Dynamic Recipient List EIP:
<setHeader headerName="theHeader">
<simple>http://foo.com?httpClient.soTimeout=${in.headers.timeout}</simple>
</setHeader>
<recipientList>
<header>theHeader</header>
</recipientList>

Not seeing header or property in Camel route

I have the following Camel context XML. I set a header named MediaType. But, when I set a breakpoint in RenamerProcessor I don't see the header (I've also tried using setProperty with the same results. Being very new to Camel, I've found several examples that make it seem like the below should work.
What is wrong?
<camel:route>
<camel:from uri="file://c:/CamelTVInput" />
<camel:setHeader headerName="MediaType">
<camel:constant>T</camel:constant>
</camel:setHeader>
<camel:to uri="file://c:/CamelReadyToRename" />
</camel:route>
<camel:route>
<camel:from uri="file://c:/CamelReadyToRename?move=//c:/CamelBackup" />
<camel:process ref="RenamerProcessor" />
<camel:to uri="file://c:/CamelOutput" />
</camel:route>
You cannot transfer headers using files. eg when you write to a file, then its only the message body that is written as the file content.
But this is component specific if headers is part of the protocol, eg JMS, HTTP support headers.
If you want to keep files then use something else, Camel has some internal components like seda / direct.

How to call setter method on ${body} in a Camel route?

I have tried to set a property on the body of a Java bean constituting the message in transit through a Camel route. I have tried various approaches e.g.
<route>
...
..
<transform>
<simple>${body.label} = ${property.label}</simple>
</transform>
...
..
</route>
in this particular case the ${body} is a Java bean with a setLabel(String label) method and the ${property.label} is set by other means in another route. In this example the result is not the desired (and I understand why), i.e. after the transform the body of the message is replaced with the ${body.label} = ${property.label} string.
My current work-around is to manually code a transformer as a Spring bean and set the label property of the Java bean in code but I like to find out if there is a simpler/smarter way to achieve this, preferably in XML DSL which is what I use?
Regards, Ola
I'm not sure if it's possible with simple, but you could do it using groovy:
<setBody>
<groovy>request.body.label = exchange.getProperty('label')
return request.body
</groovy>
</setBody>
Maybe it can help someone in the future:
As I know You can use standard Java approach with settters anf getters in body:
.split(body())
.setBody(simple("${body.setLogin('TEST')}"))
.end()
It works inside <split></split>. Maybe inside another blocks.

Apache Camel Endpoint injection to direct route "No consumers available on endpoint"

I want to use Camel to take a message from ActiveMQ and then, based on the message contents (a protobuf), send one or more messages to Twitter. I've written a bean that is called from within a route and which uses injection to send multiple messages to a "direct:xyz" endpoint.
However, Camel is complaining at runtime that:
2012-11-16 09:56:33,376 | WARN | ication.twitter] | DirectProducer | 160 - org.apache.camel.camel-core - 2.10.2 | No consumers available on endpoint: Endpoint[direct://twitter] to process: Exchange[Message: hello world]
If I instead inject directly to the Twitter endpoint from within the bean, it works fine. However, in order to ease testing, simplify configuration etc, I'd like to keep the actual Twitter config separate, hence wanting to send to a separate route.
The camel context config looks like:-
<camelContext id="NotificationTwitter"
trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<dataFormats>
<protobuf id="notificationProto" instanceClass="org.abc.schemas.protobuf.NotificationDef$NotificationMsg" />
</dataFormats>
<route id="TwitterPreparation">
<from uri="activemq:notification.twitter" />
<unmarshal ref="notificationProto" />
<log logName="abc" loggingLevel="INFO"
message="Twitter request received: ${body}" />
<bean ref="NotificationTweeter" method="createTweets" />
</route>
<route id="Twitter">
<from uri="direct:twitter" />
<log logName="abc" loggingLevel="INFO"
message="Tweeting: ${body}" />
<to uri="twitter://timeline/user?consumerKey=itsasecret&consumerSecret=itsasecret&accessToken=itsasecret&accessTokenSecret=itsasecret" />
</route>
</camelContext>
The bean looks like:-
public class NotificationTweeter {
#EndpointInject(uri = "direct:twitter")
private ProducerTemplate producerTemplate;
public void createTweets(NotificationMsg notification) {
String tweet = notification.getMessageDetail().getTitle();
try {
// only send tweets where the notification message contains the Twitter mechanism
for (MechanismMsg mechanism : notification.getMechanismList()) {
if (mechanism.getType() == MechanismTypeEnum.TWITTER) {
// Cycle round the recipients
for (RecipientMsg recipient : mechanism.getRecipientList()) {
tweet = "#" + recipient.getIdentifier() + " " + tweet;
producerTemplate.sendBody(tweet);
}
// TODO exceptions if no recipients found, etc
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I've had this problem in other routes (it's certainly not related to the Twitter feature) but have just worked around it. This time, however, I'd like to actually understand what the issue is! Any help gratefully received, thanks.
According to your setup, it might also depend on the CamelContext you have picked up. I got the same error message because I was sending messages on a route that existed in another CamelContext than the one I actually was using.
(Although the previous answer was already accepted, this might be the working solution for other people searching for that error message.)
It sounds like a problem with the startup ordering of your routes. See more detail here http://camel.apache.org/configuring-route-startup-ordering-and-autostartup.html
You can configure the "direct" route to start before the other route, then that issue should be resolved.
For others coming here, this error can also be caused by an OSGI error for a dependency that has not been deployed.
A bit late to the party but this error happened to me when I had two separate blueprint files, one for normal running and one for test. In my test I was referring to the test blueprint but noticed that the normal one was also automatically started which caused errors.
In the documentation http://camel.apache.org/blueprint-testing.html it says you can disable certain bundles from starting up. That helped me in my case.
This can also be caused by having a . in the route name. Replace my.Route.Name with myRouteName fixed the issue for me.

Resources