Camel File component - skip file - apache-camel

I'm using the camel file component to poll files from a directory.
Before I can handle a file some conditions have to be satisfied,
if not camel should skip the file without deleting/moving it and
go to the next one.
To do this I use this:
public InputStream myMethod(#Body InputStream is, #Headers .....) {
if( !checkPrerequisites )
throw new MyRuntimeException("conditions not satisfied yet");
So I'm wondering if there is another way to archive the desired behaviour.

You could implement a GenericFileFilter. Create the filter, like so:
public class AnotherFileExistsFilter<T> implements GenericFileFilter<T> {
#Override
public boolean accept(GenericFile<T> firstFile) {
return Files.exists(Paths.get("/some/other/folder/" + firstFile.getFileName()));
}
}
Add it to your endpoint using filter=#anotherFileExistsBeanName.
If you want to keep checking the file, set idempotent=false, and I recommend setting a delay (delay=xxx in ms) in order to not poll the folder continuously.
More details are on the Apache Camel File2 page.

Related

Calling a camel route using Producer Template

My use case is based on the rest controller input I need to fetch or move files from different source system to destination system.
Route :-
#Component
public class MoveFile extends RouteBuilder {
#override
public void configure() throws Exception {
from("file:tmp/${header.inPath}")
.to("file:/tmp${header.outPath}?fileName=${header.fileName}")
.setBody().constant("File - ${header.inPath}/${header.fileName} Moved Succesfully")
}
}
My rest controller will pass the jobName along the getMapping to invoke this specific route inPath , outPath and File Names
#Resource(name=RouteProperties)
private Prosperties props;
#GetMapping("/runJob/{jobToInvoke}")
public String runJob (#PathVariable final String jobToInvoke){
String inPath=props.getProperty("inPath"+jobToInvoke)
String outPath=props.getProperty("outPath"+jobToInvoke)
String fileName=props.getProperty("fileName"+jobToInvoke)
String jobStatus = ProducerTemplate.withHeader("inPath",inPath)
.
.
.to(??)
.request(String.class)
}
I need help to use Producer Template to pass the properties using to ?
I tried some search on the google, but there is an example available in youtube (link) , But in that Video it is calling uri , (Direct:sendMessage) and from in the route also has that.
How to handle in this scenario ?
Thanks in Advance
A route beginning with a direct: endpoint can be invoked programmatically from Java code. In the route, the pollEnrich component invokes a consumer endpoint to read a file and replace the exchange message body with the file contents.
from("direct:start")
.pollEnrich().simple("file:/tmp?fileName=${header.inPath}")
.toD("file:/tmp?fileName=${header.outPath}")
.setBody().simple("File - ${header.inPath} Moved Successfully");
To invoke the route from Java code:
String jobStatus = producerTemplate.withHeader("inPath", inPath)
.withHeader("outPath", outPath)
.to("direct:start")
.request(String.class);
I don't know if these dynamic file URIs in from work, but at least the Camel File documentation states
Also, the starting directory must not contain dynamic expressions with
${ } placeholders. Again use the fileName option to specify the
dynamic part of the filename.
So the docs are suggesting to change
from("file:tmp/${header.inPath}")
into
from("file:tmp?fileName=${header.inPath}")
The fileName option can be a relative path (not just a filename).
If that change works for you, your question becomes obsolete because the route URI is no more dynamic.
.withHeader("inPath",inPath)
.to("file:tmp")

Apache Camel - moving file with uri from yaml properties

I'm trying to process a file using Apache Camel, and after processing move it to a specific folder, while keeping the filename and directory structure.
What I have in a application.yml file:
camel-from: "file:/C:/in/received?move=../in/processed/${file:name}&recursive=true&readLock=changed&readLockMarkerFile=false&delay=1000&maxDepth=2&minDepth=2"
Using Java the Route is as follows:
#Component
#RequiredArgsConstructor
public class TestRoute extends RouteBuilder {
#Value("${camel-from}")
private String fromUri;
#Override
public final void configure() {
from(fromUri)
// rest of code
}
}
If I use the string directly in the route from, it works just fine. However, reading it from the application.yml file, no matter which characters I try to escape, I can't get it to read the uri properly. (I always end up with either an error, or creating folders such as processed/name instead of ${file:name} getting interpreted).
Any ideas?
Thanks
Property replacement needs to be escaped in SPEL language, so Apache Camel gets the value in raw form. You can escape it with #{'$'}. There is open issue spring-framework#9628 about making this escape sequence shorter / more intuitive.
camel-from: "file:/C:/in/received?move=../in/processed/#{'$'}{file:name}"

Dynamic Apache Camel Output Route

Hi i want to compute a dynamic output route using apache Camel. I receive a bunch of files in a folder location, based on its contents i want to move the file to dynamic output folder. The name of the ouput folder will be constructed based on the input content of the file. How do i acheive it.
The Following piece of code read the files, processes them, but i am not sure how to set the value of ${foldername} based on the contents of the file
from("file:D:\\camel\\input\\one?recursive=true&delete=true")
.process(new LogProcessor())
.to("file:D:\\camel\\output\\${foldername}")
Please assist
You could create a custom processor to construct the foldername and insert into a header.
public class DirectoryNameProcessor implements Processor {
#Override
public void process(Exchange exchange) {
Message in = exchange.getIn();
// Get the contents of the processed file
String body = in.getBody(String.class);
//Get the original file name
String fileName = in.getHeader("CamelFileName", String.class);
// Perform your logic
in.setHeader("foldername");
}
}
Then in your route you could access the newly created foldername-header:
.to("file:D:\\camel\\output\\${header.foldername}");
The short answer is, you can use the dynamic to endpoint toD.
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
It would look like:
from("file:D:\\camel\\input\\one?recursive=true&delete=true")
.process(new LogProcessor())
.toD("file:D:\\camel\\output\\${foldername}")

What is the best way to store user specific files in Wicket?

I am creating a file that is user specific. This file is basically a results csv that is created with the option for the user to download or not. When the user leaves the page, or ends their session I want to be able to delete this file. What is the best way to handle this?
Currently I am using the File class for Java.
Thanks!
You don't have to write a file in the first place. Create the content on the fly and stream it back to the client. Wicket has a few classes in the package org.apache.wicket.request.resource to help with that.
As a starting point, look at Wicket 6 resource management and Wicket 1.5 Mounting resources
You basically mount a resource in the WicketApplication.init():
mountResource("somePath/${param1}/${param2}", new SomeResourceReference());
Than the SomeResourceReference:
public class SomeResourceReference extends ResourceReference {
#Override
public IResource getResource() {
return new SomeResource();
}
}
And finally in SomeResource:
public class SomeResource extends AbstractResource {
#Override
public AbstractResource.ResourceResponse
newResourceResponse(Attributes attributes) {
// get the parameters
PageParameters parameters = attributes.getParameters();
final String param1 = parameters.get("param1").toStringObject();
AbstractResource.ResourceResponse response
= new AbstractResource.ResourceResponse();
response.setContentType("application/CSV");
response.setCacheDuration(Duration.NONE);
response.setCacheScope(WebResponse.CacheScope.PRIVATE);
response.setContentDisposition(ContentDisposition.INLINE);
response.setWriteCallback(new AbstractResource.WriteCallback() {
#Override
public void writeData(final Attributes attributes) throws IOException {
// create your data here
attributes.getResponse().write(dataAsString);
}
});
return response;
}
}
Wicket doesn't control destroying the session. It is the concern of the servlet container you are using.
If you want to create a file in Wicket and delete the file when the session is destroyed or user want logout, it has two parts:
User logout (in Wikcet)
Store the file path or the file reference in the WebSession (Wicket)
Override the method invalidate() of your WebSession or AutheticatedWebSession, see http://ci.apache.org/projects/wicket/apidocs/6.x/org/apache/wicket/protocol/http/WebSession.html#invalidate%28%29
Session destroyed
Store the file path or the file reference into the container session and write your listener and add it to the your servlet context (e.g. tomcat using web.xml file).
See http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionListener.html

Using apache camel csv processor with pollEnrich pattern?

Apache Camel 2.12.1
Is it possible to use the Camel CSV component with a pollEnrich? Every example I see is like:
from("file:somefile.csv").marshal...
Whereas I'm using the pollEnrich, like:
pollEnrich("file:somefile.csv", new CSVAggregator())
So within CSVAggregator I have no csv...I just have a file, which I have to do csv processing myself. So is there a way of hooking up the marshalling to the enrich bit somehow...?
EDIT
To make this more general... eg:
from("direct:start")
.to("http:www.blah")
.enrich("file:someFile.csv", new CSVAggregationStrategy) <--how can I call marshal() on this?
...
public class CSVAggregator implements AggregationStrategy {
#Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
/* Here I have:
oldExchange = results of http blah endpoint
newExchange = the someFile.csv GenericFile object */
}
Is there any way I can avoid this and use marshal().csv sort of call on the route itself?
Thanks,
Mr Tea
You can use any endpoint in enrich. That includes direct endpoints pointing to other routes. Your example...
Replace this:
from("direct:start")
.to("http:www.blah")
.enrich("file:someFile.csv", new CSVAggregationStrategy)
With this:
from("direct:start")
.to("http:www.blah")
.enrich("direct:readSomeFile", new CSVAggregationStrategy);
from("direct:readSomeFile")
.to("file:someFile.csv")
.unmarshal(myDataFormat);
I ran into the same issue and managed to solve it with the following code (note, I'm using the scala dsl). My use case was slightly different, I wanted to load a CSV file and enrich it with data from an additional static CSV file.
from("direct:start") pollEnrich("file:c:/data/inbox?fileName=vipleaderboard.inclusions.csv&noop=true") unmarshal(csv)
from("file:c:/data/inbox?fileName=vipleaderboard.${date:now:yyyyMMdd}.csv") unmarshal(csv) enrich("direct:start", (current:Exchange, myStatic:Exchange) => {
// both exchange in bodies will contain lists instead of the file handles
})
Here the second route is the one which looks for a file in a specific directory. It unmarshals the CSV data from any matching file it finds and enriches it with the direct route defined in the preceding line. That route is pollEnriching with my static file and as I don't define an aggregation strategy it just replaces the contents of the body with the static file data. I can then unmarshal that from CSV and return the data.
The aggregation function in the second route then has access to both files' CSV data as List<List<String>> instead of just a file.

Resources