SftpSession#rename(String,String) using hard coded SftpClient.CopyMode.Overwrite flag #3962
Description
In what version(s) of Spring Integration are you seeing this issue?
Spring Integration 6.0.0
Describe the bug
Since upgrading from Spring Integration 5.5.14 to 6.0.0. uploading files via SFTP using SftpMessageHandler does not work anymore in my setup.
The automatic rename after uploading the file with a temporary filename (.writing) to the final filename fails with the following exception:
Error handling message for file [/var/folders/28/wfkzpgdj5g3d_nv279t12qkc0000gn/T/junit11372797161836036558/localOutbound/testfileOutbound.xml -> testfileOutbound.xml], failedMessage=GenericMessage [payload=/var/folders/28/wfkzpgdj5g3d_nv279t12qkc0000gn/T/junit11372797161836036558/localOutbound/testfileOutbound.xml, headers={file_originalFile=/var/folders/28/wfkzpgdj5g3d_nv279t12qkc0000gn/T/junit11372797161836036558/localOutbound/testfileOutbound.xml, id=7b1ca413-05a5-f7a0-124d-af7f6fc31b55, file_name=testfileOutbound.xml, file_relativePath=testfileOutbound.xml, timestamp=1670494014101}]
at org.springframework.integration.file.remote.RemoteFileTemplate.doSend(RemoteFileTemplate.java:367)
[Stack Trace shortend]
Caused by: org.springframework.messaging.MessagingException: Failed to write to 'testfileOutbound.xml.writing' while uploading the file
at org.springframework.integration.file.remote.RemoteFileTemplate.sendFileToRemoteDirectory(RemoteFileTemplate.java:573)
at org.springframework.integration.file.remote.RemoteFileTemplate.doSend(RemoteFileTemplate.java:353)
... 58 more
Caused by: java.lang.UnsupportedOperationException: rename(testfileOutbound.xml.writing => testfileOutbound.xml) - copy options can not be used with this SFTP version: [Overwrite]
at org.apache.sshd.sftp.client.impl.AbstractSftpClient.rename(AbstractSftpClient.java:644)
at org.apache.sshd.sftp.client.SftpClient.rename(SftpClient.java:621)
at org.springframework.integration.sftp.session.SftpSession.rename(SftpSession.java:153)
at org.springframework.integration.file.remote.session.CachingSessionFactory$CachedSession.rename(CachingSessionFactory.java:252)
at org.springframework.integration.file.remote.RemoteFileTemplate.doSend(RemoteFileTemplate.java:606)
at org.springframework.integration.file.remote.RemoteFileTemplate.sendFileToRemoteDirectory(RemoteFileTemplate.java:570)
... 59 more
The exception is thrown by the MINA sshd-sftp client which is now used instead of JSch. The new client checks if the SFTP version used is at least 5 when trying to specify options for the rename operation, which is it not in my case (Version 3 from atmoz/sftp testcontainer).
This check done in org.apache.sshd.sftp.client.impl.AbstractSftpClient#rename(String, String, Collection<CopyMode>)
Unfortunately, the method in Spring Integration class org.springframework.integration.sftp.session.SftpSession
initiating the rename looks this:
@Override
public void rename(String pathFrom, String pathTo) throws IOException {
this.sftpClient.rename(pathFrom, pathTo, **SftpClient.CopyMode.Overwrite**);
}
So the Apache SftClient option CopyMode.Overwrite
is hard-coded here which means, copying with temporary files (to avoid partially written files being picked up) will never work on SFTP version 3.
Maybe it would be possible to use the FileExistsMode
from org.springframework.integration.file.remote.handler.FileTransferringMessageHandler
or allow the user to configure the mode in another way.
In any way, it should be possible to invoke sftpClient#rename
with empty options to use with a SFTP-Server understanding only version 3.
To Reproduce
Use a SftpMessageHandler
to upload files with the (default) configuration to use temporary files to upload to a SFTP server using version 3. I used a atmoz/sftp testcontainer in my integration test, which now fails.
Expected behavior
Uploading to SFTP with temporary files should also work for SFTP version 3 like it did with the JSsch client
Sample
I hope the problem is clear from the provided explanation and code snippets. If not let me know so I can provide an integration test to show the problem.