Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Camel - Multipart File upload

Using Apache-Camel ESB, trying to upload a xlsx file to Spring Rest Web application. Upload fails from apache-camel ESB. But upload works fine from Postman. Shared code snippets below.

  1. Processor Code in Router of Camel looks like

        from("file://data/PASInput").process(new Processor() {
        @Override
        public void process(Exchange exchange) throws Exception {
    
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            String filename = (String) exchange.getIn().getHeader(Exchange.FILE_NAME);
            File file = exchange.getIn().getBody(File.class);
            multipartEntityBuilder.addPart("file",
                new FileBody(file, ContentType.MULTIPART_FORM_DATA, filename));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            multipartEntityBuilder.build().writeTo(out);
            InputStream  inputStream = new ByteArrayInputStream(out.toByteArray());
            exchange.getOut().setBody(inputStream);         
        }
    }).to("http://localhost:8080/Pastel/api/convertor/pas/pastel")
            .log(LoggingLevel.ERROR, "RESPONSE BODY ${body}").end();
    
  2. Pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>2.21.0.fuse-000077-redhat-1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-cxf</artifactId>
            <version>2.21.0.fuse-000077-redhat-1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-http</artifactId>
            <version>2.21.0.fuse-000077-redhat-1</version>
        </dependency>       
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-http4</artifactId>
            <version>2.17.2</version>
        </dependency>
    
  3. Error

        org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking http://localhost:8080/Pastel/api/convertor/pas/pastel with statusCode: 500
        at org.apache.camel.component.http.HttpProducer.populateHttpOperationFailedException(HttpProducer.java:274)
       at org.apache.camel.component.http.HttpProducer.process(HttpProducer.java:183)
       at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
       at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:148)
       at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
       at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
       at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
       at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
       at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
       at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:452)
       at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:219)
       at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:183)
       at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:174)
       at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:101)
       at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    
  4. When we hit the webservice using postman, there are no errors. Able to upload the servers successfully. Spring mvc code,

                @RequestMapping(value = "/pas/pastel", method = RequestMethod.POST)
                @ResponseBody
                public void convertPASToPastel(HttpServletRequest request, HttpServletResponse response,
                @RequestParam(value = "file") final MultipartFile pasFile) {
                   try {
                      System.out.print("Here");
                   }
                }
    
like image 707
Naveen Kumar Avatar asked Dec 23 '22 06:12

Naveen Kumar


1 Answers

You can probably see this error message in your Spring backend log:

org.springframework.web.multipart.MultipartException: Current request is not a multipart request.

You need to set correct ContentType header. Please refer this similar question for solution, if you want to implement it in this way.


But you can get out this mess, if you switch co camel-http4 component (you already have this component in pom.xml). This component contains logic for converting HttpEntity to InputStream. Then you can set HttpEntity directly to exchange body.

Then your route will look something like this:

from("file://data/PASInput").process(new Processor() {
    @Override
    public void process(Exchange exchange) throws Exception {
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        String filename = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
        File file = exchange.getIn().getBody(File.class);
        multipartEntityBuilder.addPart("file",
                new FileBody(file, ContentType.MULTIPART_FORM_DATA, filename));
        exchange.getOut().setBody(multipartEntityBuilder.build());
    }
}).to("http4://localhost:8080/Pastel/api/convertor/pas/pastel")
        .log(LoggingLevel.ERROR, "RESPONSE BODY ${body}").end();

And just a note. Never mix component versions, always use for components the same version as Apache Camel version. Otherwise you can see upredictable results. And why you have annotation @ResponseBody in Spring controller, when the method is void? You don`t need that.

like image 176
Bedla Avatar answered Jan 07 '23 05:01

Bedla