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
Related
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>
I'm trying to call bean's public method by passing parameter .But i'm unable to run it.Here is my sample blueprint code(I have written from clause but here i'm pasting only necessary code)-
<bean id="ProcessorRef" class="com.healthedge.customer.THC.extractor.ProcessorClass">
<to uri="bean:ProcessorRef" />
Processor class-
public class ProcessorClass{
public String whatAmI(String str) {
return "I am "+str;
}
}
Now in above example how can I invoke whatAmI method with parameter from blueprint?TIA
You can do it by calling directly the method you want
<bean id="ProcessorRef" class="com.healthedge.customer.THC.extractor.ProcessorClass">
<bean ref="ProcessorRef" method="whatAmI('your_parameter_here')" />
If the value you want to pass to whatAmI method is in header, you can do like this.
<to uri="bean:ProcessorRef?method=whatAmI(${header.xyz})" />
If its a constant string, you can put the string directly in place of ${header.xyz}
Another option is to modify your whatAmI method to
public class ProcessorClass{
public String whatAmI(Exchange exchange) {
// exchange has many methods, with which you can access headers and body.
}
}
In such a case you can write the route like this
<to uri="bean:ProcessorRef?method=whatAmI" />
Personally, I would prefer second option, because it gives you access to complete exchange object, which would have all the details.
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");
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
How can i call a SOAP web service with an empty message body using Apache Camel?
For example, the final endpoint on a route would be the invocation of a method on my proxy that takes 0 arguments.
EDIT:
example xml configuration:
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<to uri="cxf:bean:someWS"/>
</route>
...
<cxf:cxfEndpoint id="someWS" address="${ws.address}"
serviceClass="com.example.ws.SomeWS"
The problem is that the method 'invoke' on the WS takes 0 arguments, and an exception is thrown stating that 1 argument is being received. Is there a way for me to specify to ignore this received input?
You can set the message body to be null, if the invocation just take 0 argument. null simple expression is added since camel 2.12.3.
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setBody>
<simple>null</simple>
</setBody>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<to uri="cxf:bean:someWS"/>
</route>
I also needed to set an empty body to Apache Camel xml and the solution below worked for me.
<setBody id="set-empty-body">
<constant/>
</setBody>
Hope this helps to whoever need it.
The xml configuration will fail if the content of the body is not with the correct type of the class required by the method of your bean. By default, it could be an Object and not a String. When the method recieves the body in an incorrect format, it would process a null value, instead of the body of the route. To solve this problem, you will need to convert the body into the expected class of the method of your bean. For example, if the method's argument of the bean is a String, then you could do something like:
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<convertBodyTo type="String"/>
<to uri="cxf:bean:someWS"/>
</route>
For more information about body conversion, you can check the docs: https://camel.apache.org/components/3.14.x/eips/convertBodyTo-eip.html