spring-integrationspring-integration-dslspring-integration-ftp

Spring Integration Ftp | how to move remote files into another directory in remote server after FTP fetch complete


We have a remote FTP server in which we have a folder "test/" which contains certain text files. The "test/" folder has another subdirectory "archive/" inside it.

FTPserver->
-test/
---abc.txt
---xyz.txt
---archive/

We are able to download all the text files via Spring Integration flows in our local directory. Now we are looking into ways to move the remote text files inside the folder "archive" within the FTP Server itself once it has been downloaded into the local.

We are trying to do it in the handle() method like this ->

@Bean
public IntegrationFlow integrationFlow() {


    File localDirectory = new File("tmp/");

    FtpInboundChannelAdapterSpec ftpInboundChannelAdapterSpec = Ftp.inboundAdapter(gimmeFactory())
            .remoteDirectory("test/")
            .autoCreateLocalDirectory(true)
            .regexFilter(".*\\.txt$")
            .localDirectory(localDirectory)
            .preserveTimestamp(true)
            .remoteFileSeparator("/");

    return IntegrationFlows.from(ftpInboundChannelAdapterSpec, pc -> pc.poller(pm -> pm.fixedRate(1000, TimeUnit.MILLISECONDS)))
            .handle((file, messageHeaders) -> {
                messageHeaders.forEach((k, v) -> System.out.println(k + ':' + v));
                return null;
            })
            .handle(Ftp.outboundGateway(gimmeFactory(), AbstractRemoteFileOutboundGateway.Command.MV, "'test/archive'"))
            .get();

}

But it is not moving into the remote "archive" folder location. We are quite not sure how to handle this operation in any other way. Is there anything we can do to fix the above code snippet or do something differently in order to achieve what we want ? Please advise.

Update

Thank you Gary for the pointers.
I was able to solve the problem by doing as given in below code snippet->

@Bean
    public IntegrationFlow integrationFlow() {            
        File localDirectory = new File("tmp/");
        FtpInboundChannelAdapterSpec ftpInboundChannelAdapterSpec = Ftp.inboundAdapter(gimmeFactory())
                .remoteDirectory("test/")
                .autoCreateLocalDirectory(true)
                .regexFilter(".*\\.txt$")
                .localDirectory(localDirectory)
                .preserveTimestamp(true)
                .remoteFileSeparator("/");
        
        return IntegrationFlows
                .from(ftpInboundChannelAdapterSpec, e -> e.poller(Pollers.fixedDelay(Duration.ofSeconds(5))))
                .handle(Ftp.outboundGateway(gimmeFactory(), AbstractRemoteFileOutboundGateway.Command.LS, "'test/'")
                        .options(AbstractRemoteFileOutboundGateway.Option.NAME_ONLY))
                .split()
                .handle(Ftp.outboundGateway(gimmeFactory(), AbstractRemoteFileOutboundGateway.Command.MV, "'test/' +payload").renameExpression("'test/archive/' +payload"))
                .channel("nullChannel")
                .get();
}

Solution

  • Since you are returning null from the first .handle(), the flow stops there; you need to return a payload containing the from path and the rename-expression is needed to specify the to path.

    https://docs.spring.io/spring-integration/docs/current/reference/html/ftp.html#using-the-mv-command

    The mv command moves files.

    The mv command has no options.

    The expression attribute defines the “from” path and the rename-expression attribute defines the “to” path. By default, the rename-expression is headers['file_renameTo']. This expression must not evaluate to null or an empty String. If necessary, any necessary remote directories are created. The payload of the result message is Boolean.TRUE. The file_remoteDirectory header provides the original remote directory, and file_remoteFile header provides the file name. The new path is in the file_renameTo header.

    Starting with version 5.5.6, the remoteDirectoryExpression can be used in the mv command for convenience. If the “from” file is not a full file path, the result of remoteDirectoryExpression is used as the remote directory. The same applies for the “to” file, for example, if the task is just to rename a remote file in some directory.