From 8ea683b71551e196ed0ee21260da7b9f398abe26 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 22 Sep 2008 00:16:13 +0000 Subject: [PATCH] Added PatternMatchingFileListFilter and namespace support for the "filename-pattern" attribute. AbstractFilePayloadTransformer now sets the "filename" Message header. Renamed the filters to include FileListFilter (rather than just FileFilter) to avoid confusion with the FileFilter interface. --- .../file/AbstractFileListFilter.java | 50 +++++++++++ ...ter.java => AcceptOnceFileListFilter.java} | 27 ++---- ...lter.java => CompositeFileListFilter.java} | 19 ++-- .../integration/file/FileListFilter.java | 21 +++++ .../file/PatternMatchingFileListFilter.java | 48 ++++++++++ .../integration/file/PollableFileSource.java | 28 +++--- .../FileInboundChannelAdapterParser.java | 18 ++++ .../config/spring-integration-file-1.0.xsd | 1 + .../AbstractFilePayloadTransformer.java | 52 +++++++---- ...java => CompositeFileListFilterTests.java} | 8 +- .../PatternMatchingFileListFilterTests.java | 90 +++++++++++++++++++ ...ableFileSourceIntegrationTests-context.xml | 26 +++--- ...ileFilter.java => TestFileListFilter.java} | 2 +- ...boundChannelAdapterParserTests-context.xml | 13 +-- .../FileInboundChannelAdapterParserTests.java | 4 +- ...alidPatternMatchingFileListFilterTests.xml | 11 +++ .../patternMatchingFileListFilterTests.xml | 11 +++ 17 files changed, 345 insertions(+), 84 deletions(-) create mode 100644 org.springframework.integration.file/src/main/java/org/springframework/integration/file/AbstractFileListFilter.java rename org.springframework.integration.file/src/main/java/org/springframework/integration/file/{AcceptOnceFileFilter.java => AcceptOnceFileListFilter.java} (75%) rename org.springframework.integration.file/src/main/java/org/springframework/integration/file/{CompositeFileFilter.java => CompositeFileListFilter.java} (77%) create mode 100644 org.springframework.integration.file/src/main/java/org/springframework/integration/file/PatternMatchingFileListFilter.java rename org.springframework.integration.file/src/test/java/org/springframework/integration/file/{CompositeFileFilterTest.java => CompositeFileListFilterTests.java} (88%) create mode 100644 org.springframework.integration.file/src/test/java/org/springframework/integration/file/PatternMatchingFileListFilterTests.java rename org.springframework.integration.file/src/test/java/org/springframework/integration/file/{TestFileFilter.java => TestFileListFilter.java} (93%) create mode 100644 org.springframework.integration.file/src/test/java/org/springframework/integration/file/invalidPatternMatchingFileListFilterTests.xml create mode 100644 org.springframework.integration.file/src/test/java/org/springframework/integration/file/patternMatchingFileListFilterTests.xml diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AbstractFileListFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AbstractFileListFilter.java new file mode 100644 index 0000000000..8e2c6e04cc --- /dev/null +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AbstractFileListFilter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2008 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; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * A convenience base class for any {@link FileListFilter} whose criteria can + * be evaluated against each File in isolation. If the entire List of files is + * required for evaluation, implement the FileListFilter interface directly. + * + * @author Mark Fisher + */ +public abstract class AbstractFileListFilter implements FileListFilter { + + /** + * Returns the list of files that are accepted by this filter. + */ + public final List filterFiles(File[] files) { + List accepted = new ArrayList(); + for (File file : files) { + if (this.accept(file)) { + accepted.add(file); + } + } + return accepted; + } + + /** + * Subclasses must implement this method. + */ + protected abstract boolean accept(File file); + +} diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileListFilter.java similarity index 75% rename from org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileFilter.java rename to org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileListFilter.java index cffff26b07..04b87b9364 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileFilter.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/AcceptOnceFileListFilter.java @@ -17,8 +17,6 @@ package org.springframework.integration.file; import java.io.File; -import java.util.ArrayList; -import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; @@ -28,9 +26,8 @@ import java.util.concurrent.LinkedBlockingQueue; * {@link PollableFileSource}. * * @author Iwein Fuld - * */ -public class AcceptOnceFileFilter implements FileListFilter { +public class AcceptOnceFileListFilter extends AbstractFileListFilter { private final Queue seen; @@ -45,34 +42,20 @@ public class AcceptOnceFileFilter implements FileListFilter { * @param maxCapacity the maximum number of Files to maintain in the 'seen' * queue. */ - public AcceptOnceFileFilter(int maxCapacity) { + public AcceptOnceFileListFilter(int maxCapacity) { this.seen = new LinkedBlockingQueue(maxCapacity); } /** * Creates an AcceptOnceFileFilter based on an unbounded queue. */ - public AcceptOnceFileFilter() { + public AcceptOnceFileListFilter() { this.seen = new LinkedBlockingQueue(); } - /** - * Returns the list of files that have not already been filtered by this - * instance. - */ - public List filterFiles(File[] files) { - List accepted = new ArrayList(); - for (File file : files) { - if (accept(file)) { - accepted.add(file); - } - } - return accepted; - } - - private boolean accept(File pathname) { - synchronized (monitor) { + protected boolean accept(File pathname) { + synchronized (this.monitor) { if (seen.contains(pathname)) { return false; } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileListFilter.java similarity index 77% rename from org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileFilter.java rename to org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileListFilter.java index c880d96d10..8e92a7ec84 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileFilter.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/CompositeFileListFilter.java @@ -26,23 +26,25 @@ import java.util.Set; /** * Composition that delegates to multiple {@link FileFilter}s. The composition - * is AND based, meaning that all filters must {@link #filterFiles(File)} in - * order for a file to be accepted by the composite. + * is AND based, meaning that a file must pass through each filter's + * {@link #filterFiles(File)} method in order to be accepted by the composite. * * @author Iwein Fuld */ -public class CompositeFileFilter implements FileListFilter { +public class CompositeFileListFilter implements FileListFilter { private final Set fileFilters; - public CompositeFileFilter(FileListFilter... fileFilters) { + + public CompositeFileListFilter(FileListFilter... fileFilters) { this.fileFilters = new HashSet(Arrays.asList(fileFilters)); } - public CompositeFileFilter(Collection fileFilters) { + public CompositeFileListFilter(Collection fileFilters) { this.fileFilters = new HashSet(fileFilters); } + /** * {@inheritDoc} */ @@ -59,7 +61,7 @@ public class CompositeFileFilter implements FileListFilter { * @param filters one or more new filters to be used * @return a new CompositeFileFilter with the additional filters */ - public CompositeFileFilter addFilter(FileListFilter... filters) { + public CompositeFileListFilter addFilter(FileListFilter... filters) { return addFilters(Arrays.asList(filters)); } @@ -70,9 +72,10 @@ public class CompositeFileFilter implements FileListFilter { * @param filtersToAdd * @return a new CompositeFileFilter with the added filters */ - public CompositeFileFilter addFilters(Collection filtersToAdd) { + public CompositeFileListFilter addFilters(Collection filtersToAdd) { HashSet newFilterSet = new HashSet(filtersToAdd); newFilterSet.addAll(fileFilters); - return new CompositeFileFilter(newFilterSet); + return new CompositeFileListFilter(newFilterSet); } + } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileListFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileListFilter.java index 2a780d0fdb..5901afd7c2 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileListFilter.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileListFilter.java @@ -1,8 +1,29 @@ +/* + * Copyright 2002-2008 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; import java.io.File; import java.util.List; +/** + * Strategy interface for filtering a group of files. + * + * @author Iwein Fuld + */ public interface FileListFilter { List filterFiles(File[] files); diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PatternMatchingFileListFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PatternMatchingFileListFilter.java new file mode 100644 index 0000000000..3dac0f7629 --- /dev/null +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PatternMatchingFileListFilter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2008 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; + +import java.io.File; +import java.util.regex.Pattern; + +import org.springframework.util.Assert; + +/** + * A {@link FileListFilter} implementation that matches against a {@link Pattern}. + * + * @author Mark Fisher + */ +public class PatternMatchingFileListFilter extends AbstractFileListFilter { + + private final Pattern pattern; + + + /** + * Create a filter for the given pattern. + */ + public PatternMatchingFileListFilter(Pattern pattern) { + Assert.notNull(pattern, "pattern must not be null"); + this.pattern = pattern; + } + + + protected boolean accept(File file) { + return (file != null) + && this.pattern.matcher(file.getName()).matches(); + } + +} diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PollableFileSource.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PollableFileSource.java index 06002669a4..4d6c34c817 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PollableFileSource.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/PollableFileSource.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.file; import java.io.File; @@ -26,6 +27,7 @@ import java.util.concurrent.PriorityBlockingQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.core.io.Resource; import org.springframework.integration.message.GenericMessage; import org.springframework.integration.message.Message; @@ -36,16 +38,17 @@ import org.springframework.util.Assert; /** * PollableSource that creates messages from a file system directory. To prevent - * messages from showing up on the source you can supply a FileFilter to it. By - * default an {@link AcceptOnceFileFilter} is used that ensures files are picked + * messages for certain files, you may supply a {@link FileListFilter}. By + * default, an {@link AcceptOnceFileListFilter} is used. It ensures files are picked * up only once from the directory. - * - * A common problem with reading files is that files are picked up that are not - * ready. The default {@link AcceptOnceFileFilter} does not prevent this. In - * most cases this can be prevented by renaming the files as soon as they are - * ready. A FileFilter that accepts only files that are ready, composed with the - * default {@link AcceptOnceFileFilter} would allow for this. - * @see CompositeFileFilter for a way to do this. + *

+ * A common problem with reading files is that a file may be detected before it + * is ready. The default {@link AcceptOnceFileListFilter} does not prevent this. In + * most cases, this can be prevented if the file-writing process renames each + * file as soon as it is ready for reading. A pattern-matching filter that + * accepts only files that are ready (e.g. based on a known suffix), composed + * with the default {@link AcceptOnceFileListFilter} would allow for this. + * See {@ link CompositeFileFilter} for a way to do this. * * @author Iwein Fuld */ @@ -57,7 +60,8 @@ public class PollableFileSource implements PollableSource, MessageDelivery private final Queue toBeReceived = new PriorityBlockingQueue(); - private volatile FileListFilter filter = new AcceptOnceFileFilter(); + private volatile FileListFilter filter = new AcceptOnceFileListFilter(); + public void setInputDirectory(Resource inputDirectory) { Assert.notNull(inputDirectory, "inputDirectory cannot be null"); @@ -73,10 +77,10 @@ public class PollableFileSource implements PollableSource, MessageDelivery /** * Sets a {@link FileFilter} on the {@link PollableSource}. By default a - * {@link AcceptOnceFileFilter} with no bounds is used. In most cases a + * {@link AcceptOnceFileListFilter} with no bounds is used. In most cases a * customized {@link FileFilter} will be needed to deal with modification * and duplication concerns. If multiple filters are required a - * {@link CompositeFileFilter} can be used to group them together

+ * {@link CompositeFileListFilter} can be used to group them together

* Note that the supplied filter must be thread safe. */ public void setFilter(FileListFilter filter) { diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java index f85cd5537a..095a990eb3 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java @@ -16,12 +16,18 @@ package org.springframework.integration.file.config; +import java.util.regex.Pattern; + import org.w3c.dom.Element; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.ConfigurationException; import org.springframework.integration.config.AbstractPollingInboundChannelAdapterParser; +import org.springframework.integration.file.AcceptOnceFileListFilter; +import org.springframework.integration.file.CompositeFileListFilter; +import org.springframework.integration.file.PatternMatchingFileListFilter; import org.springframework.integration.file.PollableFileSource; import org.springframework.util.StringUtils; @@ -29,6 +35,7 @@ import org.springframework.util.StringUtils; * Parser for the <inbound-channel-adapter> element of the 'file' namespace. * * @author Iwein Fuld + * @author Mark Fisher */ public class FileInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { @@ -43,6 +50,17 @@ public class FileInboundChannelAdapterParser extends AbstractPollingInboundChann if (StringUtils.hasText(filter)){ builder.addPropertyReference("filter", filter); } + String filenamePattern = element.getAttribute("filename-pattern"); + if (StringUtils.hasText(filenamePattern)) { + if (StringUtils.hasText(filter)) { + throw new ConfigurationException("at most one of 'filter' and 'filename-pattern' may be provided"); + } + AcceptOnceFileListFilter acceptOnceFilter = new AcceptOnceFileListFilter(); + Pattern pattern = Pattern.compile(filenamePattern); + PatternMatchingFileListFilter patternFilter = new PatternMatchingFileListFilter(pattern); + CompositeFileListFilter compositeFilter = new CompositeFileListFilter(acceptOnceFilter, patternFilter); + builder.addPropertyValue("filter", compositeFilter); + } return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/spring-integration-file-1.0.xsd b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/spring-integration-file-1.0.xsd index f65546df9e..d6bb945b0d 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/spring-integration-file-1.0.xsd +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/spring-integration-file-1.0.xsd @@ -32,6 +32,7 @@ + diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/transformer/AbstractFilePayloadTransformer.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/transformer/AbstractFilePayloadTransformer.java index 70c96c84be..ccf957e7af 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/transformer/AbstractFilePayloadTransformer.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/transformer/AbstractFilePayloadTransformer.java @@ -18,8 +18,13 @@ package org.springframework.integration.file.transformer; import java.io.File; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageBuilder; import org.springframework.integration.message.MessagingException; -import org.springframework.integration.transformer.AbstractPayloadTransformer; +import org.springframework.integration.transformer.Transformer; import org.springframework.util.Assert; /** @@ -27,32 +32,41 @@ import org.springframework.util.Assert; * * @author Mark Fisher */ -public abstract class AbstractFilePayloadTransformer extends AbstractPayloadTransformer { +public abstract class AbstractFilePayloadTransformer implements Transformer { - private volatile boolean deleteFile; + private final Log logger = LogFactory.getLog(this.getClass()); + + private volatile boolean deleteFileAfterTransformation; /** * Specify whether to delete the File after transformation. */ - public void setDeleteFile(boolean deleteFile) { - this.deleteFile = deleteFile; + public void setDeleteFileAfterTransformation(boolean deleteFileAfterTransformation) { + this.deleteFileAfterTransformation = deleteFileAfterTransformation; } - @Override - protected final T transformPayload(File file) throws Exception { - Assert.notNull(file, "File must not be null"); - if (!file.exists()) { - throw new MessagingException("File '" + file + "' no longer exists."); - } - if (!file.canRead()) { - throw new MessagingException("Unable to read File '" + file + "'"); - } - T result = transformFile(file); - if (this.deleteFile) { - file.delete(); - } - return result; + public final Message transform(Message message) { + try { + Assert.notNull(message, "Message must not be null"); + Object payload = message.getPayload(); + Assert.notNull(payload, "Mesasge payload must not be null"); + Assert.isInstanceOf(File.class, payload, "Message payload must be of type [java.io.File]"); + File file = (File) payload; + T result = this.transformFile(file); + Message transformedMessage = MessageBuilder.withPayload(result) + .copyHeaders(message.getHeaders()) + .setHeaderIfAbsent("filename", file.getName()) + .build(); + if (this.deleteFileAfterTransformation) { + if (!file.delete() && this.logger.isWarnEnabled()) { + this.logger.warn("failed to delete File '" + file + "'"); + } + } + return transformedMessage; + } catch (Exception e) { + throw new MessagingException(message, "failed to transform File Message", e); + } } /** diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileFilterTest.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileListFilterTests.java similarity index 88% rename from org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileFilterTest.java rename to org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileListFilterTests.java index 4640ebc7bc..f5d8ddc149 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileFilterTest.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/CompositeFileListFilterTests.java @@ -35,7 +35,7 @@ import org.junit.Test; /** * @author Iwein Fuld */ -public class CompositeFileFilterTest { +public class CompositeFileListFilterTests { private FileListFilter fileFilterMock1 = createMock(FileListFilter.class); @@ -45,7 +45,7 @@ public class CompositeFileFilterTest { @Test public void forwardedToFilters() throws Exception { - CompositeFileFilter compositeFileFilter = new CompositeFileFilter(fileFilterMock1, fileFilterMock2); + CompositeFileListFilter compositeFileFilter = new CompositeFileListFilter(fileFilterMock1, fileFilterMock2); List returnedFiles = Arrays.asList(new File[] { fileMock }); expect(fileFilterMock1.filterFiles(isA(File[].class))).andReturn(returnedFiles).times(1); expect(fileFilterMock2.filterFiles(isA(File[].class))).andReturn(returnedFiles).times(1); @@ -56,7 +56,7 @@ public class CompositeFileFilterTest { @Test public void forwardedToAddedFilters() throws Exception { - CompositeFileFilter compositeFileFilter = new CompositeFileFilter().addFilter(fileFilterMock1, fileFilterMock2); + CompositeFileListFilter compositeFileFilter = new CompositeFileListFilter().addFilter(fileFilterMock1, fileFilterMock2); List returnedFiles = Arrays.asList(new File[] { fileMock }); expect(fileFilterMock1.filterFiles(isA(File[].class))).andReturn(returnedFiles).times(1); expect(fileFilterMock2.filterFiles(isA(File[].class))).andReturn(returnedFiles).times(1); @@ -67,7 +67,7 @@ public class CompositeFileFilterTest { @Test public void negative() throws Exception { - CompositeFileFilter compositeFileFilter = new CompositeFileFilter(fileFilterMock1, fileFilterMock2); + CompositeFileListFilter compositeFileFilter = new CompositeFileListFilter(fileFilterMock1, fileFilterMock2); expect(fileFilterMock2.filterFiles(isA(File[].class))).andReturn(new ArrayList()).times(1); expect(fileFilterMock1.filterFiles(isA(File[].class))).andReturn(new ArrayList()).times(1); replay(fileFilterMock1, fileFilterMock2); diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PatternMatchingFileListFilterTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PatternMatchingFileListFilterTests.java new file mode 100644 index 0000000000..c86e12b9d5 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PatternMatchingFileListFilterTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2008 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; +import java.util.regex.Pattern; + +import org.junit.Test; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Mark Fisher + */ +public class PatternMatchingFileListFilterTests { + + @Test + public void matchSingleFile() { + File[] files = new File[] { new File("/some/path/test.txt") }; + Pattern pattern = Pattern.compile("[a-z]+\\.txt"); + PatternMatchingFileListFilter filter = new PatternMatchingFileListFilter(pattern); + List accepted = filter.filterFiles(files); + assertEquals(1, accepted.size()); + } + + @Test + public void noMatchWithSingleFile() { + File[] files = new File[] { new File("/some/path/Test.txt") }; + Pattern pattern = Pattern.compile("[a-z]+\\.txt"); + PatternMatchingFileListFilter filter = new PatternMatchingFileListFilter(pattern); + List accepted = filter.filterFiles(files); + assertEquals(0, accepted.size()); + } + + @Test + public void matchSubset() { + File[] files = new File[] { + new File("/some/path/foo.txt"), + new File("/some/path/foo.not"), + new File("/some/path/bar.txt"), + new File("/some/path/bar.not") + }; + Pattern pattern = Pattern.compile("[a-z]+\\.txt"); + PatternMatchingFileListFilter filter = new PatternMatchingFileListFilter(pattern); + List accepted = filter.filterFiles(files); + assertEquals(2, accepted.size()); + assertTrue(accepted.contains(new File("/some/path/foo.txt"))); + assertTrue(accepted.contains(new File("/some/path/bar.txt"))); + } + + @Test(expected = IllegalArgumentException.class) + public void nullPattern() { + new PatternMatchingFileListFilter(null); + } + + @Test + public void patternEditorInContext() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "patternMatchingFileListFilterTests.xml", this.getClass()); + FileListFilter filter = (FileListFilter) context.getBean("filter"); + File[] files = new File[] { new File("/some/path/foo.txt") }; + List accepted = filter.filterFiles(files); + assertEquals(1, accepted.size()); + } + + @Test(expected = BeanCreationException.class) + public void invalidPatternSyntax() throws Throwable { + new ClassPathXmlApplicationContext("invalidPatternMatchingFileListFilterTests.xml", this.getClass()); + } + +} diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PollableFileSourceIntegrationTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PollableFileSourceIntegrationTests-context.xml index b834a26b15..6a4896bd93 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PollableFileSourceIntegrationTests-context.xml +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/PollableFileSourceIntegrationTests-context.xml @@ -1,21 +1,25 @@ - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:p="http://www.springframework.org/schema/p" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + - - + p:filter-ref="compositeFilter"/> + + + - - + + - + + + \ No newline at end of file diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileFilter.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileListFilter.java similarity index 93% rename from org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileFilter.java rename to org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileListFilter.java index 41b1ec106b..88d4ad9d24 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileFilter.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/TestFileListFilter.java @@ -23,7 +23,7 @@ import java.util.List; /** * @author Iwein Fuld */ -public class TestFileFilter implements FileListFilter { +public class TestFileListFilter implements FileListFilter { public List filterFiles(File[] files) { return Arrays.asList(files); diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests-context.xml index f9f61c70b1..982bf5f873 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests-context.xml +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests-context.xml @@ -1,6 +1,7 @@ + - + + - + + + \ No newline at end of file diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests.java index 72b4bf77b7..d43918093e 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterParserTests.java @@ -27,7 +27,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.channel.MessageChannel; -import org.springframework.integration.file.CompositeFileFilter; +import org.springframework.integration.file.CompositeFileListFilter; import org.springframework.integration.file.PollableFileSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -63,7 +63,7 @@ public class FileInboundChannelAdapterParserTests { @Test public void filter() throws Exception { - assertTrue("'filter' should be set", accessor.getPropertyValue("filter") instanceof CompositeFileFilter); + assertTrue("'filter' should be set", accessor.getPropertyValue("filter") instanceof CompositeFileListFilter); } } diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/invalidPatternMatchingFileListFilterTests.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/invalidPatternMatchingFileListFilterTests.xml new file mode 100644 index 0000000000..3401588dcd --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/invalidPatternMatchingFileListFilterTests.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/patternMatchingFileListFilterTests.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/patternMatchingFileListFilterTests.xml new file mode 100644 index 0000000000..ddd5f8f965 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/patternMatchingFileListFilterTests.xml @@ -0,0 +1,11 @@ + + + + + + + +