diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java index d23f377baf..1a14a4a198 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.file.config; import org.w3c.dom.Element; @@ -53,8 +54,13 @@ public abstract class AbstractRemoteFileOutboundGatewayParser extends AbstractCo builder.addConstructorArgValue(templateDefinition); - builder.addConstructorArgValue(element.getAttribute("command")); - builder.addConstructorArgValue(element.getAttribute(EXPRESSION_ATTRIBUTE)); + if (element.hasAttribute("session-callback")) { + builder.addConstructorArgReference(element.getAttribute("session-callback")); + } + else { + builder.addConstructorArgValue(element.getAttribute("command")); + builder.addConstructorArgValue(element.getAttribute(EXPRESSION_ATTRIBUTE)); + } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "command-options", "options"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel"); diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/MessageSessionCallback.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/MessageSessionCallback.java new file mode 100644 index 0000000000..ed871c547a --- /dev/null +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/MessageSessionCallback.java @@ -0,0 +1,45 @@ +/* + * Copyright 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.file.remote; + +import java.io.IOException; + +import org.springframework.integration.file.remote.session.Session; +import org.springframework.messaging.Message; + +/** + * Callback invoked by {@code RemoteFileOperations.executeForMessage()} + * - allows multiple operations on a session. + * + * @author Artem Bilan + * @since 4.2 + */ +public interface MessageSessionCallback { + + /** + * Called within the context of a session and requestMessage. + * Perform some operation(s) on the session. + * The caller will take care of closing the session after this method exits. + * + * @param session The session. + * @param requestMessage The message to take in account with session operation(s). + * @return The result of type T. + * @throws IOException Any IOException. + */ + T doInSession(Session session, Message requestMessage) throws IOException; + +} 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 3e0793b742..d5bd99eb46 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 @@ -39,6 +39,7 @@ import org.springframework.integration.expression.ExpressionUtils; import org.springframework.integration.file.FileHeaders; import org.springframework.integration.file.filters.FileListFilter; import org.springframework.integration.file.remote.AbstractFileInfo; +import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.RemoteFileTemplate; import org.springframework.integration.file.remote.SessionCallback; import org.springframework.integration.file.remote.session.Session; @@ -71,7 +72,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply /** * Enumeration of commands supported by the gateways. */ - public static enum Command { + public enum Command { /** * List remote files. @@ -110,7 +111,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply private String command; - private Command(String command) { + Command(String command) { this.command = command; } @@ -126,13 +127,14 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } throw new IllegalArgumentException("No Command with value '" + cmd + "'"); } + } /** * Enumeration of options supported by various commands. * */ - public static enum Option { + public enum Option { /** * Don't return full file information; just the name (ls). @@ -181,7 +183,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply private String option; - private Option(String option) { + Option(String option) { this.option = option; } @@ -197,10 +199,13 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } throw new IllegalArgumentException("No option with value '" + opt + "'"); } + } private final ExpressionEvaluatingMessageProcessor fileNameProcessor; + private final MessageSessionCallback messageSessionCallback; + private volatile ExpressionEvaluatingMessageProcessor renameProcessor = new ExpressionEvaluatingMessageProcessor( new SpelExpressionParser().parseExpression("headers." + FileHeaders.RENAME_TO)); @@ -226,33 +231,75 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply private volatile FileExistsMode fileExistsMode; + /** + * Construct an instance using the provided session factory and callback for + * performing operations on the session. + * @param sessionFactory the session factory. + * @param messageSessionCallback the callback. + */ + public AbstractRemoteFileOutboundGateway(SessionFactory sessionFactory, + MessageSessionCallback messageSessionCallback) { + this(new RemoteFileTemplate(sessionFactory), messageSessionCallback); + } + + /** + * Construct an instance with the supplied remote file template and callback + * for performing operations on the session. + * @param remoteFileTemplate the remote file template. + * @param messageSessionCallback the callback. + */ + public AbstractRemoteFileOutboundGateway(RemoteFileTemplate remoteFileTemplate, + MessageSessionCallback messageSessionCallback) { + Assert.notNull(remoteFileTemplate, "'remoteFileTemplate' cannot be null"); + Assert.notNull(messageSessionCallback, "'messageSessionCallback' cannot be null"); + this.remoteFileTemplate = remoteFileTemplate; + this.messageSessionCallback = messageSessionCallback; + this.fileNameProcessor = null; + this.command = null; + } + + /** + * Construct an instance with the supplied session factory, a command ('ls', 'get' + * etc), and an expression to determine the filename. + * @param sessionFactory the session factory. + * @param command the command. + * @param expression the filename expression. + */ public AbstractRemoteFileOutboundGateway(SessionFactory sessionFactory, String command, String expression) { - Assert.notNull(sessionFactory, "'sessionFactory' cannot be null"); - this.remoteFileTemplate = new RemoteFileTemplate(sessionFactory); - this.command = Command.toCommand(command); - this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor( - new SpelExpressionParser().parseExpression(expression)); + this(sessionFactory, Command.toCommand(command), expression); } - public AbstractRemoteFileOutboundGateway(SessionFactory sessionFactory, Command command, - String expression) { - Assert.notNull(sessionFactory, "'sessionFactory' cannot be null"); - this.remoteFileTemplate = new RemoteFileTemplate(sessionFactory); - this.command = command; - this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor( - new SpelExpressionParser().parseExpression(expression)); + /** + * Construct an instance with the supplied session factory, a command ('ls', 'get' + * etc), and an expression to determine the filename. + * @param sessionFactory the session factory. + * @param command the command. + * @param expression the filename expression. + */ + public AbstractRemoteFileOutboundGateway(SessionFactory sessionFactory, Command command, String expression) { + this(new RemoteFileTemplate(sessionFactory), command, expression); } + /** + * Construct an instance with the supplied remote file template, a command ('ls', + * 'get' etc), and an expression to determine the filename. + * @param remoteFileTemplate the remote file template. + * @param command the command. + * @param expression the filename expression. + */ public AbstractRemoteFileOutboundGateway(RemoteFileTemplate remoteFileTemplate, String command, String expression) { - Assert.notNull(remoteFileTemplate, "'remoteFileTemplate' cannot be null"); - this.remoteFileTemplate = remoteFileTemplate; - this.command = Command.toCommand(command); - this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor( - new SpelExpressionParser().parseExpression(expression)); + this(remoteFileTemplate, Command.toCommand(command), expression); } + /** + * Construct an instance with the supplied remote file template, a command ('ls', + * 'get' etc), and an expression to determine the filename. + * @param remoteFileTemplate the remote file template. + * @param command the command. + * @param expression the filename expression. + */ public AbstractRemoteFileOutboundGateway(RemoteFileTemplate remoteFileTemplate, Command command, String expression) { Assert.notNull(remoteFileTemplate, "'remoteFileTemplate' cannot be null"); @@ -260,6 +307,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply this.command = command; this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor( new SpelExpressionParser().parseExpression(expression)); + this.messageSessionCallback = null; } /** @@ -366,7 +414,8 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply @Override protected void doInit() { - Assert.notNull(this.command, "command must not be null"); + Assert.state(this.command != null || this.messageSessionCallback != null, + "'command' or 'messageSessionCallback' must be specified."); if (Command.RM.equals(this.command) || Command.GET.equals(this.command)) { Assert.isNull(this.filter, "Filters are not supported with the rm and get commands"); @@ -402,10 +451,10 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } if (Command.MGET.equals(this.command)) { Assert.isTrue(!(this.options.contains(Option.SUBDIRS)), - "Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " + Option.RECURSIVE.toString() + - " to obtain files in subdirectories"); + "Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " + + Option.RECURSIVE.toString() + " to obtain files in subdirectories"); } - if (this.getBeanFactory() != null) { + if (this.fileNameProcessor != null && getBeanFactory() != null) { this.fileNameProcessor.setBeanFactory(this.getBeanFactory()); this.renameProcessor.setBeanFactory(this.getBeanFactory()); this.remoteFileTemplate.setBeanFactory(this.getBeanFactory()); @@ -413,25 +462,33 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } @Override - protected Object handleRequestMessage(Message requestMessage) { - switch (this.command) { - case LS: - return doLs(requestMessage); - case GET: - return doGet(requestMessage); - case MGET: - return doMget(requestMessage); - case RM: - return doRm(requestMessage); - case MV: - return doMv(requestMessage); - case PUT: - return doPut(requestMessage); - case MPUT: - return doMput(requestMessage); - default: - return null; + protected Object handleRequestMessage(final Message requestMessage) { + if (this.command != null) { + switch (this.command) { + case LS: + return doLs(requestMessage); + case GET: + return doGet(requestMessage); + case MGET: + return doMget(requestMessage); + case RM: + return doRm(requestMessage); + case MV: + return doMv(requestMessage); + case PUT: + return doPut(requestMessage); + case MPUT: + return doMput(requestMessage); + } } + return this.remoteFileTemplate.execute(new SessionCallback() { + + @Override + public Object doInSession(Session session) throws IOException { + return messageSessionCallback.doInSession(session, requestMessage); + } + + }); } private Object doLs(Message requestMessage) { 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 0a80125af6..008867ac2f 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 @@ -23,6 +23,7 @@ import java.util.List; import org.apache.commons.net.ftp.FTPFile; import org.springframework.integration.file.remote.AbstractFileInfo; +import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.RemoteFileTemplate; import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway; import org.springframework.integration.file.remote.session.SessionFactory; @@ -32,15 +33,51 @@ import org.springframework.integration.ftp.session.FtpFileInfo; * Outbound Gateway for performing remote file operations via FTP/FTPS. * * @author Gary Russell + * @author Artem Bilan * @since 2.1 */ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway { - public FtpOutboundGateway(SessionFactory sessionFactory, String command, - String expression) { + /** + * Construct an instance using the provided session factory and callback for + * performing operations on the session. + * @param sessionFactory the session factory. + * @param messageSessionCallback the callback. + */ + public FtpOutboundGateway(SessionFactory sessionFactory, + MessageSessionCallback messageSessionCallback) { + super(sessionFactory, messageSessionCallback); + } + + /** + * Construct an instance with the supplied remote file template and callback + * for performing operations on the session. + * @param remoteFileTemplate the remote file template. + * @param messageSessionCallback the callback. + */ + public FtpOutboundGateway(RemoteFileTemplate remoteFileTemplate, + MessageSessionCallback messageSessionCallback) { + super(remoteFileTemplate, messageSessionCallback); + } + + /** + * Construct an instance with the supplied session factory, a command ('ls', 'get' + * etc), and an expression to determine the filename. + * @param sessionFactory the session factory. + * @param command the command. + * @param expression the filename expression. + */ + public FtpOutboundGateway(SessionFactory sessionFactory, String command, String expression) { super(sessionFactory, command, expression); } + /** + * Construct an instance with the supplied remote file template, a command ('ls', + * 'get' etc), and an expression to determine the filename. + * @param remoteFileTemplate the remote file template. + * @param command the command. + * @param expression the filename expression. + */ public FtpOutboundGateway(RemoteFileTemplate remoteFileTemplate, String command, String expression) { super(remoteFileTemplate, command, expression); } @@ -82,7 +119,6 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway - + FTP command. @@ -256,6 +256,20 @@ + + + + + + + + + The 'MessageSessionCallback' bean reference to perform custom operation(s) on 'Session' + with 'requestMessage'. + + + @@ -272,7 +286,7 @@ - + SpEL expression representing the path in the @@ -462,8 +476,7 @@ - + Tells this adapter if local directory must be diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml index 94564cb7b8..2d2925e481 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml @@ -160,4 +160,14 @@ + + + + + diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests.java b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests.java index d035bbde43..7a83af0d48 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests.java +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests.java @@ -60,6 +60,7 @@ import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.file.FileHeaders; import org.springframework.integration.file.filters.FileListFilter; import org.springframework.integration.file.remote.InputStreamCallback; +import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.RemoteFileTemplate; import org.springframework.integration.file.remote.SessionCallback; import org.springframework.integration.file.remote.session.Session; @@ -135,6 +136,9 @@ public class FtpServerOutboundTests { @Autowired private DirectChannel inboundGetStream; + @Autowired + private DirectChannel inboundCallback; + @Before public void setup() { this.ftpServer.recursiveDelete(ftpServer.getTargetLocalDirectory()); @@ -535,6 +539,14 @@ public class FtpServerOutboundTests { assertEquals(6, files[0].getSize()); } + @Test + public void testMessageSessionCallback() { + this.inboundCallback.send(new GenericMessage("foo")); + Message receive = this.output.receive(10000); + assertNotNull(receive); + assertEquals("FOO", receive.getPayload()); + } + public static class SortingFileListFilter implements FileListFilter { @Override @@ -560,4 +572,15 @@ public class FtpServerOutboundTests { } } + + private static final class TestMessageSessionCallback + implements MessageSessionCallback { + + @Override + public Object doInSession(Session session, Message requestMessage) throws IOException { + return ((String) requestMessage.getPayload()).toUpperCase(); + } + + } + } 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 9648eb02d9..7692626ec0 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 @@ -22,6 +22,7 @@ import java.util.List; import org.springframework.beans.DirectFieldAccessor; import org.springframework.integration.file.remote.AbstractFileInfo; +import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.RemoteFileTemplate; import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway; import org.springframework.integration.file.remote.session.SessionFactory; @@ -33,19 +34,55 @@ import com.jcraft.jsch.ChannelSftp.LsEntry; * Outbound Gateway for performing remote file operations via SFTP. * * @author Gary Russell + * @author Artem Bilan * @since 2.1 */ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway { + /** + * Construct an instance using the provided session factory and callback for + * performing operations on the session. + * @param sessionFactory the session factory. + * @param messageSessionCallback the callback. + */ + public SftpOutboundGateway(SessionFactory sessionFactory, + MessageSessionCallback messageSessionCallback) { + super(sessionFactory, messageSessionCallback); + } + + /** + * Construct an instance with the supplied remote file template and callback + * for performing operations on the session. + * @param remoteFileTemplate the remote file template. + * @param messageSessionCallback the callback. + */ + public SftpOutboundGateway(RemoteFileTemplate remoteFileTemplate, + MessageSessionCallback messageSessionCallback) { + super(remoteFileTemplate, messageSessionCallback); + } + + /** + * Construct an instance with the supplied session factory, a command ('ls', 'get' + * etc), and an expression to determine the filename. + * @param sessionFactory the session factory. + * @param command the command. + * @param expression the filename expression. + */ public SftpOutboundGateway(SessionFactory sessionFactory, String command, String expression) { super(sessionFactory, command, expression); } + /** + * Construct an instance with the supplied remote file template, a command ('ls', + * 'get' etc), and an expression to determine the filename. + * @param remoteFileTemplate the remote file template. + * @param command the command. + * @param expression the filename expression. + */ public SftpOutboundGateway(RemoteFileTemplate remoteFileTemplate, String command, String expression) { super(remoteFileTemplate, command, expression); } - @Override protected boolean isDirectory(LsEntry file) { return file.getAttrs().isDir(); diff --git a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-4.2.xsd b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-4.2.xsd index c9ce585370..33d6efcd8e 100644 --- a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-4.2.xsd +++ b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-4.2.xsd @@ -250,7 +250,7 @@ - + sftp command. @@ -260,6 +260,20 @@ + + + + + + + + + The 'MessageSessionCallback' bean reference to perform custom operation(s) on 'Session' + with 'requestMessage'. + + + @@ -276,7 +290,7 @@ - + SpEL expression representing the path in the diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests-context.xml b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests-context.xml index 10a1d2b843..200c807b1c 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests-context.xml +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests-context.xml @@ -153,4 +153,13 @@ + + + + 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 fe9c59d169..955fb29f0b 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 @@ -47,6 +47,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.file.FileHeaders; +import org.springframework.integration.file.remote.MessageSessionCallback; import org.springframework.integration.file.remote.SessionCallback; import org.springframework.integration.file.remote.session.Session; import org.springframework.integration.sftp.TestSftpServer; @@ -62,6 +63,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.FileCopyUtils; +import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp.LsEntry; /** @@ -129,6 +131,9 @@ public class SftpServerOutboundTests { @Autowired private DirectChannel inboundGetStream; + @Autowired + private DirectChannel inboundCallback; + @Before @After public void setup() { @@ -420,6 +425,14 @@ public class SftpServerOutboundTests { assertFalse(((Session) result.getHeaders().get(FileHeaders.REMOTE_SESSION)).isOpen()); } + @Test + public void testMessageSessionCallback() { + this.inboundCallback.send(new GenericMessage("foo")); + Message receive = this.output.receive(10000); + assertNotNull(receive); + assertEquals("FOO", receive.getPayload()); + } + private void assertLength6(SftpRemoteFileTemplate template) { LsEntry[] files = template.execute(new SessionCallback() { @@ -432,4 +445,14 @@ public class SftpServerOutboundTests { assertEquals(6, files[0].getAttrs().getSize()); } + private static final class TestMessageSessionCallback + implements MessageSessionCallback { + + @Override + public Object doInSession(Session session, Message requestMessage) throws IOException { + return ((String) requestMessage.getPayload()).toUpperCase(); + } + + } + } diff --git a/src/reference/asciidoc/ftp.adoc b/src/reference/asciidoc/ftp.adoc index 9ec6197303..affa81faa0 100644 --- a/src/reference/asciidoc/ftp.adoc +++ b/src/reference/asciidoc/ftp.adoc @@ -581,7 +581,8 @@ If you want your Sessions to be cached, simply configure your default Session Fa ---- -In the above example you see a `CachingSessionFactory` created with the `sessionCacheSize` set to 10 and the `sessionWaitTimeout` set to 1 second (its value is in millliseconds). +In the above example you see a `CachingSessionFactory` created with the `sessionCacheSize` set to 10 and the +`sessionWaitTimeout` set to 1 second (its value is in milliseconds). Starting with _Spring Integration version 3.0_, the `CachingConnectionFactory` provides a `resetCache()` method. When invoked, all idle sessions are immediately closed and in-use sessions are closed when they are returned to the cache. @@ -594,6 +595,35 @@ Starting with _Spring Integration version 3.0_ a new abstraction is provided ove The template provides methods to send, retrieve (as an `InputStream`), remove, and rename files. In addition an `execute` method is provided allowing the caller to execute multiple operations on the session. In all cases, the template takes care of reliably closing the session. -For more information, refer to the http://docs.spring.io/spring-integration/api/org/springframework/integration/file/remote/RemoteFileTemplate.html[javadocs for `RemoteFileTemplate`] There is a subclass for FTP: `FtpRemoteFileTemplate`. +For more information, refer to the +http://docs.spring.io/spring-integration/api/org/springframework/integration/file/remote/RemoteFileTemplate.html[JavaDocs for `RemoteFileTemplate`]. +There is a subclass for FTP: `FtpRemoteFileTemplate`. Additional methods were added in _version 4.1_ including `getClientInstance()` which provides access to the underlying `FTPClient` enabling access to low-level APIs. + +[[ftp-session-callback]] +=== MessageSessionCallback + +Starting with _Spring Integration version 4.2_, a `MessageSessionCallback` implementation can be used with the +`` (`FtpOutboundGateway`) to perform any operation(s) on the `Session` with +the `requestMessage` context. +It can be used for any non-standard or low-level FTP operation (or several); for example, allowing access +from an integration flow definition, and _functional_ interface (Lambda) implementation injection: + +[source,java] +---- +@Bean +@ServiceActivator(inputChannel = "ftpChannel") +public MessageHandler ftpOutboundGateway(SessionFactory sessionFactory) { + return new FtpOutboundGateway(sessionFactory, + (session, requestMessage) -> session.list(requestMessage.getPayload())); +} +---- + +Another example might be to pre- or post- process the file data being sent/retrieved. + +When using XML configuration, the `` provides a `session-callback` attribute to allow you to +specify the `MessageSessionCallback` bean name. + +NOTE: The `session-callback` is mutually exclusive with the `command` and `expression` attributes. +When configuring with Java, different constructors are available in the `FtpOutboundGateway` class. diff --git a/src/reference/asciidoc/sftp.adoc b/src/reference/asciidoc/sftp.adoc index 869a4d3477..11ac9b0c04 100644 --- a/src/reference/asciidoc/sftp.adoc +++ b/src/reference/asciidoc/sftp.adoc @@ -244,7 +244,7 @@ If you want your Sessions to be cached, simply configure your default Session Fa ---- -In the above example you see a `CachingSessionFactory` created with the `sessionCacheSize` set to 10 and the `sessionWaitTimeout` set to 1 second (its value is in millliseconds). +In the above example you see a `CachingSessionFactory` created with the `sessionCacheSize` set to 10 and the `sessionWaitTimeout` set to 1 second (its value is in milliseconds). Starting with _Spring Integration version 3.0_, the `CachingConnectionFactory` provides a `resetCache()` method. When invoked, all idle sessions are immediately closed and in-use sessions are closed when they are returned to the cache. @@ -646,3 +646,30 @@ For example, here is valid configuration of a logger using Log4J. ---- log4j.category.com.jcraft.jsch=DEBUG ---- + +[[sftp-session-callback]] +=== MessageSessionCallback + +Starting with _Spring Integration version 4.2_, a `MessageSessionCallback` implementation can be used with the +`` (`FtpOutboundGateway`) to perform any operation(s) on the `Session` with +the `requestMessage` context. +It can be used for any non-standard or low-level FTP operation (or several); for example, allowing access +from an integration flow definition, and _functional_ interface (Lambda) implementation injection: + +[source,java] +---- +@Bean +@ServiceActivator(inputChannel = "sftpChannel") +public MessageHandler sftpOutboundGateway(SessionFactory sessionFactory) { + return new SftpOutboundGateway(sessionFactory, + (session, requestMessage) -> session.list(requestMessage.getPayload())); +} +---- + +Another example might be to pre- or post- process the file data being sent/retrieved. + +When using XML configuration, the `` provides a `session-callback` attribute to allow you +to specify the `MessageSessionCallback` bean name. + +NOTE: The `session-callback` is mutually exclusive with the `command` and `expression` attributes. +When configuring with Java, different constructors are available in the `SftpOutboundGateway` class. diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index e1bb8f120b..845cffac59 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -323,6 +323,14 @@ false). See <> for more information. +===== MessageSessionCallback + +The `MessageSessionCallback` has been introduced to perform any custom `Session` operation(s) with the +`requestMessage` context in the ``. + +See <> and <> for more information. + + ==== Websocket Changes `WebSocketHandlerDecoratorFactory` support has been added to the `ServerWebSocketContainer`