diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java index e0e7e71d27..ef59cbb3da 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java @@ -386,7 +386,7 @@ public class RemoteFileTemplate implements RemoteFileOperations, Initializ public boolean get(Message message, InputStreamCallback callback) { Assert.notNull(this.fileNameProcessor, "A 'fileNameExpression' is needed to use get"); String remotePath = this.fileNameProcessor.processMessage(message); - return this.get(remotePath, callback); + return get(remotePath, callback); } @Override @@ -571,7 +571,7 @@ public class RemoteFileTemplate implements RemoteFileOperations, Initializ session.append(stream, tempFilePath); } else { - if (exists(remoteFilePath)) { + if (session.exists(remoteFilePath)) { if (FileExistsMode.FAIL.equals(mode)) { throw new MessagingException( "The destination file already exists at '" + remoteFilePath + "'."); diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.java b/spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.java index a6ce6297bc..eb2a19dc55 100644 --- a/spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.java +++ b/spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.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. @@ -22,6 +22,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -804,14 +805,10 @@ public class RemoteFileOutboundGatewayTests { SessionFactory sessionFactory = mock(SessionFactory.class); @SuppressWarnings("unchecked") Session session = mock(Session.class); - RemoteFileTemplate template = new RemoteFileTemplate(sessionFactory) { - - @Override - public boolean exists(String path) { - return true; - } - - }; + willReturn(Boolean.TRUE) + .given(session) + .exists(anyString()); + RemoteFileTemplate template = new RemoteFileTemplate<>(sessionFactory); template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); template.setBeanFactory(mock(BeanFactory.class)); template.afterPropertiesSet(); @@ -932,7 +929,7 @@ public class RemoteFileOutboundGatewayTests { TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", null); assertThatIllegalStateException() .isThrownBy(() -> gw.setRemoteDirectoryExpression(new LiteralExpression("testRemoteDirectory"))) - .withMessageContaining("The 'remoteDirectoryExpression' must be set on the externally provided"); + .withMessageContaining("The 'remoteDirectoryExpression' must be set on the externally provided"); } @Test @@ -942,6 +939,7 @@ public class RemoteFileOutboundGatewayTests { Session session = mock(Session.class); TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mput", "payload"); gw.setRemoteDirectoryExpression(new LiteralExpression("foo/")); + gw.setBeanFactory(mock(BeanFactory.class)); gw.afterPropertiesSet(); when(sessionFactory.getSession()).thenReturn(session); final AtomicReference written = new AtomicReference<>(); diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/session/SftpRemoteFileTemplateTests.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/session/SftpRemoteFileTemplateTests.java index feaafc238f..af0d43f1c6 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/session/SftpRemoteFileTemplateTests.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/session/SftpRemoteFileTemplateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-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,6 +17,8 @@ package org.springframework.integration.sftp.session; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; import java.util.Arrays; import java.util.List; @@ -25,6 +27,7 @@ import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,11 +37,13 @@ import org.springframework.integration.file.remote.ClientCallbackWithoutResult; import org.springframework.integration.file.remote.SessionCallbackWithoutResult; import org.springframework.integration.file.remote.session.CachingSessionFactory; import org.springframework.integration.file.remote.session.SessionFactory; +import org.springframework.integration.file.support.FileExistsMode; import org.springframework.integration.sftp.SftpTestSupport; +import org.springframework.messaging.MessageDeliveryException; +import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.GenericMessage; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp.LsEntry; @@ -47,11 +52,12 @@ import com.jcraft.jsch.SftpException; /** * @author Gary Russell + * @author Artem Bilan + * * @since 4.1 * */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @DirtiesContext public class SftpRemoteFileTemplateTests extends SftpTestSupport { @@ -63,15 +69,19 @@ public class SftpRemoteFileTemplateTests extends SftpTestSupport { SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sessionFactory); DefaultFileNameGenerator fileNameGenerator = new DefaultFileNameGenerator(); fileNameGenerator.setExpression("'foobar.txt'"); + fileNameGenerator.setBeanFactory(mock(BeanFactory.class)); template.setFileNameGenerator(fileNameGenerator); template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); template.setUseTemporaryFileName(false); + template.setBeanFactory(mock(BeanFactory.class)); + template.afterPropertiesSet(); + template.execute(session -> { session.mkdir("foo/"); return session.mkdir("foo/bar/"); }); - template.append(new GenericMessage("foo")); - template.append(new GenericMessage("bar")); + template.append(new GenericMessage<>("foo")); + template.append(new GenericMessage<>("bar")); assertThat(template.exists("foo/foobar.txt")).isTrue(); template.executeWithClient((ClientCallbackWithoutResult) client -> { try { @@ -96,6 +106,29 @@ public class SftpRemoteFileTemplateTests extends SftpTestSupport { assertThat(template.exists("foo")).isFalse(); } + @Test + public void testNoDeadLockOnSend() { + CachingSessionFactory cachingSessionFactory = new CachingSessionFactory<>(sessionFactory(), 1); + SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(cachingSessionFactory); + template.setRemoteDirectoryExpression(new LiteralExpression("")); + template.setBeanFactory(mock(BeanFactory.class)); + template.setUseTemporaryFileName(false); + DefaultFileNameGenerator fileNameGenerator = new DefaultFileNameGenerator(); + fileNameGenerator.setExpression("'test.file'"); + fileNameGenerator.setBeanFactory(mock(BeanFactory.class)); + template.setFileNameGenerator(fileNameGenerator); + template.afterPropertiesSet(); + + template.send(new GenericMessage<>("")); + + assertThatExceptionOfType(MessageDeliveryException.class) + .isThrownBy(() -> template.send(new GenericMessage<>(""), FileExistsMode.FAIL)) + .withCauseInstanceOf(MessagingException.class) + .withStackTraceContaining("he destination file already exists at 'test.file'."); + + cachingSessionFactory.destroy(); + } + @Configuration public static class Config {