INT-4334: Adds a DirectoryScanner to RemoteFileMS
JIRA: https://jira.springsource.org/browse/INT-4334 * Add a `DirectoryScanner` setter named `setScanner` in `AbstractInboundFileSynchronizingMessageSource` to set the `FileReadingMessageSource`'s scanner. * Add tests to `AbstractRemoteFileSynchronizerTests`. Polish. Updates xsd, tests and documentation. Fix xsd formatting. Addresses review comments. * Some code style polishing
This commit is contained in:
committed by
Artem Bilan
parent
2427a7d426
commit
797e5045bf
@@ -37,6 +37,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
* @author Venil Noronha
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
@@ -75,6 +76,7 @@ public abstract class AbstractRemoteFileInboundChannelAdapterParser extends Abst
|
|||||||
messageSourceBuilder.addConstructorArgReference(comparator);
|
messageSourceBuilder.addConstructorArgReference(comparator);
|
||||||
}
|
}
|
||||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(messageSourceBuilder, element, "local-filter");
|
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(messageSourceBuilder, element, "local-filter");
|
||||||
|
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(messageSourceBuilder, element, "scanner");
|
||||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element, "local-directory");
|
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element, "local-directory");
|
||||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element,
|
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element,
|
||||||
"auto-create-local-directory");
|
"auto-create-local-directory");
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.regex.Pattern;
|
|||||||
import org.springframework.beans.factory.BeanInitializationException;
|
import org.springframework.beans.factory.BeanInitializationException;
|
||||||
import org.springframework.context.Lifecycle;
|
import org.springframework.context.Lifecycle;
|
||||||
import org.springframework.integration.endpoint.AbstractFetchLimitingMessageSource;
|
import org.springframework.integration.endpoint.AbstractFetchLimitingMessageSource;
|
||||||
|
import org.springframework.integration.file.DirectoryScanner;
|
||||||
import org.springframework.integration.file.FileReadingMessageSource;
|
import org.springframework.integration.file.FileReadingMessageSource;
|
||||||
import org.springframework.integration.file.RecursiveDirectoryScanner;
|
import org.springframework.integration.file.RecursiveDirectoryScanner;
|
||||||
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
||||||
@@ -59,6 +60,7 @@ import org.springframework.util.Assert;
|
|||||||
* @author Oleg Zhurakousky
|
* @author Oleg Zhurakousky
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
* @author Venil Noronha
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractInboundFileSynchronizingMessageSource<F>
|
public abstract class AbstractInboundFileSynchronizingMessageSource<F>
|
||||||
extends AbstractFetchLimitingMessageSource<File> implements Lifecycle {
|
extends AbstractFetchLimitingMessageSource<File> implements Lifecycle {
|
||||||
@@ -88,6 +90,10 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
|
|||||||
|
|
||||||
private volatile FileListFilter<File> localFileListFilter;
|
private volatile FileListFilter<File> localFileListFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the {@link DirectoryScanner} was explicitly set.
|
||||||
|
*/
|
||||||
|
private volatile boolean scannerExplicitlySet = false;
|
||||||
|
|
||||||
public AbstractInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<F> synchronizer) {
|
public AbstractInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<F> synchronizer) {
|
||||||
this(synchronizer, null);
|
this(synchronizer, null);
|
||||||
@@ -145,6 +151,17 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the local {@link FileReadingMessageSource} to use a custom
|
||||||
|
* {@link DirectoryScanner}.
|
||||||
|
* @param scanner the {@link DirectoryScanner} to use.
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public void setScanner(DirectoryScanner scanner) {
|
||||||
|
this.fileSource.setScanner(scanner);
|
||||||
|
this.scannerExplicitlySet = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
super.afterPropertiesSet();
|
super.afterPropertiesSet();
|
||||||
@@ -167,7 +184,12 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
|
|||||||
new SimpleMetadataStore(), getComponentName());
|
new SimpleMetadataStore(), getComponentName());
|
||||||
}
|
}
|
||||||
FileListFilter<File> filter = buildFilter();
|
FileListFilter<File> filter = buildFilter();
|
||||||
if (!this.fileSource.isUseWatchService()) {
|
if (this.scannerExplicitlySet) {
|
||||||
|
Assert.state(!this.fileSource.isUseWatchService(),
|
||||||
|
"'useWatchService' and 'scanner' are mutually exclusive.");
|
||||||
|
this.fileSource.getScanner().setFilter(filter);
|
||||||
|
}
|
||||||
|
else if (!this.fileSource.isUseWatchService()) {
|
||||||
RecursiveDirectoryScanner directoryScanner = new RecursiveDirectoryScanner();
|
RecursiveDirectoryScanner directoryScanner = new RecursiveDirectoryScanner();
|
||||||
directoryScanner.setFilter(filter);
|
directoryScanner.setFilter(filter);
|
||||||
this.fileSource.setScanner(directoryScanner);
|
this.fileSource.setScanner(directoryScanner);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.integration.file.HeadDirectoryScanner;
|
||||||
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
||||||
import org.springframework.integration.file.remote.session.Session;
|
import org.springframework.integration.file.remote.session.Session;
|
||||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||||
@@ -41,6 +42,7 @@ import org.springframework.messaging.MessagingException;
|
|||||||
/**
|
/**
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
* @author Venil Noronha
|
||||||
*
|
*
|
||||||
* @since 4.0.4
|
* @since 4.0.4
|
||||||
*
|
*
|
||||||
@@ -116,21 +118,7 @@ public class AbstractRemoteFileSynchronizerTests {
|
|||||||
public void testMaxFetchSizeSource() throws Exception {
|
public void testMaxFetchSizeSource() throws Exception {
|
||||||
final AtomicInteger count = new AtomicInteger();
|
final AtomicInteger count = new AtomicInteger();
|
||||||
AbstractInboundFileSynchronizer<String> sync = createLimitingSynchronizer(count);
|
AbstractInboundFileSynchronizer<String> sync = createLimitingSynchronizer(count);
|
||||||
|
AbstractInboundFileSynchronizingMessageSource<String> source = createSource(sync);
|
||||||
AbstractInboundFileSynchronizingMessageSource<String> source =
|
|
||||||
new AbstractInboundFileSynchronizingMessageSource<String>(sync) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getComponentType() {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
source.setLocalDirectory(new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID()));
|
|
||||||
source.setAutoCreateLocalDirectory(true);
|
|
||||||
source.setBeanFactory(mock(BeanFactory.class));
|
|
||||||
source.setMaxFetchSize(1);
|
|
||||||
source.setBeanName("maxFetchSizeSource");
|
|
||||||
source.afterPropertiesSet();
|
source.afterPropertiesSet();
|
||||||
source.start();
|
source.start();
|
||||||
|
|
||||||
@@ -143,6 +131,60 @@ public class AbstractRemoteFileSynchronizerTests {
|
|||||||
source.stop();
|
source.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExclusiveScanner() throws Exception {
|
||||||
|
final AtomicInteger count = new AtomicInteger();
|
||||||
|
AbstractInboundFileSynchronizingMessageSource<String> source = createSource(count);
|
||||||
|
source.setScanner(new HeadDirectoryScanner(1));
|
||||||
|
source.afterPropertiesSet();
|
||||||
|
source.start();
|
||||||
|
source.receive();
|
||||||
|
assertEquals(1, count.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExclusiveWatchService() throws Exception {
|
||||||
|
final AtomicInteger count = new AtomicInteger();
|
||||||
|
AbstractInboundFileSynchronizingMessageSource<String> source = createSource(count);
|
||||||
|
source.setUseWatchService(true);
|
||||||
|
source.afterPropertiesSet();
|
||||||
|
source.start();
|
||||||
|
source.receive();
|
||||||
|
assertEquals(1, count.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testScannerAndWatchServiceConflict() throws Exception {
|
||||||
|
final AtomicInteger count = new AtomicInteger();
|
||||||
|
AbstractInboundFileSynchronizingMessageSource<String> source = createSource(count);
|
||||||
|
source.setUseWatchService(true);
|
||||||
|
source.setScanner(new HeadDirectoryScanner(1));
|
||||||
|
source.afterPropertiesSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractInboundFileSynchronizingMessageSource<String> createSource(AtomicInteger count) {
|
||||||
|
return createSource(createLimitingSynchronizer(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractInboundFileSynchronizingMessageSource<String> createSource(
|
||||||
|
AbstractInboundFileSynchronizer<String> sync) {
|
||||||
|
AbstractInboundFileSynchronizingMessageSource<String> source =
|
||||||
|
new AbstractInboundFileSynchronizingMessageSource<String>(sync) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getComponentType() {
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
source.setMaxFetchSize(1);
|
||||||
|
source.setLocalDirectory(new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID()));
|
||||||
|
source.setAutoCreateLocalDirectory(true);
|
||||||
|
source.setBeanFactory(mock(BeanFactory.class));
|
||||||
|
source.setBeanName("fooSource");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
private AbstractInboundFileSynchronizer<String> createLimitingSynchronizer(final AtomicInteger count) {
|
private AbstractInboundFileSynchronizer<String> createLimitingSynchronizer(final AtomicInteger count) {
|
||||||
SessionFactory<String> sf = new StringSessionFactory();
|
SessionFactory<String> sf = new StringSessionFactory();
|
||||||
AbstractInboundFileSynchronizer<String> sync = new AbstractInboundFileSynchronizer<String>(sf) {
|
AbstractInboundFileSynchronizer<String> sync = new AbstractInboundFileSynchronizer<String>(sf) {
|
||||||
@@ -194,7 +236,7 @@ public class AbstractRemoteFileSynchronizerTests {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] list(String path) throws IOException {
|
public String[] list(String path) throws IOException {
|
||||||
return new String[] {"foo", "bar", "baz"};
|
return new String[] { "foo", "bar", "baz" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -163,6 +163,19 @@
|
|||||||
</xsd:documentation>
|
</xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
<xsd:attribute name="scanner" type="xsd:string">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:appinfo>
|
||||||
|
<tool:annotation kind="ref">
|
||||||
|
<tool:expected-type
|
||||||
|
type="org.springframework.integration.file.DirectoryScanner" />
|
||||||
|
</tool:annotation>
|
||||||
|
</xsd:appinfo>
|
||||||
|
<xsd:documentation>
|
||||||
|
Reference to a custom DirectoryScanner implementation.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:attribute>
|
||||||
<xsd:attributeGroup ref="tempSuffixGroup" />
|
<xsd:attributeGroup ref="tempSuffixGroup" />
|
||||||
</xsd:extension>
|
</xsd:extension>
|
||||||
</xsd:complexContent>
|
</xsd:complexContent>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<int-ftp:inbound-channel-adapter id="ftpInbound"
|
<int-ftp:inbound-channel-adapter id="ftpInbound"
|
||||||
channel="ftpChannel"
|
channel="ftpChannel"
|
||||||
session-factory="ftpSessionFactory"
|
session-factory="ftpSessionFactory"
|
||||||
|
scanner="dirScanner"
|
||||||
auto-create-local-directory="true"
|
auto-create-local-directory="true"
|
||||||
auto-startup="false"
|
auto-startup="false"
|
||||||
delete-remote-files="true"
|
delete-remote-files="true"
|
||||||
@@ -35,6 +36,10 @@
|
|||||||
</int:poller>
|
</int:poller>
|
||||||
</int-ftp:inbound-channel-adapter>
|
</int-ftp:inbound-channel-adapter>
|
||||||
|
|
||||||
|
<bean id="dirScanner" class="org.springframework.integration.file.HeadDirectoryScanner">
|
||||||
|
<constructor-arg value="1" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="fooString" class="java.lang.String">
|
<bean id="fooString" class="java.lang.String">
|
||||||
<constructor-arg value="foo" />
|
<constructor-arg value="foo" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||||
|
import org.springframework.integration.file.DirectoryScanner;
|
||||||
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
||||||
import org.springframework.integration.file.filters.FileListFilter;
|
import org.springframework.integration.file.filters.FileListFilter;
|
||||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||||
@@ -66,6 +67,7 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
* @author Gunnar Hillert
|
* @author Gunnar Hillert
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
* @author Venil Noronha
|
||||||
*/
|
*/
|
||||||
@ContextConfiguration
|
@ContextConfiguration
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@@ -88,20 +90,26 @@ public class FtpInboundChannelAdapterParserTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationContext context;
|
private ApplicationContext context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DirectoryScanner dirScanner;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFtpInboundChannelAdapterComplete() throws Exception {
|
public void testFtpInboundChannelAdapterComplete() throws Exception {
|
||||||
assertFalse(TestUtils.getPropertyValue(ftpInbound, "autoStartup", Boolean.class));
|
assertFalse(TestUtils.getPropertyValue(ftpInbound, "autoStartup", Boolean.class));
|
||||||
PriorityBlockingQueue<?> blockingQueue = TestUtils.getPropertyValue(ftpInbound, "source.fileSource.toBeReceived", PriorityBlockingQueue.class);
|
PriorityBlockingQueue<?> blockingQueue =
|
||||||
|
TestUtils.getPropertyValue(ftpInbound, "source.fileSource.toBeReceived", PriorityBlockingQueue.class);
|
||||||
Comparator<?> comparator = blockingQueue.comparator();
|
Comparator<?> comparator = blockingQueue.comparator();
|
||||||
assertNotNull(comparator);
|
assertNotNull(comparator);
|
||||||
assertEquals("ftpInbound", ftpInbound.getComponentName());
|
assertEquals("ftpInbound", ftpInbound.getComponentName());
|
||||||
assertEquals("ftp:inbound-channel-adapter", ftpInbound.getComponentType());
|
assertEquals("ftp:inbound-channel-adapter", ftpInbound.getComponentType());
|
||||||
assertEquals(context.getBean("ftpChannel"), TestUtils.getPropertyValue(ftpInbound, "outputChannel"));
|
assertEquals(context.getBean("ftpChannel"), TestUtils.getPropertyValue(ftpInbound, "outputChannel"));
|
||||||
FtpInboundFileSynchronizingMessageSource inbound =
|
FtpInboundFileSynchronizingMessageSource inbound =
|
||||||
(FtpInboundFileSynchronizingMessageSource) TestUtils.getPropertyValue(ftpInbound, "source");
|
(FtpInboundFileSynchronizingMessageSource) TestUtils.getPropertyValue(ftpInbound, "source");
|
||||||
|
|
||||||
|
assertSame(dirScanner, TestUtils.getPropertyValue(inbound, "fileSource.scanner"));
|
||||||
|
|
||||||
FtpInboundFileSynchronizer fisync =
|
FtpInboundFileSynchronizer fisync =
|
||||||
(FtpInboundFileSynchronizer) TestUtils.getPropertyValue(inbound, "synchronizer");
|
(FtpInboundFileSynchronizer) TestUtils.getPropertyValue(inbound, "synchronizer");
|
||||||
assertEquals("'foo/bar'", TestUtils.getPropertyValue(fisync, "remoteDirectoryExpression", Expression.class)
|
assertEquals("'foo/bar'", TestUtils.getPropertyValue(fisync, "remoteDirectoryExpression", Expression.class)
|
||||||
.getExpressionString());
|
.getExpressionString());
|
||||||
assertNotNull(TestUtils.getPropertyValue(fisync, "localFilenameGeneratorExpression"));
|
assertNotNull(TestUtils.getPropertyValue(fisync, "localFilenameGeneratorExpression"));
|
||||||
@@ -123,7 +131,8 @@ public class FtpInboundChannelAdapterParserTests {
|
|||||||
Object sessionFactory = TestUtils.getPropertyValue(fisync, "remoteFileTemplate.sessionFactory");
|
Object sessionFactory = TestUtils.getPropertyValue(fisync, "remoteFileTemplate.sessionFactory");
|
||||||
assertTrue(DefaultFtpSessionFactory.class.isAssignableFrom(sessionFactory.getClass()));
|
assertTrue(DefaultFtpSessionFactory.class.isAssignableFrom(sessionFactory.getClass()));
|
||||||
FileListFilter<?> acceptAllFilter = context.getBean("acceptAllFilter", FileListFilter.class);
|
FileListFilter<?> acceptAllFilter = context.getBean("acceptAllFilter", FileListFilter.class);
|
||||||
assertTrue(TestUtils.getPropertyValue(inbound, "fileSource.scanner.filter.fileFilters", Collection.class).contains(acceptAllFilter));
|
assertTrue(TestUtils.getPropertyValue(inbound, "fileSource.scanner.filter.fileFilters", Collection.class)
|
||||||
|
.contains(acceptAllFilter));
|
||||||
final AtomicReference<Method> genMethod = new AtomicReference<Method>();
|
final AtomicReference<Method> genMethod = new AtomicReference<Method>();
|
||||||
ReflectionUtils.doWithMethods(AbstractInboundFileSynchronizer.class, method -> {
|
ReflectionUtils.doWithMethods(AbstractInboundFileSynchronizer.class, method -> {
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
@@ -135,16 +144,19 @@ public class FtpInboundChannelAdapterParserTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cachingSessionFactory() throws Exception {
|
public void cachingSessionFactory() throws Exception {
|
||||||
Object sessionFactory = TestUtils.getPropertyValue(simpleAdapterWithCachedSessions, "source.synchronizer.remoteFileTemplate.sessionFactory");
|
Object sessionFactory = TestUtils.getPropertyValue(simpleAdapterWithCachedSessions,
|
||||||
|
"source.synchronizer.remoteFileTemplate.sessionFactory");
|
||||||
assertEquals(CachingSessionFactory.class, sessionFactory.getClass());
|
assertEquals(CachingSessionFactory.class, sessionFactory.getClass());
|
||||||
FtpInboundFileSynchronizer fisync =
|
FtpInboundFileSynchronizer fisync =
|
||||||
TestUtils.getPropertyValue(simpleAdapterWithCachedSessions, "source.synchronizer", FtpInboundFileSynchronizer.class);
|
TestUtils.getPropertyValue(simpleAdapterWithCachedSessions, "source.synchronizer",
|
||||||
|
FtpInboundFileSynchronizer.class);
|
||||||
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
|
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
|
||||||
assertNotNull(remoteFileSeparator);
|
assertNotNull(remoteFileSeparator);
|
||||||
assertEquals("/", remoteFileSeparator);
|
assertEquals("/", remoteFileSeparator);
|
||||||
assertEquals("foo/bar", TestUtils.getPropertyValue(fisync, "remoteDirectoryExpression", Expression.class)
|
assertEquals("foo/bar", TestUtils.getPropertyValue(fisync, "remoteDirectoryExpression", Expression.class)
|
||||||
.getExpressionString());
|
.getExpressionString());
|
||||||
assertEquals(Integer.MIN_VALUE, TestUtils.getPropertyValue(simpleAdapterWithCachedSessions, "source.maxFetchSize"));
|
assertEquals(Integer.MIN_VALUE,
|
||||||
|
TestUtils.getPropertyValue(simpleAdapterWithCachedSessions, "source.maxFetchSize"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -171,6 +183,7 @@ public class FtpInboundChannelAdapterParserTests {
|
|||||||
public boolean isSingleton() {
|
public boolean isSingleton() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,6 +167,19 @@
|
|||||||
</xsd:documentation>
|
</xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
<xsd:attribute name="scanner" type="xsd:string">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:appinfo>
|
||||||
|
<tool:annotation kind="ref">
|
||||||
|
<tool:expected-type
|
||||||
|
type="org.springframework.integration.file.DirectoryScanner" />
|
||||||
|
</tool:annotation>
|
||||||
|
</xsd:appinfo>
|
||||||
|
<xsd:documentation>
|
||||||
|
Reference to a custom DirectoryScanner implementation.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:attribute>
|
||||||
<xsd:attributeGroup ref="tempSuffixGroup" />
|
<xsd:attributeGroup ref="tempSuffixGroup" />
|
||||||
</xsd:extension>
|
</xsd:extension>
|
||||||
</xsd:complexContent>
|
</xsd:complexContent>
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ The _FTP Inbound Channel Adapter_ is a special listener that will connect to the
|
|||||||
remote-file-separator="/"
|
remote-file-separator="/"
|
||||||
preserve-timestamp="true"
|
preserve-timestamp="true"
|
||||||
local-filename-generator-expression="#this.toUpperCase() + '.a'"
|
local-filename-generator-expression="#this.toUpperCase() + '.a'"
|
||||||
|
scanner="myDirScanner"
|
||||||
local-filter="myFilter"
|
local-filter="myFilter"
|
||||||
temporary-file-suffix=".writing"
|
temporary-file-suffix=".writing"
|
||||||
max-fetch-size="-1"
|
max-fetch-size="-1"
|
||||||
@@ -259,6 +260,7 @@ The inbound channel adapter first retrieves the file to a local directory and th
|
|||||||
Starting with _version 5.0_, you can now limit the number of files fetched from the FTP server when new file retrievals are needed.
|
Starting with _version 5.0_, you can now limit the number of files fetched from the FTP server when new file retrievals are needed.
|
||||||
This can be beneficial when the target files are very large and/or when running in a clustered system with a persistent file list filter discussed below.
|
This can be beneficial when the target files are very large and/or when running in a clustered system with a persistent file list filter discussed below.
|
||||||
Use `max-fetch-size` for this purpose; a negative value (default) means no limit and all matching files will be retrieved; see <<ftp-max-fetch>> for more information.
|
Use `max-fetch-size` for this purpose; a negative value (default) means no limit and all matching files will be retrieved; see <<ftp-max-fetch>> for more information.
|
||||||
|
Since _version 5.0_, you can also provide a custom `DirectoryScanner` implementation to the `inbound-channel-adapter` via the `scanner` attribute.
|
||||||
|
|
||||||
Starting with _Spring Integration 3.0_, you can specify the `preserve-timestamp` attribute (default `false`); when `true`, the local file's modified timestamp will be set to the value retrieved from the server; otherwise it will be set to the current time.
|
Starting with _Spring Integration 3.0_, you can specify the `preserve-timestamp` attribute (default `false`); when `true`, the local file's modified timestamp will be set to the value retrieved from the server; otherwise it will be set to the current time.
|
||||||
|
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ The _SFTP Inbound Channel Adapter_ is a special listener that will connect to th
|
|||||||
local-directory="file:target/foo"
|
local-directory="file:target/foo"
|
||||||
auto-create-local-directory="true"
|
auto-create-local-directory="true"
|
||||||
local-filename-generator-expression="#this.toUpperCase() + '.a'"
|
local-filename-generator-expression="#this.toUpperCase() + '.a'"
|
||||||
|
scanner="myDirScanner"
|
||||||
local-filter="myFilter"
|
local-filter="myFilter"
|
||||||
temporary-file-suffix=".writing"
|
temporary-file-suffix=".writing"
|
||||||
max-fetch-size="-1"
|
max-fetch-size="-1"
|
||||||
@@ -330,6 +331,7 @@ The inbound channel adapter first retrieves the file to a local directory and th
|
|||||||
Starting with _version 5.0_ you can now limit the number of files fetched from the FTP server when new file retrievals are needed.
|
Starting with _version 5.0_ you can now limit the number of files fetched from the FTP server when new file retrievals are needed.
|
||||||
This can be beneficial when the target files are very large and/or when running in a clustered system with a persistent file list filter discussed below.
|
This can be beneficial when the target files are very large and/or when running in a clustered system with a persistent file list filter discussed below.
|
||||||
Use `max-fetch-size` for this purpose; a negative value (default) means no limit and all matching files will be retrieved; see <<sftp-max-fetch>> for more information.
|
Use `max-fetch-size` for this purpose; a negative value (default) means no limit and all matching files will be retrieved; see <<sftp-max-fetch>> for more information.
|
||||||
|
Since _version 5.0_, you can also provide a custom `DirectoryScanner` implementation to the `inbound-channel-adapter` via the `scanner` attribute.
|
||||||
|
|
||||||
Starting with _Spring Integration 3.0_, you can specify the `preserve-timestamp` attribute (default `false`); when `true`, the local file's modified timestamp will be set to the value retrieved from the server; otherwise it will be set to the current time.
|
Starting with _Spring Integration 3.0_, you can specify the `preserve-timestamp` attribute (default `false`); when `true`, the local file's modified timestamp will be set to the value retrieved from the server; otherwise it will be set to the current time.
|
||||||
|
|
||||||
|
|||||||
@@ -168,8 +168,9 @@ See <<files>> for more information.
|
|||||||
|
|
||||||
==== (S)FTP Changes
|
==== (S)FTP Changes
|
||||||
|
|
||||||
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 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.
|
||||||
They also are configured with a `FileSystemPersistentAcceptOnceFileListFilter` in the `local-filter` by default.
|
They also are configured with a `FileSystemPersistentAcceptOnceFileListFilter` in the `local-filter` by default.
|
||||||
|
You can also provide a custom `DirectoryScanner` implementation to Inbound Channel Adapters via the newly introduced `scanner` attribute.
|
||||||
|
|
||||||
The regex and pattern filters can now be configured to always pass directories.
|
The regex and pattern filters can now be configured to always pass directories.
|
||||||
This can be useful when using recursion in the outbound gateways.
|
This can be useful when using recursion in the outbound gateways.
|
||||||
|
|||||||
Reference in New Issue
Block a user