Removing already deprecated instances of *FileList*Filters in favor of their entries.* equivalents which are generics-friendly and can be reused across adapters. Also, added some documentaton to the AbstractInboundRemoteFileSystemSynchroniz*.java classes so that the lifecycle hooks are explained for subsequent file system adapter implementations

This commit is contained in:
Josh Long
2010-08-20 18:08:32 +00:00
parent 1562d53118
commit b5b0e06e81
9 changed files with 53 additions and 547 deletions

View File

@@ -11,7 +11,10 @@ import java.util.concurrent.ScheduledFuture;
/**
* This handles a lot of the common ground in our approach for synchronizing a remote file system locally
* Strategy class charged with knowing how to connect to a remote file system, scan it for new files and then downloading the file.
* <p/>
* The implementation should run through any configured {@link org.springframework.integration.file.entries.EntryListFilter}s
* to ensure the entry is worth downloading.
*
* @author Josh Long
*/
@@ -20,7 +23,8 @@ public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends Abst
* 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
* At the moment I can simply see this triggering an implementation specific {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy}
* implementation that knows how to delete an entry on the remote file system.
*/
protected boolean shouldDeleteSourceFile;
@@ -48,9 +52,9 @@ public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends Abst
* 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 acknowledge(Object o, T msg) {
}
};
public void setEntryAcknowledgmentStrategy(EntryAcknowledgmentStrategy<T> entryAcknowledgmentStrategy) {
this.entryAcknowledgmentStrategy = entryAcknowledgmentStrategy;
@@ -69,22 +73,27 @@ public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends Abst
}
/**
* @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
* @param usefulContextOrClientData this is context information to be passed to the individual {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy} implementation.
* {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy#acknowledge(Object, Object)} will be called
* in line with the {@link org.springframework.integration.core.MessageSource#receive()} call so this could conceivably be a 'live' stateful
* client (a connection?) that is inappropriate to cache as it has per-request state.
* @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 escape hatch exception, let the adapter deal with it.
*/
protected void acknowledge(Object usefulContextOrClientData, T t)
throws Throwable {
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
*
* @throws Exception thrown if anything goes wrong
*/
protected abstract void syncRemoteToLocalFileSystem()
throws Exception ;
throws Exception;
/**
* {@inheritDoc}
@@ -114,9 +123,13 @@ public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends Abst
}
/**
* Strategy interface to expose a hook for dispatching, moving, or deleting the file once it's been delivered
* Strategy interface to expose a hook for dispatching, moving, or deleting the file once it's been delivered.
* This will typically be a NOOP for the implementation. Adapters should (for consistency) expose an attribute
* dictating whether the adapter will delete the <emphasis>source</emphasis> entry on the remote file system.
* This is the file-system version of an <code>ack-mode</code>. Future implementations should consider
* exposing a custom attribute that plugs a custom {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy}
* into the pipeline and also some more advanced scenarios (i.e., 'move file to another folder on delete ', or 'rename on delete')
*
* @author Josh Long
* @param <T> the entry type (file, sftp, ftp, ...)
*/
public static interface EntryAcknowledgmentStrategy<T> {
@@ -141,7 +154,7 @@ public abstract class AbstractInboundRemoteFileSystemSychronizer<T> extends Abst
try {
syncRemoteToLocalFileSystem();
} catch (Exception e) {
throw new RuntimeException(e) ;
throw new RuntimeException(e);
}
}
}

View File

@@ -1,22 +1,28 @@
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
* Ultimately, this factors out a lot of the common logic between the FTP and SFTP adapters. Designed to be extendable to handle
* adapters whose task it is to synchronize a remote file system with a local file system (NB: this does *NOT* handle pushing files TO the remote
* file system that exist uniquely in the local file system. It only handles bringing down the remote file system - as you'd expect
* an 'inbound' adapter would).
* <p/>
* The base class supports configuration of whether the remote file system and local file system's directories should
* be created on start (what 'creating a directory' means to the specific adapter is of course implementaton specific).
* <p/>
* This class is to be used as a pair with an implementation of
* {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer<T>}. This synchronizer
* must handle the work of actually connecting to the remote file system and delivering new {@link java.io.File}s.
* The synchronizer is designed to be
*
* @author Josh Long
*/
@@ -32,7 +38,7 @@ public abstract class AbstractInboundRemoteFileSystemSynchronizingMessageSource<
protected volatile boolean autoCreateDirectories = true;
/**
* An implementation that will handle the chores of actually syncing up the remote FS
* An implementation that will handle the chores of actually connecting to and syncing up the remote FS with the local one, in an inbound direction
*/
protected volatile T synchronizer;
@@ -80,13 +86,10 @@ public abstract class AbstractInboundRemoteFileSystemSynchronizingMessageSource<
}
if (this.autoCreateDirectories) {
if((this.localDirectory != null) && !this.localDirectory.exists() && this.localDirectory.getFile().mkdirs())
logger.debug( "the localDirectory " + this.localDirectory + " doesn't exist");
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
*/