camel throttle properties not work - apache-camel

I use a throttle on my route like this:
<throttle id="_throttle1" rejectExecution="true" timePeriodMillis="10000">
<constant>1</constant>
<bean beanType="com.company.Test"
id="_bean1" method="test"/>
</throttle>
I'm using org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigure in my route, that works.
I would like to make the timePeriodMillis parametric, for example:
<throttle id="_throttle1" rejectExecution="true" timePeriodMillis="{{test}}">
<constant>1</constant>
<bean beanType="com.company.Test"
id="_bean1" method="test"/>
</throttle>
I have the following error:
java.lang.NumberFormatException: For input string: "{{test}}"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_162]
at java.lang.Long.parseLong(Long.java:578) ~[na:1.8.0_162]
at java.lang.Long.parseLong(Long.java:631) ~[na:1.8.0_162]
at com.sun.xml.bind.DatatypeConverterImpl._parseLong(DatatypeConverterImpl.java:133) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$19.parse(RuntimeBuiltinLeafInfoImpl.java:759) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$19.parse(RuntimeBuiltinLeafInfoImpl.java:757) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.parse(TransducedAccessor.java:245) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:212) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:577) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:556) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:75) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:168) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:244) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:281) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:250) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:281) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:250) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:127) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:110) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:103) ~[jaxb-core-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.BinderImpl.associativeUnmarshal(BinderImpl.java:161) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at com.sun.xml.bind.v2.runtime.BinderImpl.unmarshal(BinderImpl.java:132) ~[jaxb-impl-2.3.0.1.jar:2.3.0.1]
at org.apache.camel.model.ModelHelper.loadRoutesDefinition(ModelHelper.java:171) ~[camel-core-2.22.0.jar:2.22.0]
at org.apache.camel.model.ModelHelper.loadRoutesDefinition(ModelHelper.java:152) ~[camel-core-2.22.0.jar:2.22.0]
at org.apache.camel.impl.DefaultCamelContext.loadRoutesDefinition(DefaultCamelContext.java:1036) ~[camel-core-2.22.0.jar:2.22.0]
at fr.erdf.ose.ile.routes.RouteManager.loadXMLRoutes(RouteManager.java:43) ~[RouteManager.class:na]
Could you help me?

According to the Camel Throttle Docs you can at least make the number of requests dynamic. However, they don't mention the time span.
So instead of configuring 1 request during X millis, you can configure X requests during a fixed number of millis.
<throttle timePeriodMillis="1000">
<!-- use a header to determine how many messages to throttle per sec -->
<header>throttleValue</header>
<to uri="..."/>
</throttle>
You could give it a try to use your property placeholder instead of a message header.
<constant>{{test}}</constant>
If that does not work you can still set the message header in the route using your property placeholder.
<setHeader headerName="throttleValue">
<constant>{{test}}</constant>
</setHeader>

See the Camel documentation about using property placeholders
http://camel.apache.org/using-propertyplaceholder.html
The section Using Property Placeholders for Any Kind of Attribute in the XML DSL, eg you need to use the prop: with the /placeholder namespace to be able to specify the value as a placeholder.

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.

Change values of property placeholders dynamically

I am using fuse6.3 and trying to make the change of following property value dynamically:
<camelContext autoStartup="true" id="_camelContext_app1"
<propertyPlaceholder
id="properties"
location="test.properties,test2.properties"
/>
...
<log id="_log_test_properties" message="===properties:{{remote.host}}"/>
In test.properties, if value of remote.host is changed, how to make camel recognize the change?
Thanks in advance.
Best regards
Lan

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");

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.

Resources