jboss fuse split List property - apache-camel

I have a proxy, which take a RequestBean as argument, which contains a list property and I need to split this list property using split EIP.
I tried
<split streaming="true">
<simple>${body}</simple>
<process ref="requestHeaderProcessor" />
</split>
My Complete route is
<route id="httpBridge">
<from uri="cxf:bean:splitterOperation?dataFormat=POJO" />
<split streaming="true">
<simple>${body}</simple>
<bean ref="requestHeaderProcessor" method="process" />
</split>
<to uri="cxf:bean:realService" />
</route>
My Proxy Service method signature is
public List<ResponseBean> splitList(List<RequestContent> requestBean);
ResponseBean.java
ResponseBean {
private String name;
}
RequestBean.java
RequestBean {
private String list;
}
The processor is not receiving individual RequestContent, I want the processor to receive RequestContent individually.
tried printing following line and
System.out.println(exchange.getIn().getBody().getClass().getName());
and got java.util.ArrayList. So its 100% Iteratable.
But, when I print the
System.out.println(exchange.getIn().getBody());
I am getting
[webservice.RequestContent#10128f3, webservice.RequestContent#1277137]
Which is list of all the RequestContent.
But, why am I seeing the list in the bean, the Exchange must contain only one RequestContent according to split definition (Since, it processes sequentially).
Where am I making mistake. or is this the way it works. How can I make sure it splits the content?
How to achieve this?

Whatever this method returns is what is used for splitting
<simple>${body.requestBean.requestContent}</simple>
So make sure that is a List or array, or can be iterated

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>

Not able to update Camel exchange property

I am setting a property of camel exchange in route 1. I am trying to update the same in the second route inside a splitter. but in the second iteration of splitter i am getting the original value that I set in the route 1 instead of the new updated value. Below is the sample i am trying..
<route handleFault="true" streamCache="true" id="route1">
<from uri="cxfrs://bean://test?synchronous=true"/>
<bean ref="testBean" method="setMyProperty"/>// setting initial value for property
<to uri="direct:directCall"/>
</route>
<route handleFault="true" streamCache="true" id="route2">
<from uri="direct:directcall"/>
<log message="Inside Second call..."/>
<split>
<jsonpath>some Json path</jsonpath>
<bean ref="formatConvertor" method ="convertLHMToJSON(${body})"/>
<split>
<jsonpath>some json path</jsonpath>
<bean ref="PropertySetter" method ="setProperty"/> //I am setting new value in this method
</split>
</split>
Inside the beans:
public void setMyProperty(Exchange exchange) {
exchange.setProperty("testProp", "hello");
}
public void setProperty(Exchange exchange) {
sysout(exchange.getProperty("testProp").toString())//this always prints "hello"
String x=exchange.getProperty("testProp")+some other value;// in all iterations of split I am getting 'hello' as the value of the property instead of new value
exchange.setProperty("testProp", x);
sysout(exchange.getProperty("testProp").toString())// this line prints the new value
}
Why the property is not updated? Even i tried setting in headers. same result. Thank you.
You must use a split-aggregate pattern and copy the property value during each iteration of the split from the old exchange to the new exchange because every time when the split iteration happens a new exchange is created from the source message (only carrying the properties & headers set before the split)
recover headers value after split apache camel

Exception handling Camel

I'm trying to pick a file from a directory, split a file and add each splitted lines to activemq. I'm facing a problem with exception handling during this process. Lets say a file in the directory is a binary file (executable), then splitter thows org.apache.camel.RuntimeCamelException and java.nio.charset.MalformedInputException exceptions. If this occurs, then I need to catch these exceptions, nothing should add in activemq and that just particular thread should exit after logging exception. Referred online and wrote the following code but don't know how to stop adding to activemq and quit specific thread.
<route id="msg_producer">
<from uri="input.file.from" />
<doTry>
<split parallelProcessing="true" executorServiceRef="msgProducer"
streaming="true">
<tokenize token="\n"></tokenize>
<to uri="input.activemq.to" />
</split>
<doCatch>
<exception>org.apache.camel.RuntimeCamelException</exception>
<exception>java.nio.charset.MalformedInputException</exception>
<handled> <constant>true</constant></handled>
<setBody>
<simple>${exception.stacktrace}</simple>
</setBody>
<setHeader headerName="CamelFileName">
<simple>${file:onlyname.noext}_error.log</simple>
</setHeader>
</doCatch>
</doTry>
</route>
as #claus Ibsen said to filter the files you can use a filefilter property so that you pick only files based on extension and some standard pattern something like this
<bean id="FileFilter" class="org.apache.camel.component.file.AntPathMatcherGenericFileFilter">
<!-- ? matches one character
* matches zero or more characters
** matches zero or more directories in a path -->
<property name="includes" value="#{databaseProperties.getProperties().getProperty('file.name.pattern')}"/>
<!-- if you wan to exclude specific files say bad in name or .exe files. Use comma to separate multiple excludes -->
<!-- <property name="excludes" value="**/*bad*,**/*.exe"/> -->
</bean>
and your file.name.pattern can be something like this **/contract.csv

Apache Camel transform not working

I have this Camel Route:
<route id="externalRestPushRoute">
<from uri="jms:pushProcessedRecordsToExternal" />
<setHeader headerName="PAYLOAD">
<simple>body</simple>
</setHeader>
<marshal ref="jack"></marshal>
<to uri="http://localhost/front/rest/karec/dummy-push"/>
<transform>
<simple>in.header[PAYLOAD]</simple>
</transform>
<to uri="bean:noAuthRecordPersistenceService?method=deliverySuccess" />
</route>
The idea is this:
I want to deliver an object in JSON format to a REST endpoint(all the headers are properly set and the rest endpoint receives the json format)/
To convert the object to JSON format I use marshal and it works.
Now, the response back from the http endpoint is of type java.io.InputStream but I don't care.
What I care is converting the body back to the original object before it was marshaled.
I did save the object in a header before marshaling in a header named PAYLOAD.
Now I want to use transform to get it back into the body of the message.
Well, that does not seem to work. When it get to the last bean it complains that body is still of type java.io.InputStream.
Stores the body on the exchange property instead of a header, that is safer.
<setProperty propertyName="PAYLOAD">
<simple>body</simple>
</setProperty>
<transform>
<simple>${property.PAYLOAD}</simple>
</transform>

How to set endpoint specific header value in Camel Multicast

I want to set the endpoint specific header value in Multicast component.
XML DSL as below:
<route>
<from uri="direct:testRoute"/>
<multicast strategyRef="MyAggregator" parallelProcessing="true">
<to uri="direct:call1"/> <!-- set the header MY_HEADER = "call_1" -->
<to uri="direct:call2/> <!-- set the header MY_HEADER = "call_2" -->
</multicast>
</route>
Basically in the response aggregation I want to know, to which service request this response belongs to.
I tried by doing this, but its not the correct way (parse exception):
<to uri="direct:call1">
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
</to>
What I see from reading the documentation is that, multicast will copy the source Exchange and multicast each copy. So its a shallow copy of the Exchange and kind of reference shared between all the multicast recipient.
But here I am looking for specific header value for individual recipient.
How to do this? Any pointers?
You can't do that in the multicast route. But it should be simple in the direct route afterwards.
<route>
<from uri="direct:call1"/>
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
.. do whatever
</from>
</route>
otherwise, if call1 is used for other things and you cannot know when to put the header once in that route, make a simple prep-route:
<route>
<from uri="direct:prepCall1"/>
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
<to uri="direct:call1"/>
</from>
</route>
As a third option, even though you cannot place DSL (xml or java) in the multicast list, you can supply an "onPrepareRef" processor bean that adds the headers to your exchange. But one processor will handle all multicast endpoints.
There is a header with the key Exchange.TO_ENDPOINT that you can see which of the 2 endpoints the response is from.

Resources