I'm implementing RESTful service (using CXFRS component) which should return files for some requests. Each file is fetched by its id and extension, i.e. restfulservice.com/path/file/1/pdf
. Each file once added never changes. Files should not be moved or deleted after fetching and generally they should be accessible concurrently. Here is part of my Camel context:
from("direct:fetchFile")
.process(fetchFileProcessor) // set file.id & file.extension
.bean(fileService, "fetchFile(${header.file.id}, ${header.file.extension})") // set body to filename
.setHeader("CamelFileName", simple("${body}"))
.choice()
.when(header("file.extension").isEqualTo("xml"))
.pollEnrich("file:///{{application.fileStorage.basePath}}/xml?noop=true", 500)
.when(header("file.extension").isEqualTo("pdf"))
.pollEnrich("file:///{{application.fileStorage.basePath}}/pdf?noop=true", 500)
.end()
.convertBodyTo(File.class)
.bean(responseProvider, "getResponse(${body}, 200)");
The problem with this configuration is that response has non-empty body only for second(why?) request, without timeout set service enters on eternal loop on second request with debug message
DEBUG o.a.c.c.f.FileConsumer - Took 0.000 seconds to poll <base path>\xml
Apace Camel version is 2.10.4
Any help would be appreciated
UPD1:
There is warning on Content Enricher page, saying 'pollEnrich does not access any data from the current Exchange'. But nothing changes if I add fileName=${body}
to file URL
UPD2:
It seems like pollEnrich do not support dynamic fileName
specified in URL (link). Route at current moment:
from("direct:fetchFile")
.process(fetchFileProcessor) // set file.id & file.extension
.bean(fileService, "fetchFile(${header.file.id}, ${header.file.extension})") // set body to filename
.choice()
.when(header("file.extension").isEqualTo("xml"))
.pollEnrich("file:///{{application.fileStorage.basePath}}/xml?fileName=${body}&noop=true", 500)
.setHeader("asset.type", simple(MediaType.APPLICATION_XML))
.when(header("file.extension").isEqualTo("pdf"))
.pollEnrich("file:///{{application.fileStorage.basePath}}/pdf?fileName=${body}&noop=true", 500)
.setHeader("asset.type", simple("application/pdf"))
.end()
.convertBodyTo(File.class)
.process(multipartProcessor) // add file ass attachment to multipart body and set it as body
.bean(responseProvider, "getResponse(${body}, 200)");
UPD3
I'm trying to to implement custom processor to use PollingConsumer with dynamic file names:
@Override
public void process(Exchange exchange) throws Exception {
Long timeout = exchange.getIn().getHeader("file.timeout", Long.class);
if (enrichUri == null) {
throw new FileNotFoundException("'file.url' header not set");
}
CamelContext context = exchange.getContext();
Endpoint endpoint = context.getEndpoint(enrichUri);
PollingConsumer consumer = endpoint.createPollingConsumer();
consumer.start();
Exchange consumedExchange;
try {
if (timeout == null || timeout < 0) {
consumedExchange = consumer.receive();
} else if (timeout == 0) {
consumedExchange = consumer.receiveNoWait();
} else {
consumedExchange = consumer.receive(timeout);
}
} catch (Exception e) {
throw new AssetNotFoundException(e);
} finally {
consumer.stop();
}
exchange.getIn().setBody(consumedExchange.getIn().getBody());
}
Now it returns file contents on first response, but on each succeeding request I got eternal loop of above log messages:
DEBUG o.a.c.c.f.FileConsumer - Took 0.000 seconds to poll <base path>\xml
UPD4
I've implemented dynamic route which is added before processing and removed after it. This method is described in this post in Apache Camel forum. Route uses above processor to consume file. The result is the same
It is usually used for Request Reply messaging, for instance to invoke an external web service. Poll Enrich EIP - Uses a Polling Consumer to obtain the additional data. It is usually used for Event Message messaging, for instance to read a file or download a FTP file.
The SetHeader EIP is used for setting a message header.
If noop=true, Camel will set idempotent=true as well, to avoid consuming the same files over and over again. Expression (such as File Language) used to dynamically set the filename when moving it before processing. For example to move in-progress files into the order directory set this value to order.
Simple way often is the best way. I refuse to deal with Apache Camel file component in this case and implemented following processor:
public class FileLoadingProcessor implements Processor {
@Override
public void process(Exchange exchange) throws Exception {
String filename = exchange.getIn().getBody(String.class); // message body contains filename
String filePath = exchange.getIn().getHeader("fileprocessor.filepath", String.class);
if (filePath == null || filename == null) {
// throw some custom exception
}
URI uri = new URI(filePath.concat(filename));
File file = new File(uri);
if (!file.exists()) {
throw new FileNotFoundException(String.format("File %s not found on %s", filename, filePath));
}
exchange.getIn().setBody(file);
}
Now it's working like a charm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With