Apache Camel split with new line token and use aggregation stategy - file

I have the following route:
from("file:/home/tmp/test?move=.done")
.routeId("file")
.split(body().tokenize("\n"),new GroupedBodyAggregationStrategy())
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getMessage().setHeader("Test", "test");
System.out.println(exchange.getIn().getBody());
}
})
and the file that is being consumed is:
1234,56676,2345
234,213,412
124,423,5236
I would expect only one exchange to reach the processor after split and that its body contains all the above lines, however it behaves like I do not use an aggregation strategy at all. 3 exchanges reach the processor each with the body that corresponds to a single line. Also, it does not matter if I use GroupedBodyAggregationStrategy or a custom one, it is always the same. What am I doing wrong?

Give a look here enter link description here
What you look is :
from("file:/home/tmp/test?move=.done")
.routeId("file")
.split(body().tokenize("\n"),new GroupedBodyAggregationStrategy())
// instructions on each message from the split (.ie each row here)
.end()
// instructions on aggregated result
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getMessage().setHeader("Test", "test");
System.out.println(exchange.getIn().getBody());
}
})

Related

filter messages coming from a specific type of camel endpoint

lets say, I have
from("direct:start").filter("...")
How can I filter out messages coming from an endpoint like smtp? Is there a way to check the type of the previous endpoint?
Edit: As per advice from vikingsteve, I have implemented the code this way:
from("direct:source")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.setProperty("source", "smtps");
}
})
.to("direct:start");
from("direct:start").filter(
new Predicate() {
#Override
public boolean matches(Exchange exchange) {
if(exchange.getProperty("source") == "smtps")
return true;
else
return false;
}}));
You would normally set an exchange property if you need to identify some information about the original message (such as where it came from, or some other metadata not contained in the body).
from("smtp:...").setProperty("source", "smtp").to("...")
edit: here's a simpler version of your solution, I havent tested it, but it might work like this:
from("direct:source")
.setProperty("source", "smtps")
.to("direct:start");
from("direct:start")
.filter(exchangeProperty("source").isEqualTo("smtp"))

Can we provide a processor before onFallbackViaNetwork() in camel-hystrix-eip

I'm using camel-hystrix-eip in my project, I want a processor before my fallback, but it's not working
from("direct:sample").id("id:direct:sample").process(requestProcessor)
.hystrix()
.to(endPoint)
.onFallbackViaNetwork()
.to(fallback_endPoint)
I want to alter my fallback_endpoint using a processor, but seems like after onFallbackViaNetwork() we have to immediately provide to().
please suggest if there any way to do so.
I tried something like below, but it's not working.
from("direct:sample").id("id:direct:sample").process(requestProcessor)
.hystrix()
.to(endPoint)
.onFallbackViaNetwork()
.process(fallbackProcessor)
.to(fallback_endPoint)
Actually, I'm using requestProcessor to override the actual endpoint, and in case of a fallback, fallback_endPoint is also getting overridden, is there any way to avoid this.
You can have a processor after onFallbackViaNetwork(). You can also use the toD EIP to send the message to a dynamic endpoint.
Based on your code, you could set a Header MyEndpoint which contains your new endpoint string, and then reference it using .toD("${header.MyEndpoint}"). Repeat this pattern whenever you need to set a dynamic endpoint.
For example:
from("direct:sample")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// do something
exchange.getIn().setHeader("EndpointHystrix", "mock:hystrix");
}
})
.hystrix()
.toD("${header.EndpointHystrix}")
.onFallbackViaNetwork()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// do something more
exchange.getIn().setHeader("EndpointFallback", "mock:fallback");
}
})
.toD("${header.EndpointFallback}")
.end()
.to("...");
I've tested this in Camel 2.20.0 and 2.21.0.

Split and Aggregate in Apache Camel

I'd like to split exchange message body (it's list of MyCustomClass object), process them (one by one) and them aggregate the all exchanges together. Split is ok, process one by one also ok, but I can't figure out how to aggregate them.
from("mysource")
.unmarshal(new ListJacksonDataFormat(MyClass.class))
.split().body()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// process MyClass item
exchange.getIn().setBody(processedItem);
}
})
.to("destinationForProcessedItem")
.aggregate(new GroupedExchangeAggregationStrategy()) <== Seems like problem is here
.process(new Processor() {
// handle result of aggregation
})
I don't need complicated aggregation, just collect list of splitted Exchanges and handle them in the final processor.
Use the built-in aggregator in the splitter, see the composed message processor EIP pattern: https://camel.apache.org/components/latest/eips/composed-message-processor.html#_sample.
write like this
.aggregate(new AggregationStrategy() {
#Override
public Exchange aggregate(Exchange exchange, Exchange exchange1) {
//logic for aggregation using exchnage and exchange1
}
})

How to use Apache Camel exchange messages?

I am newcomer in Apache Camel. Please have a look to my code bellow:
I have a service which exposed as cxf webservice:
interface CxfService{
public OutputType hello(InputType input);
}
This is my route:
from("cxf:/test?serviceClass=" + CxfService.class.getName())
.to("log:cxfLog1")
.recipientList(simple("direct:${header.operationName}"));
from("direct:hello")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {
InputType file = exchange.getIn().getBody(InputType.class);
exchange.getOut().setBody(new OutputType());
}
});
The code works as expected, it consume InputType and produce OutputType.
I want to borrow my body to do another stuffs, so i rewrite that like this:
from("cxf:/test?serviceClass=" + CxfService.class.getName())
.to("log:cxfLog1")
.recipientList(simple("direct:${header.operationName}"));
from("direct:hello")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {
InputType file = exchange.getIn().getBody(InputType.class);
exchange.getOut().setHeader("header.temporary", new OutputType());
}
})
.to("some endpoint")
.setBody(simple("${header.temporary}"));
This webservice consume InputType and produce nothing. What wrong with that?
In your second piece of code, when setting the header.temporary, you should change two things:
setHeader("temporary", new OutputType()) - the 'header' prefix isn't
needed - you're addressing headers directly via the method call.
Use getIn() instead of getOut(). The input will get copied to the
output. You may want to do some research into the procedure for
Camel building the out message for details - I'm not 100% sure of
this one.
Change
exchange.getOut().setHeader("header.temporary", new OutputType());
To
exchange.getIn().setHeader("temporary"), new OutputType());
.setHeader() is when you use the simple language. In 99% of the cases getIn() is sufficient.

Apache Camel split and aggregate exception handling

We defined a route in Camel with split and aggregate functionality, but can't propagate the exception back to split after the aggregator. Which cause's the split to run even if we encounter an exception
below is the code which is not working
from("direct:MyRoute")
.routeId("MyRouteID")
.split().tokenize("\n", 1)
.streaming().stopOnException()
.choice()
.when(simple("${property.CamelSplitIndex} > 0"))
.unmarshal(domainDataFormat)
.choice()
.when(simple("${property.CamelSplitComplete}"))
.process(
new Processor()
{
#Override
public void process(Exchange exchange) throws Exception
{
exchange.getIn().getHeaders().put(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE, true);
}
}
)
.end()
.aggregate(myAggregationStrategy).constant(true) //if i comment this line split will be stop on exception
.threads().executorService(executorService)
.process(myProcessor).end()
.end();
Processor(myProcessor) from the above code is below:
counter.incrementAndGet(); //atomic counter
if(counter.get()==3)
{
exchange.setException(new RuntimeException());
throw new RuntimeCamelException();
}
But, the moment I remove the aggregate from the route, Split is able to stop the route on Exception.
Use the composite message processor EIP which is split + aggregate (fork/join) in the same unit of work.
See docs at: https://camel.apache.org/components/next/eips/composed-message-processor.html
And see the splitter only section where you can specify an aggregation strategy to the splitter to have it work together.

Resources