diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java index 076a8ff4c8..5ca635475b 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.integration.sftp.session; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.List; import java.util.Vector; @@ -108,16 +109,15 @@ public class SftpSession implements Session { @Override public String[] listNames(String path) throws IOException { LsEntry[] entries = this.list(path); - List names = new ArrayList(); - for (int i = 0; i < entries.length; i++) { - String fileName = entries[i].getFilename(); - SftpATTRS attrs = entries[i].getAttrs(); + List names = new ArrayList<>(); + for (LsEntry entry : entries) { + String fileName = entry.getFilename(); + SftpATTRS attrs = entry.getAttrs(); if (!attrs.isDir() && !attrs.isLink()) { names.add(fileName); } } - String[] fileNames = new String[names.size()]; - return names.toArray(fileNames); + return names.toArray(new String[0]); } @@ -251,10 +251,15 @@ public class SftpSession implements Session { this.channel.lstat(path); return true; } - catch (SftpException e) { - // ignore + catch (SftpException ex) { + if (ex.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { + return false; + } + else { + throw new UncheckedIOException("Cannot check 'lstat' for path " + path, + new IOException(ex)); + } } - return false; } void connect() { diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundTests.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundTests.java index acce3faf5c..1770421006 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundTests.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,16 @@ package org.springframework.integration.sftp.outbound; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -32,7 +37,9 @@ import static org.mockito.Mockito.when; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; @@ -40,7 +47,7 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.DirectFieldAccessor; @@ -69,6 +76,7 @@ import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpException; /** * @author Oleg Zhurakousky @@ -78,7 +86,7 @@ import com.jcraft.jsch.SftpATTRS; */ public class SftpOutboundTests { - private static com.jcraft.jsch.Session jschSession = mock(com.jcraft.jsch.Session.class); + private static final com.jcraft.jsch.Session jschSession = mock(com.jcraft.jsch.Session.class); @Test public void testHandleFileMessage() throws Exception { @@ -86,7 +94,7 @@ public class SftpOutboundTests { assertTrue("target directory does not exist: " + targetDir.getName(), targetDir.exists()); SessionFactory sessionFactory = new TestSftpSessionFactory(); - FileTransferringMessageHandler handler = new FileTransferringMessageHandler(sessionFactory); + FileTransferringMessageHandler handler = new FileTransferringMessageHandler<>(sessionFactory); handler.setRemoteDirectoryExpression(new LiteralExpression(targetDir.getName())); DefaultFileNameGenerator fGenerator = new DefaultFileNameGenerator(); fGenerator.setBeanFactory(mock(BeanFactory.class)); @@ -135,7 +143,7 @@ public class SftpOutboundTests { file.delete(); } SessionFactory sessionFactory = new TestSftpSessionFactory(); - FileTransferringMessageHandler handler = new FileTransferringMessageHandler(sessionFactory); + FileTransferringMessageHandler handler = new FileTransferringMessageHandler<>(sessionFactory); DefaultFileNameGenerator fGenerator = new DefaultFileNameGenerator(); fGenerator.setBeanFactory(mock(BeanFactory.class)); fGenerator.setExpression("'foo.txt'"); @@ -173,7 +181,7 @@ public class SftpOutboundTests { } @Test //INT-2275 - public void testFtpOutboundGatewayInsideChain() throws Exception { + public void testFtpOutboundGatewayInsideChain() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "SftpOutboundInsideChainTests-context.xml", getClass()); @@ -204,12 +212,12 @@ public class SftpOutboundTests { @SuppressWarnings("unchecked") SessionFactory sessionFactory = mock(SessionFactory.class); when(sessionFactory.getSession()).thenReturn(session); - FileTransferringMessageHandler handler = new FileTransferringMessageHandler(sessionFactory); + FileTransferringMessageHandler handler = new FileTransferringMessageHandler<>(sessionFactory); handler.setAutoCreateDirectory(true); handler.setRemoteDirectoryExpression(new LiteralExpression("/foo/bar/baz")); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); - final List madeDirs = new ArrayList(); + final List madeDirs = new ArrayList<>(); doAnswer(invocation -> { madeDirs.add(invocation.getArgument(0)); return null; @@ -374,6 +382,38 @@ public class SftpOutboundTests { verify(jschSession2).disconnect(); } + @Test + public void testExists() throws SftpException, IOException { + ChannelSftp channelSftp = mock(ChannelSftp.class); + + willReturn(mock(SftpATTRS.class)) + .given(channelSftp) + .lstat(eq("exist")); + + willThrow(new SftpException(ChannelSftp.SSH_FX_NO_SUCH_FILE, "Path does not exist.")) + .given(channelSftp) + .lstat(eq("notExist")); + + willThrow(new SftpException(ChannelSftp.SSH_FX_CONNECTION_LOST, "Connection lost.")) + .given(channelSftp) + .lstat(eq("foo")); + + SftpSession sftpSession = new SftpSession(mock(com.jcraft.jsch.Session.class)); + DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(sftpSession); + fieldAccessor.setPropertyValue("channel", channelSftp); + + assertTrue(sftpSession.exists("exist")); + + assertFalse(sftpSession.exists("notExist")); + + try { + sftpSession.exists("foo"); + fail("Expected exception"); + } + catch (UncheckedIOException e) { + } + } + private void noopConnect(ChannelSftp channel1) throws JSchException { doAnswer(invocation -> null).when(channel1).connect(); } diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests.java index e175de8316..9ecfcc9dd5 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests.java @@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; @@ -35,6 +36,7 @@ import java.io.File; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.io.UncheckedIOException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; @@ -56,6 +58,7 @@ import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.session.Session; import org.springframework.integration.file.remote.session.SessionFactory; import org.springframework.integration.sftp.SftpTestSupport; +import org.springframework.integration.sftp.session.DefaultSftpSessionFactory; import org.springframework.integration.sftp.session.SftpRemoteFileTemplate; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; @@ -497,6 +500,29 @@ public class SftpServerOutboundTests extends SftpTestSupport { assertEquals(6, files[0].getAttrs().getSize()); } + @Test + public void testSessionExists() throws IOException { + DefaultSftpSessionFactory sessionFactory = new DefaultSftpSessionFactory(); + sessionFactory.setHost("localhost"); + sessionFactory.setPort(port); + sessionFactory.setUser("foo"); + sessionFactory.setPassword("foo"); + sessionFactory.setAllowUnknownKeys(true); + Session session = sessionFactory.getSession(); + + assertTrue(session.exists("sftpSource")); + assertFalse(session.exists("notExist")); + + session.close(); + + try { + session.exists("any"); + fail("expected exception"); + } + catch (UncheckedIOException e) { + } + } + @SuppressWarnings("unused") private static final class TestMessageSessionCallback implements MessageSessionCallback {