Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Camel enrich message with file content on request

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

like image 407
nikagra Avatar asked Apr 11 '13 11:04

nikagra


People also ask

What is enrich in Apache Camel?

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.

What is Camel SetHeader?

The SetHeader EIP is used for setting a message header.

What is Noop true in Camel?

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.


1 Answers

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

like image 119
nikagra Avatar answered Sep 28 '22 07:09

nikagra