read value from property file for from URI in apache camel - 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>

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.

Is There a way to treat a large file?

I m using apache Camel to treat files.
However, i m asking if i can split a file depending on the number of byte.
For exemple , if i have a file with a size like 1 GO, is that possible to read it by block of 10 MO. (with a parameter that defines the size of a block)
Is there a component Camel EIP able to do this ?
I have tried with stream-caching but nothing happened.
<camelContext xmlns="http://camel.apache.org/schema/spring" trace="true">
<properties>
<property key="CamelCachedOutputStreamBufferSize" value="1024"/>
</properties>
<route id="READ-FILE-STREAM-CACHE" streamCache="true">
<from uri="file:src/data?noop=true"/>
<bean ref="readBean" method="readFileStream"/>
<to uri="file:src/out"/>
</route>
</camelContext>
Thanks

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>

Camel Split and Aggregate failing because messages going to multiple concurrent consumers

I have a simple camel route that takes a list of items, splits them sending each element to a mq node for processing then joins them back together via an aggregator.
Very close to the Composed Message Processor: http://camel.apache.org/composed-message-processor.html
But we noticed that after the split, camel will create multiple concurrent consumers? or exchanges? Since the message is being sent to multiple consumers they never complete.
List: 1,2,3,4
Split: amq::process_each_item
Aggregate:
[Camel (camel-3) thread #41 - Aggregating 1 - Waiting on 3 more items
[Camel (camel-1) thread #16 - Aggregating 2 - Waiting on 3 more items
[Camel (camel-3) thread #49 - Aggregating 3 - Waiting on 2 more items
[Camel (camel-1) thread #15 - Aggregating 4 - Waiting on 2 more items
So, camel spawned 2 aggregators, and each is waiting on 4 items, but they only ever get two each.
Camel Route:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route> <!-- This route splits the reg request into it's items. Adding needed info to the message header. -->
<from uri="activemq:registration.splitByItemQueue" /> <!-- pick up the reg req -->
<setHeader headerName="regReqId"> <!-- Need to store the Reg Req in the header -->
<simple>${body.registrationRequest.id}</simple>
</setHeader>
<split parallelProcessing="false" strategyRef="groupedExchangeAggregator"> <!-- Split the RegRequestInfo into it's individual requestItems (add, drop, etc) -->
<method ref="requestSplitter" method="split" /> <!-- does the actual splitting -->
<setHeader headerName="JMSXGroupID"> <!-- This is CRITICAL. It is how we ensure valid seat check counts without db locking -->
<simple>FOID=${body.formatOfferingId}</simple> <!-- grouping on the foid -->
</setHeader>
<to uri="activemq:registration.lprActionQueue"/> <!-- send to queue's for processing-->
</split>
</route>
<route> <!-- performs the registration + seat check -->
<from uri="activemq:registration.lprActionQueue" />
<bean ref="actionProcessor" method="process"/> <!-- go to the java code that makes all the decisions -->
<to uri="activemq:registration.regReqItemJoinQueue"/> <!-- send to join queue's for final processing-->
</route>
<route> <!-- This route joins items from the reg req item split. Once all items have completed, update state-->
<from uri="activemq:registration.regReqItemJoinQueue" /> <!-- Every Reg Req Item will come here-->
<aggregate strategyRef="groupedExchangeAggregator" ignoreInvalidCorrelationKeys="false" completionFromBatchConsumer="true"> <!-- take all the Reg Req Items an join them to their req -->
<correlationExpression>
<header>regReqId</header> <!-- correlate on the regReqId we stored in the header -->
</correlationExpression>
<bean ref="actionProcessor" method="updateRegistrationRequestStatus"/> <!-- update status -->
</aggregate>
</route>
</camelContext>
<bean id="groupedExchangeAggregator" class="org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy" />
On my local machine the above works fine, but when we deploy to our test server half of the messages go to one camel aggregator, half to the other. causing none to ever finish. Notice in the config below that we've set concurrent consumers to 1 for camel.
Here's the camel / activemq config
<amq:broker useJmx="false" persistent="false">
<amq:plugins>
<amq:statisticsBrokerPlugin />
</amq:plugins>
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
<!-- Basic AMQ connection factory -->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="vm://localhost" />
<!-- Wraps the AMQ connection factory in Spring's caching (ie: pooled) factory
From the AMQ "Spring Support"-page: "You can use the PooledConnectionFactory for efficient pooling... or you
can use the Spring JMS CachingConnectionFactory to achieve the same effect."
See "Consuming JMS from inside Spring" at http://activemq.apache.org/spring-support.html
Also see http://codedependents.com/2010/07/14/connectionfactories-and-caching-with-spring-and-activemq/
Note: there are pros/cons to using Spring's caching factory vs Apache's PooledConnectionFactory; but, until
we have more explicit reasons to favor one over the other, Spring's is less tightly-coupled to a specific
AMQP-implementation.
See http://stackoverflow.com/a/19594974
-->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory"/>
<property name="sessionCacheSize" value="1"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="connectionFactory" />
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="concurrentConsumers" value="1"/>
</bean>
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
Turns out we had another spring context / servlet importing our config. We believe this was the issue.

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