Apache Camel avoid duplicating options across similar XML routes - java

I have some Apache Camel routes with many options, like this one:
<from uri="sftp://user#host:22/path?
password=vvvvv;delay=3000&streamDownload=true&
delete=true&idempotent=true&idempotentRepository=#jpaStore&
inProgressRepository=#jpaStore"/>
This isn't so bad, but I have six other routes with the same options but different paths. I'd like to put all the options in a constant to avoid duplication:
<from uri="sftp://user#host:22/path?OPTIONS"/>
I might be able to use Camel EL to accomplish this, but none of the examples show it, and my attempts to guess the syntax aren't working.
I create a Spring bean like this:
<bean id="myoptions" class="java.lang.String">
<constructor-arg value="allmyoptions"/>
</bean>
And try to refer to it like this:
<from uri="sftp://user#host:22/path?${myoptions}"/>
But I get an error:
There are 1 parameters that couldn't be set on the endpoint. Check the uri if the parameters are spelt correctly and that they are properties of the endpoint. Unknown parameters=[{${myoptions}=}]
This question, Simple Expression in apache-camel uri, is attempting something similar, but they use Java DSL and my routes are configured in XML.
Does anyone know a good way to avoid duplicating all this options across routes?

From this page, How do I use Spring Property Placeholder with Camel XML, I read that "We do NOT yet support the ${something} notation inside arbitrary Camel XML." This said, they suggest various workarounds on this page, Properties.
What worked for me was to configure a BridgePropertyPlaceholderConfigurer as follows:
<bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="location" value="classpath:myproperties.properties"/>
</bean>
In the properties file I have:
OPTIONS=password=vvvvv;delay=3000&streamDownload=true&delete=true&idepotent=true&idempotentRepository=#jpaStore&inProgressRepository=#jpaStore
This allows me to use both the Spring property placeholder notation ${} and the Camel placeholder notation with {{ }}:
<from uri="sftp://user#host:22/path?{{OPTIONS}}"/>
One gotcha is that I needed to get rid of my encoded ampersands in the properties file, replacing & with just &.
See also:
Answer: How to use a dynamic URI in From()
Documentation: How do I use Spring Property Placeholder with Camel XML
Documentation: Properties

Related

Camel Rest DSL Removing another extra Route

I am building a rest route on camel based on rest DSL. For example, based on the configuration, the rest route uses a direct component.
Rest Route
rest("resturi")
.post()
.to(direct:inbox);
resturi is dynamic
from(direct:inbox)
.process(camelprocessor)
.to(queue);
Is there any way we can remove the direct component and combine into one route.
I appreciate any advice regarding the above.
You can do that by adding .route()
.post().route().process(camelprocessor).to(queue);
But think from the feature reusable perspective, direct component will be the best choice.
https://access.redhat.com/documentation/en-us/red_hat_jboss_fuse/6.2/html/apache_camel_development_guide/restservices-restdsl
XML dsl example
<get uri="/some">
<route>
<setBody>
<constant>HW!</constant>
</setBody>
</route>
</get>
You can call your processor in this route.

Automatically converting JSON bytes from RabbitMQ queue to object

Is it possible to configure Spring AMQP so it will automatically convert messages from queue (which are essentially JSON strings) into the objects of desired type?
What I have tried so far:
1) My cfg:
<rabbit:listener-container connection-factory="rabbitConnectionFactory" message-converter="jsonMessageConverter">
<rabbit:listener ref="foo" method="listen" queue-names="test_queue"/>
</rabbit:listener-container>
<bean id="foo" class="foo.FooListener"/>
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.JsonMessageConverter"/>
2) My listener FooListener has method listen(FooMessage foo) { ... }
and
3) My FooMessage is just simple POJO and messages in my test_queue are just serialized instances of FooMessage in JSON format.
So it doesn't work, Spring claims for listen(byte[] msg) method:
java.lang.NoSuchMethodException: foo.FooListener.listen([B).
Is it possible to do?
Well, actually this thing works like a charm with Spring AMQP even prior version 1.6. The problem was with incorrect content-type of my message, it was just text/plain.
If message with json is sent in appropriate way, say
template.convertAndSend("test_queue", "test_queue", new FooMessage("blablabla","blabla"));
with correctly setup template:
<rabbit:template id="amqpTemplate"
connection-factory="rabbitConnectionFactory"
message-converter="jsonMessageConverter"
/>
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"/>
so method listen(FooMessage foo) { ... } is invoked with automatically created object of type FooMessage from message.
Please, read the documentation for the Jackson2JsonMessageConverter.
And pay attention to the note:
In versions prior to 1.6, if type information is not present, conversion would fail. Starting with version 1.6, if type information is missing, the converter will convert the JSON using Jackson defaults (usually a map).
So, independently of the target argument type of the POJO handler, the MessageProperties must contain __TypeId__ information.
To meet your requirement consider to use #RabbitListener instead.
See the same section for news in the Spring AMQP 1.6.
Although feel free to raise a JIRA issue and we may consider some hooks for general MessageListenerAdapter where we know the method via listener ref="foo" method="listen" and, therefore, can infer the target argument type before conversion.

Apache Camel: Query Params vs Header Params

I'm currently trying out Apache camel (as routing engine). I understand that Camel supports multiple DSLs and that it could be configured using Java (Java DSL) or Spring (Spring DSL).
Question:
I have the following Spring DSL configuration. The idea is that if the incoming request has header-param called "name", it would hit when clause or else to would route the request to google:
<camel:route>
<camel:from uri="servlet:///test" />
<camel:choice>
<camel:when>
<camel:header>name</camel:header>
<camel:transform>
<camel:simple>Hello ${header.name} how are you?</camel:simple>
</camel:transform>
</camel:when>
<camel:otherwise>
<camel:to uri="http://www.google.com?bridgeEndpoint=true" />
</camel:otherwise>
</camel:choice>
</camel:route>
I expected the above config to work only for Header Param. However, I noticed that this configuration is working even for Query params as shown in the following request:
http://localhost:8080/<war-context>/test?name=test
Is there a way to make sure that it is made to work only for header params ?
It's well documented here that query params are copied to exchange headers in the servlet component.

What is the from uri= when you are defining the Camel route in xml?

I have several services that I would like to add Camel routes. The examples in xml I see are like so:
<route id="myId"
from uri="direct:inside"/>
to uri="mock:inside"/>
</route>
Where can I find the acceptable values for the string after "from uri="?
Also if I'm in ServiceA that seems like what I should put in the from uri. How do I do that?
All the Camel components have documentation which options they support. For example the direct component, has only 1 option listed
http://camel.apache.org/direct
You can see a list of all the components here:
http://camel.apache.org/components

DWR + Spring - Multiple ajax filters not working

Is there a problem defining more than one DWR (v2.0.5) ajax filter in a Spring (v2.5.1) configuration file?
For example:
<bean id="..." class="...">
<dwr:remote javascript="...">
<dwr:filter class="foo1"/>
<dwr:filter class="foo2"/>
</dwr:remote>
</bean>
In my case the only filter getting called is foo2, or more accurately the last filter in the list (checked this by switching filters around etc).
The strangest thing is I can't find anything about such a problem, I've tried Google and searching DWR's bug database both of which turned up nothing!
Thanks,
Chris
This is a dwr's bug in DwrNamespaceHandler.java. It creates new list of filters on every discovery of dwr:filter tag.

Categories

Resources