Skip to content

SftpSession#rename(String,String) using hard coded SftpClient.CopyMode.Overwrite flag #3962

Closed
@Ingo13F

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.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions