I have a route that looks like this:
from(getEndpoint())
.id(endpoint)
.filter(notDeleted)
.process(get)
.filter(exists)
.choice()
.when(hasProperty)
.wireTap("direct:" + AlternateRoute.ENDPOINT)
.end()
.log("Got here")
.process(postProcessor)
.bean(dao, "save")
.end();
I've tried a few different combinations of end() and endChoice() but no matter what I do nothing after the .choice()/.wireTap() seems to run. I don't see the "Got here" line logged and I don't see my postProcessor or dao get hit.
What am I doing wrong?
Choices are weird in apache camel when you are using java DSL.
Try to simplify your route processing the property in another route:
from(getEndpoint())
.id(endpoint)
.filter(notDeleted)
.process(get)
.filter(exists)
.wireTap("direct:" + AlternateRoute.ENDPOINT)
.log("Got here")
.process(postProcessor)
.bean(dao, "save")
.end();
from("direct:" + AlternateRoute.ENDPOINT)
.choice()
.when(hasProperty)
.log("Do something")
.endchoice();
Related
I'm trying to add error handling to my parallel processing:
...
.multicast(new GroupedMessageAggregationStrategy())
.parallelProcessing()
.to("direct:getAndSaveRoute1")
.to("direct:getAndSaveRoute2")
.end()
.split(body())
.choice()
.when(simple("${body.errorOcurred} == true"))
//TODO:: end route returning current body
.endChoice()
.otherwise()
.log(...)
.endChoice()
.end()
//after split, if no error occurred
.to("direct:nextRoute")
.end()
I can't seem to figure out though how to return/ end the route (and pass back the current body as the rest response body) within the choice in the split. end() and endRest() seem to cause issues...
It is also not clear as how many end()s I need; Adding an end() for the split causes an exception and makes Spring fail to boot.
For those in the future, I ended up making a bean to turn the list into a single message, and then do a choice based on that.
Not very 'camel', but needed to be wrapped up
I am trying to stop camel route when there is no more data in the database to pool, but unable to stop.
from("timer://pollTheDatabase?delay=50s")
.routeId("db-pooling-route")
.to("mybatis:queryToSelectData?statementType=SelectOne")
.choice()
.when().simple("${in.header.CamelMyBatisResult} == ''").stop()
.otherwise().to("direct:processing-data")
.end()
.end()
.end();
stop() means stop routing the current message, not the route itself. To stop/start routes etc you can use the controlbus component.
https://camel.apache.org/components/latest/controlbus-component.html
And since you want to stop the route from itself, then set the option async=true on the controlbus endpoint.
I tried using control-bus and it worked.
from("timer://pollTheDatabase?delay=50s&synchronous=false")
.routeId("db-pooling-route")
.to("mybatis:queryToSelectData?statementType=SelectOne")
.choice()
.when().simple("${in.header.CamelMyBatisResult} == ''")
.to("controlbus:route?async=true&routeId=db-pooling-route&action=stop")
.end()
.to("direct:processing-data");
How to use choice in try catch block using Apache Camel in a Route with Java DSL?
I have a situation in which, I need the following structure:
route-->from--> doTry-->choice-->when-->simple-->to-->otherwise-->to-->enddoTry-->docatch-->to-->enddocatch-->endroute
As of now I tried below lines:
.doTry()
.choice()
.when(header("CamelFileName").contains("xxxxx"))
.to()
.otherwise().to("controlbus:route?routeId=XXXX&action=stop")
.doCatch(java.lang.Exception.class)
.log("STOPPING ROUTE")
.to("controlbus:route?routeId=XXXX&action=stop&async=true")
But I am getting "cannot find symbol" error at docatch()
Could you please suggest way to use "choice" in try catch block with Java DSL?
Try this. This should work
.doTry()
.choice()
.when(header("CamelFileName").contains("xxxxx"))
.to()
.otherwise()
.to("controlbus:route?routeId=XXXX&action=stop")
.endDoTry()
.doCatch(java.lang.Exception.class)
.log("STOPPING ROUTE")
.to("controlbus:route?routeId=XXXX&action=stop&async=true")
I have a setup like below.
The issue I have is that the key from the Idempotent Repository is not being removed when an exception is thrown (on line stated below) when using seda component within OnException. When I change to use direct within the OnException the key is removed from the cache. On both trials the email is also being sent correctly.
My queries are:
why is the key not being removed from the repository cache when using seda within the OnException?
is there an issue with using seda within the OnException?
Here is the routes:
MyRouteClass1
onException(Exception.class)
.setHeader("subjectText", simple("failure email!"))
.to("seda:notifySupportOnFailure")
.end();
from("direct:findWorkItems")
.bean(someService, "findWorkItems")
.split(body())
.throttle(1).timePeriodMillis(5000L)
.to("direct:handleWorkItem")
.choice().when(header("resultId").isGreaterThan(0))
.bean(someService, "updateWorkItemToHandled")
.end();
from("direct:handleWorkItem")
.idempotentConsumer(simple("${body.workItemId}"), duplicatesRepo)
.bean(someService, "handleWorkItem") // e.g. exception would be thrown within here
.setHeader("resultId", body())
.end();
MyRouteClass2
from("seda:notifySupportOnFailure")
.setHeader("from", simple("sender#mail.com"))
.setHeader("to", simple("recipient#mail.com"))
.setBody(simple("Failure:\n ${exception.message} \n\ndetail: \n${body}"))
.to("smtp://localhost")
.log("Failure email now sent.")
.end();
I have also attempted another workaround. I have modified the onException clause as per below. This does allow the key to be removed from the Repository when the exception is thrown. I am wondering if this is a correct approach ?
onException(Exception.class)
.setHeader("subjectText", simple("failure email!"))
.multicast().to("seda:notifySupportOnFailure").end()
.end();
A work around would be to put the idempotentConsumer call in your parent route 'findWorkItems' and setting the completionEager flag on it to true.
onException(Exception.class)
.setHeader("subjectText", simple("failure email!"))
.to("seda:notifySupportOnFailure")
.end();
from("direct:findWorkItems")
.idempotentConsumer(simple("${body.workItemId}"), duplicatesRepo).completionEager(true)
.bean(someService, "findWorkItems")
.split(body())
.throttle(1).timePeriodMillis(5000L)
.to("direct:handleWorkItem")
.choice().when(header("resultId").isGreaterThan(0))
.bean(someService, "updateWorkItemToHandled")
.end();
from("direct:handleWorkItem")
.bean(someService, "handleWorkItem") // e.g. exception would be thrown within here
.setHeader("resultId", body())
.end();
I'm trying to build a route that tries to validate an xml and if everything is correct then has to split this file otherwise an exception is thrown and it has to do something else. So I did the following:
from("file:"+fileOutboxTransformed+"?preMove=inprogress&move="+backupFolderTransformed+"/"+labelMessageType+"_${date:now:yyyyMMddHHmmssSSS}-${file:name.noext}.${file:ext}")
.log(LoggingLevel.INFO, "Got transformed file and sending it to jms queue: "+queue)
.doTry()
.to("validator:classpath:"+validator)
.split(xPathMessageTypeSplit)
.to("jms:"+queue+"?jmsMessageType=Text")
.doCatch(ValidationException.class)
.log(LoggingLevel.INFO, "Validation Exception for message ${body}")
.to("xslt:classpath:"+transformationsErrorAfter)
.split(xPathNotificationSplit)
.to("file:"+fileOutboxInvalid+"?fileName=${file:name.noext}-${date:now:yyyyMMddHHmmssSSS}.err2")
.end();
But it does not compile (if I do not use the split then it compiles and works) and the error is:
The method doCatch(Class<ValidationException>) is undefined for the type ExpressionNode
So I tried the following
from("file:"+fileOutboxTransformed+"?preMove=inprogress&move="+backupFolderTransformed+"/"+labelMessageType+"_${date:now:yyyyMMddHHmmssSSS}-${file:name.noext}.${file:ext}")
.log(LoggingLevel.INFO, "Got transformed file and sending it to jms queue: "+queue)
.doTry()
.to("direct:validate")
.doCatch(ValidationException.class)
.log(LoggingLevel.INFO, "Validation Exception for message ${body}")
.to("xslt:classpath:"+transformationsErrorAfter)
.split(xPathNotificationSplit)
.to("file:"+fileOutboxInvalid+"?fileName=${file:name.noext}-${date:now:yyyyMMddHHmmssSSS}.err2")
.end();
from("direct:validate")
.to("validator:classpath:"+validator)
.to("direct:split_message");
from("direct:split_message")
.split(xPathMessageTypeSplit)
.to("jms:"+queue+"?jmsMessageType=Text");
This time I get the error of duplicate endpoint
org.apache.camel.FailedToStartRouteException: Failed to start route route312 because of Multiple consumers for the same endpoint is not allowed: Endpoint[direct://validate]
do you have any idea on how to solve this problem?
In order to get back to the doTry() block from a split() block (or choice or other nested type), you need to use the endDoTry(). Contrary to its name, this method will end the nested split block and return back to the doTry() DSL.
I'd use the first route you posted with these changes:
from("file:"+fileOutboxTransformed+"?preMove=inprogress&move="+backupFolderTransformed+"/"+labelMessageType+"_${date:now:yyyyMMddHHmmssSSS}-${file:name.noext}.${file:ext}")
.log(LoggingLevel.INFO, "Got transformed file and sending it to jms queue: "+queue)
.doTry()
.to("validator:classpath:"+validator)
.split(xPathMessageTypeSplit)
.to("jms:"+queue+"?jmsMessageType=Text")
.endDoTry()
.doCatch(ValidationException.class)
.log(LoggingLevel.INFO, "Validation Exception for message ${body}")
.to("xslt:classpath:"+transformationsErrorAfter)
.split(xPathNotificationSplit)
.to("file:"+fileOutboxInvalid+"?fileName=${file:name.noext}-${date:now:yyyyMMddHHmmssSSS}.err2")
.endDoTry()
.end();
Your second try seems fine. The error you're getting is caused by two routes beginning with from("direct:validate")
Don't you have an other route in your application consuming from the same endpoint?
Edit : Try to name it differently, maybe validate exists already (in your app or inside camel)