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

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.

Related

read value from property file for from URI in apache camel

Below is my camel context, but reading vlaue from property file doesnt work, it is not listening to Queue which is mentioned in queueName. Is using poll
enrich A good Idea, because it uses direct component?
<bean id="bridgePropertyPlaceholder"
class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="location" value="classpath:/config/queue.properties"/>
</bean>
<Route>
<from uri="activemq:queue:{{queueName}}/>
.......
</Route>

From ActiveMQ to Java Bean

I'm trying to learn Camel on Fuse- within this example an ActiveMQ message is converted in a Java object named CustInfo using the Dozer component:
<camelContext id="context-43faded0-825e-454b-8037-c72122aa0418" xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder location="classpath:sql.properties" id="properties"/>
<endpoint uri="dozer:toCustInfo?sourceModel=homeloancust.CustInfo&targetModel=org.blogdemo.homeloan.model.CustInfo&unmarshalId=homeloancust&mappingFile=toCustInfo.xml" id="toCustInfo"/>
<dataFormats>
<jaxb contextPath="homeloancust" id="homeloancust"/>
</dataFormats>
<route id="CustomerEvaluation">
<from uri="activemq:queue:customer"/>
<to ref="CustInfo" id="to3"/>
. . . .
</route>
</camelContext>
My question is, in case I don't need transformations in the Java object, can I convert the message into the Java class directly (without Dozer).
Tried with:
<bean id="CustInfo" class="homeloancust.CustInfo"/>
. . .
<to ref="CustInfo" id="to3"/>
Without success! Any help ?
Assuming that the incoming message has a contract (which it should if it follows a good contract-first approach), then you can simply unmarshall the payload into a Java object using JAXB. If it doesn't have a contract, you can still annotate your Java class with JAXB annotations and unmarshall to it:
<unmarshal>
<jaxb prettyPrint="true" contextPath="org.apache.camel.example"/>
</unmarshal>
http://camel.apache.org/jaxb.html

Camel Component: setting a Property dynamically from a Bean

I have defined a Camel Route in a Jboss Fuse BluePrint. I'd need to set one variable at runtime from a Bean. See this example:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="wsClient">
<from uri="timer:foo?repeatCount=1" />
<setBody>
<simple>Message</simple>
</setBody>
<transform>
<method bean="myBean" method="transform" />
</transform>
<to uri="cxf:bean:MyWebService?defaultOperationName={{operation}}" />
<to uri="mock:result" />
</route>
</camelContext>
In this example, I'd like to set the property named "operation" within the bean "myBean". Is it possible to do it?
Thanks!
Yes, it is possible.
First, set a header from the bean and later use http://camel.apache.org/recipient-list.html
I am not familiar with Spring DSL, but in Java DSL it would look like this:
.recipientList(simple("cxf:bean:MyWebService?defaultOperationName=${header.operation}"))
Yes you can do that inside the bean. No need to pass any specific parameter. Camel can bind the exchange, body...etc as a method parameter automatically. Ref: http://camel.apache.org/bean-binding.html
using below code you can set the header or property
exchange.getIn().setHeader("HeaderName", "Value");
exchange.setProperty("Key", "Value");

Reading Camel Constant From Property file

I am trying to read time delay from property file .
have defined in my property file :
time_inMilis=15000
I have configured my camel context xml to be :
<bean id="property" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>file:/D:/Develop/resources/my.properties
</value>
</property>
</bean>
<camel:camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="file:/D:/Develop/resources/my.properties"/>
<camel:route id="delayQueue">
<camel:from uri="seda:queue1" />
<delay asyncDelayed="true">
<constant>${time_inMilis}</constant>
</delay>
<camel:to uri="seda:queue2" />
</camel:route>
</camel:camelContext>
camel do not throw any error but it seems that it ignores ${time_inMilis} and set 0 for my delay time.
What is the right way to read the delay constant from my property file ?
First, it would be enough just to use camel:propertyPlaceholder instead of declaring bean property.
Second mistake is that you are using Constant instead of Simple expression when trying to read your time_inMilis property value.
Third, when trying to get value of you property, you should specifically tell Camel that your are looking at properties.
If your context defines propertiesPlaceholder like this:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="props" location="classpath:/org/smp/eip/sample.properties"/>
<package>org.apache.camel.example.spring</package>
</camelContext>
them with java DSL you'll be able to read the textProeprty value like this
from("file:src/data?noop=true")
.transform().simple("Text read from properties: ${properties:textProperty}")
.bean(new SomeBean());
Using Spring DSL from your original post, the correct way of reading property would be:
<camel:route id="delayQueue">
<camel:from uri="seda:queue1" />
<delay asyncDelayed="true">
<simple>${properties:time_inMilis}</simple>
</delay>
<camel:to uri="seda:queue2" />
</camel:route>

Multiple data models Apache camel Bindy

I am working with Apache Camel Bindy to process csv files of different data models.
e.g. file one is of data model on and file two is of data model two.
In the camel route, I associated two calls of the BindyCsvDataFormat with different data models as:
<bean id="bindyDataformat" class="org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat">
<constructor-arg name="type" value="com.barclays.creditit.cls.eoddata.model.risk.DataModel1" />
</bean>
<bean id="aBindyDataformat" class="org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat">
<constructor-arg name="type" value="DataModel2" />
</bean>
route looks like this:
<from uri="direct:start"/>
<bean ref="fileReader"/>
<unmarshal ref="bindyDataformat" />
<bean ref="flattener"/>
<bean ref="fileReader"/>
<unmarshal ref="aBindyDataformat" />
<bean ref="flattener"/>
When I run the code though, the factory has two models associated automatically, not one per run. And both the files are read into objects of the first data model and never the second data model. Any suggestions about how I could get this to work?
Thanks!
Create two different routes with different file filters and process them separately with one of the Bindy formaters.

Resources