Apache Camel enrich message with file content on r

2020-06-04 03:23发布

问题:

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

回答1:

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