initial commit of my work to make building filesystem based adapters more consistent, cleaner.
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.file.entries.AcceptAllEntryListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
|
||||
/**
|
||||
* This handles a lot of the common ground in our approach for synchronizing a remote file system locally
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends AbstractEndpoint {
|
||||
/**
|
||||
* Should we <emphasis>delete</emphasis> the <b>source</b> file?
|
||||
* For an FTP server, for example, this would delete the original FTPFile instance
|
||||
* <p/>
|
||||
* At the moment I can simply see this triggering the setting
|
||||
*/
|
||||
protected boolean shouldDeleteSourceFile;
|
||||
|
||||
/**
|
||||
* the directory we're writing our synchronizations to
|
||||
*/
|
||||
protected volatile Resource localDirectory;
|
||||
|
||||
/**
|
||||
* a {@link org.springframework.integration.file.entries.EntryListFilter} that we're running against the <emphasis>remote</emphasis> file system view!
|
||||
*/
|
||||
protected volatile EntryListFilter<T> filter = new AcceptAllEntryListFilter<T>();
|
||||
|
||||
/**
|
||||
* the {@link java.util.concurrent.ScheduledFuture} instance we get when we schedule our {@link AbstractInboundRemoteFileSystemSychronizer.SynchronizeTask}
|
||||
*/
|
||||
protected ScheduledFuture<?> scheduledFuture;
|
||||
|
||||
/**
|
||||
* Used to store the {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy} implementation
|
||||
*/
|
||||
protected EntryAcknowledgmentStrategy<T> entryAcknowledgmentStrategy;
|
||||
|
||||
/**
|
||||
* Obviously thread safe - simply provides a NOOP impl so we don't have to keep dancing around NPE's
|
||||
*/
|
||||
private EntryAcknowledgmentStrategy<T> noOpEntryAcknowledgmentStrategy = new EntryAcknowledgmentStrategy<T>() {
|
||||
public void acknowledge(Object o, T msg) {
|
||||
}
|
||||
};
|
||||
|
||||
public void setEntryAcknowledgmentStrategy(EntryAcknowledgmentStrategy<T> entryAcknowledgmentStrategy) {
|
||||
this.entryAcknowledgmentStrategy = entryAcknowledgmentStrategy;
|
||||
}
|
||||
|
||||
public void setShouldDeleteSourceFile(boolean shouldDeleteSourceFile) {
|
||||
this.shouldDeleteSourceFile = shouldDeleteSourceFile;
|
||||
}
|
||||
|
||||
public void setLocalDirectory(Resource localDirectory) {
|
||||
this.localDirectory = localDirectory;
|
||||
}
|
||||
|
||||
public void setFilter(EntryListFilter<T> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param usefulContextOrClientData
|
||||
* @param t leverages strategy implementations to enable different behavior. It's a hook to the entry ({@link T}) after it's been successfully downloaded.
|
||||
* Conceptually, you might delete the remote one or rename it or something
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected void acknowledge(Object usefulContextOrClientData, T t)
|
||||
throws Throwable {
|
||||
Assert.notNull(this.entryAcknowledgmentStrategy != null, "entryAcknowledgmentStrategy can't be null!");
|
||||
this.entryAcknowledgmentStrategy.acknowledge(usefulContextOrClientData, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the callback where we need the implementation to do some specific work
|
||||
*/
|
||||
protected abstract void syncRemoteToLocalFileSystem()
|
||||
throws Exception ;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected void doStop() {
|
||||
Assert.notNull(this.scheduledFuture, "the 'scheduledFuture' can't be null!");
|
||||
this.scheduledFuture.cancel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in millis dictating how frequently the trigger should fire
|
||||
*
|
||||
* @return a {@link org.springframework.scheduling.Trigger} implementation (likely,
|
||||
* {@link org.springframework.scheduling.support.PeriodicTrigger})
|
||||
*/
|
||||
protected abstract Trigger getTrigger();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected void doStart() {
|
||||
if (this.entryAcknowledgmentStrategy == null) {
|
||||
this.entryAcknowledgmentStrategy = noOpEntryAcknowledgmentStrategy;
|
||||
}
|
||||
|
||||
this.scheduledFuture = this.getTaskScheduler().schedule(new SynchronizeTask(), this.getTrigger());
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface to expose a hook for dispatching, moving, or deleting the file once it's been delivered
|
||||
*
|
||||
* @author Josh Long
|
||||
* @param <T> the entry type (file, sftp, ftp, ...)
|
||||
*/
|
||||
public static interface EntryAcknowledgmentStrategy<T> {
|
||||
/**
|
||||
* Semantics are simple. You get a pointer to the entry just processed and any kind of helper data you could ask for. Since the strategy is a
|
||||
* singleton and the clients you might ask for as context data are pooled, it's not recommended that you try to cache them.
|
||||
*
|
||||
* @param useful any context data
|
||||
* @param msg the data / file / entry you want to process -- specific to sublcasses
|
||||
* @throws Exception thrown for any old reason
|
||||
*/
|
||||
void acknowledge(Object useful, T msg) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* This {@link Runnable} is launched as a background thread and is used to babysit the
|
||||
* {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer#localDirectory},
|
||||
* queueing and delivering accumulated files as possible.
|
||||
*/
|
||||
class SynchronizeTask implements Runnable {
|
||||
public void run() {
|
||||
try {
|
||||
syncRemoteToLocalFileSystem();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.file.entries.*;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* Ultimately, this factors out a lot of the common logic between the FTP and SFTP adapters
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public abstract class AbstractInboundRemoteFileSystemSynchronizingMessageSource<Y, T extends AbstractInboundRemoteFileSystemSychronizer<Y>> extends AbstractEndpoint implements MessageSource<File> {
|
||||
/**
|
||||
* Extension used when downloading files. We change it right after we know it's downloaded
|
||||
*/
|
||||
public static final String INCOMPLETE_EXTENSION = ".INCOMPLETE";
|
||||
|
||||
/**
|
||||
* Should the endpoint attempt to create the local directory and / or the remote directory?
|
||||
*/
|
||||
protected volatile boolean autoCreateDirectories = true;
|
||||
|
||||
/**
|
||||
* An implementation that will handle the chores of actually syncing up the remote FS
|
||||
*/
|
||||
protected volatile T synchronizer;
|
||||
|
||||
/**
|
||||
* What directory should things be synced to locally ?
|
||||
*/
|
||||
protected volatile Resource localDirectory;
|
||||
|
||||
/**
|
||||
* The actual {@link FileReadingMessageSource} that we continue to trust to do the job monitoring the filesystem once files are moved down
|
||||
*/
|
||||
protected volatile FileReadingMessageSource fileSource;
|
||||
|
||||
/**
|
||||
* The predicate to use in scanning the remote Fs for downloads
|
||||
*/
|
||||
protected EntryListFilter<Y> remotePredicate;
|
||||
|
||||
public void setAutoCreateDirectories(boolean autoCreateDirectories) {
|
||||
this.autoCreateDirectories = autoCreateDirectories;
|
||||
}
|
||||
|
||||
public void setSynchronizer(T synchronizer) {
|
||||
this.synchronizer = synchronizer;
|
||||
}
|
||||
|
||||
public void setLocalDirectory(Resource localDirectory) {
|
||||
this.localDirectory = localDirectory;
|
||||
}
|
||||
|
||||
public void setRemotePredicate(EntryListFilter<Y> remotePredicate) {
|
||||
this.remotePredicate = remotePredicate;
|
||||
}
|
||||
|
||||
private EntryListFilter<File> buildFilter() {
|
||||
FileEntryNamer fileEntryNamer = new FileEntryNamer();
|
||||
Pattern completePattern = Pattern.compile("^.*(?<!" + INCOMPLETE_EXTENSION + ")$");
|
||||
return new CompositeEntryListFilter<File>(new AcceptOnceEntryFileListFilter<File>(), new PatternMatchingEntryListFilter<File>(fileEntryNamer, completePattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
if (this.remotePredicate != null) {
|
||||
this.synchronizer.setFilter(this.remotePredicate);
|
||||
}
|
||||
|
||||
if (this.autoCreateDirectories) {
|
||||
|
||||
|
||||
|
||||
if((this.localDirectory != null) && !this.localDirectory.exists() && this.localDirectory.getFile().mkdirs())
|
||||
logger.debug( "the localDirectory " + this.localDirectory + " doesn't exist");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles making sure the remote files get here in one piece
|
||||
*/
|
||||
this.synchronizer.setLocalDirectory(this.localDirectory);
|
||||
this.synchronizer.setTaskScheduler(this.getTaskScheduler());
|
||||
this.synchronizer.setBeanFactory(this.getBeanFactory());
|
||||
this.synchronizer.setPhase(this.getPhase());
|
||||
this.synchronizer.setBeanName(this.getComponentName());
|
||||
|
||||
/**
|
||||
* Handles forwarding files once they ultimately appear in the {@link #localDirectory}
|
||||
*/
|
||||
this.fileSource = new FileReadingMessageSource();
|
||||
this.fileSource.setFilter(buildFilter());
|
||||
this.fileSource.setDirectory(this.localDirectory.getFile());
|
||||
this.fileSource.afterPropertiesSet();
|
||||
this.synchronizer.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public Message<File> receive() {
|
||||
return this.fileSource.receive();
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Default directory scanner and base class for other directory scanners. It takes care of the default interrelations
|
||||
* between filtering, scanning and locking.
|
||||
@@ -29,16 +32,17 @@ import java.util.List;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DefaultDirectoryScanner implements DirectoryScanner {
|
||||
private FileListFilter filter = new AcceptOnceFileListFilter();
|
||||
private EntryListFilter<File> filter = new AcceptOnceEntryFileListFilter<File>();
|
||||
private FileLocker locker;
|
||||
|
||||
public final List<File> listFiles(File directory) throws IllegalArgumentException {
|
||||
File[] files = listEligibleFiles(directory);
|
||||
|
||||
if (files == null) {
|
||||
throw new MessagingException("The path [" + directory
|
||||
+ "] does not denote a properly accessible directory.");
|
||||
throw new MessagingException("The path [" + directory + "] does not denote a properly accessible directory.");
|
||||
}
|
||||
return this.filter.filterFiles(files);
|
||||
|
||||
return this.filter.filterEntries(files);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,10 +56,7 @@ public class DefaultDirectoryScanner implements DirectoryScanner {
|
||||
return directory.listFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final void setFilter(FileListFilter filter) {
|
||||
public void setFilter(EntryListFilter<File> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ public class DefaultDirectoryScanner implements DirectoryScanner {
|
||||
* This class takes the minimal implementation and merely delegates to the locker if set.
|
||||
*/
|
||||
public final boolean tryClaim(File file) {
|
||||
return locker != null ? locker.lock(file) : true;
|
||||
return (locker == null) || locker.lock(file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,13 +16,15 @@
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Strategy for scanning directories. Implementations may select all children and grandchildren of the scanned directory
|
||||
* in any order. This interface is intended to enable the customization of selection, locking and ordering of files in a
|
||||
* directory like RecursiveDirectoryScanner. If the only requirement is to ignore certain files a FileListFilter
|
||||
* directory like RecursiveDirectoryScanner. If the only requirement is to ignore certain files a EntryListFilter
|
||||
* implementation should suffice.
|
||||
*
|
||||
*
|
||||
@@ -37,6 +39,7 @@ public interface DirectoryScanner {
|
||||
*
|
||||
* @param directory the directory to scan for files
|
||||
* @return a list of files representing the content of the directory
|
||||
* @throws IllegalArgumentException thrown if the input is incorrect
|
||||
*/
|
||||
List<File> listFiles(File directory) throws IllegalArgumentException;
|
||||
|
||||
@@ -47,7 +50,7 @@ public interface DirectoryScanner {
|
||||
*
|
||||
* @param filter the custom filter to be used
|
||||
*/
|
||||
void setFilter(FileListFilter filter);
|
||||
void setFilter(EntryListFilter<File> filter);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,33 +13,38 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.aggregator.ResequencingMessageGroupProcessor;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
|
||||
|
||||
/**
|
||||
* {@link MessageSource} that creates messages from a file system directory. To prevent messages for certain files, you
|
||||
* may supply a {@link FileListFilter}. By default, an {@link AcceptOnceFileListFilter} is used. It ensures files are
|
||||
* may supply a {@link org.springframework.integration.file.filters.FileListFilter}. By default, an {@link org.springframework.integration.file.filters.AcceptOnceFileListFilter} is used. It ensures files are
|
||||
* picked up only once from the directory.
|
||||
* <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
|
||||
* org.springframework.integration.file.filters.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 org.springframework.integration.file.CompositeFileListFilter} for a way to do this.
|
||||
* ready (e.g. based on a known suffix), composed with the default {@link org.springframework.integration.file.filters.AcceptOnceFileListFilter} would allow for
|
||||
* this. See {@link org.springframework.integration.file.filters.CompositeFileListFilter} for a way to do this.
|
||||
* <p/>
|
||||
* A {@link Comparator} can be used to ensure internal ordering of the Files in a {@link PriorityBlockingQueue}. This
|
||||
* does not provide the same guarantees as a {@link ResequencingMessageGroupProcessor}, but in cases where writing files and failure
|
||||
@@ -51,18 +56,11 @@ import java.util.concurrent.PriorityBlockingQueue;
|
||||
* @author Iwein Fuld
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class FileReadingMessageSource implements MessageSource<File>,
|
||||
InitializingBean {
|
||||
|
||||
public class FileReadingMessageSource implements MessageSource<File>, InitializingBean {
|
||||
private static final int DEFAULT_INTERNAL_QUEUE_CAPACITY = 5;
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(FileReadingMessageSource.class);
|
||||
|
||||
private static final Log logger = LogFactory.getLog(FileReadingMessageSource.class);
|
||||
private volatile File directory;
|
||||
|
||||
private volatile DirectoryScanner scanner = new DefaultDirectoryScanner();
|
||||
|
||||
private volatile boolean autoCreateDirectory = true;
|
||||
|
||||
/*
|
||||
@@ -70,7 +68,6 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
* There is no locking around the queue, so there is also no iteration.
|
||||
*/
|
||||
private final Queue<File> toBeReceived;
|
||||
|
||||
private boolean scanEachPoll = false;
|
||||
|
||||
/**
|
||||
@@ -92,7 +89,7 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
*/
|
||||
public FileReadingMessageSource(int internalQueueCapacity) {
|
||||
this(null);
|
||||
Assert.isTrue(internalQueueCapacity>0, "Cannot create a queue with non positive capacity");
|
||||
Assert.isTrue(internalQueueCapacity > 0, "Cannot create a queue with non positive capacity");
|
||||
this.setScanner(new HeadDirectoryScanner(internalQueueCapacity));
|
||||
}
|
||||
|
||||
@@ -108,8 +105,7 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
* @param receptionOrderComparator the comparator to be used to order the files in the internal queue
|
||||
*/
|
||||
public FileReadingMessageSource(Comparator<File> receptionOrderComparator) {
|
||||
toBeReceived = new PriorityBlockingQueue<File>(DEFAULT_INTERNAL_QUEUE_CAPACITY,
|
||||
receptionOrderComparator);
|
||||
toBeReceived = new PriorityBlockingQueue<File>(DEFAULT_INTERNAL_QUEUE_CAPACITY, receptionOrderComparator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,13 +133,13 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link FileListFilter}. By default a {@link AcceptOnceFileListFilter} with no bounds is used. In most
|
||||
* cases a customized {@link FileListFilter} will be needed to deal with modification and duplication concerns. If
|
||||
* multiple filters are required a {@link CompositeFileListFilter} can be used to group them together.
|
||||
* Sets a {@link org.springframework.integration.file.filters.FileListFilter}. By default a {@link org.springframework.integration.file.filters.AcceptOnceFileListFilter} with no bounds is used. In most
|
||||
* cases a customized {@link org.springframework.integration.file.filters.FileListFilter} will be needed to deal with modification and duplication concerns. If
|
||||
* multiple filters are required a {@link org.springframework.integration.file.filters.CompositeFileListFilter} can be used to group them together.
|
||||
* <p/>
|
||||
* <b>The supplied filter must be thread safe.</b>.
|
||||
*/
|
||||
public void setFilter(FileListFilter filter) {
|
||||
public void setFilter(EntryListFilter<File> filter) {
|
||||
Assert.notNull(filter, "'filter' must not be null");
|
||||
this.scanner.setFilter(filter);
|
||||
}
|
||||
@@ -175,43 +171,50 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
|
||||
public final void afterPropertiesSet() {
|
||||
Assert.notNull(directory, "'directory' must not be set before initialization");
|
||||
|
||||
if (!this.directory.exists() && this.autoCreateDirectory) {
|
||||
this.directory.mkdirs();
|
||||
}
|
||||
Assert.isTrue(this.directory.exists(), "Source directory ["
|
||||
+ directory + "] does not exist.");
|
||||
Assert.isTrue(this.directory.isDirectory(), "Source path ["
|
||||
+ this.directory + "] does not point to a directory.");
|
||||
Assert.isTrue(this.directory.canRead(), "Source directory ["
|
||||
+ this.directory + "] is not readable.");
|
||||
|
||||
Assert.isTrue(this.directory.exists(), "Source directory [" + directory + "] does not exist.");
|
||||
Assert.isTrue(this.directory.isDirectory(), "Source path [" + this.directory + "] does not point to a directory.");
|
||||
Assert.isTrue(this.directory.canRead(), "Source directory [" + this.directory + "] is not readable.");
|
||||
}
|
||||
|
||||
public Message<File> receive() throws MessagingException {
|
||||
Message<File> message = null;
|
||||
|
||||
// rescan only if needed or explicitly configured
|
||||
if (scanEachPoll || toBeReceived.isEmpty()) {
|
||||
scanInputDirectory();
|
||||
}
|
||||
|
||||
File file = toBeReceived.poll();
|
||||
|
||||
// file == null means the queue was empty
|
||||
// we can't rely on isEmpty for concurrency reasons
|
||||
while (file != null && !scanner.tryClaim(file)) {
|
||||
while ((file != null) && !scanner.tryClaim(file)) {
|
||||
file = toBeReceived.poll();
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
message = MessageBuilder.withPayload(file).build();
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Created message: [" + message + "]");
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private void scanInputDirectory() {
|
||||
List<File> filteredFiles = scanner.listFiles(directory);
|
||||
Set<File> freshFiles = new HashSet<File>(filteredFiles);
|
||||
|
||||
if (!freshFiles.isEmpty()) {
|
||||
toBeReceived.addAll(freshFiles);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added to queue: " + freshFiles);
|
||||
}
|
||||
@@ -225,6 +228,7 @@ public class FileReadingMessageSource implements MessageSource<File>,
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to send: " + failedMessage);
|
||||
}
|
||||
|
||||
toBeReceived.offer(failedMessage.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* A custom scanner that only returns the first <code>maxNumberOfFiles</code> elements from a directory listing. This is
|
||||
* useful to limit the number of File objects in memory and therefore mutually exclusive with AcceptOnceFileListFilter.
|
||||
@@ -28,19 +31,18 @@ import java.util.List;
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class HeadDirectoryScanner extends DefaultDirectoryScanner {
|
||||
|
||||
public HeadDirectoryScanner(int maxNumberOfFiles) {
|
||||
this.setFilter(new HeadFilter(maxNumberOfFiles));
|
||||
}
|
||||
|
||||
private class HeadFilter implements FileListFilter {
|
||||
private class HeadFilter implements EntryListFilter<File> {
|
||||
private final int maxNumberOfFiles;
|
||||
|
||||
public HeadFilter(int maxNumberOfFiles) {
|
||||
this.maxNumberOfFiles = maxNumberOfFiles;
|
||||
}
|
||||
|
||||
public List<File> filterFiles(File[] files) {
|
||||
public List<File> filterEntries(File[] files) {
|
||||
return Arrays.asList(files).subList(0, Math.min(files.length, maxNumberOfFiles));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,110 +13,114 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.config;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import org.springframework.integration.file.entries.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.integration.file.AbstractFileListFilter;
|
||||
import org.springframework.integration.file.AcceptOnceFileListFilter;
|
||||
import org.springframework.integration.file.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.FileListFilter;
|
||||
import org.springframework.integration.file.PatternMatchingFileListFilter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public class FileListFilterFactoryBean implements FactoryBean<FileListFilter> {
|
||||
public class FileListFilterFactoryBean implements FactoryBean<EntryListFilter<File>> {
|
||||
private volatile EntryListFilter<File> fileListFilter;
|
||||
private volatile EntryListFilter<File> filterReference;
|
||||
private volatile Pattern filenamePattern;
|
||||
private volatile Boolean preventDuplicates;
|
||||
private final Object monitor = new Object();
|
||||
private volatile Collection<EntryListFilter<File>> filterReferences;
|
||||
private FileEntryNamer fileNamer = new FileEntryNamer();
|
||||
|
||||
private volatile FileListFilter fileListFilter;
|
||||
public void setFilterReferences(Collection<EntryListFilter<File>> filterReferences) {
|
||||
this.filterReferences = filterReferences;
|
||||
}
|
||||
|
||||
private volatile FileListFilter filterReference;
|
||||
public void setFilterReference(EntryListFilter<File> filterReference) {
|
||||
this.filterReference = filterReference;
|
||||
}
|
||||
|
||||
private volatile Pattern filenamePattern;
|
||||
public void setFilenamePattern(Pattern filenamePattern) {
|
||||
this.filenamePattern = filenamePattern;
|
||||
}
|
||||
|
||||
private volatile Boolean preventDuplicates;
|
||||
public void setPreventDuplicates(Boolean preventDuplicates) {
|
||||
this.preventDuplicates = preventDuplicates;
|
||||
}
|
||||
|
||||
private final Object monitor = new Object();
|
||||
public EntryListFilter<File> getObject() throws Exception {
|
||||
if (this.fileListFilter == null) {
|
||||
synchronized (this.monitor) {
|
||||
this.intializeFileListFilter();
|
||||
}
|
||||
}
|
||||
|
||||
return this.fileListFilter;
|
||||
}
|
||||
|
||||
public void setFilterReference(FileListFilter filterReference) {
|
||||
this.filterReference = filterReference;
|
||||
}
|
||||
public Class<?> getObjectType() {
|
||||
return (this.fileListFilter != null) ? this.fileListFilter.getClass() : EntryListFilter.class;
|
||||
}
|
||||
|
||||
public void setFilenamePattern(Pattern filenamePattern) {
|
||||
this.filenamePattern = filenamePattern;
|
||||
}
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setPreventDuplicates(Boolean preventDuplicates) {
|
||||
this.preventDuplicates = preventDuplicates;
|
||||
}
|
||||
private void intializeFileListFilter() {
|
||||
if (this.fileListFilter != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
public FileListFilter getObject() throws Exception {
|
||||
if (this.fileListFilter == null) {
|
||||
synchronized (this.monitor) {
|
||||
this.intializeFileListFilter();
|
||||
}
|
||||
}
|
||||
return this.fileListFilter;
|
||||
}
|
||||
EntryListFilter<File> flf=null;
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return (this.fileListFilter != null)
|
||||
? this.fileListFilter.getClass() : FileListFilter.class;
|
||||
}
|
||||
if ((this.filterReference != null) && (this.filenamePattern != null)) {
|
||||
throw new IllegalArgumentException("The 'filter' reference and " + "'filename-pattern' attributes are mutually exclusive.");
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
if (this.filterReference != null) {
|
||||
if (Boolean.TRUE.equals(this.preventDuplicates)) {
|
||||
flf = this.createCompositeWithAcceptOnceFilter(this.filterReference);
|
||||
} else { // preventDuplicates is either FALSE or NULL
|
||||
flf = this.filterReference;
|
||||
}
|
||||
} else if (this.filenamePattern != null) {
|
||||
PatternMatchingEntryListFilter<File> patternFilter = new PatternMatchingEntryListFilter<File>(fileNamer, this.filenamePattern);
|
||||
|
||||
private void intializeFileListFilter() {
|
||||
if (this.fileListFilter != null) {
|
||||
return;
|
||||
}
|
||||
FileListFilter flf = null;
|
||||
if (this.filterReference != null && this.filenamePattern != null) {
|
||||
throw new IllegalArgumentException("The 'filter' reference and " +
|
||||
"'filename-pattern' attributes are mutually exclusive.");
|
||||
}
|
||||
if (this.filterReference != null) {
|
||||
if (Boolean.TRUE.equals(this.preventDuplicates)) {
|
||||
flf = this.createCompositeWithAcceptOnceFilter(this.filterReference);
|
||||
}
|
||||
else { // preventDuplicates is either FALSE or NULL
|
||||
flf = this.filterReference;
|
||||
}
|
||||
}
|
||||
else if (this.filenamePattern != null) {
|
||||
PatternMatchingFileListFilter patternFilter = new PatternMatchingFileListFilter(this.filenamePattern);
|
||||
if (Boolean.FALSE.equals(this.preventDuplicates)) {
|
||||
flf = patternFilter;
|
||||
}
|
||||
else { // preventDuplicates is either TRUE or NULL
|
||||
flf = this.createCompositeWithAcceptOnceFilter(patternFilter);
|
||||
}
|
||||
}
|
||||
else if (Boolean.FALSE.equals(this.preventDuplicates)) {
|
||||
flf = new AbstractFileListFilter() {
|
||||
@Override
|
||||
protected boolean accept(File file) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
else { // preventDuplicates is either TRUE or NULL
|
||||
flf = new AcceptOnceFileListFilter();
|
||||
}
|
||||
this.fileListFilter = flf;
|
||||
}
|
||||
if (Boolean.FALSE.equals(this.preventDuplicates)) {
|
||||
flf = patternFilter;
|
||||
} else { // preventDuplicates is either TRUE or NULL
|
||||
flf = this.createCompositeWithAcceptOnceFilter(patternFilter);
|
||||
}
|
||||
} else if (Boolean.FALSE.equals(this.preventDuplicates)) {
|
||||
flf = new AcceptAllEntryListFilter<File>();
|
||||
} else { // preventDuplicates is either TRUE or NULL
|
||||
flf = new AcceptOnceEntryFileListFilter<File>();
|
||||
}
|
||||
|
||||
private FileListFilter createCompositeWithAcceptOnceFilter(FileListFilter otherFilter) {
|
||||
CompositeFileListFilter compositeFilter = new CompositeFileListFilter();
|
||||
compositeFilter.addFilter(new AcceptOnceFileListFilter(), otherFilter);
|
||||
return compositeFilter;
|
||||
}
|
||||
// finally, it might be that they simply want a {@link CompositeEntryListFilter}
|
||||
if ((this.filterReferences != null) && (this.filterReferences.size() > 0) ) {
|
||||
CompositeEntryListFilter<File> flfc = new CompositeEntryListFilter<File>();
|
||||
|
||||
for (EntryListFilter<File> ff : filterReferences)
|
||||
flfc.addFilter(ff);
|
||||
|
||||
flf = flfc;
|
||||
}
|
||||
if( flf== null)flf =new CompositeEntryListFilter<File>();
|
||||
|
||||
this.fileListFilter = flf;
|
||||
}
|
||||
|
||||
private CompositeEntryListFilter<File> createCompositeWithAcceptOnceFilter(EntryListFilter<File> otherFilter) {
|
||||
CompositeEntryListFilter<File> compositeFilter = new CompositeEntryListFilter<File>();
|
||||
compositeFilter.addFilter(new AcceptOnceEntryFileListFilter<File>(), otherFilter);
|
||||
|
||||
return compositeFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ package org.springframework.integration.file.config;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.integration.file.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.DirectoryScanner;
|
||||
import org.springframework.integration.file.FileListFilter;
|
||||
import org.springframework.integration.file.FileReadingMessageSource;
|
||||
import org.springframework.integration.file.entries.CompositeEntryListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
import org.springframework.integration.file.locking.AbstractFileLockerFilter;
|
||||
|
||||
import java.io.File;
|
||||
@@ -41,7 +41,7 @@ public class FileReadingMessageSourceFactoryBean implements FactoryBean<FileRead
|
||||
|
||||
private volatile File directory;
|
||||
|
||||
private volatile FileListFilter filter;
|
||||
private volatile EntryListFilter<File> filter;
|
||||
|
||||
private volatile AbstractFileLockerFilter locker;
|
||||
|
||||
@@ -69,7 +69,7 @@ public class FileReadingMessageSourceFactoryBean implements FactoryBean<FileRead
|
||||
this.scanner = scanner;
|
||||
}
|
||||
|
||||
public void setFilter(FileListFilter filter) {
|
||||
public void setFilter(EntryListFilter<File> filter) {
|
||||
if (filter instanceof AbstractFileLockerFilter && this.locker == null) {
|
||||
this.setLocker((AbstractFileLockerFilter) filter);
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class FileReadingMessageSourceFactoryBean implements FactoryBean<FileRead
|
||||
if (this.locker == null) {
|
||||
this.source.setFilter(this.filter);
|
||||
} else {
|
||||
this.source.setFilter(new CompositeFileListFilter(this.filter, this.locker));
|
||||
this.source.setFilter(new CompositeEntryListFilter<File>(this.filter, this.locker));
|
||||
this.source.setLocker(locker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.entries;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class AbstractEntryListFilter<T> implements EntryListFilter<T> {
|
||||
|
||||
protected abstract boolean accept(T t);
|
||||
/**
|
||||
* A convenience base class for any {@link EntryListFilter} whose criteria can be
|
||||
* evaluated against each File in isolation. If the entire List of files is
|
||||
* required for evaluation, implement the {@link EntryListFilter} interface directly.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Iwein Fuld
|
||||
* @author Josh Long
|
||||
*/
|
||||
public abstract class AbstractEntryListFilter<T> implements InitializingBean, EntryListFilter<T> {
|
||||
public abstract boolean accept(T t);
|
||||
|
||||
public List<T> filterEntries(T[] entries) {
|
||||
List<T> accepted = new ArrayList<T>();
|
||||
@@ -37,4 +47,8 @@ public abstract class AbstractEntryListFilter<T> implements EntryListFilter<T> {
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// its all you!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.entries;
|
||||
|
||||
|
||||
/**
|
||||
* Simple NOOP implementation for {@link org.springframework.integration.file.entries.EntryListFilter} implementation.
|
||||
* Suitable as a default in implementations.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @param <T>
|
||||
*/
|
||||
public class AcceptAllEntryListFilter<T> extends AbstractEntryListFilter<T> {
|
||||
@Override
|
||||
public boolean accept(T t) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -13,20 +13,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.entries;
|
||||
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@link EntryListFilter} that passes files only one time. This can
|
||||
* conveniently be used to prevent duplication of files, as is done in
|
||||
* {@link org.springframework.integration.file.FileReadingMessageSource}.
|
||||
* <p/>
|
||||
* This implementation is thread safe.
|
||||
*
|
||||
* @author Iwein Fuld
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AcceptOnceEntryFileListFilter<T> extends AbstractEntryListFilter<T> {
|
||||
private final Queue<T> seen;
|
||||
private final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* Creates an AcceptOnceFileFilter that is based on a bounded queue. If the
|
||||
* Creates an {@link org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter} that is based on a bounded queue. If the
|
||||
* queue overflows, files that fall out will be passed through this filter
|
||||
* again if passed to the {@link #filterEntries(Object[])} method.
|
||||
*
|
||||
@@ -44,7 +53,7 @@ public class AcceptOnceEntryFileListFilter<T> extends AbstractEntryListFilter<T>
|
||||
this.seen = new LinkedBlockingQueue<T>();
|
||||
}
|
||||
|
||||
protected boolean accept(T pathname) {
|
||||
public boolean accept(T pathname) {
|
||||
synchronized (this.monitor) {
|
||||
if (seen.contains(pathname)) {
|
||||
return false;
|
||||
|
||||
@@ -13,32 +13,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.entries;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class CompositeEntryListFilter<T> implements EntryListFilter<T> {
|
||||
private final Set<EntryListFilter> fileFilters;
|
||||
private final Set<EntryListFilter<T>> fileFilters;
|
||||
|
||||
public CompositeEntryListFilter(EntryListFilter... fileFilters) {
|
||||
this.fileFilters = new LinkedHashSet<EntryListFilter>(Arrays.asList(fileFilters));
|
||||
public CompositeEntryListFilter(EntryListFilter<T>... fileFilters) {
|
||||
this.fileFilters = new LinkedHashSet<EntryListFilter<T>>(Arrays.asList(fileFilters));
|
||||
}
|
||||
|
||||
public CompositeEntryListFilter(Collection<EntryListFilter> fileFilters) {
|
||||
this.fileFilters = new LinkedHashSet<EntryListFilter>(fileFilters);
|
||||
public CompositeEntryListFilter(Collection<? extends EntryListFilter<T>> fileFilters) {
|
||||
this.fileFilters = new LinkedHashSet<EntryListFilter<T>>(fileFilters);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> filterEntries(T[] entries) {
|
||||
Assert.notNull(entries, "'files' should not be null");
|
||||
List<T> leftOver = Arrays.asList(entries);
|
||||
for (EntryListFilter fileFilter : this.fileFilters) {
|
||||
T[] ts =(T[]) leftOver.toArray();
|
||||
|
||||
List<T> leftOver = Arrays.asList(entries);
|
||||
|
||||
for (EntryListFilter<T> fileFilter : this.fileFilters) {
|
||||
T[] ts = (T[]) leftOver.toArray();
|
||||
leftOver = fileFilter.filterEntries(ts);
|
||||
}
|
||||
|
||||
return leftOver;
|
||||
}
|
||||
|
||||
@@ -47,7 +52,7 @@ public class CompositeEntryListFilter<T> implements EntryListFilter<T> {
|
||||
* @return this CompositeFileFilter instance with the added filters
|
||||
* @see #addFilters(Collection)
|
||||
*/
|
||||
public CompositeEntryListFilter addFilter(EntryListFilter... filters) {
|
||||
public CompositeEntryListFilter addFilter(EntryListFilter<T>... filters) {
|
||||
return addFilters(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
@@ -59,7 +64,16 @@ public class CompositeEntryListFilter<T> implements EntryListFilter<T> {
|
||||
* @param filtersToAdd a list of filters to add
|
||||
* @return this CompositeEntryListFilter instance with the added filters
|
||||
*/
|
||||
public CompositeEntryListFilter addFilters(Collection<EntryListFilter> filtersToAdd) {
|
||||
public CompositeEntryListFilter addFilters(Collection<EntryListFilter<T>> filtersToAdd) {
|
||||
for (EntryListFilter<T> elf : filtersToAdd)
|
||||
if (elf instanceof InitializingBean) {
|
||||
try {
|
||||
((InitializingBean) elf).afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
this.fileFilters.addAll(filtersToAdd);
|
||||
|
||||
return this;
|
||||
|
||||
@@ -18,6 +18,19 @@ package org.springframework.integration.file.entries;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface EntryListFilter <T> {
|
||||
List<T> filterEntries(T [] entries );
|
||||
/**
|
||||
* Strategy interface for filtering a group of entries / files.
|
||||
* <p/>
|
||||
* {@link EntryListFilter} that passes file entries only one time. This can
|
||||
* conveniently be used to prevent duplication of files, as is done in
|
||||
* {@link org.springframework.integration.file.FileReadingMessageSource}.
|
||||
* <p/>
|
||||
* This implementation is thread safe.
|
||||
*
|
||||
* @author Iwein Fuld
|
||||
* @author Josh Long
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface EntryListFilter<T> {
|
||||
List<T> filterEntries(T[] entries);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,21 @@
|
||||
*/
|
||||
package org.springframework.integration.file.entries;
|
||||
|
||||
/**
|
||||
* Responsible for coercing a String identification out of the {@link T} entry.
|
||||
* @param <T> the type of entry (there's an implementation for FTP, SFTP, and plain-old java.io.Files)
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public interface EntryNamer<T> {
|
||||
|
||||
/**
|
||||
* This is the one place I couldn't spackle over the interface differences between an FTPFile (FTP adapter), File (File adapter), and LsEntry (SFTP adapter)
|
||||
* with generics alone. So we have a typed strategy implementation for accessing a property ....
|
||||
*
|
||||
*
|
||||
* @param entry the entry in a file system listing
|
||||
* @return the String name that might be used to reference that entry or to do regular expression checks against
|
||||
*/
|
||||
String nameOf(T entry);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.entries;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* {@link java.io.File} implementation of the {@link org.springframework.integration.file.entries.EntryNamer} strategy.
|
||||
*
|
||||
* This part feels a little over-engineered...
|
||||
*
|
||||
* @author Josh Long
|
||||
*
|
||||
*/
|
||||
public class FileEntryNamer implements EntryNamer<File> {
|
||||
public String nameOf(File entry) {
|
||||
return (entry != null) ? entry.getName() : null;
|
||||
}
|
||||
}
|
||||
@@ -24,16 +24,29 @@ import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* experimental
|
||||
* <emphasis>experimental</emphasis>
|
||||
* <p/>
|
||||
* Filters a listing of entries (T) by qualifying their 'name' (as determined by {@link org.springframework.integration.file.entries.EntryNamer})
|
||||
* against a regular expression (an instance of {@link java.util.regex.Pattern})
|
||||
*
|
||||
* @author Josh Long
|
||||
* @param <T> the type of entry
|
||||
*/
|
||||
public abstract class PatternMatchingEntryListFilter<T> extends AbstractEntryListFilter<T> implements InitializingBean {
|
||||
public class PatternMatchingEntryListFilter<T> extends AbstractEntryListFilter<T> implements InitializingBean {
|
||||
private Pattern pattern;
|
||||
private String patternExpression;
|
||||
private EntryNamer<T> entryNamer;
|
||||
|
||||
public PatternMatchingEntryListFilter(EntryNamer<T> en, String p) {
|
||||
this.entryNamer = en;
|
||||
this.patternExpression = p;
|
||||
}
|
||||
|
||||
public PatternMatchingEntryListFilter(EntryNamer<T> en, Pattern p) {
|
||||
this.entryNamer = en;
|
||||
this.pattern = p;
|
||||
}
|
||||
|
||||
public void setPattern(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
@@ -46,13 +59,12 @@ public abstract class PatternMatchingEntryListFilter<T> extends AbstractEntryLis
|
||||
if (StringUtils.hasText(this.patternExpression) && (pattern == null)) {
|
||||
this.pattern = Pattern.compile(this.patternExpression);
|
||||
}
|
||||
|
||||
Assert.notNull(this.entryNamer,"'entryNamer' must not be null!");
|
||||
Assert.notNull(this.entryNamer, "'entryNamer' must not be null!");
|
||||
Assert.notNull(this.pattern, "'pattern' mustn't be null!");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean accept(T t) {
|
||||
public boolean accept(T t) {
|
||||
return (t != null) && this.pattern.matcher(this.entryNamer.nameOf(t)).matches();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.entries;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* this simply takes an {@link org.springframework.integration.file.entries.EntryListFilter}
|
||||
* and produces an object that can field just <b>one</b> argument instea of an array
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class SingleEntryAdaptingEntryListFilter<T> extends AbstractEntryListFilter<T> {
|
||||
|
||||
/**
|
||||
* the {@link org.springframework.integration.file.entries.EntryListFilter} that you'd like to delegate to
|
||||
*/
|
||||
private volatile EntryListFilter<T> entryFilter;
|
||||
|
||||
public SingleEntryAdaptingEntryListFilter(EntryListFilter<T> ef) {
|
||||
this.entryFilter = ef;
|
||||
Assert.notNull(this.entryFilter, "the entryFilter can't be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean accept(T t) {
|
||||
T[] ts = (T[]) new Object[] { t };
|
||||
return this.entryFilter.filterEntries(ts).size() == 1;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
package org.springframework.integration.file.filters;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
package org.springframework.integration.file.filters;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Queue;
|
||||
@@ -23,13 +23,13 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
/**
|
||||
* {@link FileListFilter} that passes files only one time. This can
|
||||
* conveniently be used to prevent duplication of files, as is done in
|
||||
* {@link FileReadingMessageSource}.
|
||||
* {@link org.springframework.integration.file.FileReadingMessageSource}.
|
||||
* <p/>
|
||||
* This implementation is thread safe.
|
||||
*
|
||||
* @author Iwein Fuld
|
||||
* @since 1.0.0
|
||||
*/
|
||||
*/ @Deprecated
|
||||
public class AcceptOnceFileListFilter extends AbstractFileListFilter {
|
||||
|
||||
private final Queue<File> seen;
|
||||
@@ -13,8 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.file.filters;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -22,13 +24,14 @@ import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Composition that delegates to multiple {@link FileFilter}s. The composition is AND based, meaning that a file must
|
||||
* pass through each filter's {@link #filterFiles(java.io.File[])} method in order to be accepted by the composite.
|
||||
*
|
||||
* @author Iwein Fuld
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
*/ @Deprecated
|
||||
public class CompositeFileListFilter implements FileListFilter {
|
||||
|
||||
private final Set<FileListFilter> fileFilters;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
package org.springframework.integration.file.filters;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
* Strategy interface for filtering a group of files.
|
||||
*
|
||||
* @author Iwein Fuld
|
||||
*/
|
||||
*/ @Deprecated
|
||||
public interface FileListFilter {
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file;
|
||||
package org.springframework.integration.file.filters;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -26,6 +26,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@Deprecated
|
||||
public class PatternMatchingFileListFilter extends AbstractFileListFilter {
|
||||
|
||||
private final Pattern pattern;
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package org.springframework.integration.file.locking;
|
||||
|
||||
import org.springframework.integration.file.AbstractFileListFilter;
|
||||
import org.springframework.integration.file.FileLocker;
|
||||
import org.springframework.integration.file.entries.AbstractEntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -29,9 +29,10 @@ import java.io.File;
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractFileLockerFilter extends AbstractFileListFilter implements FileLocker {
|
||||
public abstract class AbstractFileLockerFilter extends AbstractEntryListFilter<File> implements FileLocker {
|
||||
|
||||
protected final boolean accept(File file) {
|
||||
return isLockable(file);
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return this.isLockable(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
package org.springframework.integration.file.monitors;
|
||||
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.integration.file.entries.*;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
|
||||
/**
|
||||
* This component will support event-based (not poller based) notifications of files from a file system.
|
||||
* Immediate implementations will center around supporting other adapters's delivery of files once they've been synced from a remote system.
|
||||
* Potential future expansions for consumer consumption might be a push / event-based file adapter based on either native code
|
||||
* or Java 7's NIO.2 WaterService or other third party implementations.
|
||||
* <p/>
|
||||
* In the meantime, this provides us with a base class for building event driven file adapters quickly. The two cases I see are:
|
||||
* <p/>
|
||||
* <ol>
|
||||
* <li></li>
|
||||
* <li></li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public abstract class AbstractEventDrivenFileMonitor extends IntegrationObjectSupport implements EventDrivenDirectoryMonitor {
|
||||
/**
|
||||
* when this component starts up, we can perform a scan of the folder this first time and to pre-seed the #additions queue
|
||||
*/
|
||||
private boolean scanDirectoryOnLoad;
|
||||
|
||||
/**
|
||||
* How many files we'll support in the backlog at a time
|
||||
*/
|
||||
private volatile int maxQueueSize = 100;
|
||||
|
||||
/**
|
||||
* the backlog
|
||||
*/
|
||||
private volatile LinkedBlockingQueue<File> additions;
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} implementation. Default is {@link org.springframework.core.task.SimpleAsyncTaskExecutor}
|
||||
*/
|
||||
private volatile Executor executor;
|
||||
|
||||
/**
|
||||
* Should the director be automatically created?
|
||||
*/
|
||||
private volatile boolean autoCreateDirectory;
|
||||
|
||||
/**
|
||||
* The directory to monitor (a {@link java.io.File})
|
||||
*/
|
||||
private volatile File directoryToMonitorCached;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.integration.file.entries.EntryListFilter} reference
|
||||
*/
|
||||
private volatile SingleEntryAdaptingEntryListFilter<File> filter;
|
||||
|
||||
/**
|
||||
* state guard (extra for post-init state)
|
||||
*/
|
||||
private final Object guard = new Object();
|
||||
|
||||
public void setScanDirectoryOnLoad(boolean scanDirectoryOnLoad) {
|
||||
this.scanDirectoryOnLoad = scanDirectoryOnLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* installs directory, and then kicks of an event pump
|
||||
*
|
||||
* @param directory the directory to start watching from. Unspecified if this implies recursion or not.
|
||||
* @param fileAdditionListener the callback
|
||||
* @throws Exception
|
||||
*/
|
||||
public void monitor(File directory, FileAdditionListener fileAdditionListener)
|
||||
throws Exception {
|
||||
this.installDirectoryIfRequired(directory);
|
||||
this.prescan();
|
||||
this.executor.execute(new FileDeliveryPump(fileAdditionListener));
|
||||
}
|
||||
|
||||
public void setMaxQueueSize(int maxQueueSize) {
|
||||
this.maxQueueSize = maxQueueSize;
|
||||
}
|
||||
|
||||
public void setFilter(EntryListFilter<File> filter) {
|
||||
this.filter = new SingleEntryAdaptingEntryListFilter<File>(filter);
|
||||
}
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public void setAutoCreateDirectory(boolean autoCreateDirectory) {
|
||||
this.autoCreateDirectory = autoCreateDirectory;
|
||||
}
|
||||
|
||||
protected void publishNewFileReceived(String path) {
|
||||
this.publishNewFileReceived(new File(path));
|
||||
}
|
||||
|
||||
protected void publishNewFileReceived(File file) {
|
||||
this.additions.add(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obviously, we're trying to keep away from scanning, but this may be necessary at startup to catch up the backlog
|
||||
*/
|
||||
protected void prescan() {
|
||||
synchronized (this.guard) {
|
||||
if (this.scanDirectoryOnLoad) {
|
||||
for (File f : this.directoryToMonitorCached.listFiles())
|
||||
this.publishNewFileReceived(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ensuring that the directory we're monitroring exists or can be created
|
||||
*
|
||||
* @param directoryToMonitor the directory to monitor
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void installDirectoryIfRequired(File directoryToMonitor)
|
||||
throws Exception {
|
||||
synchronized (this.guard) {
|
||||
this.directoryToMonitorCached = directoryToMonitor;
|
||||
Assert.state(null != this.directoryToMonitorCached, "the directory to monitor can't be null");
|
||||
|
||||
boolean directoryIsReady = this.directoryToMonitorCached.exists();
|
||||
|
||||
if (!directoryIsReady) {
|
||||
if (!directoryToMonitorCached.exists()) {
|
||||
if (this.autoCreateDirectory) {
|
||||
Assert.state(directoryToMonitorCached.mkdirs() && directoryToMonitorCached.exists(),
|
||||
String.format("Couldn't create the directory %s", directoryToMonitorCached.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom initialization hook - override at your discretion
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void start() throws Exception{
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
additions = new LinkedBlockingQueue<File>(this.maxQueueSize);
|
||||
|
||||
if (this.executor == null) {
|
||||
this.executor = new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
if (this.filter == null) {
|
||||
this.filter = new SingleEntryAdaptingEntryListFilter<File>(new AcceptAllEntryListFilter<File>());
|
||||
}
|
||||
|
||||
Assert.notNull(this.filter, "the filter can't be null");
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* a way to remove the responsibility of reacting to the file system from implementations while still being thread safe and handling backlog
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
class FileDeliveryPump implements Runnable {
|
||||
private volatile FileAdditionListener fileAdditionListener;
|
||||
|
||||
public FileDeliveryPump(FileAdditionListener fileAdditionListener) {
|
||||
this.fileAdditionListener = fileAdditionListener;
|
||||
Assert.notNull(this.fileAdditionListener, "the FileAdditionListener can't be null");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
do {
|
||||
try {
|
||||
File taken = additions.take();
|
||||
|
||||
if (filter.accept(taken)) {
|
||||
fileAdditionListener.fileAdded(taken);
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
|
||||
class MyEDFRM extends AbstractEventDrivenFileMonitor {
|
||||
@Override
|
||||
protected void start() throws Exception {
|
||||
System.out.println("start()");
|
||||
}
|
||||
|
||||
public void addToHeap(File file) {
|
||||
this.publishNewFileReceived(file);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
|
||||
|
||||
final MyEDFRM myEDFRM = new MyEDFRM();
|
||||
myEDFRM.setExecutor(simpleAsyncTaskExecutor);
|
||||
myEDFRM.setAutoCreateDirectory(true);
|
||||
myEDFRM.afterPropertiesSet();
|
||||
|
||||
AcceptOnceEntryFileListFilter <File> acceptOnceEntryFileListFilter=new AcceptOnceEntryFileListFilter<File>() ;
|
||||
acceptOnceEntryFileListFilter.afterPropertiesSet();
|
||||
PatternMatchingEntryListFilter <File> patternMatchingEntryListFilter=
|
||||
new PatternMatchingEntryListFilter<File>(new FileEntryNamer(), ".*?jpg");
|
||||
patternMatchingEntryListFilter.afterPropertiesSet();
|
||||
|
||||
Collection<? extends EntryListFilter<File>> l=Arrays.asList( acceptOnceEntryFileListFilter, patternMatchingEntryListFilter);
|
||||
CompositeEntryListFilter compositeEntryListFilter = new CompositeEntryListFilter<File>(l );
|
||||
|
||||
|
||||
myEDFRM.setFilter(compositeEntryListFilter);
|
||||
|
||||
final File desktop = new File(System.getProperty("user.home"), "Desktop");
|
||||
myEDFRM.monitor(desktop, new FileAdditionListener() {
|
||||
public void fileAdded(File f) {
|
||||
System.out.println("Got one! " + f.getAbsolutePath());
|
||||
}
|
||||
});
|
||||
System.out.println("enjoying the world");
|
||||
simpleAsyncTaskExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1000 * 10);
|
||||
|
||||
for (File f : desktop.listFiles())
|
||||
myEDFRM.addToHeap(f);
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.springframework.integration.file.monitors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* simply takes a hint and publishes an event as appropriate
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class DirectedEventDrivenFileMonitor extends AbstractEventDrivenFileMonitor {
|
||||
public void directlyNotifyOfNewFile(File file) {
|
||||
this.publishNewFileReceived(file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.integration.file.monitors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* Defines an interface for a component that reacts to file system events
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public interface EventDrivenDirectoryMonitor {
|
||||
/**
|
||||
* the implementation should know how to publish events on the {@link FileAdditionListener}
|
||||
* for a given #directory
|
||||
*
|
||||
* @param directory the directory to start watching from. Unspecified if this implies recursion or not.
|
||||
* @param fileAdditionListener the callback
|
||||
* @throws Exception if anything should go wrong
|
||||
*/
|
||||
void monitor(File directory, FileAdditionListener fileAdditionListener) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.integration.file.monitors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A generic hook into the arrival of a new {@link java.io.File}
|
||||
*
|
||||
* @author Josh Long
|
||||
* @see org.springframework.integration.file.monitors.MessageSendingFileAdditionListener
|
||||
*/
|
||||
public interface FileAdditionListener {
|
||||
|
||||
/**
|
||||
* a callback method that's invoked when a new {@link java.io.File} is detected.
|
||||
*
|
||||
* @param f the {@link java.io.File} that was detected
|
||||
*/
|
||||
void fileAdded(File f);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.springframework.integration.file.monitors;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* Supports propagating a {@link org.springframework.integration.Message} on the receipt of a new {@link java.io.File}
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class MessageSendingFileAdditionListener extends IntegrationObjectSupport implements FileAdditionListener {
|
||||
private MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
private MessageChannel channel;
|
||||
private PlatformTransactionManager platformTransactionManager;
|
||||
|
||||
public void setChannel(MessageChannel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
Assert.notNull(this.channel, "'channel' can't be null!");
|
||||
|
||||
if (this.platformTransactionManager != null) {
|
||||
this.messagingTemplate.setTransactionManager(platformTransactionManager);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
|
||||
this.platformTransactionManager = platformTransactionManager;
|
||||
}
|
||||
|
||||
public void fileAdded(File f) {
|
||||
Message<File> fileMsg = MessageBuilder.withPayload(f).build();
|
||||
this.messagingTemplate.send(fileMsg);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.file.FileListFilter"/>
|
||||
<tool:expected-type type="org.springframework.integration.file.filters.FileListFilter"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.file.FileListFilter"/>
|
||||
<tool:expected-type type="org.springframework.integration.file.entries.EntryListFilter"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -26,13 +26,15 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.filters.FileListFilter;
|
||||
|
||||
/**
|
||||
* @author Iwein Fuld
|
||||
*/
|
||||
public class CompositeFileListFilterTests {
|
||||
|
||||
private FileListFilter fileFilterMock1 = mock(FileListFilter.class);
|
||||
private FileListFilter fileFilterMock1 = mock( FileListFilter.class);
|
||||
|
||||
private FileListFilter fileFilterMock2 = mock(FileListFilter.class);
|
||||
|
||||
@@ -51,7 +53,8 @@ public class CompositeFileListFilterTests {
|
||||
|
||||
@Test
|
||||
public void forwardedToAddedFilters() throws Exception {
|
||||
CompositeFileListFilter compositeFileFilter = new CompositeFileListFilter().addFilter(fileFilterMock1, fileFilterMock2);
|
||||
CompositeFileListFilter compositeFileFilter = new CompositeFileListFilter();
|
||||
compositeFileFilter.addFilter(fileFilterMock1, fileFilterMock2);
|
||||
List<File> returnedFiles = Arrays.asList(new File[] { fileMock });
|
||||
when(fileFilterMock1.filterFiles(isA(File[].class))).thenReturn(returnedFiles);
|
||||
when(fileFilterMock2.filterFiles(isA(File[].class))).thenReturn(returnedFiles);
|
||||
|
||||
@@ -1,28 +1,49 @@
|
||||
<?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">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
||||
|
||||
<!-- under test -->
|
||||
<bean id="pollableFileSource" class="org.springframework.integration.file.FileReadingMessageSource"
|
||||
p:directory="file:${java.io.tmpdir}/FileReadingMessageSourceIntegrationTests"
|
||||
p:filter-ref="compositeFilter"/>
|
||||
<!-- under test -->
|
||||
<bean id="pollableFileSource" class="org.springframework.integration.file.FileReadingMessageSource"
|
||||
p:directory="file:${java.io.tmpdir}/FileReadingMessageSourceIntegrationTests"
|
||||
p:filter-ref="compositeFilter"/>
|
||||
|
||||
<!-- customized filter -->
|
||||
<bean id="compositeFilter" class="org.springframework.integration.file.CompositeFileListFilter">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.integration.file.AcceptOnceFileListFilter" />
|
||||
<bean class="org.springframework.integration.file.TestFileListFilter" />
|
||||
<bean class="org.springframework.integration.file.PatternMatchingFileListFilter">
|
||||
<constructor-arg value="^test.*$"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
<bean class="org.springframework.integration.file.entries.FileEntryNamer" id="entryNamer"/>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
|
||||
<!-- customized filter -->
|
||||
<!--
|
||||
<bean id="compositeFilter" class="org.springframework.integration.file.entries.CompositeEntryListFilter">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter"/>
|
||||
<bean class="org.springframework.integration.file.TestFileListFilter"/>
|
||||
<bean class="org.springframework.integration.file.entries.PatternMatchingEntryListFilter">
|
||||
<constructor-arg ref="entryNamer"/>
|
||||
<constructor-arg value="^test.*$"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
-->
|
||||
|
||||
</beans>
|
||||
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" id="compositeFilter">
|
||||
<property name="filterReferences">
|
||||
|
||||
<util:list>
|
||||
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:preventDuplicates="true"/>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:preventDuplicates="false"/>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:filenamePattern="^test.*$"/>
|
||||
|
||||
</util:list>
|
||||
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -80,7 +80,8 @@ public class FileReadingMessageSourceIntegrationTests {
|
||||
@Test
|
||||
public void getFiles() throws Exception {
|
||||
Message<File> received1 = pollableFileSource.receive();
|
||||
assertNotNull("This should return the first message", received1);
|
||||
System.out.println( "getfiels() round 1");
|
||||
assertNotNull("This should return the first message", received1);
|
||||
pollableFileSource.onSend(received1);
|
||||
Message<File> received2 = pollableFileSource.receive();
|
||||
assertNotNull(received2);
|
||||
@@ -154,12 +155,13 @@ public class FileReadingMessageSourceIntegrationTests {
|
||||
/**
|
||||
* Convenience method to run part of a test concurrently in multiple threads
|
||||
*
|
||||
* @param numberOfThreads
|
||||
* @param todo the runnable that should be run by all the threads
|
||||
* @param numberOfThreads how many threads to spawn
|
||||
* @param runnable the runnable that should be run by all the threads
|
||||
* @param start the {@link java.util.concurrent.CountDownLatch} instance telling it when to assume everything works
|
||||
* @return a latch that will be counted down once all threads have run their
|
||||
* runnable.
|
||||
*/
|
||||
private CountDownLatch doConcurrently(int numberOfThreads, final Runnable todo, final CountDownLatch start) {
|
||||
private CountDownLatch doConcurrently(int numberOfThreads, final Runnable runnable, final CountDownLatch start) {
|
||||
final CountDownLatch started = new CountDownLatch(numberOfThreads);
|
||||
final CountDownLatch done = new CountDownLatch(numberOfThreads);
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
@@ -174,7 +176,7 @@ public class FileReadingMessageSourceIntegrationTests {
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
todo.run();
|
||||
runnable.run();
|
||||
done.countDown();
|
||||
}
|
||||
}).start();
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:file="http://www.springframework.org/schema/integration/file"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:si="http://www.springframework.org/schema/integration" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/file
|
||||
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd">
|
||||
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
||||
|
||||
<!-- under test -->
|
||||
<file:inbound-channel-adapter
|
||||
directory="#{inputDirectory.path}"
|
||||
channel="fileMessages" filter="compositeFilter"/>
|
||||
<!-- under test -->
|
||||
<file:inbound-channel-adapter
|
||||
directory="#{inputDirectory.path}"
|
||||
channel="fileMessages" filter="compositeFilter"/>
|
||||
|
||||
<bean id="temp" class="org.junit.rules.TemporaryFolder"
|
||||
init-method="create" destroy-method="delete"/>
|
||||
<bean id="temp" class="org.junit.rules.TemporaryFolder"
|
||||
init-method="create" destroy-method="delete"/>
|
||||
|
||||
<bean id="inputDirectory" class="java.io.File">
|
||||
<constructor-arg value="#{temp.newFolder('FileToChannelIntegrationTests').path}"/>
|
||||
</bean>
|
||||
<bean id="inputDirectory" class="java.io.File">
|
||||
<constructor-arg value="#{temp.newFolder('FileToChannelIntegrationTests').path}"/>
|
||||
</bean>
|
||||
|
||||
<si:channel id="fileMessages">
|
||||
<si:queue capacity="10" />
|
||||
</si:channel>
|
||||
<si:channel id="fileMessages">
|
||||
<si:queue capacity="10"/>
|
||||
</si:channel>
|
||||
|
||||
<!-- customized filter -->
|
||||
<bean id="compositeFilter"
|
||||
class="org.springframework.integration.file.CompositeFileListFilter">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.integration.file.AcceptOnceFileListFilter"/>
|
||||
<bean class="org.springframework.integration.file.TestFileListFilter"/>
|
||||
<bean class="org.springframework.integration.file.PatternMatchingFileListFilter">
|
||||
<constructor-arg value="^test.*$"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<si:poller default="true" fixed-rate="10"/>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" id="compositeFilter">
|
||||
<property name="filterReferences">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
<util:list>
|
||||
|
||||
</beans>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:preventDuplicates="true"/>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:preventDuplicates="false"/>
|
||||
<bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" p:filenamePattern="^test.*$"/>
|
||||
|
||||
</util:list>
|
||||
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<si:poller default="true" fixed-rate="10"/>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.file.filters.FileListFilter;
|
||||
import org.springframework.integration.file.filters.PatternMatchingFileListFilter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.integration.file;
|
||||
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -23,10 +25,8 @@ import java.util.List;
|
||||
/**
|
||||
* @author Iwein Fuld
|
||||
*/
|
||||
public class TestFileListFilter implements FileListFilter {
|
||||
|
||||
public List<File> filterFiles(File[] files) {
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
|
||||
public class TestFileListFilter implements EntryListFilter<File> {
|
||||
public List<File> filterEntries(File[] entries) {
|
||||
return Arrays.asList(entries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,19 @@
|
||||
</integration:poller>
|
||||
</inbound-channel-adapter>
|
||||
|
||||
<beans:bean id="filter" class="org.springframework.integration.file.CompositeFileListFilter">
|
||||
<beans:bean id="filter" class="org.springframework.integration.file.config.FileListFilterFactoryBean">
|
||||
|
||||
</beans:bean>
|
||||
<!--
|
||||
<beans:bean id="filter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
|
||||
<beans:constructor-arg>
|
||||
<beans:list></beans:list>
|
||||
</beans:constructor-arg>
|
||||
</beans:bean>
|
||||
</beans:bean>-->
|
||||
|
||||
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
|
||||
<beans:bean id="testComparator"
|
||||
class="org.springframework.integration.file.config.FileInboundChannelAdapterParserTests$TestComparator"/>
|
||||
|
||||
</beans:beans>
|
||||
</beans:beans>
|
||||
|
||||
@@ -32,7 +32,9 @@ import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.file.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter;
|
||||
import org.springframework.integration.file.entries.CompositeEntryListFilter;
|
||||
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.DefaultDirectoryScanner;
|
||||
import org.springframework.integration.file.FileReadingMessageSource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -77,8 +79,9 @@ public class FileInboundChannelAdapterParserTests {
|
||||
public void filter() throws Exception {
|
||||
DefaultDirectoryScanner scanner = (DefaultDirectoryScanner) accessor.getPropertyValue("scanner");
|
||||
DirectFieldAccessor scannerAccessor = new DirectFieldAccessor(scanner);
|
||||
assertTrue("'filter' should be set",
|
||||
scannerAccessor.getPropertyValue("filter") instanceof CompositeFileListFilter);
|
||||
Object filter = scannerAccessor.getPropertyValue("filter");
|
||||
assertTrue("'filter' should be set",
|
||||
filter instanceof AcceptOnceEntryFileListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -34,11 +34,15 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.file.AcceptOnceFileListFilter;
|
||||
import org.springframework.integration.file.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.FileListFilter;
|
||||
import org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter;
|
||||
import org.springframework.integration.file.entries.CompositeEntryListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
import org.springframework.integration.file.entries.PatternMatchingEntryListFilter;
|
||||
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
||||
import org.springframework.integration.file.filters.*;
|
||||
import org.springframework.integration.file.FileReadingMessageSource;
|
||||
import org.springframework.integration.file.PatternMatchingFileListFilter;
|
||||
import org.springframework.integration.file.filters.PatternMatchingFileListFilter;
|
||||
import org.springframework.integration.file.filters.FileListFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -88,7 +92,7 @@ public class FileInboundChannelAdapterWithPatternParserTests {
|
||||
@Test
|
||||
public void compositeFilterType() {
|
||||
DirectFieldAccessor scannerAccessor = new DirectFieldAccessor(accessor.getPropertyValue("scanner"));
|
||||
assertTrue(scannerAccessor.getPropertyValue("filter") instanceof CompositeFileListFilter);
|
||||
assertTrue(scannerAccessor.getPropertyValue("filter") instanceof CompositeEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,11 +110,11 @@ public class FileInboundChannelAdapterWithPatternParserTests {
|
||||
public void acceptOnceFilter() {
|
||||
DirectFieldAccessor scannerAccessor = new DirectFieldAccessor(accessor.getPropertyValue("scanner"));
|
||||
|
||||
Set<FileListFilter> filters = (Set<FileListFilter>) new DirectFieldAccessor(
|
||||
Set<EntryListFilter<File>> filters = (Set<EntryListFilter<File>>) new DirectFieldAccessor(
|
||||
scannerAccessor.getPropertyValue("filter")).getPropertyValue("fileFilters");
|
||||
boolean hasAcceptOnceFilter = false;
|
||||
for (FileListFilter filter : filters) {
|
||||
if (filter instanceof AcceptOnceFileListFilter) {
|
||||
for (EntryListFilter<File> filter : filters) {
|
||||
if (filter instanceof AcceptOnceEntryFileListFilter) {
|
||||
hasAcceptOnceFilter = true;
|
||||
}
|
||||
}
|
||||
@@ -122,11 +126,11 @@ public class FileInboundChannelAdapterWithPatternParserTests {
|
||||
public void patternFilter() {
|
||||
DirectFieldAccessor scannerAccessor = new DirectFieldAccessor(accessor.getPropertyValue("scanner"));
|
||||
|
||||
Set<FileListFilter> filters = (Set<FileListFilter>) new DirectFieldAccessor(
|
||||
Set<EntryListFilter> filters = (Set<EntryListFilter>) new DirectFieldAccessor(
|
||||
scannerAccessor.getPropertyValue("filter")).getPropertyValue("fileFilters");
|
||||
Pattern pattern = null;
|
||||
for (FileListFilter filter : filters) {
|
||||
if (filter instanceof PatternMatchingFileListFilter) {
|
||||
for (EntryListFilter filter : filters) {
|
||||
if (filter instanceof PatternMatchingEntryListFilter) {
|
||||
pattern = (Pattern) new DirectFieldAccessor(filter).getPropertyValue("pattern");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.file.*;
|
||||
import org.springframework.integration.file.entries.AcceptOnceEntryFileListFilter;
|
||||
import org.springframework.integration.file.entries.CompositeEntryListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
import org.springframework.integration.file.entries.PatternMatchingEntryListFilter;
|
||||
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
|
||||
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.filters.FileListFilter;
|
||||
import org.springframework.integration.file.filters.PatternMatchingFileListFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -50,95 +58,95 @@ public class FileInboundChannelAdapterWithPreventDuplicatesFlagTests {
|
||||
|
||||
@Test
|
||||
public void filterAndNull() {
|
||||
FileListFilter filter = this.extractFilter("filterAndNull");
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("filterAndNull");
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertSame(testFilter, filter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void filterAndTrue() {
|
||||
FileListFilter filter = this.extractFilter("filterAndTrue");
|
||||
assertTrue(filter instanceof CompositeFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("filterAndTrue");
|
||||
assertTrue(filter instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(filter).getPropertyValue("fileFilters");
|
||||
assertTrue(filters.iterator().next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(filters.iterator().next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(filters.contains(testFilter));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterAndFalse() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("filterAndFalse");
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("filterAndFalse");
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertSame(testFilter, filter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void patternAndNull() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("patternAndNull");
|
||||
assertTrue(filter instanceof CompositeFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("patternAndNull");
|
||||
assertTrue(filter instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(filter).getPropertyValue("fileFilters");
|
||||
Iterator<FileListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingFileListFilter);
|
||||
assertTrue(iterator.next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void patternAndTrue() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("patternAndTrue");
|
||||
assertTrue(filter instanceof CompositeFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("patternAndTrue");
|
||||
assertTrue(filter instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(filter).getPropertyValue("fileFilters");
|
||||
Iterator<FileListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingFileListFilter);
|
||||
assertTrue(iterator.next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patternAndFalse() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("patternAndFalse");
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
assertTrue(filter instanceof PatternMatchingFileListFilter);
|
||||
EntryListFilter <File> filter = this.extractFilter("patternAndFalse");
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertTrue(filter instanceof PatternMatchingEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAndNull() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("defaultAndNull");
|
||||
EntryListFilter <File>filter = this.extractFilter("defaultAndNull");
|
||||
assertNotNull(filter);
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
assertTrue(filter instanceof AcceptOnceFileListFilter);
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertTrue(filter instanceof AcceptOnceEntryFileListFilter);
|
||||
File testFile = new File("test");
|
||||
File[] files = new File[]{testFile, testFile, testFile};
|
||||
List<File> result = filter.filterFiles(files);
|
||||
assertEquals(1, result.size());
|
||||
List<File> result = filter.filterEntries(files);
|
||||
assertEquals(1 , result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAndTrue() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("defaultAndTrue");
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
assertTrue(filter instanceof AcceptOnceFileListFilter);
|
||||
EntryListFilter filter = this.extractFilter("defaultAndTrue");
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertTrue(filter instanceof AcceptOnceEntryFileListFilter);
|
||||
File testFile = new File("test");
|
||||
File[] files = new File[]{testFile, testFile, testFile};
|
||||
List<File> result = filter.filterFiles(files);
|
||||
List<File> result = filter.filterEntries(files);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAndFalse() throws Exception {
|
||||
FileListFilter filter = this.extractFilter("defaultAndFalse");
|
||||
EntryListFilter filter = this.extractFilter("defaultAndFalse");
|
||||
assertNotNull(filter);
|
||||
assertFalse(filter instanceof CompositeFileListFilter);
|
||||
assertFalse(filter instanceof AcceptOnceFileListFilter);
|
||||
assertFalse(filter instanceof CompositeEntryListFilter);
|
||||
assertFalse(filter instanceof AcceptOnceEntryFileListFilter);
|
||||
File testFile = new File("test");
|
||||
File[] files = new File[]{testFile, testFile, testFile};
|
||||
List<File> result = filter.filterFiles(files);
|
||||
List<File> result = filter.filterEntries(files);
|
||||
assertEquals(3, result.size());
|
||||
}
|
||||
|
||||
|
||||
private FileListFilter extractFilter(String beanName) {
|
||||
return (FileListFilter) new DirectFieldAccessor(
|
||||
private EntryListFilter<File> extractFilter(String beanName) {
|
||||
return (EntryListFilter<File>) new DirectFieldAccessor(
|
||||
new DirectFieldAccessor(
|
||||
new DirectFieldAccessor(context.getBean(beanName))
|
||||
.getPropertyValue("source"))
|
||||
|
||||
@@ -35,8 +35,9 @@
|
||||
<integration:interval-trigger interval="5000"/>
|
||||
</integration:poller>
|
||||
</inbound-channel-adapter>
|
||||
<beans:bean class="org.springframework.integration.file.config.FileListFilterFactoryBean" />
|
||||
|
||||
<beans:bean id="filter" class="org.springframework.integration.file.CompositeFileListFilter">
|
||||
<beans:bean id="filter" class="org.springframework.integration.file.entries.CompositeEntryListFilter">
|
||||
<beans:constructor-arg>
|
||||
<beans:list></beans:list>
|
||||
</beans:constructor-arg>
|
||||
@@ -47,4 +48,4 @@
|
||||
<beans:bean id="testComparator"
|
||||
class="org.springframework.integration.file.config.FileInboundChannelAdapterParserTests$TestComparator"/>
|
||||
|
||||
</beans:beans>
|
||||
</beans:beans>
|
||||
|
||||
@@ -18,7 +18,8 @@ package org.springframework.integration.file.config;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.integration.file.*;
|
||||
import org.springframework.integration.file.entries.*;
|
||||
import org.springframework.integration.file.filters.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
@@ -45,7 +46,7 @@ public class FileListFilterFactoryBeanTests {
|
||||
FileListFilterFactoryBean factory = new FileListFilterFactoryBean();
|
||||
TestFilter testFilter = new TestFilter();
|
||||
factory.setFilterReference(testFilter);
|
||||
FileListFilter result = factory.getObject();
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertFalse(result instanceof CompositeFileListFilter);
|
||||
assertSame(testFilter, result);
|
||||
}
|
||||
@@ -57,10 +58,10 @@ public class FileListFilterFactoryBeanTests {
|
||||
TestFilter testFilter = new TestFilter();
|
||||
factory.setFilterReference(testFilter);
|
||||
factory.setPreventDuplicates(Boolean.TRUE);
|
||||
FileListFilter result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeFileListFilter);
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(result).getPropertyValue("fileFilters");
|
||||
assertTrue(filters.iterator().next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(filters.iterator().next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(filters.contains(testFilter));
|
||||
}
|
||||
|
||||
@@ -70,8 +71,8 @@ public class FileListFilterFactoryBeanTests {
|
||||
TestFilter testFilter = new TestFilter();
|
||||
factory.setFilterReference(testFilter);
|
||||
factory.setPreventDuplicates(Boolean.FALSE);
|
||||
FileListFilter result = factory.getObject();
|
||||
assertFalse(result instanceof CompositeFileListFilter);
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertFalse(result instanceof CompositeEntryListFilter);
|
||||
assertSame(testFilter, result);
|
||||
}
|
||||
|
||||
@@ -80,12 +81,12 @@ public class FileListFilterFactoryBeanTests {
|
||||
public void filenamePatternAndPreventDuplicatesNull() throws Exception {
|
||||
FileListFilterFactoryBean factory = new FileListFilterFactoryBean();
|
||||
factory.setFilenamePattern(Pattern.compile("foo"));
|
||||
FileListFilter result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeFileListFilter);
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(result).getPropertyValue("fileFilters");
|
||||
Iterator<FileListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingFileListFilter);
|
||||
Iterator<EntryListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,12 +95,12 @@ public class FileListFilterFactoryBeanTests {
|
||||
FileListFilterFactoryBean factory = new FileListFilterFactoryBean();
|
||||
factory.setFilenamePattern(Pattern.compile("foo"));
|
||||
factory.setPreventDuplicates(Boolean.TRUE);
|
||||
FileListFilter result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeFileListFilter);
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertTrue(result instanceof CompositeEntryListFilter);
|
||||
Collection filters = (Collection) new DirectFieldAccessor(result).getPropertyValue("fileFilters");
|
||||
Iterator<FileListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingFileListFilter);
|
||||
Iterator<EntryListFilter> iterator = filters.iterator();
|
||||
assertTrue(iterator.next() instanceof AcceptOnceEntryFileListFilter);
|
||||
assertTrue(iterator.next() instanceof PatternMatchingEntryListFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,18 +108,18 @@ public class FileListFilterFactoryBeanTests {
|
||||
FileListFilterFactoryBean factory = new FileListFilterFactoryBean();
|
||||
factory.setFilenamePattern(Pattern.compile("foo"));
|
||||
factory.setPreventDuplicates(Boolean.FALSE);
|
||||
FileListFilter result = factory.getObject();
|
||||
assertFalse(result instanceof CompositeFileListFilter);
|
||||
assertTrue(result instanceof PatternMatchingFileListFilter);
|
||||
EntryListFilter<File> result = factory.getObject();
|
||||
assertFalse(result instanceof CompositeEntryListFilter);;
|
||||
// CompositeEntryListFilter
|
||||
assertTrue(result instanceof PatternMatchingEntryListFilter ) ;
|
||||
}
|
||||
|
||||
|
||||
private static class TestFilter extends AbstractFileListFilter {
|
||||
|
||||
@Override
|
||||
protected boolean accept(File file) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private static class TestFilter extends AbstractEntryListFilter<File> {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
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">
|
||||
<bean id="filter" class="org.springframework.integration.file.filters.PatternMatchingFileListFilter">
|
||||
<constructor-arg value="[fo+\.[tx]{3}"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.file.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.entries.CompositeEntryListFilter;
|
||||
import org.springframework.integration.file.filters.CompositeFileListFilter;
|
||||
import org.springframework.integration.file.FileReadingMessageSource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -64,7 +65,7 @@ public class FileLockingNamespaceTests {
|
||||
@Test
|
||||
public void shouldSetCustomLockerProperly() {
|
||||
assertThat(extractFromScanner("locker", customLockingSource), is(StubLocker.class));
|
||||
assertThat(extractFromScanner("filter", customLockingSource), is(CompositeFileListFilter.class));
|
||||
assertThat(extractFromScanner("filter", customLockingSource), is(CompositeEntryListFilter.class));
|
||||
}
|
||||
|
||||
private Object extractFromScanner(String propertyName, FileReadingMessageSource source) {
|
||||
@@ -74,7 +75,7 @@ public class FileLockingNamespaceTests {
|
||||
@Test
|
||||
public void shouldSetNioLockerProperly() {
|
||||
assertThat(extractFromScanner("locker", nioLockingSource), is(NioFileLocker.class));
|
||||
assertThat(extractFromScanner("filter", nioLockingSource), is(CompositeFileListFilter.class));
|
||||
assertThat(extractFromScanner("filter", nioLockingSource), is(CompositeEntryListFilter.class));
|
||||
}
|
||||
|
||||
public static class StubLocker extends AbstractFileLockerFilter {
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.integration.file.locking;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.integration.file.FileListFilter;
|
||||
import org.springframework.integration.file.entries.EntryListFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -49,20 +49,20 @@ public class NioFileLockerTests {
|
||||
NioFileLocker filter = new NioFileLocker();
|
||||
File testFile = new File(workdir, "test0");
|
||||
testFile.createNewFile();
|
||||
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
|
||||
assertThat(filter.filterEntries(workdir.listFiles()).get(0), is(testFile));
|
||||
filter.lock(testFile);
|
||||
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
|
||||
assertThat(filter.filterEntries(workdir.listFiles()).get(0), is(testFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNotListedWhenLockedByOtherFilter() throws IOException {
|
||||
NioFileLocker filter1 = new NioFileLocker();
|
||||
FileListFilter filter2 = new NioFileLocker();
|
||||
EntryListFilter<File> filter2 = new NioFileLocker();
|
||||
File testFile = new File(workdir, "test1");
|
||||
testFile.createNewFile();
|
||||
assertThat(filter1.filterFiles(workdir.listFiles()).get(0), is(testFile));
|
||||
assertThat(filter1.filterEntries(workdir.listFiles()).get(0), is(testFile));
|
||||
filter1.lock(testFile);
|
||||
assertThat(filter2.filterFiles(workdir.listFiles()), is((List<File>)new ArrayList<File>()));
|
||||
assertThat(filter2.filterEntries(workdir.listFiles()), is((List<File>)new ArrayList<File>()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
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">
|
||||
<bean id="filter" class="org.springframework.integration.file.filters.PatternMatchingFileListFilter">
|
||||
<constructor-arg value="fo+\.[tx]{3}"/>
|
||||
</bean>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user