How to split existing collection in Camel - apache-camel

I have a producer which sends a Set<Status>. I want to split the Set so downstream components have to process single Status objects. My route looks like this:
public Set<Status> loadStatus() { ... }
from("direct:start").
split().
to("mock:end");
ProducerTemplate template = context.createProducerTemplate();
template.sendBody("direct:start", loadStatuses());
How is this achieved?

the Camel Splitter documentation describes how a Collection, Iterator or Array can be used...
A common use case is to split a Collection, Iterator or Array from the
message. In the sample below we simply use an Expression to identify
the value to split.
from("direct:splitUsingBody").split(body()).to("mock:result");
from("direct:splitUsingHeader").split(header("foo")).to("mock:result");
In Spring XML you can use the Simple language to identify the value to
split.
<split>
<simple>${body}</simple>
<to uri="mock:result"/>
</split>
<split>
<simple>${header.foo}</simple>
<to uri="mock:result"/>
</split>

Turns out the docs are a bit unclear: none of the examples explicitly mention having a body that's a Java collection. The solution is to split the body without any expression. In that case, Camel will use it's internal conversion engine to return an Iterator from a Set. The final route is:
from("direct:start").
split(body()).
to("mock:end");
Found a reference in the Camel JDBC samples documentation:
from("direct:hello")
// here we split the data from the testdb into new messages one by one
// so the mock endpoint will receive a message per row in the table
.to("jdbc:testdb").split(body()).to("mock:result");

Related

How to count substring instances in a exchange body

I have a body consisting of something like: OK,OK,NOK,OK,NOK, using Spring DSL.
I want to count the instances of substring 'OK' in the body. I tried StringHelper countChar, but you can only pass it chars.
Is there a way to count substrings in a body without resorting to java beans?
You can use bean to invoke an static method, such org.apache.commons.lang.StringUtils.countMatches to get the number of matches in the body:
from("direct:source")
.bean(StringUtils.class, "countMatches(${body}, OK)")
.to("log:org.orzowei.so.question.q69134695?level=WARN")
.end();
Or using Spring DSL:
<route id="abcRoute" autoStartup="true">
<from uri="direct:source"/>
<bean beanType="org.apache.commons.lang.StringUtils" method="countMatches(${body}, OK)"/>
<to uri="log:org.orzowei.so.question.q69134695?level=WARN"/>
</route>

Apache Camel - JSONPath expressions to fetch multiple values

In a camel route need to read values from an incoming json data through rest client. Using JsonPath to parse and get the values from it.
The expression used to fetch the json data works for one value and not for the other.
The JSON data incoming form the rest client:
[{"var1": 10,"var2": 20}]
JSONPath expression used inside the camel route:
<setHeader headerName="data1">
<jsonpath suppressExceptions="true">$[0].var1</jsonpath>
</setHeader>
<log message="value1 : ${header.data1}" />
<setHeader headerName="data2">
<jsonpath suppressExceptions="true">$[0].var2</jsonpath>
</setHeader>
<log message="valu2 : ${header.data2}" />
Can see the value getting logged in the first logger, but the second logger is 'null' and camel throws an 'NullPointerException'.
Question:
Can some one guide me if this is the right json path expression to get the values. If not do guide me to a solution.
Have checked the expressions working and returning values using various online tools available for json path.

Exchange id in camel request ends with even number

I am using Apache Camel in OSGI scenario using Karaf in version 2.15.1. I am using the exchange.getExchangeId() to print the exchange id in a request/reply. The exchange pattern is set to InOnly. The route looks like this:
<route id="ip_client_rpc">
<from uri="restlet:http://localhost:7070/lsp/patron/id?restletMethod=POST&synchronous=true"/>
<to uri="log:${headers}"/>
<setExchangePattern pattern="InOnly"/>
<process ref="rabbit_client"/>
<to uri="log:${headers}"/>
</route>
However when I print the exchange id sent to the rabbitmq queue it always ends with an even number.
Request from client:ID-VirtualDev-49301-1443430754519-5-6
Request from client:ID-VirtualDev-49301-1443430754519-5-8
Request from client:ID-VirtualDev-49301-1443430754519-5-10
Request from client:ID-VirtualDev-49301-1443430754519-5-12
Request from client:ID-VirtualDev-49301-1443430754519-5-14
Is there a reason why the final digit is always even? Is there another exchange being created that I am missing?
Thanks
Camel uses the same id generator for generating unique ids for different things, its just by chance that its even in this case. Could be that a breadcrumb or message id was also generated that takes the odd number.

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.

Do we need #InOnly annotation or <setExchangePattern pattern="InOnly"/> if we are using sendBody method of ProducerTemplate?

For POJO producing, it is mentioned in Camel docs that InOut is the default.
But, if we are using the sendBody() of ProducerTemplate, is there any need of setting #InOnly also as in the example below.
public class MyBean {
#Produce(uri = "direct:hello")
private ProducerTemplate producerTemplate;
#InOnly
void someInOnlyMethod()
{
...
producerTemplate.sendBody("mystr");
...
}
}
Similarly in the example below, if direct:hello gets a message from the above MyBean object configured without the #InOnly annotation, do we need the setExchangePattern element?
<route>
<from uri="direct:hello"/>
<setExchangePattern pattern="InOnly"/>
<to uri="mock:result"/>
</route>
1)
No when you use the producer template then the MEP is set accordingly to the method you use on the template. eg all send methods is InOnly, and all request methods is InOut. Though some methods has a pattern parameter where you can specify the MEP.
2)
No you often dont have to set/change the MEP. Though in situations where you send a message to a endpoint which supports both InOnly or InOut (and behaves differently) you may want to set the MEP explicit to your needs.
See about these EIPs for details
http://camel.apache.org/event-message.html
http://camel.apache.org/request-reply.html
for example a JMS endpoint can do InOnly (send only to a queue) or InOut (do request/reply over JMS) etc.

Resources