Is there a way to do smth like this to work? I am talking about the condition inside when.
.choice()
.when(Exchange::isFailed)
.to(direct(URI_DEADLETTER))
I tried:
.when(method(Exchange.class, "isFailed"))
.when().exchange(Exchange::isFailed)
For the first solution an error is thrown and the second is not working.
I know that I can create a new class and a method inside, from here: How do i use java boolean condition in camel route?
And I read about the predicat here: http://www.davsclaus.com/2009/02/apache-camel-and-using-compound.html.
But without using a new class or predicat, is there a way that I can achieve this?
A lazy solution is to use Camel simple language (http://camel.apache.org/simple.html) which allows you to access anything (headers, properties, body, method, etc..) of current exchange
.choice()
.when( simple("${exception} != null") )
A more OO solution would be to use Camel Predicate (Builder):
Predicate condition1 = ...
Predicate condition2 = ...;
Predicate isFailed = PredicateBuilder.or(condition1, condition2);
.choice()
.when( isFailed )
Related
I tried to instantiate multiple routes from the same camel route template which resulted in a misbehaviour in the evaluation of several simple expressions.
I am using camel 3.20.1 in a spring boot application and i am having problems creating routes from the following route template. I am using constants for the specific template parameter keys - these are also used in several expressions (simple expression etc). At one point in the route template / instantiation of a route based on the following route template, especially at the aggregate / completionSize definition, an expression (templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE)) evaluates to a value specified for a second route which is using this template.
Route template:
#Override
public void configure() throws Exception {
routeTemplate("generic-data-file-based-template")
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX)
.from(templateParameterString(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE))
.filter(FILENAME_FILTER_PREDICATE)
.aggregate(templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX), new GroupedMessageAggregationStrategy())
.completionSize(templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE))
.log("correlation completed by ${header." + Exchange.AGGREGATED_COMPLETED_BY + "} with ${header." + Exchange.AGGREGATED_SIZE + "} files")
.setHeader(INTERNAL_HEADER_REFERENCE_DATE, headerSubstring2(header(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX), Exchange.FILE_NAME))
.to(templateParameterString(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI));
}
private Expression templateParameterExpression(String value) {
return simple("{{"+value+"}}");
}
Route I based on this template:
public void configure() throws Exception {
templatedRoute("generic-data-file-based-template")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI, "sftp:localhost:22/test/application/cashflows?username=tester&password=password")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI, "mock:cashflow-watch-mock")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE, "CASHFLOW")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX, "[0-9]{8}(Flow_tot|Head_tot|IntPeriod_tot){1}.csv")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX, "[0-9]{8}")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX, "[0-9]{8}")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE, "3")
.routeId("file-watch-1");
}
Route II based on this template:
public void configure() throws Exception {
templatedRoute("generic-data-file-based-template")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI, "sftp:localhost:22/test/application/bookvalues?username=tester&password=password")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI, "mock:bookvalue-watch-mock")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE, "BOOKVALUE")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX, "BW_BVA_[0-9]{8}.csv")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX, "BW_BVA_[0-9]{8}.csv")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX, "[0-9]{8}")
.parameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE, "1")
.routeId("file-watch-2");
}
It depends on the order in which these two routes are added to the camel context, to which value the expression templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE) evaluates for both routes. For example, if file-watch-1 was added first, then the expression in file-watch-2 will evaluate to the value 3 instead of 1.
I debugged my code and saw that camel uses an expressions cache which returns the upper value for the second route - but only for the expression used in the completionSize definition. Other expressions have the right value.
I already took a look on the official documentation which isn't exactly stating that this is common behaviour for the way i specified the templateParameter.
So, am i doing something wrong? Is this an error in the framework? Common behaviour? Should i use templateBeans instead?
Thanks in advance!
I investigated my problem further and found out that the two routes i am instantiating are using the same instance of AggregationDefinition which evaluates the simple expression in completionSize always to the same value once set (expressions cache !?).
I fixed this behaviour using another signature of the method completionSize in the template itself (completionSize(String completionSize)) and used the property method to specify the size:
#Override
public void configure() throws Exception {
routeTemplate("generic-data-file-based-template")
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX)
.templateParameter(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX)
.from(property(RouteTemplateConstants.TEMPLATE_PARAMETER_FROM_URI))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILENAME_FILTER_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_GENERIC_DATA_TYPE))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_REFERENCE_DATE_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX))
.setHeader(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE, templateParameterExpression(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE))
.filter(FILENAME_FILTER_PREDICATE)
.aggregate(simple(property(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX)), new GroupedMessageAggregationStrategy())
.completionSize(property(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_COMPLETION_SIZE))
.log("correlation completed by ${header." + Exchange.AGGREGATED_COMPLETED_BY + "} with ${header." + Exchange.AGGREGATED_SIZE + "} files")
.setHeader(INTERNAL_HEADER_REFERENCE_DATE, headerSubstring2(header(RouteTemplateConstants.TEMPLATE_PARAMETER_FILE_CORRELATION_REGEX), Exchange.FILE_NAME))
.to(property(RouteTemplateConstants.TEMPLATE_PARAMETER_TO_URI));
}
Now my code works as expected.
In my Apache Camel application I have multiple conditions checking the existence of keys in a JSON. I want to reduce the boiler plate code, therefore I need to transform my Expressions to a Predicate.
My code with Expressions:
.choice()
.when().jsonpath("$.score", true).to("direct:b")
.when().jsonpath("$.points", true).to("direct:b")
.otherwise().to("direct:c");
See also: JSONPATH
My code with Predicates:
.choice()
.when(PredicateBuilder.or(jsonpath("$.score", true), jsonpath("$.points", true))).to("direct:b")
.otherwise().to("direct:c");
See also: PREDICATES
But this is not working, because there is no suppressExceptions parameter (see BuilderSupport#jsonpath). Unfortunately, there is also no exists mehod (see ValueBuilder).
How can I write a Predicate for checking the existence of a key in a JSON?
this code solve your problem .
.choice()
.when(PredicateBuilder.and(jsonpath("$[?(#.score)]"), jsonpath("$.score"))).to("direct:b")
.when(PredicateBuilder.and(jsonpath("$[?(#.points)]"), jsonpath("$.points"))).to("direct:b")
.otherwise().to("direct:c");
I have to write to multiple if condition in camel and I need help to go around.
if(token is NULL)
if(condition is NULL)
if(Dates does not match)
Then execute this...
What I am trying is
.choice
.when(token is NULL)
.when(condition is NULL)
.when(Dates does not match)
.log(update DB)
.endchoice()
which dont work..
Please help
Two conditions:
Predicate p1 = header("token").isEqualTo("001"):
Predicate p2 = header("condition").isEqualTo("002");
Combine these conditions:
Predicate cond = PredicateBuilder.and(p1, p2);
Then In Camel:
.choice
.when(cond)
.log(update DB)
.endchoice()
The best way to do this is to use Predicates.
You can define Predicates as private field if you are using Java DSL, by using expression builder, to build multiple conditions, then use the predicate in your when(), your route would looks much cleaner and easier to read.
private static final Predicate invalidHeaders = or(header(XXX).isNull(), header(YYY).isNull());
...
.when(invalidHeaders)
You need to do this in a single when and use and &&
.when(token is NULL && condition is NULL && XXX)
There are various ways to do this.
If you use Java code then you can append multiple predicates together: http://www.davsclaus.com/2009/02/apache-camel-and-using-compound.html
I have some FixedLengthRecord objects that I initialize a BindyFixedLengthDataFormat object via one of those records. First I have to know if that POJO isHeader or isFooter (I have annotated on those pojos), and then other steps:
from(myUri)
.split().tokenize(myToken)
.process(initializeMyFixedLengthDataFormat)
.choice()
.when(/*fixedLengthRecord.IsHeader*/)
//do something
.when(/*fixedLengthRecord.IsFooter*/)
//do something
.otherwishe()
//do something
.end()
.end()
My problem is, I cannot figure out how to fetch if that FixedLengthRecord isHeader/isFooter or not.
Appreciate for any help. (Google could not help.)
bindy object (for my case an object of type BindyFixedLengthDataFormat) has a factory property (of type BindyAbstractFactory).
For FixedLengthDataFormat I casted the factory object to BindyFixedLengthFactory and reached isHeader/isFooter methods.
I'm trying to set a property called "articleId" on the exchange's body and I thought the most explicit way to do this would be to use bean(). However, I can't get it to work. When I have the following in my route:
.bean(body(Article.class), "setArticleId(${header.articleId})")
I get this error message:
Caused by: org.apache.camel.component.bean.MethodNotFoundException: Method with name: setArticleId(${header.articleId}) not found on bean: bodyAs[com.example.model.Article] of type: org.apache.camel.builder.ValueBuilder
My solution has been to use a processor() and a few lines of code in order to set the articleId property from the header value, but to me that seems like overkill.
I've been complaining on camel-users that there isn't a good way to do this. For now here is how I tackle it:
.setHeader("dummy").ognl("request.body.articleId = request.headers.articleId")
Which requires adding camel-ognl dependency.
UPDATE
Actually, there is also a language endpoint that can do this without the setHeader, but you have to say transform=false or else it replaces your body with the result:
.to("language:ognl:request.body.articleId = request.headers.articleId?transform=false") // remember ?transform=false
I think you need to spend some time to go through this page, if you don't know how to tell camel which method of the bean you want it invoke.
If you just want to set the exchange property, you can just use the DSL
setProperty("articleId", body());
to do this kind of work.