From a43299213effe14847fba0add6ee5272ccc6cb43 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 28 Oct 2016 13:56:43 -0400 Subject: [PATCH] INT-4149: Improve (S)FTP Recursive MGET JIRA: https://jira.spring.io/browse/INT-4149 Add an option to always pass directories while recursing. * Fix typos in docs * Revert `SyslogReceivingChannelAdapterTests` `Thread.sleep()` fixes --- .../config/FileListFilterFactoryBean.java | 31 +++++++++-- .../AbstractDirectoryAwareFileListFilter.java | 53 +++++++++++++++++++ .../AbstractRegexPatternFileListFilter.java | 5 +- .../AbstractSimplePatternFileListFilter.java | 4 +- .../filters/RegexPatternFileListFilter.java | 8 ++- .../filters/SimplePatternFileListFilter.java | 9 +++- .../FileListFilterFactoryBeanTests.java | 9 +++- .../RemoteFileOutboundGatewayTests.java | 7 ++- .../FtpRegexPatternFileListFilter.java | 8 ++- .../FtpSimplePatternFileListFilter.java | 8 ++- .../FtpServerOutboundTests-context.xml | 6 +++ .../SftpRegexPatternFileListFilter.java | 8 ++- .../SftpSimplePatternFileListFilter.java | 8 ++- .../SftpServerOutboundTests-context.xml | 7 +++ .../SyslogReceivingChannelAdapterTests.java | 5 ++ src/reference/asciidoc/ftp.adoc | 21 ++++++++ src/reference/asciidoc/sftp.adoc | 22 ++++++++ src/reference/asciidoc/whats-new.adoc | 4 ++ 18 files changed, 207 insertions(+), 16 deletions(-) create mode 100644 spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractDirectoryAwareFileListFilter.java diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileListFilterFactoryBean.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileListFilterFactoryBean.java index 65587acd28..3c532f6e05 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileListFilterFactoryBean.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileListFilterFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -32,6 +32,7 @@ import org.springframework.integration.file.filters.SimplePatternFileListFilter; /** * @author Mark Fisher * @author Gunnar Hillert + * @author Gary Russell * @since 1.0.3 */ public class FileListFilterFactoryBean implements FactoryBean> { @@ -48,6 +49,8 @@ public class FileListFilterFactoryBean implements FactoryBean filter) { @@ -76,6 +79,18 @@ public class FileListFilterFactoryBean implements FactoryBean getObject() throws Exception { if (this.result == null) { synchronized (this.monitor) { @@ -85,10 +100,12 @@ public class FileListFilterFactoryBean implements FactoryBean getObjectType() { return (this.result != null) ? this.result.getClass() : FileListFilter.class; } + @Override public boolean isSingleton() { return true; } @@ -132,10 +149,18 @@ public class FileListFilterFactoryBean implements FactoryBean()); } if (this.filenamePattern != null) { - filtersNeeded.add(new SimplePatternFileListFilter(this.filenamePattern)); + SimplePatternFileListFilter patternFilter = new SimplePatternFileListFilter(this.filenamePattern); + if (this.alwaysAcceptDirectories != null) { + patternFilter.setAlwaysAcceptDirectories(this.alwaysAcceptDirectories); + } + filtersNeeded.add(patternFilter); } if (this.filenameRegex != null) { - filtersNeeded.add(new RegexPatternFileListFilter(this.filenameRegex)); + RegexPatternFileListFilter regexFilter = new RegexPatternFileListFilter(this.filenameRegex); + if (this.alwaysAcceptDirectories != null) { + regexFilter.setAlwaysAcceptDirectories(this.alwaysAcceptDirectories); + } + filtersNeeded.add(regexFilter); } } diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractDirectoryAwareFileListFilter.java b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractDirectoryAwareFileListFilter.java new file mode 100644 index 0000000000..e1a3c2b672 --- /dev/null +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractDirectoryAwareFileListFilter.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016 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.filters; + +/** + * A file list filter that can be configured to always accept (pass) directories. + * This permits, for example, pattern matching on just files when using recursion + * to examine a directory tree. + * + * @author Gary Russell + * @since 5.0 + * + */ +public abstract class AbstractDirectoryAwareFileListFilter extends AbstractFileListFilter { + + private boolean alwaysAcceptDirectories; + + /** + * Set to true so that filters that support this feature can unconditionally pass + * directories; default false. + * @param alwaysAcceptDirectories true to always pass directories. + */ + public void setAlwaysAcceptDirectories(boolean alwaysAcceptDirectories) { + this.alwaysAcceptDirectories = alwaysAcceptDirectories; + } + + protected boolean alwaysAccept(F file) { + return file != null && this.alwaysAcceptDirectories && isDirectory(file); + } + + /** + * Subclasses must implement this method to indicate whether the file + * is a directory or not. + * @param file the file. + * @return true if it's a directory. + */ + protected abstract boolean isDirectory(F file); + +} diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractRegexPatternFileListFilter.java b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractRegexPatternFileListFilter.java index 953576100b..1d846197d2 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractRegexPatternFileListFilter.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractRegexPatternFileListFilter.java @@ -30,7 +30,8 @@ import org.springframework.util.Assert; * @param the type of file entry * @since 2.0 */ -public abstract class AbstractRegexPatternFileListFilter extends AbstractFileListFilter implements InitializingBean { +public abstract class AbstractRegexPatternFileListFilter extends AbstractDirectoryAwareFileListFilter + implements InitializingBean { private volatile Pattern pattern; @@ -59,7 +60,7 @@ public abstract class AbstractRegexPatternFileListFilter extends AbstractFile @Override public boolean accept(F file) { - return (file != null) && this.pattern.matcher(this.getFilename(file)).matches(); + return alwaysAccept(file) || (file != null && this.pattern.matcher(getFilename(file)).matches()); } /** diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractSimplePatternFileListFilter.java b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractSimplePatternFileListFilter.java index 4c23e5c842..757d63f69f 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractSimplePatternFileListFilter.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/AbstractSimplePatternFileListFilter.java @@ -29,7 +29,7 @@ import org.springframework.util.AntPathMatcher; * @see org.springframework.integration.file.filters.AbstractRegexPatternFileListFilter * @since 2.0 */ -public abstract class AbstractSimplePatternFileListFilter extends AbstractFileListFilter { +public abstract class AbstractSimplePatternFileListFilter extends AbstractDirectoryAwareFileListFilter { private final AntPathMatcher matcher = new AntPathMatcher(); @@ -46,7 +46,7 @@ public abstract class AbstractSimplePatternFileListFilter extends AbstractFil */ @Override public final boolean accept(F file) { - return this.matcher.match(this.path, this.getFilename(file)); + return alwaysAccept(file) || (file != null && this.matcher.match(this.path, this.getFilename(file))); } /** diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/RegexPatternFileListFilter.java b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/RegexPatternFileListFilter.java index c059fa91ee..ad42ea5755 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/RegexPatternFileListFilter.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/RegexPatternFileListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2016 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. @@ -23,6 +23,7 @@ import java.util.regex.Pattern; * Implementation of AbstractRegexPatternMatchingFileListFilter for java.io.File instances. * * @author Mark Fisher + * @author Gary Russell */ public class RegexPatternFileListFilter extends AbstractRegexPatternFileListFilter { @@ -40,4 +41,9 @@ public class RegexPatternFileListFilter extends AbstractRegexPatternFileListFilt return (file != null) ? file.getName() : null; } + @Override + protected boolean isDirectory(File file) { + return file.isDirectory(); + } + } diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/SimplePatternFileListFilter.java b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/SimplePatternFileListFilter.java index 9b5e315aad..6fff0c7069 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/filters/SimplePatternFileListFilter.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/filters/SimplePatternFileListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2016 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. @@ -23,6 +23,7 @@ import java.io.File; * This filter only filters on the name of the file, the rest of the path is ignored. * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class SimplePatternFileListFilter extends AbstractSimplePatternFileListFilter { @@ -37,4 +38,10 @@ public class SimplePatternFileListFilter extends AbstractSimplePatternFileListFi return file.getName(); } + + @Override + protected boolean isDirectory(File file) { + return file.isDirectory(); + } + } diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java b/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java index 02586df0d5..be9019d38c 100644 --- a/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java +++ b/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java @@ -16,8 +16,8 @@ package org.springframework.integration.file.config; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; @@ -35,6 +35,7 @@ import org.springframework.integration.file.filters.AcceptOnceFileListFilter; import org.springframework.integration.file.filters.CompositeFileListFilter; import org.springframework.integration.file.filters.FileListFilter; import org.springframework.integration.file.filters.SimplePatternFileListFilter; +import org.springframework.integration.test.util.TestUtils; /** * @author Mark Fisher @@ -117,7 +118,9 @@ public class FileListFilterFactoryBeanTests { new DirectFieldAccessor(result).getPropertyValue("fileFilters"); Iterator> iterator = filters.iterator(); assertTrue(iterator.next() instanceof AcceptOnceFileListFilter); - assertThat(iterator.next(), is(instanceOf(SimplePatternFileListFilter.class))); + FileListFilter patternFilter = iterator.next(); + assertThat(patternFilter, is(instanceOf(SimplePatternFileListFilter.class))); + assertFalse(TestUtils.getPropertyValue(patternFilter, "alwaysAcceptDirectories", Boolean.class)); } @Test @@ -125,10 +128,12 @@ public class FileListFilterFactoryBeanTests { FileListFilterFactoryBean factory = new FileListFilterFactoryBean(); factory.setIgnoreHidden(false); factory.setFilenamePattern(("foo")); + factory.setAlwaysAcceptDirectories(true); factory.setPreventDuplicates(Boolean.FALSE); FileListFilter result = factory.getObject(); assertFalse(result instanceof CompositeFileListFilter); assertThat(result, is(instanceOf(SimplePatternFileListFilter.class))); + assertTrue(TestUtils.getPropertyValue(result, "alwaysAcceptDirectories", Boolean.class)); } private static class TestFilter extends AbstractFileListFilter { 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 c9c1a9bbe4..560771f528 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 @@ -1051,7 +1051,7 @@ public class RemoteFileOutboundGatewayTests { static class TestRemoteFileOutboundGateway extends AbstractRemoteFileOutboundGateway { - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("unchecked") TestRemoteFileOutboundGateway(SessionFactory sessionFactory, String command, String expression) { super(sessionFactory, Command.toCommand(command), expression); @@ -1180,6 +1180,11 @@ public class RemoteFileOutboundGatewayTests { return file.getFilename(); } + @Override + protected boolean isDirectory(TestLsEntry file) { + return file.isDirectory(); + } + } } diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpRegexPatternFileListFilter.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpRegexPatternFileListFilter.java index 785072b662..e462409ec2 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpRegexPatternFileListFilter.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpRegexPatternFileListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2016 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. @@ -26,6 +26,7 @@ import org.springframework.integration.file.filters.AbstractRegexPatternFileList * Implementation of {@link AbstractRegexPatternFileListFilter} for FTP. * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class FtpRegexPatternFileListFilter extends AbstractRegexPatternFileListFilter { @@ -44,4 +45,9 @@ public class FtpRegexPatternFileListFilter extends AbstractRegexPatternFileListF return (file != null) ? file.getName() : null; } + @Override + protected boolean isDirectory(FTPFile file) { + return file.isDirectory(); + } + } diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpSimplePatternFileListFilter.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpSimplePatternFileListFilter.java index 05c59fa186..9081b333e9 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpSimplePatternFileListFilter.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/FtpSimplePatternFileListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2016 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. @@ -24,6 +24,7 @@ import org.springframework.integration.file.filters.AbstractSimplePatternFileLis * Implementation of {@link AbstractSimplePatternFileListFilter} for FTP. * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class FtpSimplePatternFileListFilter extends AbstractSimplePatternFileListFilter { @@ -38,4 +39,9 @@ public class FtpSimplePatternFileListFilter extends AbstractSimplePatternFileLis return (file != null) ? file.getName() : null; } + @Override + protected boolean isDirectory(FTPFile file) { + return file.isDirectory(); + } + } 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 f9ac5780a3..da284492a5 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 @@ -52,10 +52,16 @@ command="mget" expression="payload" command-options="-R" + filter="startDotTxtFilter" local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory" local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')" reply-channel="output"/> + + + + + { @@ -45,4 +46,9 @@ public class SftpRegexPatternFileListFilter extends AbstractRegexPatternFileList return (entry != null) ? entry.getFilename() : null; } + @Override + protected boolean isDirectory(LsEntry file) { + return file.getAttrs().isDir(); + } + } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/filters/SftpSimplePatternFileListFilter.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/filters/SftpSimplePatternFileListFilter.java index 5a0574e169..c153d7f070 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/filters/SftpSimplePatternFileListFilter.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/filters/SftpSimplePatternFileListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2016 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. @@ -25,6 +25,7 @@ import com.jcraft.jsch.ChannelSftp.LsEntry; * Implementation of {@link AbstractSimplePatternFileListFilter} for SFTP. * * @author Mark Fisher + * @author Gary Russell * @since 2.0 */ public class SftpSimplePatternFileListFilter extends AbstractSimplePatternFileListFilter { @@ -39,4 +40,9 @@ public class SftpSimplePatternFileListFilter extends AbstractSimplePatternFileLi return (entry != null) ? entry.getFilename() : null; } + @Override + protected boolean isDirectory(LsEntry file) { + return file.getAttrs().isDir(); + } + } 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 62d00206ec..8423aa63f8 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 @@ -51,10 +51,17 @@ command="mget" expression="payload" command-options="-R" + filter="dotStarDotTxtFilter" local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory" local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')" reply-channel="output"/> + + + + + 1 2014-06-20T09:14:07+00:00 loggregator d0602076-b14a-4c55-852a-981e7afeed38 DEA - " + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"]" + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"] Removing instance") @@ -217,6 +221,7 @@ public class SyslogReceivingChannelAdapterTests { factory.afterPropertiesSet(); factory.start(); UdpSyslogReceivingChannelAdapter adapter = (UdpSyslogReceivingChannelAdapter) factory.getObject(); + Thread.sleep(1000); byte[] buf = ("<14>1 2014-06-20T09:14:07+00:00 loggregator d0602076-b14a-4c55-852a-981e7afeed38 DEA - " + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"]" + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"] Removing instance") diff --git a/src/reference/asciidoc/ftp.adoc b/src/reference/asciidoc/ftp.adoc index 1bbbdc0c05..ec36d1eb4f 100644 --- a/src/reference/asciidoc/ftp.adoc +++ b/src/reference/asciidoc/ftp.adoc @@ -790,6 +790,8 @@ By default, the entire remote tree is retrieved. However, files in the tree can be filtered, by providing a`FileListFilter`; directories in the tree can also be filtered this way. A `FileListFilter` can be provided by reference or by `filename-pattern` or `filename-regex` attributes. For example, `filename-regex="(subDir|.*1.txt)"` will retrieve all files ending with `1.txt` in the remote directory and the subdirectory `subDir`. +However, see below for an alternative available in _version 5.0_. + If a subdirectory is filtered, no additional traversal of that subdirectory is performed. The `-dirs` option is not allowed (the recursive mget uses the recursive `ls` to obtain the directory tree and the directories themselves cannot be included in the list). @@ -797,6 +799,25 @@ The `-dirs` option is not allowed (the recursive mget uses the recursive `ls` to Typically, you would use the `#remoteDirectory` variable in the `local-directory-expression` so that the remote directory structure is retained locally. ===== +Starting with _version 5.0_, the `FtpSimplePatternFileListFilter` and `FtpRegexPatternFileListFilter` can be configured to always pass directories by setting the `alwaysAcceptDirectorties` to `true`. +This allows recursion for a simple pattern; examples follow: + +[code, xml] +---- + + + + + + + + + +---- + +and provide one of these filters using `filter` property on the gateway. + See also <>. *put* diff --git a/src/reference/asciidoc/sftp.adoc b/src/reference/asciidoc/sftp.adoc index f9cbf5fdc6..e6bb0d3d60 100644 --- a/src/reference/asciidoc/sftp.adoc +++ b/src/reference/asciidoc/sftp.adoc @@ -879,6 +879,8 @@ By default, the entire remote tree is retrieved. However, files in the tree can be filtered, by providing a`FileListFilter`; directories in the tree can also be filtered this way. A `FileListFilter` can be provided by reference or by `filename-pattern` or `filename-regex` attributes. For example, `filename-regex="(subDir|.*1.txt)"` will retrieve all files ending with `1.txt` in the remote directory and the subdirectory `subDir`. +However, see below for an alternative available in _version 5.0_. + If a subdirectory is filtered, no additional traversal of that subdirectory is performed. The `-dirs` option is not allowed (the recursive mget uses the recursive `ls` to obtain the directory tree and the directories themselves cannot be included in the list). @@ -886,6 +888,26 @@ The `-dirs` option is not allowed (the recursive mget uses the recursive `ls` to Typically, you would use the `#remoteDirectory` variable in the `local-directory-expression` so that the remote directory structure is retained locally. ===== +Starting with _version 5.0_, the `SftpSimplePatternFileListFilter` and `SftpRegexPatternFileListFilter` can be configured to always pass directories by setting the `alwaysAcceptDirectorties` to `true`. +This allows recursion for a simple pattern; examples follow: + +[code, xml] +---- + + + + + + + + + +---- + +and provide one of these filters using `filter` property on the gateway. + + See also <> *put* diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 97e08db496..f0aa4b4691 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -46,6 +46,10 @@ See <> for more information. The inbound channel adapters now have a property `max-fetch-size` which is used to limit the number of files fetched during a poll when there are no files currently in the local directory. +The regex and pattern filters can now be configured to always pass directories. +This can be useful when using recursion in the outbound gateways. +See <> and <> for more information. + ==== Integration Properties Since _version 4.3.2_ a new `spring.integration.readOnly.headers` global property has been added to customize the list of headers which should not be copied to a newly created `Message` by the `MessageBuilder`.