user3332279
user3332279

Reputation: 59

Does Apache Camel support nested routes?

Apache Camel Route:

    from("file:/tmp/test?include=.*.csv").process(new Processor() {
        public void process(Exchange exchange) throws Exception {
            // set output file name
            exchange.setProperty("outputFile", exchange.getIn().getHeader(Exchange.FILE_NAME, String.class) + ".tmp." + exchange.getExchangeId());
        }
    }).onCompletion().split().tokenize("\n", 100).process(new RequestProcessor()).to("direct:response").end().process(new Processor() {
        public void process(Exchange exchange) throws Exception {
            final String outputFile = exchange.getProperty("outputFile", String.class);

            // add new rout to encrypt
            CamelContext context = new DefaultCamelContext();
            context.addRoutes(new RouteBuilder() {
                public void configure() {

            from("file:/tmp/test/output?fileName=" + outputFile).marshal().pgp(keyFileName, keyUserid).to("file:/tmp/test/output?fileName=" + outputFile + ".pgp");
                }
            });

            context.start();
            Thread.sleep(5000);
            context.stop();
        }
    });

    from("direct:response").to("file:/tmp/test/output?fileName=${header.outputFile}&fileExist=Append");

Above route is processing big file splitting into chunk (for batch processing) and generate output file with results. once generated the output file I need to encrypt. So I added NEW route inside a processor on onCompletion file split/process route. It works but I feel it is not a good design (since involve TWO context and need context shutdown explicitly).

Can you anyone suggest me the proper way to fire the encryption route.

Upvotes: 1

Views: 3589

Answers (2)

Peter Keller
Peter Keller

Reputation: 7646

Often (or always) nested routes as you suggest may be bypassed. Perhaps this simple route will meet your requirements:

@Override
public void configure() throws Exception {
    from("file:/tmp/test?include=.*.csv")
       .split().tokenize("\n", 100)
       .setProperty("outputFile", simple("${header.CamelFileName}.${exchangeId}.pgp"))
       .log("The splitted body will be PGP encoded & written to file ${property.outputFile}")
       .marshal().pgp("keyFileName", "keyUserid")
       .to("file:/tmp/test/output?fileName=${property.outputFile}");
    }
}

No temporary file will be written, but the split content will be directly encrypted in memory.

EDIT:

If you want to handle one file by one, then your route will look as follows:

@Override
public void configure() throws Exception {
    from("file:/tmp/test?include=.*.csv")
       .setProperty("outputFile", simple("${header.CamelFileName}.${exchangeId}.pgp"))
       .log("The body will be PGP encoded & written to file ${property.outputFile}")
       .marshal().pgp("keyFileName", "keyUserid")
       .to("file:/tmp/test/output?fileName=${property.outputFile}");
    }
}    

If you want first want to create one big file and then to PGP encode this file, then you may use an aggregator that is sampling the content of all input files in memory. Of course this is only possible if your memory constraints allow that.

Upvotes: 0

user3332279
user3332279

Reputation: 59

I enhanced the initial design with your feedback. But the encryption route is getting the original file as the input, are there any mechanism to redirect the generated output file as the input for encryption.

    from("file:/tmp/test/input?include=.*.csv&noop=true")
        .setProperty("outputFile", simple("${header.CamelFileName}.${exchangeId}"))
        .onCompletion()
            .split().tokenize("\n", 100)
            .log("splitted body processed & written to file ${property.outputFile}.csv")
            .process(new RequestProcessor())
            .to("file:/tmp/test/temp?fileName=${property.outputFile}.csv&fileExist=Append")
        .end()
        .marshal().pgp(keyFileName, keyUserid)
        .log("PGP encrypted written to file ${property.outputFile}.pgp")
        .to("file:/tmp/test/output?fileName=${property.outputFile}.pgp");

Note: RequestProcessor:

public class RequestProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
String body = exchange.getIn().getBody(String.class);
String[] split = body.split("\n");
StringBuilder output = new StringBuilder();

// TODO begin trx

for (String input : split) {
    if (input.startsWith("InputHeader")) {
        output.append("OutputHeader").append(input.substring(11) + ",");
    } else {
        // TODO process here
        output.append("\n").append(input).append(",DONE");
    }
}

// TODO commit trx

DefaultMessage message = new DefaultMessage();
message.setBody(output.toString());

exchange.setOut(message);

}

Upvotes: 0

Related Questions