1
votes

I have the following Apache Camel Spring XML configuration which process a file (input). I try to rename the file before it is copied (move option). I'd like the name of a file to contain a string which is the result of a method call from a bean returning a string (getHash).

Apache Camel version

<dependency>
    <groupId>org.apache.camel</groupId>
    <version>3.0.0</version>
    <type>pom</type>
</dependency>

camel-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Configures the Camel Context-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="camelContext-89c763e9" xmlns="http://camel.apache.org/schema/spring">

    <route id="FileConsumption" shutdownRoute="Defer">
        <from id="_from2" uri="file:/home/spool_in/?move=.done&amp;moveFailed=.bad&amp;fileName={bean:videoProcessor.getHash}.{file:name.ext}"/>
        <bean
            beanType="org.mediaprocessor.VideoProcessor" id="_videoProcessor" ref="videoProcessor"/>
    </route>
</camelContext>

<bean id="videoProcessor" class="org.mediaprocessor.VideoProcessor" />
</beans>

I have a problem with the File component (first endpoint of the route)

<from id="_from2" uri="file:/home/matthieu/spool_in/?move=.done&amp;moveFailed=.bad&amp;fileName=${bean:videoProcessor.getHash}.{file:name.ext}"/>

Bean VideoProcessor.java

@Bean
public static String getHash(File file) throws NoSuchAlgorithmException, IOException {
    //Use MD5 algorithm
    MessageDigest md5Digest = MessageDigest.getInstance("MD5");

    //Get the checksum
    String checksum = getFileChecksum(md5Digest, file);
    return checksum;
}

Apache Camel doesn't seem to recognize the videoProcessor bean and raise the following exception :

Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route FileConsumption at: >>> Bean[] <<< in route: Route(FileConsumption)[From[file:/home/spool_in/?mo... because of bean, ref or beanType must be provided
...
Caused by: java.lang.IllegalArgumentException: bean, ref or beanType must be provided
    at org.apache.camel.component.bean.DefaultBeanProcessorFactory.createBeanProcessor(DefaultBeanProcessorFactory.java:67)
    at org.apache.camel.reifier.BeanReifier.createProcessor(BeanReifier.java:47)
    at org.apache.camel.reifier.ProcessorReifier.makeProcessorImpl(ProcessorReifier.java:571)
    at org.apache.camel.reifier.ProcessorReifier.makeProcessor(ProcessorReifier.java:537)
    at org.apache.camel.reifier.ProcessorReifier.addRoutes(ProcessorReifier.java:250)
    at org.apache.camel.reifier.RouteReifier.doCreateRoute(RouteReifier.java:384)
    ... 37 more

According to documentation :

And finally we can also use a bean expression to invoke a POJO class that generates some String output (or convertible to String) to be used:

fileName="uniquefile-${bean:myguidgenerator.generateid}.txt"

https://camel.apache.org/manual/latest/file-language.html

Any ideas on what I have missing ? Thanks!

Update: Added "$" sign (typo) in "${bean:videoProcessor.getHash}" according to Julian answer : problem is not solved (same exception)

2

2 Answers

0
votes

I am not familiar with the Camel XML as I find Camel DSL much easier to read and use. However in the documentation from camel you provided it was ${bean:myguidgenerator.generateid} whereas you did not use the "$" sign in your route: fileName={bean:videoProcessor.getHash}

You will also need to add a "$" sign in from of the file extension. ${file:name.ext}

I also replicated your project and after making those "$" changes the application started on my side. However I believe you have more issues with your implementation and even if you get it started it will not do what you expect.

here is what I think your issues are:

  1. Using that bean getHash in the fileName will set act as a filter for the file name you want to consume. From what you are saying this is not what you want.
  2. If my understanding is right you want to pick up a video file from the spool_in folder process it with the video processor been and once processed move it within .done folder and change the name at the same time. To do this you need to move the file expression under the move option like below:

uri="file:/home/matthieu/spool_in/?move=.done/${bean:videoProcessor.getHash}.${file:name.ext}

This is my version of the simplified VideoProcessor:

@Component
@Slf4j
public class VideoProcessor {
    public void process(Exchange exchange) {
        log.info("Processing {} video ", ((GenericFile) exchange.getIn().getBody()).getFileName());
    }

    public String getHash(File file) {
        return FilenameUtils.removeExtension(file.getName()) + "_copy";
    }
}

And here are the log entries:

2020-01-03 11:19:50.444  INFO 27988 --- [/temp/spool_in/] c.v.t.g.webservice.camel.VideoProcessor  : Processing Video_1.mpg video 
2020-01-03 11:20:41.284  INFO 27988 --- [/temp/spool_in/] c.v.t.g.webservice.camel.VideoProcessor  : Processing Video_2.mpg video 
2020-01-03 11:20:53.342  INFO 27988 --- [/temp/spool_in/] c.v.t.g.webservice.camel.VideoProcessor  : Processing Video_3.mpg video 

as well as the moved files:

enter image description here

0
votes

As @julian already pointed out, you cannot use the filename option to rename a file. This option is used to filter the files to be consumed.

So, if you want to rename the files before processing them, you can, for example, create a "preprocessing" route, that just renames the files and hands them over to the real processing route.

<route id="FileRenaming" shutdownRoute="Defer">
    <from id="spool_in" uri="file:/home/spool_in/?move=.done&amp;moveFailed=.bad"/>
    <setHeader name="CamelFileName">
        <simple>${bean:videoProcessor.getHash}.${file:name.ext}</simple>
    </setHeader>
    <to uri="file:/home/process/"/>
</route>

<route id="FileProcessing" shutdownRoute="Defer">
    <from id="process" uri="file:/home/process/" />
    ...