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 5b7a7c71a7..d9d3b56dcb 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -35,6 +35,7 @@ import org.springframework.integration.MessagingException; 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.session.ExtendedSession; import org.springframework.integration.file.remote.session.Session; import org.springframework.integration.file.remote.session.SessionFactory; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; @@ -42,6 +43,7 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces import org.springframework.integration.support.MessageBuilder; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; /** * Base class for Outbound Gateways that perform remote file operations. @@ -61,7 +63,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply public static final String COMMAND_RM = "rm"; - protected Set options = new HashSet(); + public static final String COMMAND_MGET = "mget"; public static final String OPTION_NAME_ONLY = "-1"; @@ -75,8 +77,15 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply public static final String OPTION_PRESERVE_TIMESTAMP = "-P"; + public static final String OPTION_EXCEPTION_WHEN_EMPTY = "-x"; + + private final Set supportedCommands = new HashSet(Arrays.asList( + COMMAND_LS, COMMAND_GET, COMMAND_RM, COMMAND_MGET)); + private final ExpressionEvaluatingMessageProcessor processor; + protected volatile Set options = new HashSet(); + private volatile String remoteFileSeparator = "/"; private volatile File localDirectory; @@ -149,12 +158,17 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply protected void onInit() { super.onInit(); Assert.notNull(this.command, "command must not be null"); - Assert.isTrue(COMMAND_LS.equals(this.command) || COMMAND_GET.equals(this.command) || - COMMAND_RM.equals(this.command), - "command must be one of ls, get, rm"); - if (COMMAND_RM.equals(this.command)) { - Assert.isNull(this.filter, "Filters are not supported with the rm command"); - } else if (COMMAND_GET.equals(this.command)) { + Assert.isTrue( + this.supportedCommands.contains(this.command), + "command must be one of " + + StringUtils + .collectionToCommaDelimitedString(this.supportedCommands)); + // NOTE: Filter also not used on GET, need to correct in 2.2. + if (COMMAND_RM.equals(this.command) || COMMAND_MGET.equals(this.command)) { + Assert.isNull(this.filter, "Filters are not supported with the rm and mget commands"); + } + if (COMMAND_GET.equals(this.command) + || COMMAND_MGET.equals(this.command)) { Assert.notNull(this.localDirectory, "localDirectory must not be null"); try { if (!this.localDirectory.exists()) { @@ -187,35 +201,54 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply try { if (COMMAND_LS.equals(this.command)) { String dir = this.processor.processMessage(requestMessage); - if (!dir.endsWith("/")) { - dir += "/"; + if (!dir.endsWith(this.remoteFileSeparator)) { + dir += this.remoteFileSeparator; } - return MessageBuilder.withPayload(ls(session, dir)) + List payload = ls(session, dir); + return MessageBuilder.withPayload(payload) .setHeader(FileHeaders.REMOTE_DIRECTORY, dir) .build(); - } else if (COMMAND_GET.equals(this.command)) { + } + else if (COMMAND_GET.equals(this.command)) { String remoteFilePath = this.processor.processMessage(requestMessage); String remoteFilename = getRemoteFilename(remoteFilePath); String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename)); if (remoteDir.length() == 0) { - remoteDir = "/"; + remoteDir = this.remoteFileSeparator; } - return MessageBuilder.withPayload(get(session, remoteFilePath, remoteFilename)) + File payload = get(session, remoteFilePath, remoteFilename, true); + return MessageBuilder.withPayload(payload) .setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir) .setHeader(FileHeaders.REMOTE_FILE, remoteFilename) .build(); - } else if (COMMAND_RM.equals(this.command)) { + } + else if (COMMAND_MGET.equals(this.command)) { String remoteFilePath = this.processor.processMessage(requestMessage); String remoteFilename = getRemoteFilename(remoteFilePath); String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename)); if (remoteDir.length() == 0) { - remoteDir = "/"; + remoteDir = this.remoteFileSeparator; } - return MessageBuilder.withPayload(rm(session, remoteFilePath)) + List payload = mGet(session, remoteDir, remoteFilename); + return MessageBuilder.withPayload(payload) .setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir) .setHeader(FileHeaders.REMOTE_FILE, remoteFilename) .build(); - } else { + } + else if (COMMAND_RM.equals(this.command)) { + String remoteFilePath = this.processor.processMessage(requestMessage); + String remoteFilename = getRemoteFilename(remoteFilePath); + String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename)); + if (remoteDir.length() == 0) { + remoteDir = this.remoteFileSeparator; + } + boolean payload = rm(session, remoteFilePath); + return MessageBuilder.withPayload(payload) + .setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir) + .setHeader(FileHeaders.REMOTE_FILE, remoteFilename) + .build(); + } + else { return null; } } catch (IOException e) { @@ -297,11 +330,14 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply * @param remoteFilePath * @throws IOException */ - protected File get(Session session, String remoteFilePath, String remoteFilename) + protected File get(Session session, String remoteFilePath, String remoteFilename, boolean lsFirst) throws IOException { - F[] files = session.list(remoteFilePath); - if (files.length != 1 || isDirectory(files[0]) || isLink(files[0])) { - throw new MessagingException(remoteFilePath + " is not a file"); + F[] files = null; + if (lsFirst) { + files = session.list(remoteFilePath); + if (files.length != 1 || isDirectory(files[0]) || isLink(files[0])) { + throw new MessagingException(remoteFilePath + " is not a file"); + } } File localFile = new File(this.localDirectory, remoteFilename); if (!localFile.exists()) { @@ -329,7 +365,7 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply if (!tempFile.renameTo(localFile)) { throw new MessagingException("Failed to rename local file"); } - if (this.options.contains(OPTION_PRESERVE_TIMESTAMP)) { + if (lsFirst && this.options.contains(OPTION_PRESERVE_TIMESTAMP)) { localFile.setLastModified(getModified(files[0])); } return localFile; @@ -339,6 +375,36 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply } } + protected List mGet(Session session, String remoteDirectory, + String remoteFilename) throws IOException { + Assert.isInstanceOf(ExtendedSession.class, session, "mget failed - "); + String path = fixPath(remoteDirectory, remoteFilename); + String[] fileNames = ((ExtendedSession) session).listNames(path); + if (fileNames.length == 0 && this.options.contains(OPTION_EXCEPTION_WHEN_EMPTY)) { + throw new MessagingException("No files found at " + remoteDirectory + + " with pattern " + remoteFilename); + } + List files = new ArrayList(); + for (String fileName : fileNames) { + files.add(this.get(session, fixPath(remoteDirectory, fileName), fileName, false)); + } + return files; + } + + private String fixPath(String remoteDirectory, String remoteFilename) { + String path; + if (this.remoteFileSeparator.equals(remoteDirectory)) { + path = remoteFilename; + } + else if (remoteDirectory.endsWith(this.remoteFileSeparator)) { + path = remoteDirectory + remoteFilename; + } + else { + path = remoteDirectory + this.remoteFileSeparator + remoteFilename; + } + return path; + } + /** * @param remoteFilePath */ diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java index 92c98a7335..d642630207 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java @@ -20,7 +20,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Collections; import java.util.LinkedList; import java.util.List; diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java index 38b352df01..2b24610a00 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java @@ -25,6 +25,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.integration.util.UpperBound; +import org.springframework.util.Assert; /** * A {@link SessionFactory} implementation that caches Sessions for reuse without @@ -34,6 +35,7 @@ import org.springframework.integration.util.UpperBound; * @author Josh Long * @author Oleg Zhurakousky * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class CachingSessionFactory implements SessionFactory, DisposableBean { @@ -115,7 +117,7 @@ public class CachingSessionFactory implements SessionFactory, DisposableBe } - private class CachedSession implements Session { + private class CachedSession implements ExtendedSession { private final Session targetSession; @@ -162,6 +164,11 @@ public class CachingSessionFactory implements SessionFactory, DisposableBe public boolean exists(String path) throws IOException{ return this.targetSession.exists(path); } + + public String[] listNames(String path) throws IOException { + Assert.isInstanceOf(ExtendedSession.class, this.targetSession, "mget failed - "); + return ((ExtendedSession) this.targetSession).listNames(path); + } } } diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/ExtendedSession.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/ExtendedSession.java new file mode 100644 index 0000000000..efe8cdb27a --- /dev/null +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/ExtendedSession.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2012 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.session; + +import java.io.IOException; + +/** + * Temporary extension to {@link Session} to avoid a breaking change + * in a point release - merge with Session in 2.2. + *

+ * **NOTE** This interface will be removed (not deprecated) in 2.2. + * It exists purely to avoid existing user implementations of Session from + * failing to compile if we had added the new method to that interface. + *

Any user implementations of ExtendedSession will need to be refactored to + * implement Session in 2.2. + * @author Gary Russell + * @since 2.1.1 + * + */ +public interface ExtendedSession extends Session { + + /** + * Returns an array of Strings containing just the names of + * the remote files at path. Will move to {@link Session} + * in 2.2. + * @param path The path + * @return The list of names + * @throws IOException + */ + String[] listNames(String path) throws IOException; +} 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 c4d72604f0..9f1462a993 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-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -34,9 +34,11 @@ import java.util.List; import org.junit.Test; import org.springframework.integration.Message; +import org.springframework.integration.MessagingException; import org.springframework.integration.file.FileHeaders; import org.springframework.integration.file.filters.AbstractSimplePatternFileListFilter; import org.springframework.integration.file.remote.AbstractFileInfo; +import org.springframework.integration.file.remote.session.ExtendedSession; import org.springframework.integration.file.remote.session.Session; import org.springframework.integration.file.remote.session.SessionFactory; import org.springframework.integration.message.GenericMessage; @@ -53,6 +55,14 @@ public class RemoteFileOutboundGatewayTests { private String tmpDir = System.getProperty("java.io.tmpdir"); + @Test(expected=IllegalArgumentException.class) + public void testBad() throws Exception { + SessionFactory sessionFactory = mock(SessionFactory.class); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway + (sessionFactory, "bad", "payload"); + gw.afterPropertiesSet(); + } + @Test public void testLs() throws Exception { SessionFactory sessionFactory = mock(SessionFactory.class); @@ -72,6 +82,163 @@ public class RemoteFileOutboundGatewayTests { out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)); } + @Test(expected=IllegalArgumentException.class) + public void testMGetSession() throws Exception { + SessionFactory sessionFactory = mock(SessionFactory.class); + Session session = mock(Session.class); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway + (sessionFactory, "mget", "payload"); + when(sessionFactory.getSession()).thenReturn(session); + gw.setLocalDirectory(new File(this.tmpDir )); + gw.afterPropertiesSet(); + gw.handleRequestMessage(new GenericMessage("testremote/*")); + } + + @Test + public void testMGetWild() throws Exception { + SessionFactory sessionFactory = mock(SessionFactory.class); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway + (sessionFactory, "mget", "payload"); + gw.setLocalDirectory(new File(this.tmpDir )); + gw.afterPropertiesSet(); + new File(this.tmpDir + "/f1").delete(); + new File(this.tmpDir + "/f2").delete(); + when(sessionFactory.getSession()).thenReturn(new ExtendedSession() { + public boolean remove(String path) throws IOException { + return false; + } + public Object[] list(String path) throws IOException { + return null; + } + public void read(String source, OutputStream outputStream) + throws IOException { + outputStream.write("testData".getBytes()); + } + public void write(InputStream inputStream, String destination) + throws IOException { + } + public boolean mkdir(String directory) throws IOException { + return false; + } + public void rename(String pathFrom, String pathTo) + throws IOException { + } + public void close() { + } + public boolean isOpen() { + return false; + } + public boolean exists(String path) throws IOException { + return false; + } + public String[] listNames(String path) throws IOException { + return new String[] {"f1", "f2"}; + } + }); + @SuppressWarnings("unchecked") + Message> out = (Message>) gw + .handleRequestMessage(new GenericMessage("testremote/*")); + assertEquals(2, out.getPayload().size()); + assertEquals("f1", out.getPayload().get(0).getName()); + assertEquals("f2", out.getPayload().get(1).getName()); + assertEquals("testremote/", + out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)); + } + + @Test + public void testMGetSingle() throws Exception { + SessionFactory sessionFactory = mock(SessionFactory.class); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway + (sessionFactory, "mget", "payload"); + gw.setLocalDirectory(new File(this.tmpDir )); + gw.afterPropertiesSet(); + new File(this.tmpDir + "/f1").delete(); + when(sessionFactory.getSession()).thenReturn(new ExtendedSession() { + public boolean remove(String path) throws IOException { + return false; + } + public Object[] list(String path) throws IOException { + return null; + } + public void read(String source, OutputStream outputStream) + throws IOException { + outputStream.write("testData".getBytes()); + } + public void write(InputStream inputStream, String destination) + throws IOException { + } + public boolean mkdir(String directory) throws IOException { + return false; + } + public void rename(String pathFrom, String pathTo) + throws IOException { + } + public void close() { + } + public boolean isOpen() { + return false; + } + public boolean exists(String path) throws IOException { + return false; + } + public String[] listNames(String path) throws IOException { + return new String[] {"f1"}; + } + }); + @SuppressWarnings("unchecked") + Message> out = (Message>) gw + .handleRequestMessage(new GenericMessage("testremote/f1")); + assertEquals(1, out.getPayload().size()); + assertEquals("f1", out.getPayload().get(0).getName()); + assertEquals("testremote/", + out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY)); + } + + @Test(expected=MessagingException.class) + public void testMGetEmpty() throws Exception { + SessionFactory sessionFactory = mock(SessionFactory.class); + TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway + (sessionFactory, "mget", "payload"); + gw.setLocalDirectory(new File(this.tmpDir )); + gw.setOptions(" -x "); + gw.afterPropertiesSet(); + new File(this.tmpDir + "/f1").delete(); + new File(this.tmpDir + "/f2").delete(); + when(sessionFactory.getSession()).thenReturn(new ExtendedSession() { + public boolean remove(String path) throws IOException { + return false; + } + public Object[] list(String path) throws IOException { + return null; + } + public void read(String source, OutputStream outputStream) + throws IOException { + outputStream.write("testData".getBytes()); + } + public void write(InputStream inputStream, String destination) + throws IOException { + } + public boolean mkdir(String directory) throws IOException { + return false; + } + public void rename(String pathFrom, String pathTo) + throws IOException { + } + public void close() { + } + public boolean isOpen() { + return false; + } + public boolean exists(String path) throws IOException { + return false; + } + public String[] listNames(String path) throws IOException { + return new String[0]; + } + }); + gw.handleRequestMessage(new GenericMessage("testremote/*")); + } + /** * @return */ diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java index dc0ef9d39a..7fb3e06061 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java @@ -24,7 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; - +import org.springframework.integration.file.remote.session.ExtendedSession; import org.springframework.integration.file.remote.session.Session; import org.springframework.util.Assert; @@ -33,9 +33,10 @@ import org.springframework.util.Assert; * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell * @since 2.0 */ -class FtpSession implements Session { +public class FtpSession implements ExtendedSession { private final Log logger = LogFactory.getLog(this.getClass()); @@ -62,6 +63,11 @@ class FtpSession implements Session { return this.client.listFiles(path); } + public String[] listNames(String path) throws IOException { + Assert.hasText(path, "path must not be null"); + return this.client.listNames(path); + } + public void read(String path, OutputStream fos) throws IOException { Assert.hasText(path, "path must not be null"); Assert.notNull(fos, "outputStream must not be null"); @@ -70,7 +76,7 @@ class FtpSession implements Session { throw new IOException("Failed to copy '" + path + "'. Server replied with: " + this.client.getReplyString()); } - logger.info("File have been successfully transfered to: " + path); + logger.info("File has been successfully transfered from: " + path); } public void write(InputStream inputStream, String path) throws IOException { 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 92e49a688a..4ea7198a81 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 @@ -19,12 +19,15 @@ package org.springframework.integration.sftp.session; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.NestedIOException; +import org.springframework.integration.file.remote.session.ExtendedSession; import org.springframework.integration.file.remote.session.Session; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; @@ -32,6 +35,7 @@ import org.springframework.util.FileCopyUtils; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpException; /** @@ -41,9 +45,10 @@ import com.jcraft.jsch.SftpException; * @author Mario Gray * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell * @since 2.0 */ -class SftpSession implements Session { +class SftpSession implements ExtendedSession { private final Log logger = LogFactory.getLog(this.getClass()); @@ -89,6 +94,21 @@ class SftpSession implements Session { return new LsEntry[0]; } + 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(); + if (!attrs.isDir() && !attrs.isLink()) { + names.add(fileName); + } + } + String[] fileNames = new String[names.size()]; + return names.toArray(fileNames); + } + + public void read(String source, OutputStream os) throws IOException { Assert.state(this.channel != null, "session is not connected"); try { diff --git a/src/reference/docbook/ftp.xml b/src/reference/docbook/ftp.xml index ba40414b5e..b9fa7ce1ed 100644 --- a/src/reference/docbook/ftp.xml +++ b/src/reference/docbook/ftp.xml @@ -304,12 +304,14 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp Commands supported are: ls (list files) - get (retrieve file(s)) + get (retrieve file) + mget (retrieve file(s)) rm (remove file(s)) + ls - ls supports the following options: + ls lists remote file(s) and supports the following options: -1 - just retrieve a list of filenames, default is to retrieve a list of FileInfo objects. @@ -332,8 +334,9 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp The remote directory that the ls command acted on is provided in the file_remoteDirectory header. + get - get supports the following option: + get retrieves a remote file and supports the following option: -P - preserve the timestamp of the remote file @@ -346,14 +349,27 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp The remote directory is provided in the file_remoteDirectory header, and the filename is provided in the file_remoteFile header. - + mget - The rm command has no options. + mget retrieves multiple remote files based on a pattern and supports the following option: + + -x - Throw an exception if no files match the pattern (otherwise an empty + list is returned) + - - Filters are not supported with the rm command. - + The message payload resulting from an mget operation is a + List<File> object - a List of File objects, each representing + a retrieved file. + + + The remote directory is provided in the file_remoteDirectory header, and the pattern + for the filenames is + provided in the file_remoteFile header. + + rm + + The rm command has no options. The message payload resulting from an rm operation is Boolean.TRUE if the @@ -361,10 +377,10 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp The remote directory is provided in the file_remoteDirectory header, and the filename is provided in the file_remoteFile header. - In each case, the PATH that these commands act on is provided by the 'expression' - property of the gateway. + property of the gateway. For the mget command, the expression might evaluate to '*', meaning + retrieve all files, or 'somedirectory/*' etc. diff --git a/src/reference/docbook/sftp.xml b/src/reference/docbook/sftp.xml index a44d94536e..e44e96b5eb 100644 --- a/src/reference/docbook/sftp.xml +++ b/src/reference/docbook/sftp.xml @@ -189,12 +189,14 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp Commands supported are: ls (list files) - get (retrieve file(s)) + get (retrieve file) + mget (retrieve file(s)) rm (remove file(s)) + ls - ls supports the following options: + ls lists remote file(s) and supports the following options: -1 - just retrieve a list of filenames, default is to retrieve a list of FileInfo objects. @@ -202,7 +204,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp -f - do not sort the list -dirs - include directories (excluded by default) -links - include symbolic links (excluded by default) - + In addition, filename filtering is provided, in the same manner as the @@ -217,8 +219,9 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp The remote directory that the ls command acted on is provided in the file_remoteDirectory header. + get - get supports the following option: + get retrieves a remote file and supports the following option: -P - preserve the timestamp of the remote file @@ -231,14 +234,27 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp The remote directory is provided in the file_remoteDirectory header, and the filename is provided in the file_remoteFile header. - + mget - The rm command has no options. + mget retrieves multiple remote files based on a pattern and supports the following option: + + -x - Throw an exception if no files match the pattern (otherwise an empty + list is returned) + - - Filters are not supported with the rm command. - + The message payload resulting from an mget operation is a + List<File> object - a List of File objects, each representing + a retrieved file. + + + The remote directory is provided in the file_remoteDirectory header, and the pattern + for the filenames is + provided in the file_remoteFile header. + + rm + + The rm command has no options. The message payload resulting from an rm operation is Boolean.TRUE if the @@ -246,10 +262,10 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp The remote directory is provided in the file_remoteDirectory header, and the filename is provided in the file_remoteFile header. - In each case, the PATH that these commands act on is provided by the 'expression' - property of the gateway. + property of the gateway. For the mget command, the expression might evaluate to '*', meaning + retrieve all files, or 'somedirectory/*' etc.