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.

This commit is contained in:
Mark Fisher
2008-09-22 00:16:13 +00:00
parent 28c7bfc4e7
commit 8ea683b715
17 changed files with 345 additions and 84 deletions

View File

@@ -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<File> filterFiles(File[] files) {
List<File> accepted = new ArrayList<File>();
for (File file : files) {
if (this.accept(file)) {
accepted.add(file);
}
}
return accepted;
}
/**
* Subclasses must implement this method.
*/
protected abstract boolean accept(File file);
}

View File

@@ -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<File> 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<File>(maxCapacity);
}
/**
* Creates an AcceptOnceFileFilter based on an unbounded queue.
*/
public AcceptOnceFileFilter() {
public AcceptOnceFileListFilter() {
this.seen = new LinkedBlockingQueue<File>();
}
/**
* Returns the list of files that have not already been filtered by this
* instance.
*/
public List<File> filterFiles(File[] files) {
List<File> accepted = new ArrayList<File>();
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;
}

View File

@@ -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<FileListFilter> fileFilters;
public CompositeFileFilter(FileListFilter... fileFilters) {
public CompositeFileListFilter(FileListFilter... fileFilters) {
this.fileFilters = new HashSet<FileListFilter>(Arrays.asList(fileFilters));
}
public CompositeFileFilter(Collection<FileListFilter> fileFilters) {
public CompositeFileListFilter(Collection<FileListFilter> fileFilters) {
this.fileFilters = new HashSet<FileListFilter>(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<FileListFilter> filtersToAdd) {
public CompositeFileListFilter addFilters(Collection<FileListFilter> filtersToAdd) {
HashSet<FileListFilter> newFilterSet = new HashSet<FileListFilter>(filtersToAdd);
newFilterSet.addAll(fileFilters);
return new CompositeFileFilter(newFilterSet);
return new CompositeFileListFilter(newFilterSet);
}
}

View File

@@ -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<File> filterFiles(File[] files);

View File

@@ -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();
}
}

View File

@@ -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.
* <p>
* 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<File>, MessageDelivery
private final Queue<File> toBeReceived = new PriorityBlockingQueue<File>();
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<File>, 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 <p/>
* {@link CompositeFileListFilter} can be used to group them together <p/>
* <b>Note that the supplied filter must be thread safe</b>.
*/
public void setFilter(FileListFilter filter) {

View File

@@ -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 &lt;inbound-channel-adapter&gt; 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());
}

View File

@@ -32,6 +32,7 @@
<xsd:attribute name="directory" type="xsd:string"/>
<xsd:attribute name="channel" type="xsd:string"/>
<xsd:attribute name="filter" type="xsd:string"/>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
</xsd:complexType>
</xsd:element>

View File

@@ -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<T> extends AbstractPayloadTransformer<File, T> {
public abstract class AbstractFilePayloadTransformer<T> 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);
}
}
/**

View File

@@ -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<File> 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<File> 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<File>()).times(1);
expect(fileFilterMock1.filterFiles(isA(File[].class))).andReturn(new ArrayList<File>()).times(1);
replay(fileFilterMock1, fileFilterMock2);

View File

@@ -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<File> 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<File> 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<File> 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<File> accepted = filter.filterFiles(files);
assertEquals(1, accepted.size());
}
@Test(expected = BeanCreationException.class)
public void invalidPatternSyntax() throws Throwable {
new ClassPathXmlApplicationContext("invalidPatternMatchingFileListFilterTests.xml", this.getClass());
}
}

View File

@@ -1,21 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!-- under test -->
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">
<!-- under test -->
<bean id="pollableFileSource" class="org.springframework.integration.file.PollableFileSource"
p:inputDirectory="file:${java.io.tmpdir}/PollableFileSourceIntegrationTests"
p:filter-ref="compositeFilter" />
<!-- customized filter -->
<bean id="compositeFilter"
class="org.springframework.integration.file.CompositeFileFilter">
p:filter-ref="compositeFilter"/>
<!-- customized filter -->
<bean id="compositeFilter" class="org.springframework.integration.file.CompositeFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.AcceptOnceFileFilter" />
<bean class="org.springframework.integration.file.TestFileFilter" />
<bean class="org.springframework.integration.file.AcceptOnceFileListFilter" />
<bean class="org.springframework.integration.file.TestFileListFilter" />
</list>
</constructor-arg>
</bean>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
</beans>

View File

@@ -23,7 +23,7 @@ import java.util.List;
/**
* @author Iwein Fuld
*/
public class TestFileFilter implements FileListFilter {
public class TestFileListFilter implements FileListFilter {
public List<File> filterFiles(File[] files) {
return Arrays.asList(files);

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration/file"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:integration="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
@@ -8,14 +9,16 @@
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd">
<inbound-channel-adapter id="inputDirPoller"
directory="file:${java.io.tmpdir}" filter="filter" />
<beans:bean id="filter"
class="org.springframework.integration.file.CompositeFileFilter">
<beans:bean id="filter" class="org.springframework.integration.file.CompositeFileListFilter">
<beans:constructor-arg>
<beans:list></beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
</beans:beans>

View File

@@ -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);
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="filter" class="org.springframework.integration.file.PatternMatchingFileListFilter">
<constructor-arg value="[fo+\.[tx]{3}"/>
</bean>
</beans>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="filter" class="org.springframework.integration.file.PatternMatchingFileListFilter">
<constructor-arg value="fo+\.[tx]{3}"/>
</bean>
</beans>