Execute route only when direct component is called - apache-camel

I want to unzip files whenever a "direct" route is called. The fileName I am getting from some other direct route.
from("direct:unZipFile")
.from("file:C:\\MYFILES\\File\\Unzipped\\?fileName=${header.fileName}&idempotent=true")
.split(new ZipSplitter())
.streaming()
.to("file:C:\\MYFILES\\File\\Unzipped\\")
.split(body().convertToString().tokenize("\n"))
.transform()
.simple("${in.body}")
.end();
Now it is working when I call the direct component but it also keeps on scanning the directory and processes the same file. I understand that the above code allows the trigger from direct as well as file component but I just want it to execute from "direct" component and I can't remove the "file" component as from that only I am reading the file.

You can also try to use pollenrich
from("direct:unZipFile")
.pollEnrich.simple("file:C:\\MYFILES\\File\\Unzipped\\?fileName=${header.fileName}")
.split(new ZipSplitter())
.streaming()
...

You can use consumerTemplate
from("direct:unZipFile")
.process(exchange -> {
Exchange recvFiles = exchange.getContext().createConsumerTemplate().receive("file:C:\\MYFILES\\File\\Unzipped\\?fileName=${header.fileName}&idempotent=true");
exchange.getIn().setBody(recvFiles.getIn().getBody());
exchange.getIn().getHeaders().putAll(recvFiles.getIn().getHeaders());
})
.split(new ZipSplitter())
.streaming()
.to("file:C:\\MYFILES\\File\\Unzipped\\")
.split(body().convertToString().tokenize("\n"))
.transform()
.simple("${in.body}")
.end();

You can also just set the message body with a java.io.File where you compute the file name in a few lines of Java code, but yeah otherwise the pollEnrich is the EIP pattern solution for this.

Related

Camel - How to stop camel route using java dsl, when using TIMER component to pool database?

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");

Apache Camel route with no "to" endpoint

I am using Apache Camel to assist with capturing message data emitted by a third party software package. In this particular instance, I only need to capture what is produced by the software, there is no receiver on the other end (really no "end" to go to).
So, I tried to set up a route with just the "from" endpoint and no "to" endpoint. Apparently this is incorrect usage as I received the following exception:
[2018-08-15 11:08:03.205] ERROR: string.Launcher:191 - Exception
org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> From[mina:udp://localhost:9877?sync=false] <<< in route: Route(route1)[[From[mina:udp://localhost:9877?sync=false]] -... because of Route route1 has no output processors. You need to add outputs to the route such as to("log:foo").
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1063)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:196)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:974)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:3301)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3024)
at org.apache.camel.impl.DefaultCamelContext.access$000(DefaultCamelContext.java:175)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2854)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2850)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2873)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2850)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2819)
at {removed}.Launcher.startCamel(Launcher.java:189)
at {removed}.Launcher.main(Launcher.java:125)
Caused by: java.lang.IllegalArgumentException: Route route1 has no output processors. You need to add outputs to the route such as to("log:foo").
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1061)
... 13 more
How do I set up a camel route that allows me to intercept (capture) the message traffic coming from the source, and not send it "to" anything? There is no need for a receiver. What would be an appropriate "to" endpoint that just drops everything it receives?
The exception suggestion of to("log:foo"). What does this do?
You can see if the Stub component can help
http://camel.apache.org/stub.html
Example:
from("...")
.to("stub:nowhere");
The exception suggestion of to("log:foo"). What does this do?
It sends your route messages to an endpoint with a component of type log:
(http://camel.apache.org/log.html) - component which basically dumps message contents (body and/or headers and/or properties) to your log file using appropriate log category.
If you just want to drop everything received, it's a good choice:
to("log:com.company.camel.sample?level=TRACE&showAll=true&multiline=true")
Apparently if you're under Linux or Unix, you can also redirect to /dev/null like in this example:
to( "file:/dev?fileName=null")
I am not sure it can be used on Windows but I don't think so.
Note that the syntax: to( "file:/dev/null") does not work as it point to a directory called null but with the fileName option it will work.

Camel , catch error and move file in different folder

I am trying to doing ETL job (read,convert, store an excel) .
This route work fine :
from("file:src/data?move=processed&moveFailed=error&idempotent=true")
.bean(ExcelTransformer.class,"process")
.to("jpa:cie.service.receiver.DatiTelefonici?entityType=java.util.ArrayList");
but I need a customization in case of Exception : I need to move file in other folder , then applied :
onException(Throwable.class).maximumRedeliveries(0).to("file:src/data?move=error");
But file component can't move the file because is locket by first file comp instance.
Then I am tryinf to use try/catch but it doesn't work (probably the move operation inside catch is unaware of correct file name ? )
from("file:src/data?noop=true")
.doTry()
.bean(ExcelTransformer.class,"process")
.to("jpa:cie.service.receiver.DatiTelefonici?entityType=java.util.ArrayList")
.to("file:src/data?move=processed")
.doCatch(Throwable.class)
.to("file:src/data?move=error")
.end();
tanks
After many comments my current code looks like :
from("file:src/data?noop=false&delete=true")
.doTry()
.bean(ExcelTransformer.class,"process") .to("jpa:cie.service.receiver.DatiTelefonici?entityType=java.util.ArrayList")
.to("file:src/data/processed")
.doCatch(Throwable.class)
.to("file:src/data/error")
/*
.doFinally()
.to("file:src/data:delete=true")
*/
.end();
It move correctly the file in processed and error folder but the file remain in main folder and is preocessed more ,recursively
If I understood your question well then you need remove the idempotent=true from the parameters, then it should work:
from("file:src/data?move=processed&moveFailed=error")
.bean(ExcelTransformer.class,"process")
.to("jpa:cie.service.receiver.DatiTelefonici?entityType=java.util.ArrayList");
The previous route moves the file to the processed folder if the routing was successful otherwise it moves the file to the error folder (if any exception happens). The filename won't be changed.
Other solution with try-catch
from("file://src/data?delete=true")
.doTry()
.bean(ExcelTransformer.class,"process")
.to("jpa:cie.service.receiver.DatiTelefonici?entityType=java.util.ArrayList")
.to("file://src/data/processed")
.doCatch(Throwable.class)
.to("file://src/data/error")
.end();

onCompletion in Camel 2.14

I'd like to wrap the result of a processed message into some reply-object to answer a webservice. This is my test-route:
this.from("cxf:someEndpoint")
.process(new SomeProcessorThatMightThrowAnException())
.process(new SomeOtherProcessorThatMightThrowAnException())
.log("normal end of route");
Nevermind if there was an exception or not, the result should be wrapped in some object, that is given back to the caller of my ws.
In camel 2.13.x I did this by adding an other processor to the end of the route and to do the same in 'onException'.
Now I tried to simplify this (technical thing and handle it outside of the 'functional route') in camel 2.14 (2.14 because of 'modeBeforeConsumer'), and added this to my routebuilder:
onCompletion()
.modeBeforeConsumer()
.process(new ConvertToWsReplyProcessor());
This ConvertToWsReplyProcessor should handle an Exception, but I found no way to see, if there was an Exception, because exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class) is allways null.
Questions:
1) Is there a way to find out if there was an excetion in onCompletion()?
2) The only way I found to prevent camel from dumping a stacktrace is to use onException(Ex...).handled(true), are there others?
3) How are these onXY processed? Do they get a copy of the exchange? And is onCompletion called last?
OnCompletionProcessor just remove some exchange properties before processing the exchange, that could explain why you cannot fine the exception here.
As camel use onException to handle the exception, I'm afraid you have to do it that way.

Camel PollEnrich not working properly

After transforming a file with xslt I have to append a file downloaded from ftp. So I did the following:
from("direct:adobe_productList_incremental")
.id("routeADOBESPtransformPI_productList")
.log(LoggingLevel.INFO, "---------Starting file: ${body}")
.convertBodyTo(InputStream.class)
.to("xslt:classpath:" + xsltTransformationProductList)
.log(LoggingLevel.INFO, "---------Transformed file: ${body}")
.pollEnrich(ftpType+"://"+ftpUsername+"#"+ ftpUrl +":" + ftpPort + ftpPath_incrementalComplete +"?password="+ftpPassword+"&fileName="+ftpFilename_incrementalComplete+"&passiveMode=true&binary=true&delete=false",10000)
.log(LoggingLevel.INFO, "---------After poll enrich: ${body}")
.to("file:{{file.root}}{{file.outbox.products_list_incremental}}?fileName={{file.outbox.products_list_incremental.name}}.final");
untill the poll everythin works (the transformation is done correctly), but after the pollEnrich the current body is overrided by the ftp content (and not appended as it should be).
Any help?
No it works as designed.
By default the content will be overridden. If you need to append/merge or whatever, you need to use a custom aggregation strategy, and implement code logic that does this.
See the Camel docs at: http://camel.apache.org/content-enricher.html about the ExampleAggregationStrategy.
The Camel docs says
The aggregation strategy is optional. If you do not provide it
Camel will by default just use the body obtained from the resource.

Resources