INT-4086: (S)FTP: Add Local File Tree Support

JIRA: https://jira.spring.io/browse/INT-4086

The remote files may be carried with sub-path, not just file name.
The same sub-dirs logic can be achieve with the `localFilenameGeneratorExpression`

* Add the logic into `AbstractInboundFileSynchronizer` to build sub-dirs for local files
* Switch on `WatchService` for the internal `FileReadingMessageSource` in the `AbstractInboundFileSynchronizingMessageSource` to react for all the changes in the `localDirectory`

Introduce `RecursiveDirectoryScanner` and use it for `AbstractInboundFileSynchronizingMessageSource` by default

* Add `maxDepth` and `fileVisitOptions` options to the `RecursiveDirectoryScanner`
* Polishing JavaDocs, tests and docs
This commit is contained in:
Artem Bilan
2016-08-09 17:52:17 -04:00
committed by Gary Russell
parent 6dbc721d73
commit 96ca9647a4
17 changed files with 289 additions and 31 deletions

View File

@@ -74,13 +74,7 @@ public class FtpInboundRemoteFileSystemSynchronizerTests {
@Before
@After
public void cleanup() {
File file = new File("test");
if (file.exists()) {
for (File f : file.listFiles()) {
f.delete();
}
file.delete();
}
recursiveDelete(new File("test"));
}
@Test
@@ -109,7 +103,7 @@ public class FtpInboundRemoteFileSystemSynchronizerTests {
synchronizer.setFilter(filter);
ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression expression = expressionParser.parseExpression("#this.toUpperCase() + '.a'");
Expression expression = expressionParser.parseExpression("'subdir/' + #this.toUpperCase() + '.a'");
synchronizer.setLocalFilenameGeneratorExpression(expression);
synchronizer.setBeanFactory(mock(BeanFactory.class));
synchronizer.afterPropertiesSet();
@@ -126,6 +120,8 @@ public class FtpInboundRemoteFileSystemSynchronizerTests {
localFileListFilter.addFilter(localAcceptOnceFilter);
ms.setLocalFilter(localFileListFilter);
ms.afterPropertiesSet();
ms.start();
Message<File> atestFile = ms.receive();
assertNotNull(atestFile);
assertEquals("A.TEST.a", atestFile.getPayload().getName());
@@ -146,13 +142,13 @@ public class FtpInboundRemoteFileSystemSynchronizerTests {
// two times because on the third receive (above) the internal queue will be empty, so it will attempt
verify(synchronizer, times(2)).synchronizeToLocalDirectory(localDirectory, Integer.MIN_VALUE);
assertTrue(new File("test/A.TEST.a").exists());
assertTrue(new File("test/B.TEST.a").exists());
assertTrue(new File("test/subdir/A.TEST.a").exists());
assertTrue(new File("test/subdir/B.TEST.a").exists());
TestUtils.getPropertyValue(localAcceptOnceFilter, "seenSet", Collection.class).clear();
new File("test/A.TEST.a").delete();
new File("test/B.TEST.a").delete();
new File("test/subdir/A.TEST.a").delete();
new File("test/subdir/B.TEST.a").delete();
// the remote filter should prevent a re-fetch
nothing = ms.receive();
assertNull(nothing);
@@ -192,6 +188,24 @@ public class FtpInboundRemoteFileSystemSynchronizerTests {
assertEquals(0, localDirectory.list().length);
}
private static void recursiveDelete(File file) {
if (file != null && file.exists()) {
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
recursiveDelete(f);
}
else {
f.delete();
}
}
}
file.delete();
}
}
public static class TestFtpSessionFactory extends AbstractFtpSessionFactory<FTPClient> {
private final Collection<FTPFile> ftpFiles = new ArrayList<FTPFile>();