3

I have a use case for transfering files to sftp under certain subdirs that are created dynamically. I got this working using custom SftpMessageHandler method and a Gateway. But the issue with this approach was, it was not deleting local temp files after successful upload. To solve that, now I am using IntegrationFlow along with expression Advice (as below), this does remove local files, but I don't know how to create remote subDirs dynamically. I read about remote directory expression, but not sure how to use/implement it.

Any one resolved this issue? Any help is appreciated!

@Bean
public IntegrationFlow sftpOutboundFlow() {

    return IntegrationFlows.from("toSftpChannel")
              .handle(Sftp.outboundAdapter(this.sftpSessionFactory())
                      .remoteFileSeparator("/")
                      .useTemporaryFileName(false)
                      .remoteDirectory("/temp"), c -> c.advice(expressionAdvice(c)))
                                     .get();
}



@Bean
public Advice expressionAdvice(GenericEndpointSpec<FileTransferringMessageHandler<ChannelSftp.LsEntry>> c) {
    ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
    advice.setOnSuccessExpressionString("payload.delete()");
    advice.setOnFailureExpressionString("payload + ' failed to upload'");
    advice.setTrapException(true);
    return advice;
}

@MessagingGateway
public interface UploadGateway {
    @Gateway(requestChannel = "toSftpChannel")
    void upload(File file);
}
Mia
  • 169
  • 1
  • 2
  • 11

1 Answers1

2

The Sftp.outboundAdapter() has these options for the remote directory:

/**
 * Specify a remote directory path.
 * @param remoteDirectory the remote directory path.
 * @return the current Spec
 */
public S remoteDirectory(String remoteDirectory) {
}

/**
 * Specify a remote directory path SpEL expression.
 * @param remoteDirectoryExpression the remote directory expression
 * @return the current Spec
 */
public S remoteDirectoryExpression(String remoteDirectoryExpression) {
}

/**
 * Specify a remote directory path {@link Function}.
 * @param remoteDirectoryFunction the remote directory {@link Function}
 * @param <P> the expected payload type.
 * @return the current Spec
 */
public <P> S remoteDirectory(Function<Message<P>, String> remoteDirectoryFunction) {
}

So, if the story is about a dynamic sub-directory, you can choose a remoteDirectoryExpression or remoteDirectory(Function) and calculate a target path against message or some bean in the application context.

For example:

.remoteDirectoryExpression("'rootDir/' + headers.subDir")

Also bear in mind that for not existing directories you need to configure an .autoCreateDirectory(true), too.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thanks for your reply, but this dosen't seem to work for me. Here is my modified code (below) I am accepting whole path in header now. remoteDirectoryExpression("headers.path") @MessagingGateway public interface LettersUploadGateway { @Gateway(requestChannel = "toSftpChannel") void upload(@Payload File file, @Header("path") String path); } – Mia Oct 18 '18 at 17:51
  • Show, please, how you try to do that – Artem Bilan Oct 18 '18 at 17:52
  • 1
    remoteDirectoryExpression("headers.path") @MessagingGateway public interface LettersUploadGateway { @Gateway(requestChannel = "toSftpChannel") void upload(@Payload File file, @Header("path") String path); } – Mia Oct 18 '18 at 17:55
  • Well, not sure then. It looks correct for me. So, when you call an `upload()` on that gateway, you build a `path` argument with the appropriate value for the remote path. What's doesn't work as you expect? And also, please, pay attention how code is not readable in the comments here on SO. Would be better to EDIT your question with proper code formatting. – Artem Bilan Oct 18 '18 at 17:59
  • lettersGateway.upload(fileName, config.getLettersDirectory() + "/" + programShortName); – Mia Oct 18 '18 at 18:09
  • Apologies for not formatting the code and comments. you can tell I am new. – Mia Oct 18 '18 at 18:10
  • This answer helped. I just need to figure out why it dosen't work. – Mia Oct 18 '18 at 18:22
  • 1
    .remoteDirectoryExpression("headers.path").autoCreateDirectory(true) and this works as expected!! – Mia Oct 18 '18 at 18:26