diff --git a/spring-integration-ftp/src/test/resources/inbound-ftp-context.xml b/spring-integration-ftp/src/test/resources/inbound-ftp-context.xml
index a5193c5af6..b30314ffd5 100644
--- a/spring-integration-ftp/src/test/resources/inbound-ftp-context.xml
+++ b/spring-integration-ftp/src/test/resources/inbound-ftp-context.xml
@@ -8,11 +8,11 @@
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
+
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/AbstractSFTPFileListFilter.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/AbstractSFTPFileListFilter.java
new file mode 100644
index 0000000000..f8a91a9107
--- /dev/null
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/AbstractSFTPFileListFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 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.sftp;
+
+import com.jcraft.jsch.ChannelSftp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Convenience implementation patterned off {@link org.springframework.integration.file.FileListFilter}
+ *
+ * @author Josh Long
+ */
+public abstract class AbstractSFTPFileListFilter implements SFTPFileListFilter {
+
+ abstract public boolean accept(ChannelSftp.LsEntry lsEntry);
+
+ public List filterFiles(ChannelSftp.LsEntry[] files) {
+ List accepted = new ArrayList();
+
+ if (files != null) {
+ for (ChannelSftp.LsEntry lsEntry : files)
+ if (this.accept(lsEntry)) {
+ accepted.add(lsEntry);
+ }
+ }
+
+ return accepted;
+ }
+}
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/CompositeFTPFileListFilter.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/CompositeFTPFileListFilter.java
new file mode 100644
index 0000000000..a906d90533
--- /dev/null
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/CompositeFTPFileListFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.sftp;
+
+import com.jcraft.jsch.ChannelSftp;
+import org.springframework.util.Assert;
+
+import java.util.*;
+
+
+/**
+ * Patterned very much on the {@link org.springframework.integration.file.CompositeFileListFilter}
+ *
+ * @author Josh Long
+ */
+public class CompositeFTPFileListFilter implements SFTPFileListFilter {
+ private Set filters;
+
+ public CompositeFTPFileListFilter(SFTPFileListFilter... ftpFileListFilter) {
+ this.filters = new LinkedHashSet(Arrays.asList(ftpFileListFilter));
+ }
+
+ public CompositeFTPFileListFilter(Collection ftpFileListFilter) {
+ this.filters = new LinkedHashSet(ftpFileListFilter);
+ }
+
+ public void addFilter(SFTPFileListFilter ftpFileListFilter) {
+ this.filters.add(ftpFileListFilter);
+ }
+
+ public List filterFiles(ChannelSftp.LsEntry[] files) {
+ Assert.notNull(files, "files[] can't be null!");
+
+ List leftOver = Arrays.asList(files);
+
+ for (SFTPFileListFilter ff : this.filters)
+ leftOver = ff.filterFiles(leftOver.toArray(new ChannelSftp.LsEntry[leftOver.size()]));
+
+ return leftOver;
+ }
+}
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/PatternMatchingSFTPFileListFilter.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/PatternMatchingSFTPFileListFilter.java
new file mode 100644
index 0000000000..a6ca0b9216
--- /dev/null
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/PatternMatchingSFTPFileListFilter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.sftp;
+
+import com.jcraft.jsch.ChannelSftp;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import java.util.regex.Pattern;
+
+
+/**
+ * Validates {@link com.jcraft.jsch.ChannelSftp.LsEntry}s against a {@link java.util.regex.Pattern}.
+ * Patterned very much like {@link org.springframework.integration.file.PatternMatchingFileListFilter}.
+ *
+ * @author Josh Long
+ */
+public class PatternMatchingSFTPFileListFilter extends AbstractSFTPFileListFilter implements InitializingBean {
+
+ private Log logger = LogFactory.getLog(getClass());
+
+ private Pattern pattern;
+ private String patternExpression;
+
+ public void setPattern(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ public void setPatternExpression(String patternExpression) {
+ this.patternExpression = patternExpression;
+ }
+
+ @Override
+ public boolean accept(ChannelSftp.LsEntry lsEntry) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("testing: " + ToStringBuilder.reflectionToString(lsEntry));
+ }
+
+ return (lsEntry != null) && this.pattern.matcher(lsEntry.getFilename()).matches();
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ if (StringUtils.hasText(this.patternExpression) && (this.pattern == null)) {
+ this.pattern = Pattern.compile(this.patternExpression);
+ }
+
+ Assert.notNull(this.pattern, "the pattern must not be null");
+ }
+}
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPFileListFilter.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPFileListFilter.java
new file mode 100644
index 0000000000..8d15dabd04
--- /dev/null
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPFileListFilter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.sftp;
+
+import com.jcraft.jsch.ChannelSftp;
+
+import java.util.List;
+
+/**
+ * Filters out all the {@link com.jcraft.jsch.ChannelSftp.LsEntry} taken in a scan of the remote mount
+ * and returns the balance. These are then sync'd to the local directory.
+ *
+ * @author Josh Long
+ */
+public interface SFTPFileListFilter {
+ List filterFiles (ChannelSftp.LsEntry [] files);
+}
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPInboundSynchronizer.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPInboundSynchronizer.java
index f050b2d800..d11ec51cfa 100644
--- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPInboundSynchronizer.java
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SFTPInboundSynchronizer.java
@@ -17,34 +17,31 @@ package org.springframework.integration.sftp;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
-
import org.apache.commons.io.IOUtils;
-
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
-
import org.springframework.core.io.Resource;
-
import org.springframework.integration.MessagingException;
-
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.support.PeriodicTrigger;
+import org.springframework.util.Assert;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-
+import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.ScheduledFuture;
/**
- *
* This handles keeping the {@link #localDirectory} in sync with the contents of the remote mount. From there, files are deposited
* into a folder where the {@link org.springframework.integration.file.FileReadingMessageSource} will eventually deliver them as events
*
- *
* @author Josh Long
* @author Mario Gray
*/
@@ -53,6 +50,7 @@ public class SFTPInboundSynchronizer implements InitializingBean {
// a lot of the approach for this (including the use of a FileReadingMessageSource and the regex / mask approach were lifted from FtpInboundSynchronizer
static final String INCOMPLETE_EXTENSION = ".INCOMPLETE";
+ private Log logger = LogFactory.getLog(getClass());
private volatile Resource localDirectory;
private volatile SFTPSessionPool pool;
private volatile ScheduledFuture> scheduledFuture;
@@ -61,11 +59,23 @@ public class SFTPInboundSynchronizer implements InitializingBean {
private volatile Trigger trigger = new PeriodicTrigger(DEFAULT_REFRESH_RATE);
private volatile boolean autoCreatePath;
private volatile boolean running;
+ private SFTPFileListFilter filter;
+
+ public void setFilter(SFTPFileListFilter filter) {
+ this.filter = filter;
+ }
+
private volatile boolean shouldDeleteDownloadedRemoteFiles; //.. this is false
+ private SFTPFileListFilter acceptAllFilteListFilter = new SFTPFileListFilter(){
+ public List filterFiles(ChannelSftp.LsEntry[] files) {
+ return Arrays.asList( files);
+ }
+ } ;
+
public void afterPropertiesSet() throws Exception {
- assert (taskScheduler != null) : "taskScheduler can't be null!";
- assert (localDirectory != null) : "the localDirectory property must not be null!";
+ Assert.state(taskScheduler != null, "taskScheduler can't be null!");
+ Assert.state(localDirectory != null, "the localDirectory property must not be null!");
File localDir = localDirectory.getFile();
@@ -76,18 +86,10 @@ public class SFTPInboundSynchronizer implements InitializingBean {
}
}
}
- }
- public ScheduledFuture> getScheduledFuture() {
- return scheduledFuture;
- }
+ if(this.filter == null)
+ this.filter = acceptAllFilteListFilter;
- public TaskScheduler getTaskScheduler() {
- return taskScheduler;
- }
-
- public Trigger getTrigger() {
- return trigger;
}
public boolean isRunning() {
@@ -134,8 +136,9 @@ public class SFTPInboundSynchronizer implements InitializingBean {
if (running) {
return;
}
- assert checkThatRemotePathExists(remotePath) : "the remotePath had better exist!";
- assert taskScheduler != null : "'taskScheduler' is required";
+
+ Assert.state(checkThatRemotePathExists(remotePath), "the remotePath should exist before we can sync with it!");
+ Assert.state(taskScheduler != null, "'taskScheduler' is required");
scheduledFuture = taskScheduler.schedule(new SynchronizeTask(), trigger);
@@ -146,7 +149,8 @@ public class SFTPInboundSynchronizer implements InitializingBean {
if (!running) {
return;
}
- assert scheduledFuture != null : "scheduledFuture is null!";
+
+ Assert.state(scheduledFuture != null, "scheduledFuture is null!");
this.scheduledFuture.cancel(true);
this.running = false;
}
@@ -160,7 +164,10 @@ public class SFTPInboundSynchronizer implements InitializingBean {
session.start();
ChannelSftp channelSftp = session.getChannel();
- Collection files = channelSftp.ls(remotePath);
+ Collection beforeFilter = channelSftp.ls(remotePath);
+ ChannelSftp.LsEntry [] entries = beforeFilter == null? new ChannelSftp.LsEntry[0] :
+ beforeFilter.toArray(new ChannelSftp.LsEntry[ beforeFilter.size()]) ;
+ Collection files = this.filter.filterFiles( entries );
for (ChannelSftp.LsEntry lsEntry : files) {
if ((lsEntry != null) && !lsEntry.getAttrs().isDir() && !lsEntry.getAttrs().isLink()) {
@@ -178,24 +185,24 @@ public class SFTPInboundSynchronizer implements InitializingBean {
/**
* there be dragons this way ... This method will check to ensure that the remote directory exists. If the directory
- * doesnt exist, and autoCreatePath is configured to be true, then this method makes a few reasonably sane attempts
+ * doesnt exist, and autoCreatePath is 'true,' then this method makes a few reasonably sane attempts
* to create it. Otherwise, it fails fast.
*
- * @param rPath the path on the remote SSH / SFTP server to create.
+ * @param remotePath the path on the remote SSH / SFTP server to create.
* @return whether or not the directory is there (regardless of whether we created it in this method or it already
* existed.)
*/
- private boolean checkThatRemotePathExists(String rPath) {
+ private boolean checkThatRemotePathExists(String remotePath) {
SFTPSession session = null;
ChannelSftp channelSftp = null;
try {
session = pool.getSession();
- assert session != null : "session's not null";
+ Assert.state(session != null, "session as returned from the pool should not be null. " + "If it is, it is most likely an error in the pool implementation. ");
session.start();
channelSftp = session.getChannel();
- SftpATTRS attrs = channelSftp.stat(rPath);
+ SftpATTRS attrs = channelSftp.stat(remotePath);
assert (attrs != null) && attrs.isDir() : "attrs can't be null, and should indicate that it's a directory!";
return true;
@@ -203,9 +210,9 @@ public class SFTPInboundSynchronizer implements InitializingBean {
if (this.autoCreatePath && (pool != null) && (session != null)) {
try {
if (channelSftp != null) {
- channelSftp.mkdir(rPath);
+ channelSftp.mkdir(remotePath);
- if (channelSftp.stat(rPath).isDir()) {
+ if (channelSftp.stat(remotePath).isDir()) {
return true;
}
}
@@ -261,10 +268,6 @@ public class SFTPInboundSynchronizer implements InitializingBean {
return false;
}
- private boolean foo() {
- return false;
- }
-
class SynchronizeTask implements Runnable {
public void run() {
try {
diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SFTPMessageSourceFactoryBean.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SFTPMessageSourceFactoryBean.java
index 274db9bfea..d6ef0cd39b 100644
--- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SFTPMessageSourceFactoryBean.java
+++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SFTPMessageSourceFactoryBean.java
@@ -15,43 +15,32 @@
*/
package org.springframework.integration.sftp.config;
-import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
-
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AbstractFactoryBean;
-
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
-
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
-
import org.springframework.integration.file.FileReadingMessageSource;
-import org.springframework.integration.sftp.QueuedSFTPSessionPool;
-import org.springframework.integration.sftp.SFTPInboundSynchronizer;
-import org.springframework.integration.sftp.SFTPMessageSource;
-import org.springframework.integration.sftp.SFTPSessionFactory;
-
+import org.springframework.integration.sftp.*;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
-
import org.springframework.util.ErrorHandler;
+import org.springframework.util.StringUtils;
import java.io.File;
-
import java.util.Map;
/**
- *
* Building a {@link org.springframework.integration.sftp.SFTPMessageSource} is a complicated because we also
* use a {@link org.springframework.integration.file.FileReadingMessageSource} to handle the "receipt" of files in
* a {@link #localWorkingDirectory}.
- *
+ *
* @author Josh Long
*/
public class SFTPMessageSourceFactoryBean extends AbstractFactoryBean implements ApplicationContextAware, ResourceLoaderAware {
@@ -72,6 +61,8 @@ public class SFTPMessageSourceFactoryBean extends AbstractFactoryBean tss = null;
@@ -245,8 +258,8 @@ public class SFTPMessageSourceFactoryBean extends AbstractFactoryBean
- Password authentication: using this opton, authenticatio is done using a username and a password.
+ Password authentication: using this opton, authentication is done using a username and a password.
Key-based authentication: using this option, you may specify a key that will be used to authenticate. If they key itself is encrypted and requires a password, you may specify that, as well.
]]>
@@ -94,6 +94,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -114,4 +125,4 @@
-
\ No newline at end of file
+
diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/TestInboundSFTP.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/TestInboundSFTP.java
new file mode 100644
index 0000000000..a2f4271322
--- /dev/null
+++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/TestInboundSFTP.java
@@ -0,0 +1,14 @@
+package org.springframework.integration.sftp;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @author Josh Long
+ */
+public class TestInboundSFTP {
+
+ static public void main(String [] args) throws Throwable {
+ ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("TestInboundSFTP.xml");
+ classPathXmlApplicationContext.start();
+ }
+}
diff --git a/spring-integration-sftp/src/test/resources/TestInboundSFTP.xml b/spring-integration-sftp/src/test/resources/TestInboundSFTP.xml
index eee6bc37f5..6ef7076255 100644
--- a/spring-integration-sftp/src/test/resources/TestInboundSFTP.xml
+++ b/spring-integration-sftp/src/test/resources/TestInboundSFTP.xml
@@ -35,24 +35,27 @@
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp-2.0.xsd">
+
-
+
-
+
-
+
-
\ No newline at end of file
+