diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/dsl/RemoteFileOutboundGatewaySpec.java b/spring-integration-file/src/main/java/org/springframework/integration/file/dsl/RemoteFileOutboundGatewaySpec.java index f240d6056c..e031792da7 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/dsl/RemoteFileOutboundGatewaySpec.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/dsl/RemoteFileOutboundGatewaySpec.java @@ -25,6 +25,7 @@ import org.springframework.expression.Expression; import org.springframework.integration.dsl.ComponentsRegistration; import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.expression.FunctionExpression; +import org.springframework.integration.file.FileNameGenerator; import org.springframework.integration.file.filters.CompositeFileListFilter; import org.springframework.integration.file.filters.ExpressionFileListFilter; import org.springframework.integration.file.filters.FileListFilter; @@ -313,8 +314,21 @@ public abstract class RemoteFileOutboundGatewaySpec the expected payload type. * @return the Spec. + * @deprecated since 5.2 in favor of {@link #localFilenameFunction(Function)} */ + @Deprecated public

S localFilename(Function, String> localFilenameFunction) { + return localFilenameFunction(localFilenameFunction); + } + + /** + * Specify a {@link Function} for local files renaming after downloading. + * @param localFilenameFunction the {@link Function} to use. + * @param

the expected payload type. + * @return the Spec. + * @since 5.2 + */ + public

S localFilenameFunction(Function, String> localFilenameFunction) { return localFilenameExpression(new FunctionExpression<>(localFilenameFunction)); } @@ -351,6 +365,167 @@ public abstract class RemoteFileOutboundGatewaySpec the expected payload type. + * @return the Spec. + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setRemoteDirectoryExpression + * @see FunctionExpression + */ + public

S remoteDirectoryFunction(Function, String> remoteDirectoryFunction) { + return remoteDirectoryExpression(new FunctionExpression<>(remoteDirectoryFunction)); + } + + /** + * Set the remote directory expression used to determine the remote directory to which + * files will be sent. + * @param remoteDirectoryExpression the remote directory expression. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setRemoteDirectoryExpression + */ + public S remoteDirectoryExpression(Expression remoteDirectoryExpression) { + this.target.setRemoteDirectoryExpression(remoteDirectoryExpression); + return _this(); + } + + /** + * Set a temporary remote directory expression; used when transferring files to the remote + * system. + * @param temporaryRemoteDirectoryExpression the temporary remote directory expression. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setRemoteDirectoryExpression + */ + public S temporaryRemoteDirectoryExpression(String temporaryRemoteDirectoryExpression) { + return temporaryRemoteDirectoryExpression(PARSER.parseExpression(temporaryRemoteDirectoryExpression)); + } + + /** + * Set a temporary remote directory function; used when transferring files to the remote + * system. + * @param temporaryRemoteDirectoryFunction the file name expression. + * @param

the expected payload type. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setRemoteDirectoryExpression + */ + public

S temporaryRemoteDirectoryFunction(Function, String> temporaryRemoteDirectoryFunction) { + return temporaryRemoteDirectoryExpression(new FunctionExpression<>(temporaryRemoteDirectoryFunction)); + } + + /** + * Set a temporary remote directory expression; used when transferring files to the remote + * system. + * @param temporaryRemoteDirectoryExpression the temporary remote directory expression. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setRemoteDirectoryExpression + */ + public S temporaryRemoteDirectoryExpression(Expression temporaryRemoteDirectoryExpression) { + this.target.setTemporaryRemoteDirectoryExpression(temporaryRemoteDirectoryExpression); + return _this(); + } + + /** + * Set the file name expression to determine the full path to the remote file. + * @param fileNameExpression the file name expression. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setFileNameExpression + */ + public S fileNameExpression(String fileNameExpression) { + return fileNameExpression(PARSER.parseExpression(fileNameExpression)); + } + + /** + * Set the file name function to determine the full path to the remote file. + * @param fileNameFunction the file name expression. + * @param

the expected payload type. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setFileNameExpression + */ + public

S fileNameFunction(Function, String> fileNameFunction) { + return fileNameExpression(new FunctionExpression<>(fileNameFunction)); + } + + /** + * Set the file name expression to determine the full path to the remote file. + * @param fileNameExpression the file name expression. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setFileNameExpression + */ + public S fileNameExpression(Expression fileNameExpression) { + this.target.setFileNameExpression(fileNameExpression); + return _this(); + } + + /** + * Set whether a temporary file name is used when sending files to the remote system. + * @param useTemporaryFileName true to use a temporary file name. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setUseTemporaryFileName + */ + public S useTemporaryFileName(boolean useTemporaryFileName) { + this.target.setUseTemporaryFileName(useTemporaryFileName); + return _this(); + } + + /** + * Set the file name generator used to generate the remote filename to be used when transferring + * files to the remote system. + * @param fileNameGenerator the file name generator. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setFileNameGenerator + */ + public S fileNameGenerator(FileNameGenerator fileNameGenerator) { + this.target.setFileNameGenerator(fileNameGenerator); + return _this(); + } + + /** + * Set the charset to use when converting String payloads to bytes as the content of the + * remote file. Default {@code UTF-8}. + * @param charset the charset. + * @return the current Spec + * @since 5.2 + * @see AbstractRemoteFileOutboundGateway#setCharset + */ + public S charset(String charset) { + this.target.setCharset(charset); + return _this(); + } @Override public Map getComponentsToRegister() { diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java index b055211e5d..7dfd58cefa 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java @@ -41,6 +41,7 @@ import org.springframework.integration.expression.ExpressionUtils; import org.springframework.integration.expression.FunctionExpression; import org.springframework.integration.expression.ValueExpression; import org.springframework.integration.file.FileHeaders; +import org.springframework.integration.file.FileNameGenerator; import org.springframework.integration.file.filters.FileListFilter; import org.springframework.integration.file.remote.AbstractFileInfo; import org.springframework.integration.file.remote.MessageSessionCallback; @@ -108,6 +109,8 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply private Integer chmod; + private boolean remoteFileTemplateExplicitlySet; + /** * Construct an instance using the provided session factory and callback for * performing operations on the session. @@ -135,6 +138,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply this.messageSessionCallback = messageSessionCallback; this.fileNameProcessor = null; this.command = null; + remoteFileTemplateExplicitlySet(true); } /** @@ -204,6 +208,16 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply setPrimaryExpression(parsedExpression); } this.messageSessionCallback = null; + remoteFileTemplateExplicitlySet(true); + } + + protected final void remoteFileTemplateExplicitlySet(boolean remoteFileTemplateExplicitlySet) { + this.remoteFileTemplateExplicitlySet = remoteFileTemplateExplicitlySet; + } + + protected void assertRemoteFileTemplateMutability(String propertyName) { + Assert.state(!this.remoteFileTemplateExplicitlySet, + () -> "The '" + propertyName + "' must be set on the externally provided: " + this.remoteFileTemplate); } /** @@ -242,6 +256,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply * @see RemoteFileTemplate#setRemoteFileSeparator(String) */ public void setRemoteFileSeparator(String remoteFileSeparator) { + assertRemoteFileTemplateMutability("remoteFileSeparator"); this.remoteFileTemplate.setRemoteFileSeparator(remoteFileSeparator); } @@ -290,9 +305,93 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply * @see RemoteFileTemplate#setTemporaryFileSuffix(String) */ public void setTemporaryFileSuffix(String temporaryFileSuffix) { + assertRemoteFileTemplateMutability("temporaryFileSuffix"); this.remoteFileTemplate.setTemporaryFileSuffix(temporaryFileSuffix); } + /** + * Determine whether the remote directory should automatically be created when + * sending files to the remote system. + * @param autoCreateDirectory true to create the directory. + * @since 5.2 + * @see RemoteFileTemplate#setAutoCreateDirectory(boolean) + */ + public void setAutoCreateDirectory(boolean autoCreateDirectory) { + assertRemoteFileTemplateMutability("autoCreateDirectory"); + this.remoteFileTemplate.setAutoCreateDirectory(autoCreateDirectory); + } + + /** + * Set the remote directory expression used to determine the remote directory to which + * files will be sent. + * @param remoteDirectoryExpression the remote directory expression. + * @since 5.2 + * @see RemoteFileTemplate#setRemoteDirectoryExpression + */ + public void setRemoteDirectoryExpression(Expression remoteDirectoryExpression) { + assertRemoteFileTemplateMutability("remoteDirectoryExpression"); + this.remoteFileTemplate.setRemoteDirectoryExpression(remoteDirectoryExpression); + } + + /** + * Set a temporary remote directory expression; used when transferring files to the remote + * system. After a successful transfer the file is renamed using the + * {@link #setRemoteDirectoryExpression(Expression) remoteDirectoryExpression}. + * @param temporaryRemoteDirectoryExpression the temporary remote directory expression. + * @since 5.2 + * @see RemoteFileTemplate#setTemporaryRemoteDirectoryExpression + */ + public void setTemporaryRemoteDirectoryExpression(Expression temporaryRemoteDirectoryExpression) { + assertRemoteFileTemplateMutability("temporaryRemoteDirectoryExpression"); + this.remoteFileTemplate.setTemporaryRemoteDirectoryExpression(temporaryRemoteDirectoryExpression); + } + + /** + * Set the file name expression to determine the full path to the remote file. + * @param fileNameExpression the file name expression. + * @since 5.2 + * @see RemoteFileTemplate#setFileNameExpression + */ + public void setFileNameExpression(Expression fileNameExpression) { + assertRemoteFileTemplateMutability("fileNameExpression"); + this.remoteFileTemplate.setFileNameExpression(fileNameExpression); + } + + /** + * Set whether a temporary file name is used when sending files to the remote system. + * @param useTemporaryFileName true to use a temporary file name. + * @since 5.2 + * @see RemoteFileTemplate#setUseTemporaryFileName + */ + public void setUseTemporaryFileName(boolean useTemporaryFileName) { + assertRemoteFileTemplateMutability("useTemporaryFileName"); + this.remoteFileTemplate.setUseTemporaryFileName(useTemporaryFileName); + } + + /** + * Set the file name generator used to generate the remote filename to be used when transferring + * files to the remote system. + * @param fileNameGenerator the file name generator. + * @since 5.2 + * @see RemoteFileTemplate#setFileNameGenerator + */ + public void setFileNameGenerator(FileNameGenerator fileNameGenerator) { + assertRemoteFileTemplateMutability("fileNameGenerator"); + this.remoteFileTemplate.setFileNameGenerator(fileNameGenerator); + } + + /** + * Set the charset to use when converting String payloads to bytes as the content of the + * remote file. Default {@code UTF-8}. + * @param charset the charset. + * @since 5.2 + * @see RemoteFileTemplate#setCharset + */ + public void setCharset(String charset) { + assertRemoteFileTemplateMutability("charset"); + this.remoteFileTemplate.setCharset(charset); + } + /** * Set a {@link FileListFilter} to filter remote files. * @param filter the filter to set 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 2a3f1e6362..a6ce6297bc 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 @@ -19,6 +19,7 @@ package org.springframework.integration.file.remote.gateway; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 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.Mockito.doAnswer; @@ -124,7 +125,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/x")); - assertThat(out.getPayload().size()).isEqualTo(2); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(2); assertThat(out.getPayload().get(0)).isSameAs(files[1]); // sort by default assertThat(out.getPayload().get(1)).isSameAs(files[0]); assertThat(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)).isEqualTo("testremote/x/"); @@ -175,7 +177,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/*")); - assertThat(out.getPayload().size()).isEqualTo(2); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(2); assertThat(out.getPayload().get(0).getName()).isEqualTo("f1"); assertThat(out.getPayload().get(1).getName()).isEqualTo("f2"); assertThat(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)).isEqualTo("testremote/"); @@ -205,7 +208,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/f1")); - assertThat(out.getPayload().size()).isEqualTo(1); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(1); assertThat(out.getPayload().get(0).getName()).isEqualTo("f1"); assertThat(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)).isEqualTo("testremote/"); } @@ -329,7 +333,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/x")); - assertThat(out.getPayload().size()).isEqualTo(2); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(2); assertThat(out.getPayload().get(0)).isSameAs(files[0]); assertThat(out.getPayload().get(1)).isSameAs(files[1]); assertThat(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)).isEqualTo("testremote/x/"); @@ -373,7 +378,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/x")); - assertThat(out.getPayload().size()).isEqualTo(4); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(4); assertThat(out.getPayload().get(0).getFilename()).isEqualTo("f1"); assertThat(out.getPayload().get(1).getFilename()).isEqualTo("d1/d2/f4"); assertThat(out.getPayload().get(2).getFilename()).isEqualTo("d1/f3"); @@ -398,7 +404,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote/x")); - assertThat(out.getPayload().size()).isEqualTo(5); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(5); assertThat(out.getPayload().get(0).getFilename()).isEqualTo("f1"); assertThat(out.getPayload().get(1).getFilename()).isEqualTo("d1"); assertThat(out.getPayload().get(2).getFilename()).isEqualTo("d1/d2"); @@ -419,7 +426,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(0); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(0); } @Test @@ -435,7 +443,8 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(2); + assertThat(out).isNotNull(); + assertThat(out.getPayload()).hasSize(2); assertThat(out.getPayload().get(0)).isEqualTo("f1"); assertThat(out.getPayload().get(1)).isEqualTo("f2"); } @@ -453,7 +462,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(2); + assertThat(out.getPayload()).hasSize(2); assertThat(out.getPayload().get(0)).isEqualTo("f2"); assertThat(out.getPayload().get(1)).isEqualTo("f1"); } @@ -471,7 +480,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(3); + assertThat(out.getPayload()).hasSize(3); assertThat(out.getPayload().get(0)).isEqualTo("f1"); assertThat(out.getPayload().get(1)).isEqualTo("f2"); assertThat(out.getPayload().get(2)).isEqualTo("f3"); @@ -490,7 +499,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(4); + assertThat(out.getPayload()).hasSize(4); assertThat(out.getPayload().get(0)).isEqualTo("f1"); assertThat(out.getPayload().get(1)).isEqualTo("f2"); assertThat(out.getPayload().get(2)).isEqualTo("f3"); @@ -510,7 +519,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(6); + assertThat(out.getPayload()).hasSize(6); assertThat(out.getPayload().get(0)).isEqualTo("f2"); assertThat(out.getPayload().get(1)).isEqualTo("f1"); assertThat(out.getPayload().get(2)).isEqualTo("f3"); @@ -533,7 +542,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder> out = (MessageBuilder>) gw .handleRequestMessage(new GenericMessage<>("testremote")); - assertThat(out.getPayload().size()).isEqualTo(1); + assertThat(out.getPayload()).hasSize(1); assertThat(out.getPayload().get(0)).isEqualTo("f4"); } @@ -748,7 +757,7 @@ public class RemoteFileOutboundGatewayTests { @SuppressWarnings("unchecked") MessageBuilder out = (MessageBuilder) gw .handleRequestMessage(new GenericMessage<>("testremote/x/f1")); - assertThat(out.getPayload()).isEqualTo(Boolean.TRUE); + assertThat(out.getPayload()).isTrue(); verify(session).remove("testremote/x/f1"); assertThat(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)).isEqualTo("testremote/x/"); assertThat(out.getHeaders().get(FileHeaders.REMOTE_FILE)).isEqualTo("f1"); @@ -876,7 +885,7 @@ public class RemoteFileOutboundGatewayTests { Message requestMessage = MessageBuilder.withPayload(tempFolder.getRoot()) .build(); List out = (List) gw.handleRequestMessage(requestMessage); - assertThat(out.size()).isEqualTo(2); + assertThat(out).hasSize(2); assertThat(out.get(0)).isNotEqualTo(out.get(1)); assertThat(out.get(0)).isIn("foo/baz.txt", "foo/qux.txt"); assertThat(out.get(1)).isIn("foo/baz.txt", "foo/qux.txt"); @@ -908,23 +917,31 @@ public class RemoteFileOutboundGatewayTests { Message requestMessage = MessageBuilder.withPayload(tempFolder.getRoot()) .build(); List out = (List) gw.handleRequestMessage(requestMessage); - assertThat(out.size()).isEqualTo(3); + assertThat(out).hasSize(3); assertThat(out.get(0)).isNotEqualTo(out.get(1)); assertThat(out.get(0)).isIn("foo/baz.txt", "foo/qux.txt", "foo/" + dir1.getName() + "/" + file3.getName()); assertThat(out.get(1)).isIn("foo/baz.txt", "foo/qux.txt", "foo/" + dir1.getName() + "/" + file3.getName()); assertThat(out.get(2)).isIn("foo/baz.txt", "foo/qux.txt", "foo/" + dir1.getName() + "/" + file3.getName()); } + @Test + @SuppressWarnings("unchecked") + public void testRemoteFileTemplateImmutability() { + SessionFactory sessionFactory = mock(SessionFactory.class); + RemoteFileTemplate template = new RemoteFileTemplate<>(sessionFactory); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", null); + assertThatIllegalStateException() + .isThrownBy(() -> gw.setRemoteDirectoryExpression(new LiteralExpression("testRemoteDirectory"))) + .withMessageContaining("The 'remoteDirectoryExpression' must be set on the externally provided"); + } + @Test @SuppressWarnings("unchecked") public void testMputCollection() throws Exception { SessionFactory sessionFactory = mock(SessionFactory.class); Session session = mock(Session.class); - RemoteFileTemplate template = new RemoteFileTemplate<>(sessionFactory); - template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); - template.setBeanFactory(mock(BeanFactory.class)); - template.afterPropertiesSet(); - TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", "payload"); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mput", "payload"); + gw.setRemoteDirectoryExpression(new LiteralExpression("foo/")); gw.afterPropertiesSet(); when(sessionFactory.getSession()).thenReturn(session); final AtomicReference written = new AtomicReference<>(); @@ -938,7 +955,7 @@ public class RemoteFileOutboundGatewayTests { Message> requestMessage = MessageBuilder.withPayload(files) .build(); List out = (List) gw.handleRequestMessage(requestMessage); - assertThat(out.size()).isEqualTo(2); + assertThat(out).isNotNull().hasSize(2); assertThat(out.get(0)).isNotEqualTo(out.get(1)); assertThat(out.get(0)).isEqualTo("foo/fiz.txt"); assertThat(out.get(1)).isEqualTo("foo/buz.txt"); @@ -1038,6 +1055,7 @@ public class RemoteFileOutboundGatewayTests { String command, String expression) { super(sessionFactory, Command.toCommand(command), expression); this.setBeanFactory(mock(BeanFactory.class)); + remoteFileTemplateExplicitlySet(false); } TestRemoteFileOutboundGateway(RemoteFileTemplate remoteFileTemplate, String command, @@ -1046,7 +1064,6 @@ public class RemoteFileOutboundGatewayTests { this.setBeanFactory(mock(BeanFactory.class)); } - @Override protected boolean isDirectory(TestLsEntry file) { return file.isDirectory(); diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/gateway/FtpOutboundGateway.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/gateway/FtpOutboundGateway.java index 656de66ba2..9ea8305183 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/gateway/FtpOutboundGateway.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/gateway/FtpOutboundGateway.java @@ -68,6 +68,7 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway sessionFactory, String command, String expression) { this(new FtpRemoteFileTemplate(sessionFactory), command, expression); ((FtpRemoteFileTemplate) getRemoteFileTemplate()).setExistsMode(FtpRemoteFileTemplate.ExistsMode.NLST); + remoteFileTemplateExplicitlySet(false); } /** diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/dsl/FtpTests.java b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/dsl/FtpTests.java index 02bdc48c0a..4edf4084f7 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/dsl/FtpTests.java +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/dsl/FtpTests.java @@ -197,13 +197,15 @@ public class FtpTests extends FtpTestSupport { public void testFtpMgetFlow() { QueueChannel out = new QueueChannel(); IntegrationFlow flow = f -> f - .handle(Ftp.outboundGateway(sessionFactory(), - AbstractRemoteFileOutboundGateway.Command.MGET, "payload") - .options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE) - .fileExistsMode(FileExistsMode.IGNORE) - .filterExpression("name matches 'subFtpSource|.*1.txt'") - .localDirectoryExpression("'" + getTargetLocalDirectoryName() + "' + #remoteDirectory") - .localFilenameExpression("#remoteFileName.replaceFirst('ftpSource', 'localTarget')")) + .handle( + Ftp.outboundGateway(sessionFactory(), AbstractRemoteFileOutboundGateway.Command.MGET, "payload") + .options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE) + .fileExistsMode(FileExistsMode.IGNORE) + .filterExpression("name matches 'subFtpSource|.*1.txt'") + .localDirectoryExpression("'" + getTargetLocalDirectoryName() + "' + #remoteDirectory") + .localFilenameExpression("#remoteFileName.replaceFirst('ftpSource', 'localTarget')") + .charset(StandardCharsets.UTF_8.name()) + .useTemporaryFileName(true)) .channel(out); IntegrationFlowRegistration registration = this.flowContext.registration(flow).register(); String dir = "ftpSource/"; diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/gateway/SftpOutboundGateway.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/gateway/SftpOutboundGateway.java index cdb7e44437..e92ba0e4fb 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/gateway/SftpOutboundGateway.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/gateway/SftpOutboundGateway.java @@ -66,6 +66,7 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway messageSessionCallback) { this(new SftpRemoteFileTemplate(sessionFactory), messageSessionCallback); + remoteFileTemplateExplicitlySet(false); } /** @@ -89,6 +90,7 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway sessionFactory, String command, String expression) { this(new SftpRemoteFileTemplate(sessionFactory), command, expression); + remoteFileTemplateExplicitlySet(false); } /**