GH-3962: Support SFTP < v5 for rename (#3964)
* GH-3962: Support SFTP < v5 for rename Fixes https://github.com/spring-projects/spring-integration/issues/3962 Turns out the `SftpClient.CopyMode` options are supported only starting SFTP v5 * Check for the version from the client and fallback to the logic we had before with JSsch: try to rename, delete existing file if such an exception status is thrown and retry to rename * * Fix `SftpOutboundTests` with answering an explicit SFTP version for an `SftpClient` mock
This commit is contained in:
@@ -154,7 +154,24 @@ public class SftpSession implements Session<SftpClient.DirEntry> {
|
||||
|
||||
@Override
|
||||
public void rename(String pathFrom, String pathTo) throws IOException {
|
||||
this.sftpClient.rename(pathFrom, pathTo, SftpClient.CopyMode.Overwrite);
|
||||
if (this.sftpClient.getVersion() >= SftpConstants.SFTP_V5) {
|
||||
this.sftpClient.rename(pathFrom, pathTo, SftpClient.CopyMode.Overwrite);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
this.sftpClient.rename(pathFrom, pathTo);
|
||||
}
|
||||
catch (SftpException sftpex) {
|
||||
if (SftpConstants.SSH_FX_FILE_ALREADY_EXISTS == sftpex.getStatus()) {
|
||||
remove(pathTo);
|
||||
// attempt to rename again
|
||||
this.sftpClient.rename(pathFrom, pathTo);
|
||||
}
|
||||
else {
|
||||
throw sftpex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -289,6 +289,7 @@ public class SftpOutboundTests {
|
||||
try {
|
||||
SftpClient sftpClient = mock(SftpClient.class);
|
||||
|
||||
when(sftpClient.getVersion()).thenReturn(SftpConstants.SFTP_V6);
|
||||
doAnswer(invocation -> {
|
||||
File file = new File((String) invocation.getArgument(0));
|
||||
assertThat(file.getName()).endsWith(".writing");
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.sshd.sftp.client.SftpClient;
|
||||
import org.apache.sshd.sftp.client.SftpVersionSelector;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -44,6 +45,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -133,6 +135,33 @@ public class SftpRemoteFileTemplateTests extends SftpTestSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renameWithOldSftpVersion() {
|
||||
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(false);
|
||||
factory.setHost("localhost");
|
||||
factory.setPort(port);
|
||||
factory.setUser("foo");
|
||||
factory.setPassword("foo");
|
||||
factory.setAllowUnknownKeys(true);
|
||||
|
||||
SftpSession currentVersionSession = factory.getSession();
|
||||
assertThatNoException()
|
||||
.isThrownBy(() ->
|
||||
currentVersionSession.rename("sftpSource/ sftpSource1.txt", "sftpSource/sftpSource2.txt"));
|
||||
|
||||
currentVersionSession.close();
|
||||
|
||||
factory.setSftpVersionSelector(SftpVersionSelector.MINIMUM);
|
||||
|
||||
SftpSession oldVersionSession = factory.getSession();
|
||||
assertThatNoException()
|
||||
.isThrownBy(() ->
|
||||
oldVersionSession.rename("sftpSource/sftpSource2.txt",
|
||||
"sftpSource/subSftpSource/subSftpSource1.txt"));
|
||||
|
||||
oldVersionSession.close();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class Config {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user