From 077b5ffffcd48e33fdbefb6b1054ec389f92911d Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 20 Sep 2017 16:10:19 -0400 Subject: [PATCH] INT-4344: AbstRemoteFileOutGw: Add assert for NPE JIRA: https://jira.spring.io/browse/INT-4344 The `FtpOutboundGateway` provides ctors without expression for remote path. In this case it is treated as a `working directory` but only for the `LS`, `NLST`, `PUT` and `MPUT` commands. * Add assertion in the `AbstractRemoteFileOutboundGateway` to discard configuration for all other commands when `expression` is `null` **Cherry-pick to 4.3.x** --- .../AbstractRemoteFileOutboundGateway.java | 37 ++++++++++++++----- .../RemoteFileOutboundGatewayTests.java | 6 +-- .../ftp/gateway/FtpOutboundGateway.java | 8 ++-- src/reference/asciidoc/ftp.adoc | 5 ++- 4 files changed, 38 insertions(+), 18 deletions(-) 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 4bd49244c3..d7733a5333 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 @@ -323,10 +323,21 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply Assert.notNull(remoteFileTemplate, "'remoteFileTemplate' cannot be null"); this.remoteFileTemplate = remoteFileTemplate; this.command = command; - Expression parsedExpression = new SpelExpressionParser().parseExpression(expression); - this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor<>(parsedExpression); + if (expression == null) { + Assert.state(Command.LS.equals(this.command) + || Command.NLST.equals(this.command) + || Command.PUT.equals(this.command) + || Command.MPUT.equals(this.command), + "Only LS, NLST, PUT and MPUT commands can rely on the working directory.\n" + + "All other commands must be supplied with the filename expression"); + this.fileNameProcessor = null; + } + else { + Expression parsedExpression = new SpelExpressionParser().parseExpression(expression); + this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor<>(parsedExpression); + setPrimaryExpression(parsedExpression); + } this.messageSessionCallback = null; - setPrimaryExpression(parsedExpression); } /** @@ -554,10 +565,14 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply "Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " + Option.RECURSIVE.toString() + " to obtain files in subdirectories"); } - if (this.fileNameProcessor != null && getBeanFactory() != null) { - this.fileNameProcessor.setBeanFactory(this.getBeanFactory()); - this.renameProcessor.setBeanFactory(this.getBeanFactory()); - this.remoteFileTemplate.setBeanFactory(this.getBeanFactory()); + + if (getBeanFactory() != null) { + if (this.fileNameProcessor != null) { + this.fileNameProcessor.setBeanFactory(getBeanFactory()); + } + + this.renameProcessor.setBeanFactory(getBeanFactory()); + this.remoteFileTemplate.setBeanFactory(getBeanFactory()); } } @@ -588,7 +603,9 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } private Object doLs(Message requestMessage) { - String dir = this.fileNameProcessor.processMessage(requestMessage); + String dir = this.fileNameProcessor != null + ? this.fileNameProcessor.processMessage(requestMessage) + : null; if (dir != null && !dir.endsWith(this.remoteFileTemplate.getRemoteFileSeparator())) { dir += this.remoteFileTemplate.getRemoteFileSeparator(); } @@ -600,7 +617,9 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } private Object doNlst(Message requestMessage) { - String dir = this.fileNameProcessor.processMessage(requestMessage); + String dir = this.fileNameProcessor != null + ? this.fileNameProcessor.processMessage(requestMessage) + : null; if (dir != null && !dir.endsWith(this.remoteFileTemplate.getRemoteFileSeparator())) { dir += this.remoteFileTemplate.getRemoteFileSeparator(); } 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 afeb3a6b04..003908cca4 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 @@ -809,7 +809,7 @@ public class RemoteFileOutboundGatewayTests { template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); template.setBeanFactory(mock(BeanFactory.class)); template.afterPropertiesSet(); - TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", null); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", "payload"); FileTransferringMessageHandler handler = new FileTransferringMessageHandler(sessionFactory); handler.setRemoteDirectoryExpressionString("'foo/'"); handler.setBeanFactory(mock(BeanFactory.class)); @@ -844,7 +844,7 @@ public class RemoteFileOutboundGatewayTests { template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); template.setBeanFactory(mock(BeanFactory.class)); template.afterPropertiesSet(); - TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", null); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", "payload"); FileTransferringMessageHandler handler = new FileTransferringMessageHandler(sessionFactory); handler.setRemoteDirectoryExpression(new LiteralExpression("foo/")); handler.setBeanFactory(mock(BeanFactory.class)); @@ -905,7 +905,7 @@ public class RemoteFileOutboundGatewayTests { template.setRemoteDirectoryExpression(new LiteralExpression("foo/")); template.setBeanFactory(mock(BeanFactory.class)); template.afterPropertiesSet(); - TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", null); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", "payload"); gw.afterPropertiesSet(); when(sessionFactory.getSession()).thenReturn(session); final AtomicReference written = new AtomicReference(); 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 bf7e67583f..87b0e7bc9f 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 @@ -102,8 +102,8 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway The {@code remoteDirectory} expression is {@code null} assuming to use * the {@code workingDirectory} from the FTP Client. * @param sessionFactory the session factory. @@ -115,8 +115,8 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway The {@code remoteDirectory} expression is {@code null} assuming to use * the {@code workingDirectory} from the FTP Client. * @param remoteFileTemplate the remote file template. diff --git a/src/reference/asciidoc/ftp.adoc b/src/reference/asciidoc/ftp.adoc index fdac53c11b..edf371a385 100644 --- a/src/reference/asciidoc/ftp.adoc +++ b/src/reference/asciidoc/ftp.adoc @@ -833,8 +833,9 @@ directories, which is achievable using the `FileInfo` objects. Starting with _version 4.3_, the `FtpSession` supports `null` for the `list()` and `listNames()` methods, therefore the `expression` attribute can be omitted. -From Java perspective there are two new constructor without `expression` argument for convenience. -The `null` for `LS` command is treated as an Client working directory according to the FTP protocol. +For Java configuration, there are two constructors without an `expression` argument for convenience. +`null` for `LS`, `NLST`, `PUT` and `MPUT` commands is treated as the Client working directory according to the FTP protocol. +All other commands must be supplied with the `expression` to evaluate remote path against request message. The working directory can be set via the `FTPClient.changeWorkingDirectory()` function when you extend the `DefaultFtpSessionFactory` and implement `postProcessClientAfterConnect()` callback. *nlst*