INT-1562 moved synchronization base classes into a dedicated package

This commit is contained in:
Mark Fisher
2010-11-05 13:22:19 -04:00
parent 541370c295
commit 9271269433
9 changed files with 364 additions and 304 deletions

View File

@@ -1,161 +0,0 @@
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;
/**
* 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
*/
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 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;
/**
* 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 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 {
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;
/**
* {@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.
* 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')
*
* @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);
}
}
}
}

View File

@@ -1,135 +0,0 @@
package org.springframework.integration.file;
import org.springframework.core.io.Resource;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.file.entries.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* 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
*/
public abstract class AbstractInboundRemoteFileSystemSynchronizingMessageSource<Y, T extends AbstractInboundRemoteFileSystemSychronizer<Y>> extends MessageProducerSupport 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 connecting to and syncing up the remote FS with the local one, in an inbound direction
*/
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;
}
@SuppressWarnings("unchecked")
private EntryListFilter<File> buildFilter() {
FileEntryNamer fileEntryNamer = new FileEntryNamer();
Pattern completePattern = Pattern.compile("^.*(?<!" + INCOMPLETE_EXTENSION + ")$");
return new CompositeEntryListFilter<File>(
Arrays.asList(
new AcceptOnceEntryFileListFilter<File>(), new PatternMatchingEntryListFilter<File>(fileEntryNamer, completePattern)));
}
@Override
protected void onInit() {
try {
if (this.remotePredicate != null) {
this.synchronizer.setFilter(this.remotePredicate);
}
if (this.localDirectory != null && !this.localDirectory.exists()){
if (this.autoCreateDirectories){
logger.debug("The '" + localDirectory + "' directory doesn't exist. Creating " + this.localDirectory);
this.localDirectory.getFile().mkdirs();
} else {
throw new FileNotFoundException(localDirectory.getFilename());
}
}
/**
* 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();
} catch (Exception e) {
if (e instanceof RuntimeException){
throw (RuntimeException)e;
} else {
throw new MessagingException("Failure during initialization of MessageSource for: " + this.getComponentType(), e);
}
}
}
public Message<File> receive() {
return this.fileSource.receive();
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright 2002-2010 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.synchronization;
import org.springframework.core.io.Resource;
import org.springframework.integration.MessagingException;
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;
/**
* Base class charged with knowing how to connect to a remote file system,
* scan it for new files and then download the files.
* <p/>
* The implementation should run through any configured
* {@link org.springframework.integration.file.entries.EntryListFilter}s to
* ensure the entry is acceptable.
*
* @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.
*/
protected boolean shouldDeleteSourceFile;
/**
* The directory to which we write our synchronizations.
*/
protected volatile Resource localDirectory;
/**
* An {@link EntryListFilter} that runs against the <emphasis>remote</emphasis> file system view.
*/
protected volatile EntryListFilter<T> filter = new AcceptAllEntryListFilter<T>();
/**
* The {@link ScheduledFuture} instance we get when we
* schedule our {@link SynchronizeTask}
*/
protected ScheduledFuture<?> scheduledFuture;
/**
* The {@link EntryAcknowledgmentStrategy} implementation.
*/
protected EntryAcknowledgmentStrategy<T> entryAcknowledgmentStrategy;
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
* this is context information to be passed to the individual {@link EntryAcknowledgmentStrategy}.
* {@link 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, etc.
* @throws Throwable
* escape hatch exception, let the adapter deal with it.
*/
protected void acknowledge(Object usefulContextOrClientData, T t) throws Throwable {
Assert.notNull(this.entryAcknowledgmentStrategy != null,
"entryAcknowledgmentStrategy can't be null!");
this.entryAcknowledgmentStrategy.acknowledge(usefulContextOrClientData, t);
}
/**
* {@inheritDoc}
*/
protected void doStart() {
if (this.entryAcknowledgmentStrategy == null) {
this.entryAcknowledgmentStrategy = new EntryAcknowledgmentStrategy<T>() {
public void acknowledge(Object o, T msg) {
// no-op
}
};
}
this.scheduledFuture = this.getTaskScheduler().schedule(new SynchronizeTask(), this.getTrigger());
}
/**
* {@inheritDoc}
*/
protected void doStop() {
if (this.scheduledFuture != null) {
this.scheduledFuture.cancel(true);
}
}
/**
* Returns the {@link Trigger} that dictates how frequently the trigger should fire.
*/
protected abstract Trigger getTrigger();
/**
* This is the callback where we need the implementation to do some specific work
*/
protected abstract void syncRemoteToLocalFileSystem() throws Exception;
/**
* This {@link Runnable} is launched as a background thread and is used to manage the
* {@link AbstractInboundRemoteFileSystemSychronizer#localDirectory} by queueing and
* delivering accumulated files as possible.
*/
class SynchronizeTask implements Runnable {
public void run() {
try {
syncRemoteToLocalFileSystem();
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new MessagingException("failure occurred in synchronization task", e);
}
}
}
/**
* Strategy interface to expose a hook for dispatching, moving, or deleting
* the file once it has 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 EntryAcknowledgmentStrategy}
* into the pipeline and also some more advanced scenarios (i.e., 'move file
* to another folder on delete ', or 'rename on delete')
*
* @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 subclasses
* @throws Exception in case of an error while acknowledging
*/
void acknowledge(Object useful, T msg) throws Exception;
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 2002-2010 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.synchronization;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.springframework.core.io.Resource;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.file.FileReadingMessageSource;
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.FileEntryNamer;
import org.springframework.integration.file.entries.PatternMatchingEntryListFilter;
/**
* Factors out the common logic between the FTP and SFTP adapters. Designed to
* be extensible 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 pulling from the remote file system - as you would expect
* from an 'inbound' adapter).
* <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 AbstractInboundRemoteFileSystemSychronizer}. The synchronizer must
* handle the work of actually connecting to the remote file system and
* delivering new {@link File}s.
*
* @author Josh Long
*/
public abstract class AbstractInboundRemoteFileSystemSynchronizingMessageSource<Y, T extends AbstractInboundRemoteFileSystemSychronizer<Y>>
extends MessageProducerSupport 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 connecting to and synching up
* the remote file system with the local one, in an inbound direction.
*/
protected volatile T synchronizer;
/**
* Directory to which things should be synched locally.
*/
protected volatile Resource localDirectory;
/**
* The actual {@link FileReadingMessageSource} that monitors the local filesystem once files are synched.
*/
protected volatile FileReadingMessageSource fileSource;
/**
* The predicate to use in scanning the remote File system 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;
}
@Override
protected void onInit() {
try {
if (this.remotePredicate != null) {
this.synchronizer.setFilter(this.remotePredicate);
}
if (this.localDirectory != null && !this.localDirectory.exists()) {
if (this.autoCreateDirectories) {
if (logger.isDebugEnabled()) {
logger.debug("The '" + this.localDirectory + "' directory doesn't exist; Will create.");
}
this.localDirectory.getFile().mkdirs();
}
else {
throw new FileNotFoundException(this.localDirectory.getFilename());
}
}
/**
* Make sure the remote files get here.
*/
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());
/**
* Forwards files once they ultimately appear in the {@link #localDirectory}.
*/
this.fileSource = new FileReadingMessageSource();
this.fileSource.setFilter(this.buildFilter());
this.fileSource.setDirectory(this.localDirectory.getFile());
this.fileSource.afterPropertiesSet();
this.synchronizer.afterPropertiesSet();
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new MessagingException("Failure during initialization of MessageSource for: "
+ this.getComponentType(), e);
}
}
public Message<File> receive() {
return this.fileSource.receive();
}
@SuppressWarnings("unchecked")
private EntryListFilter<File> buildFilter() {
FileEntryNamer fileEntryNamer = new FileEntryNamer();
Pattern completePattern = Pattern.compile("^.*(?<!" + INCOMPLETE_EXTENSION + ")$");
return new CompositeEntryListFilter<File>(Arrays.asList(
new AcceptOnceEntryFileListFilter<File>(),
new PatternMatchingEntryListFilter<File>(fileEntryNamer, completePattern)));
}
}

View File

@@ -20,8 +20,8 @@ import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.core.io.Resource;
import org.springframework.integration.MessagingException;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSychronizer;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.ftp.FtpClientPool;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.support.PeriodicTrigger;
@@ -34,7 +34,7 @@ import java.io.IOException;
import java.util.Collection;
/**
* An FTP-adapter implementation of {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer}
* An FTP-adapter implementation of {@link org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSychronizer}
*
* @author Iwein Fuld
* @author Josh Long

View File

@@ -18,7 +18,7 @@ package org.springframework.integration.ftp;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
/**
* A {@link org.springframework.integration.core.MessageSource} implementation for FTP.

View File

@@ -21,8 +21,8 @@ import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.Resource;
import org.springframework.integration.MessagingException;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSychronizer;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.sftp.SftpSession;
import org.springframework.integration.sftp.SftpSessionPool;
import org.springframework.scheduling.Trigger;

View File

@@ -17,7 +17,8 @@ package org.springframework.integration.sftp.impl;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.sftp.SftpSession;
import org.springframework.integration.sftp.SftpSessionPool;
import org.springframework.util.Assert;

View File

@@ -25,7 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy;
import org.springframework.integration.file.synchronization.AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy;
import org.springframework.integration.sftp.SftpSession;
import org.springframework.util.ReflectionUtils;