moved spaces to tabs for the sftp package

This commit is contained in:
Josh Long
2010-08-24 22:12:24 +00:00
parent d2d4104d86
commit aef97c4012
19 changed files with 977 additions and 988 deletions

View File

@@ -1,99 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-sftp</artifactId>
<packaging>jar</packaging>
<name>Spring Integration SFTP Support</name>
<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.42</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<!-- <plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins> -->
</build>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-sftp</artifactId>
<packaging>jar</packaging>
<name>Spring Integration SFTP Support</name>
<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.42</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<!-- <plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins> -->
</build>
</project>

View File

@@ -31,68 +31,68 @@ import java.util.concurrent.ArrayBlockingQueue;
* @since 2.0
*/
public class QueuedSftpSessionPool implements SftpSessionPool, InitializingBean {
public static final int DEFAULT_POOL_SIZE = 10;
private Queue<SftpSession> queue;
private final SftpSessionFactory sftpSessionFactory;
private int maxPoolSize;
public static final int DEFAULT_POOL_SIZE = 10;
private Queue<SftpSession> queue;
private final SftpSessionFactory sftpSessionFactory;
private int maxPoolSize;
public QueuedSftpSessionPool(SftpSessionFactory factory) {
this(DEFAULT_POOL_SIZE, factory);
}
public QueuedSftpSessionPool(SftpSessionFactory factory) {
this(DEFAULT_POOL_SIZE, factory);
}
public QueuedSftpSessionPool(int maxPoolSize, SftpSessionFactory sessionFactory) {
this.sftpSessionFactory = sessionFactory;
this.maxPoolSize = maxPoolSize;
}
public QueuedSftpSessionPool(int maxPoolSize, SftpSessionFactory sessionFactory) {
this.sftpSessionFactory = sessionFactory;
this.maxPoolSize = maxPoolSize;
}
public void afterPropertiesSet() throws Exception {
assert maxPoolSize > 0 : "poolSize must be greater than 0!";
queue = new ArrayBlockingQueue<SftpSession>(maxPoolSize, true); // size, faireness to avoid starvation
assert sftpSessionFactory != null : "sftpSessionFactory must not be null!";
}
public void afterPropertiesSet() throws Exception {
assert maxPoolSize > 0 : "poolSize must be greater than 0!";
queue = new ArrayBlockingQueue<SftpSession>(maxPoolSize, true); // size, faireness to avoid starvation
assert sftpSessionFactory != null : "sftpSessionFactory must not be null!";
}
public SftpSession getSession() throws Exception {
SftpSession session = this.queue.poll();
public SftpSession getSession() throws Exception {
SftpSession session = this.queue.poll();
if (null == session) {
session = this.sftpSessionFactory.getObject();
if (null == session) {
session = this.sftpSessionFactory.getObject();
if (queue.size() < maxPoolSize) {
queue.add(session);
}
}
if (queue.size() < maxPoolSize) {
queue.add(session);
}
}
if (null == session) {
session = queue.poll();
}
if (null == session) {
session = queue.poll();
}
return session;
}
return session;
}
public void release(SftpSession session) {
if (queue.size() < maxPoolSize) {
queue.add(session); // somehow one snuck in before <code>session</code> was finished!
} else {
dispose(session);
}
}
public void release(SftpSession session) {
if (queue.size() < maxPoolSize) {
queue.add(session); // somehow one snuck in before <code>session</code> was finished!
} else {
dispose(session);
}
}
private void dispose(SftpSession s) {
if (s == null) {
return;
}
private void dispose(SftpSession s) {
if (s == null) {
return;
}
if (queue.contains(s)) //this should never happen, but if it does ...
{
queue.remove(s);
}
if (queue.contains(s)) //this should never happen, but if it does ...
{
queue.remove(s);
}
if ((s.getChannel() != null) && s.getChannel().isConnected()) {
s.getChannel().disconnect();
}
if ((s.getChannel() != null) && s.getChannel().isConnected()) {
s.getChannel().disconnect();
}
if (s.getSession().isConnected()) {
s.getSession().disconnect();
}
}
if (s.getSession().isConnected()) {
s.getSession().disconnect();
}
}
}

View File

@@ -21,5 +21,5 @@ package org.springframework.integration.sftp;
* @author Josh Long
*/
public class SftpConstants {
public static final String SFTP_REMOTE_DIRECTORY_HEADER = "SFTP_REMOTE_DIRECTORY_HEADER";
public static final String SFTP_REMOTE_DIRECTORY_HEADER = "SFTP_REMOTE_DIRECTORY_HEADER";
}

View File

@@ -8,9 +8,9 @@ import org.springframework.integration.file.entries.EntryNamer;
*
* @author Josh Long
*/
public class SftpEntryNamer implements EntryNamer<ChannelSftp.LsEntry>{
public class SftpEntryNamer implements EntryNamer<ChannelSftp.LsEntry> {
public String nameOf(ChannelSftp.LsEntry entry) {
return entry.getFilename() ;
}
public String nameOf(ChannelSftp.LsEntry entry) {
return entry.getFilename();
}
}

View File

@@ -41,179 +41,178 @@ import java.io.*;
* @author Josh Long
*/
public class SftpSendingMessageHandler implements MessageHandler, InitializingBean {
private SftpSessionPool pool;
private String remoteDirectory;
private volatile boolean afterPropertiesSetRan;
private SftpSessionPool pool;
private String remoteDirectory;
private volatile boolean afterPropertiesSetRan;
public SftpSendingMessageHandler(SftpSessionPool pool) {
this.pool = pool;
}
public SftpSendingMessageHandler(SftpSessionPool pool) {
this.pool = pool;
}
public void afterPropertiesSet() throws Exception {
Assert.state( this.pool != null , "the pool can't be null!");
public void afterPropertiesSet() throws Exception {
Assert.state(this.pool != null, "the pool can't be null!");
temporaryBufferFolderFile = this.temporaryBufferFolder.getFile();
temporaryBufferFolderFile = this.temporaryBufferFolder.getFile();
if (!afterPropertiesSetRan) {
if (StringUtils.isEmpty(this.remoteDirectory)) {
remoteDirectory = null;
}
if (!afterPropertiesSetRan) {
if (StringUtils.isEmpty(this.remoteDirectory)) {
remoteDirectory = null;
}
this.afterPropertiesSetRan = true;
}
}
this.afterPropertiesSetRan = true;
}
}
public String getRemoteDirectory() {
return remoteDirectory;
}
public String getRemoteDirectory() {
return remoteDirectory;
}
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
private File handleFileMessage(File sourceFile, File tempFile, File resultFile)
throws IOException {
if (sourceFile.renameTo(resultFile)) {
return resultFile;
}
private File handleFileMessage(File sourceFile, File tempFile, File resultFile)
throws IOException {
if (sourceFile.renameTo(resultFile)) {
return resultFile;
}
FileCopyUtils.copy(sourceFile, tempFile);
tempFile.renameTo(resultFile);
FileCopyUtils.copy(sourceFile, tempFile);
tempFile.renameTo(resultFile);
return resultFile;
}
return resultFile;
}
private File handleByteArrayMessage(byte[] bytes, File tempFile, File resultFile)
throws IOException {
FileCopyUtils.copy(bytes, tempFile);
tempFile.renameTo(resultFile);
private File handleByteArrayMessage(byte[] bytes, File tempFile, File resultFile)
throws IOException {
FileCopyUtils.copy(bytes, tempFile);
tempFile.renameTo(resultFile);
return resultFile;
}
return resultFile;
}
private File handleStringMessage(String content, File tempFile, File resultFile, String charset)
throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tempFile), charset);
FileCopyUtils.copy(content, writer);
tempFile.renameTo(resultFile);
private File handleStringMessage(String content, File tempFile, File resultFile, String charset)
throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tempFile), charset);
FileCopyUtils.copy(content, writer);
tempFile.renameTo(resultFile);
return resultFile;
}
return resultFile;
}
private static final String TEMPORARY_FILE_SUFFIX = ".writing";
private FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
private File temporaryBufferFolderFile;
private Resource temporaryBufferFolder = new FileSystemResource(SystemUtils.getJavaIoTmpDir());
private static final String TEMPORARY_FILE_SUFFIX = ".writing";
private FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
private File temporaryBufferFolderFile;
private Resource temporaryBufferFolder = new FileSystemResource(SystemUtils.getJavaIoTmpDir());
public void setTemporaryBufferFolder(Resource temporaryBufferFolder) {
this.temporaryBufferFolder = temporaryBufferFolder;
}
public void setTemporaryBufferFolder(Resource temporaryBufferFolder) {
this.temporaryBufferFolder = temporaryBufferFolder;
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
this.fileNameGenerator = fileNameGenerator;
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
this.fileNameGenerator = fileNameGenerator;
}
private File redeemForStorableFile(Message<?> msg) throws MessageDeliveryException {
try {
Object payload = msg.getPayload();
String generateFileName = this.fileNameGenerator.generateFileName(msg);
File tempFile = new File(temporaryBufferFolderFile, generateFileName + TEMPORARY_FILE_SUFFIX);
File resultFile = new File(temporaryBufferFolderFile, generateFileName);
File sendableFile;
if (payload instanceof String)
sendableFile = this.handleStringMessage((String) payload, tempFile, resultFile, this.charset);
else if (payload instanceof File)
sendableFile = this.handleFileMessage((File) payload, tempFile, resultFile);
else if (payload instanceof byte[])
sendableFile = this.handleByteArrayMessage((byte[]) payload, tempFile, resultFile);
else sendableFile = null;
return sendableFile;
} catch (Throwable th) {
throw new MessageDeliveryException(msg);
}
private File redeemForStorableFile(Message<?> msg) throws MessageDeliveryException {
try {
Object payload = msg.getPayload();
String generateFileName = this.fileNameGenerator.generateFileName(msg);
File tempFile = new File(temporaryBufferFolderFile, generateFileName + TEMPORARY_FILE_SUFFIX);
File resultFile = new File(temporaryBufferFolderFile, generateFileName);
File sendableFile;
if (payload instanceof String)
sendableFile = this.handleStringMessage((String) payload, tempFile, resultFile, this.charset);
else if (payload instanceof File)
sendableFile = this.handleFileMessage((File) payload, tempFile, resultFile);
else if (payload instanceof byte[])
sendableFile = this.handleByteArrayMessage((byte[]) payload, tempFile, resultFile);
else sendableFile = null;
return sendableFile;
} catch (Throwable th) {
throw new MessageDeliveryException(msg);
}
}
}
private String charset;
private String charset;
public void setCharset(String charset) {
this.charset = charset;
}
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
public void setCharset(String charset) {
this.charset = charset;
}
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
public void handleMessage(final Message<?> message)
throws MessageRejectedException, MessageHandlingException, MessageDeliveryException {
Assert.state(this.pool != null, "need a working pool");
File inboundFilePayload = this.redeemForStorableFile(message);
try {
public void handleMessage(final Message<?> message)
throws MessageRejectedException, MessageHandlingException, MessageDeliveryException {
Assert.state(this.pool != null , "need a working pool");
File inboundFilePayload = this.redeemForStorableFile( message);
try {
if ((inboundFilePayload != null) && inboundFilePayload.exists()) {
sendFileToRemoteEndpoint(message, inboundFilePayload);
}
} catch (Throwable thr) {
// logger.debug("recieved an exception.", thr);
throw new MessageDeliveryException(message, "couldn't deliver the message!", thr);
} finally {
if (inboundFilePayload != null && inboundFilePayload.exists())
inboundFilePayload.delete();
if ((inboundFilePayload != null) && inboundFilePayload.exists()) {
sendFileToRemoteEndpoint(message, inboundFilePayload);
}
} catch (Throwable thr) {
// logger.debug("recieved an exception.", thr);
throw new MessageDeliveryException(message, "couldn't deliver the message!", thr);
} finally {
if(inboundFilePayload!=null&&inboundFilePayload.exists())
inboundFilePayload.delete() ;
}
}
}
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
private boolean sendFileToRemoteEndpoint(Message<?> message, File file)
throws Throwable {
assert this.pool != null : "need a working pool";
private boolean sendFileToRemoteEndpoint(Message<?> message, File file)
throws Throwable {
assert this.pool != null : "need a working pool";
SftpSession session = this.pool.getSession();
SftpSession session = this.pool.getSession();
if (session == null) {
throw new RuntimeException("the session returned from the pool is null, can't possibly proceed.");
}
if (session == null) {
throw new RuntimeException("the session returned from the pool is null, can't possibly proceed.");
}
session.start();
session.start();
ChannelSftp sftp = session.getChannel();
ChannelSftp sftp = session.getChannel();
InputStream fileInputStream = null;
InputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
try {
fileInputStream = new FileInputStream(file);
String baseOfRemotePath = StringUtils.isEmpty(this.remoteDirectory) ? StringUtils.EMPTY : remoteDirectory; // the safe default
String baseOfRemotePath = StringUtils.isEmpty(this.remoteDirectory) ? StringUtils.EMPTY : remoteDirectory; // the safe default
// logger.debug("going to send " + file.getAbsolutePath() + " to a remote sftp endpoint");
String dynRd = null;
MessageHeaders messageHeaders = null;
// logger.debug("going to send " + file.getAbsolutePath() + " to a remote sftp endpoint");
String dynRd = null;
MessageHeaders messageHeaders = null;
if (message != null) {
messageHeaders = message.getHeaders();
if (message != null) {
messageHeaders = message.getHeaders();
if ((messageHeaders != null) && messageHeaders.containsKey(SftpConstants.SFTP_REMOTE_DIRECTORY_HEADER)) {
dynRd = (String) messageHeaders.get(SftpConstants.SFTP_REMOTE_DIRECTORY_HEADER);
if ((messageHeaders != null) && messageHeaders.containsKey(SftpConstants.SFTP_REMOTE_DIRECTORY_HEADER)) {
dynRd = (String) messageHeaders.get(SftpConstants.SFTP_REMOTE_DIRECTORY_HEADER);
if (!StringUtils.isEmpty(dynRd)) {
baseOfRemotePath = dynRd;
}
}
}
if (!StringUtils.isEmpty(dynRd)) {
baseOfRemotePath = dynRd;
}
}
}
if (!StringUtils.defaultString(baseOfRemotePath).endsWith("/")) {
baseOfRemotePath += "/";
}
if (!StringUtils.defaultString(baseOfRemotePath).endsWith("/")) {
baseOfRemotePath += "/";
}
sftp.put(fileInputStream, baseOfRemotePath + file.getName());
sftp.put(fileInputStream, baseOfRemotePath + file.getName());
return true;
} finally {
IOUtils.closeQuietly(fileInputStream);
return true;
} finally {
IOUtils.closeQuietly(fileInputStream);
if (pool != null) {
pool.release(session);
}
}
}
if (pool != null) {
pool.release(session);
}
}
}
}

View File

@@ -25,133 +25,132 @@ import org.apache.commons.lang.StringUtils;
import java.io.InputStream;
/** c
/**
* c
* There are many ways to create a {@link SftpSession} just as there are many ways to SSH into a remote system.
* You may use a username and password, you may use a username and private key, you may use a username and a private key with a password, etc.
*
* <p/>
* This object represents the connection to the remote server, and to use it you must provide it with all the components you'd normally provide an
* incantation of the <code>ssh</code> command.
*
*
* @author Josh Long
* @author Mario Gray
*/
public class SftpSession {
private volatile ChannelSftp channel;
private volatile Session session;
private String privateKey;
private String privateKeyPassphrase;
private volatile UserInfo userInfo;
private volatile ChannelSftp channel;
private volatile Session session;
private String privateKey;
private String privateKeyPassphrase;
private volatile UserInfo userInfo;
/**
* @param userName the name of the account being logged into.
* @param hostName this should be the host. I found values like <code>foo.com</code> work, where
* <code>http://foo.com</code> don't.
* @param userPassword if you are not using key based authentication, then you are likely being prompted
* for a password each time you login. This is that password. It is <em>not</em> the
* passphrase for the private key!
* @param port the default is 22, and if you specify N<0 for this value we'll default it to 22
* @param knownHostsFile this is the known hosts file. If you don't specify it, jsch does some magic to work
* without your specification. If you have it in a non well-known location, however,
* this property is for you. An example: <code>/home/user/.ssh/known_hosts</code>
* @param knownHostsInputStream this is the known hosts file. If you don't specify it, jsch does some magic to work
* without your specification. If you have it in a non well-known location, however,
* this property is for you. An example: <code>/home/user/.ssh/known_hosts</code>. Note
* that you may specify this <em>or</em> the #knownHostsFile - not both!
* @param privateKey this is usually used when you want passwordless automation (obviously, for this
* integration it's useless since this lets you specify a password once, anyway, but
* still good to have if required). This file might be ~/.ssh/id_dsa, or a
* <code>.pem</code> for your remote server (for example, on EC2)
* @param pvKeyPassPhrase sometimes, to be extra secure, the private key itself is extra encrypted. In order
* to surmount that, we need the private key passphrase. Specify that here.
*
* @throws Exception thrown if any of a myriad of scenarios plays out
*/
public SftpSession(String userName, String hostName, String userPassword, int port, String knownHostsFile, InputStream knownHostsInputStream, String privateKey, String pvKeyPassPhrase)
throws Exception {
JSch jSch = new JSch();
/**
* @param userName the name of the account being logged into.
* @param hostName this should be the host. I found values like <code>foo.com</code> work, where
* <code>http://foo.com</code> don't.
* @param userPassword if you are not using key based authentication, then you are likely being prompted
* for a password each time you login. This is that password. It is <em>not</em> the
* passphrase for the private key!
* @param port the default is 22, and if you specify N<0 for this value we'll default it to 22
* @param knownHostsFile this is the known hosts file. If you don't specify it, jsch does some magic to work
* without your specification. If you have it in a non well-known location, however,
* this property is for you. An example: <code>/home/user/.ssh/known_hosts</code>
* @param knownHostsInputStream this is the known hosts file. If you don't specify it, jsch does some magic to work
* without your specification. If you have it in a non well-known location, however,
* this property is for you. An example: <code>/home/user/.ssh/known_hosts</code>. Note
* that you may specify this <em>or</em> the #knownHostsFile - not both!
* @param privateKey this is usually used when you want passwordless automation (obviously, for this
* integration it's useless since this lets you specify a password once, anyway, but
* still good to have if required). This file might be ~/.ssh/id_dsa, or a
* <code>.pem</code> for your remote server (for example, on EC2)
* @param pvKeyPassPhrase sometimes, to be extra secure, the private key itself is extra encrypted. In order
* to surmount that, we need the private key passphrase. Specify that here.
* @throws Exception thrown if any of a myriad of scenarios plays out
*/
public SftpSession(String userName, String hostName, String userPassword, int port, String knownHostsFile, InputStream knownHostsInputStream, String privateKey, String pvKeyPassPhrase)
throws Exception {
JSch jSch = new JSch();
if (port <= 0) {
port = 22;
}
if (port <= 0) {
port = 22;
}
this.privateKey = privateKey;
this.privateKeyPassphrase = pvKeyPassPhrase;
this.privateKey = privateKey;
this.privateKeyPassphrase = pvKeyPassPhrase;
if (!StringUtils.isEmpty(knownHostsFile)) {
jSch.setKnownHosts(knownHostsFile);
} else if (null != knownHostsInputStream) {
jSch.setKnownHosts(knownHostsInputStream);
}
if (!StringUtils.isEmpty(knownHostsFile)) {
jSch.setKnownHosts(knownHostsFile);
} else if (null != knownHostsInputStream) {
jSch.setKnownHosts(knownHostsInputStream);
}
// private key
if (!StringUtils.isEmpty(this.privateKey)) {
if (!StringUtils.isEmpty(privateKeyPassphrase)) {
jSch.addIdentity(this.privateKey, privateKeyPassphrase);
} else {
jSch.addIdentity(this.privateKey);
}
}
// private key
if (!StringUtils.isEmpty(this.privateKey)) {
if (!StringUtils.isEmpty(privateKeyPassphrase)) {
jSch.addIdentity(this.privateKey, privateKeyPassphrase);
} else {
jSch.addIdentity(this.privateKey);
}
}
session = jSch.getSession(userName, hostName, port);
session = jSch.getSession(userName, hostName, port);
if (!StringUtils.isEmpty(userPassword)) {
session.setPassword(userPassword);
}
if (!StringUtils.isEmpty(userPassword)) {
session.setPassword(userPassword);
}
userInfo = new OptimisticUserInfoImpl(userPassword);
session.setUserInfo(userInfo);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
}
userInfo = new OptimisticUserInfoImpl(userPassword);
session.setUserInfo(userInfo);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
}
public ChannelSftp getChannel() {
return channel;
}
public ChannelSftp getChannel() {
return channel;
}
public Session getSession() {
return session;
}
public Session getSession() {
return session;
}
public void start() throws Exception {
if (!channel.isConnected()) {
channel.connect();
}
}
public void start() throws Exception {
if (!channel.isConnected()) {
channel.connect();
}
}
/**
* this is a simple, optimistic implementation of this interface. It simply returns in the positive where possible
* and handles interactive authentication (ie, 'Please enter your password: ' prompts are dispatched automatically using this)
*/
private static class OptimisticUserInfoImpl implements UserInfo {
private String pw;
/**
* this is a simple, optimistic implementation of this interface. It simply returns in the positive where possible
* and handles interactive authentication (ie, 'Please enter your password: ' prompts are dispatched automatically using this)
*/
private static class OptimisticUserInfoImpl implements UserInfo {
private String pw;
public OptimisticUserInfoImpl(String password) {
this.pw = password;
}
public OptimisticUserInfoImpl(String password) {
this.pw = password;
}
public String getPassphrase() {
return null; // pass
}
public String getPassphrase() {
return null; // pass
}
public String getPassword() {
return pw;
}
public String getPassword() {
return pw;
}
public boolean promptPassphrase(String string) {
return true;
}
public boolean promptPassphrase(String string) {
return true;
}
public boolean promptPassword(String string) {
return true;
}
public boolean promptPassword(String string) {
return true;
}
public boolean promptYesNo(String string) {
return true;
}
public boolean promptYesNo(String string) {
return true;
}
public void showMessage(String string) {
}
}
public void showMessage(String string) {
}
}
}

View File

@@ -30,59 +30,59 @@ import org.springframework.util.StringUtils;
* @author Mario Gray
*/
public class SftpSessionFactory implements FactoryBean<SftpSession>, InitializingBean {
private volatile String knownHosts;
private volatile String password;
private volatile String privateKey;
private volatile String privateKeyPassphrase;
private volatile String remoteHost;
private volatile String user;
private volatile int port = 22; // the default
private volatile String knownHosts;
private volatile String password;
private volatile String privateKey;
private volatile String privateKeyPassphrase;
private volatile String remoteHost;
private volatile String user;
private volatile int port = 22; // the default
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.remoteHost, "remoteHost can't be empty!");
Assert.hasText(this.user, "user can't be empty!");
Assert.state(StringUtils.hasText(this.password) || StringUtils.hasText(this.privateKey) || StringUtils.hasText(this.privateKeyPassphrase),
"you must configure either a password or a private key and/or a private key passphrase!");
Assert.state(this.port >= 0, "port must be a valid number! ");
}
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.remoteHost, "remoteHost can't be empty!");
Assert.hasText(this.user, "user can't be empty!");
Assert.state(StringUtils.hasText(this.password) || StringUtils.hasText(this.privateKey) || StringUtils.hasText(this.privateKeyPassphrase),
"you must configure either a password or a private key and/or a private key passphrase!");
Assert.state(this.port >= 0, "port must be a valid number! ");
}
public SftpSession getObject() throws Exception {
return new SftpSession( this.user, this.remoteHost , this.password ,this.port, this.knownHosts, null, this.privateKey , this.privateKeyPassphrase);
}
public SftpSession getObject() throws Exception {
return new SftpSession(this.user, this.remoteHost, this.password, this.port, this.knownHosts, null, this.privateKey, this.privateKeyPassphrase);
}
public Class<?extends SftpSession> getObjectType() {
return SftpSession.class;
}
public Class<? extends SftpSession> getObjectType() {
return SftpSession.class;
}
public boolean isSingleton() {
return false;
}
public boolean isSingleton() {
return false;
}
public void setKnownHosts(String knownHosts) {
this.knownHosts = knownHosts;
}
public void setKnownHosts(String knownHosts) {
this.knownHosts = knownHosts;
}
public void setPassword(String password) {
this.password = password;
}
public void setPassword(String password) {
this.password = password;
}
public void setPort(int port) {
this.port = port;
}
public void setPort(int port) {
this.port = port;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public void setPrivateKeyPassphrase(String privateKeyPassphrase) {
this.privateKeyPassphrase = privateKeyPassphrase;
}
public void setPrivateKeyPassphrase(String privateKeyPassphrase) {
this.privateKeyPassphrase = privateKeyPassphrase;
}
public void setRemoteHost(String remoteHost) {
this.remoteHost = remoteHost;
}
public void setRemoteHost(String remoteHost) {
this.remoteHost = remoteHost;
}
public void setUser(String user) {
this.user = user;
}
public void setUser(String user) {
this.user = user;
}
}

View File

@@ -17,28 +17,26 @@
package org.springframework.integration.sftp;
/**
*
* Holds instances of {@link SftpSession} since they're stateful
* and might be in use while another run happens.
*
*
* @author Josh Long
* @author Josh Long
*/
public interface SftpSessionPool {
/**
* this returns a session that can be used to connct to an sftp instance and perform operations
*
* @return the session from the pool ready to be connected to.
* @throws Exception thrown if theres any of the numerous faults possible when trying to connect to the remote
* server
*/
SftpSession getSession() throws Exception;
/**
* this returns a session that can be used to connct to an sftp instance and perform operations
*
* @return the session from the pool ready to be connected to.
* @throws Exception thrown if theres any of the numerous faults possible when trying to connect to the remote
* server
*/
SftpSession getSession() throws Exception;
/**
* Frees up the client. Im not sure what the meaningful semantics of this are. Perhaps it just calls <code>(session
* ,channel).disconnect()</code> ?
*
* @param session the session to relinquish / renew
*/
void release(SftpSession session);
/**
* Frees up the client. Im not sure what the meaningful semantics of this are. Perhaps it just calls <code>(session
* ,channel).disconnect()</code> ?
*
* @param session the session to relinquish / renew
*/
void release(SftpSession session);
}

View File

@@ -28,66 +28,66 @@ import org.springframework.integration.sftp.SftpSessionFactory;
* @author Josh Long
*/
public class SftpMessageSendingConsumerFactoryBean implements FactoryBean<SftpSendingMessageHandler> {
private String host;
private String keyFile;
private String keyFilePassword;
private String password;
private String remoteDirectory;
private String username;
private boolean autoCreateDirectories;
private int port;
private String host;
private String keyFile;
private String keyFilePassword;
private String password;
private String remoteDirectory;
private String username;
private boolean autoCreateDirectories;
private int port;
public SftpSendingMessageHandler getObject() throws Exception {
SftpSessionFactory sessionFactory = SftpSessionUtils.buildSftpSessionFactory(
this.host, this.password, this.username, this.keyFile , this.keyFilePassword, this.port);
public SftpSendingMessageHandler getObject() throws Exception {
SftpSessionFactory sessionFactory = SftpSessionUtils.buildSftpSessionFactory(
this.host, this.password, this.username, this.keyFile, this.keyFilePassword, this.port);
QueuedSftpSessionPool queuedSFTPSessionPool = new QueuedSftpSessionPool(15, sessionFactory);
queuedSFTPSessionPool.afterPropertiesSet();
QueuedSftpSessionPool queuedSFTPSessionPool = new QueuedSftpSessionPool(15, sessionFactory);
queuedSFTPSessionPool.afterPropertiesSet();
SftpSendingMessageHandler sftpSendingMessageHandler = new SftpSendingMessageHandler(queuedSFTPSessionPool);
sftpSendingMessageHandler.setRemoteDirectory(this.remoteDirectory);
sftpSendingMessageHandler.afterPropertiesSet();
SftpSendingMessageHandler sftpSendingMessageHandler = new SftpSendingMessageHandler(queuedSFTPSessionPool);
sftpSendingMessageHandler.setRemoteDirectory(this.remoteDirectory);
sftpSendingMessageHandler.afterPropertiesSet();
return sftpSendingMessageHandler;
}
return sftpSendingMessageHandler;
}
public Class<?extends SftpSendingMessageHandler> getObjectType() {
return SftpSendingMessageHandler.class;
}
public Class<? extends SftpSendingMessageHandler> getObjectType() {
return SftpSendingMessageHandler.class;
}
public boolean isSingleton() {
return false;
}
public boolean isSingleton() {
return false;
}
public void setAutoCreateDirectories(final boolean autoCreateDirectories) {
this.autoCreateDirectories = autoCreateDirectories;
}
public void setAutoCreateDirectories(final boolean autoCreateDirectories) {
this.autoCreateDirectories = autoCreateDirectories;
}
public void setHost(final String host) {
this.host = host;
}
public void setHost(final String host) {
this.host = host;
}
public void setKeyFile(final String keyFile) {
this.keyFile = keyFile;
}
public void setKeyFile(final String keyFile) {
this.keyFile = keyFile;
}
public void setKeyFilePassword(final String keyFilePassword) {
this.keyFilePassword = keyFilePassword;
}
public void setKeyFilePassword(final String keyFilePassword) {
this.keyFilePassword = keyFilePassword;
}
public void setPassword(final String password) {
this.password = password;
}
public void setPassword(final String password) {
this.password = password;
}
public void setPort(final int port) {
this.port = port;
}
public void setPort(final int port) {
this.port = port;
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
public void setUsername(final String username) {
this.username = username;
}
public void setUsername(final String username) {
this.username = username;
}
}

View File

@@ -23,13 +23,11 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.sftp.impl.SftpInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.sftp.impl.SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean;
import org.w3c.dom.Element;
/**
*
* Provides namespace support for using SFTP
*
* @author Josh Long
@@ -37,44 +35,44 @@ import org.w3c.dom.Element;
@SuppressWarnings("unused")
public class SftpNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new SFTPMessageSourceBeanDefinitionParser());
registerBeanDefinitionParser("outbound-channel-adapter", new SFTPMessageSendingConsumerBeanDefinitionParser());
}
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new SFTPMessageSourceBeanDefinitionParser());
registerBeanDefinitionParser("outbound-channel-adapter", new SFTPMessageSendingConsumerBeanDefinitionParser());
}
/**
* Configures an object that can take inbound messages and send them.
*/
private static class SFTPMessageSendingConsumerBeanDefinitionParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SftpMessageSendingConsumerFactoryBean.class.getName());
/**
* Configures an object that can take inbound messages and send them.
*/
private static class SFTPMessageSendingConsumerBeanDefinitionParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SftpMessageSendingConsumerFactoryBean.class.getName());
for (String p : "auto-create-directories,username,password,host,key-file,key-file-password,remote-directory".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
for (String p : "auto-create-directories,username,password,host,key-file,key-file-password,remote-directory".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
return builder.getBeanDefinition();
}
}
return builder.getBeanDefinition();
}
}
/**
* Configures an object that can recieve files from a remote SFTP endpoint and broadcast their arrival to the
* consumer
*/
private static class SFTPMessageSourceBeanDefinitionParser extends AbstractPollingInboundChannelAdapterParser {
@Override
protected String parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.class.getName());
/**
* Configures an object that can recieve files from a remote SFTP endpoint and broadcast their arrival to the
* consumer
*/
private static class SFTPMessageSourceBeanDefinitionParser extends AbstractPollingInboundChannelAdapterParser {
@Override
protected String parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.class.getName());
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "filter");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "filter");
for (String p : "filename-pattern,auto-create-directories,username,password,host,key-file,key-file-password,remote-directory,local-working-directory,auto-delete-remote-files-on-sync".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
for (String p : "filename-pattern,auto-create-directories,username,password,host,key-file,key-file-password,remote-directory,local-working-directory,auto-delete-remote-files-on-sync".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
}
}
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
}
}
}

View File

@@ -24,32 +24,32 @@ import org.springframework.integration.sftp.SftpSessionFactory;
* @author Josh Long
*/
public class SftpSessionUtils {
/**
* This method hides the minutae required to build an #SftpSessionFactory.
*
* @param host the host to connect to.
* @param usr this is required. It is the username of the credentials being authenticated.
* @param pw if password authentication is being used (as opposed to key-based authentication) then this is
* where you configure the password.
* @param pvKey the file that is the private key
* @param pvKeyPass the passphrase used to use the key file
* @param port the default (22) is used if the value here is N< 0. The value should be only be set if the port
* is non-standard (not 22)
* @return the SftpSessionFactory that's used to create connections and get us in the right state to start issue
* commands against a remote SFTP/SSH filesystem
* @throws Exception thrown in case of darned near <em>anything</em>
*/
public static SftpSessionFactory buildSftpSessionFactory(String host, String pw, String usr, String pvKey, String pvKeyPass, int port)
throws Exception {
SftpSessionFactory sftpSessionFactory = new SftpSessionFactory();
sftpSessionFactory.setPassword(pw);
sftpSessionFactory.setPort(port);
sftpSessionFactory.setRemoteHost(host);
sftpSessionFactory.setUser(usr);
sftpSessionFactory.setPrivateKey(pvKey);
sftpSessionFactory.setPrivateKeyPassphrase(pvKeyPass);
sftpSessionFactory.afterPropertiesSet();
/**
* This method hides the minutae required to build an #SftpSessionFactory.
*
* @param host the host to connect to.
* @param usr this is required. It is the username of the credentials being authenticated.
* @param pw if password authentication is being used (as opposed to key-based authentication) then this is
* where you configure the password.
* @param pvKey the file that is the private key
* @param pvKeyPass the passphrase used to use the key file
* @param port the default (22) is used if the value here is N< 0. The value should be only be set if the port
* is non-standard (not 22)
* @return the SftpSessionFactory that's used to create connections and get us in the right state to start issue
* commands against a remote SFTP/SSH filesystem
* @throws Exception thrown in case of darned near <em>anything</em>
*/
public static SftpSessionFactory buildSftpSessionFactory(String host, String pw, String usr, String pvKey, String pvKeyPass, int port)
throws Exception {
SftpSessionFactory sftpSessionFactory = new SftpSessionFactory();
sftpSessionFactory.setPassword(pw);
sftpSessionFactory.setPort(port);
sftpSessionFactory.setRemoteHost(host);
sftpSessionFactory.setUser(usr);
sftpSessionFactory.setPrivateKey(pvKey);
sftpSessionFactory.setPrivateKeyPassphrase(pvKeyPass);
sftpSessionFactory.afterPropertiesSet();
return sftpSessionFactory;
}
return sftpSessionFactory;
}
}

View File

@@ -26,117 +26,117 @@ import java.util.Collection;
* @author Josh Long
*/
public class SftpInboundRemoteFileSystemSynchronizer extends AbstractInboundRemoteFileSystemSychronizer<ChannelSftp.LsEntry> {
/**
* the path on the remote mount
*/
private volatile String remotePath;
/**
* the path on the remote mount
*/
private volatile String remotePath;
/**
* the pool of {@link org.springframework.integration.sftp.SftpSessionPool} SFTP sessions
*/
private volatile SftpSessionPool clientPool;
/**
* the pool of {@link org.springframework.integration.sftp.SftpSessionPool} SFTP sessions
*/
private volatile SftpSessionPool clientPool;
public void setRemotePath(String remotePath) {
this.remotePath = remotePath;
}
public void setRemotePath(String remotePath) {
this.remotePath = remotePath;
}
@Override
protected void onInit() throws Exception {
Assert.notNull(this.clientPool, "'clientPool' can't be null");
Assert.notNull(this.remotePath, "'remotePath' can't be null");
if (this.shouldDeleteSourceFile) {
this.entryAcknowledgmentStrategy = new DeletionEntryAcknowledgmentStrategy();
}
}
@Override
protected void onInit() throws Exception {
Assert.notNull(this.clientPool, "'clientPool' can't be null");
Assert.notNull(this.remotePath, "'remotePath' can't be null");
if (this.shouldDeleteSourceFile) {
this.entryAcknowledgmentStrategy = new DeletionEntryAcknowledgmentStrategy();
}
}
@Required
public void setClientPool(SftpSessionPool clientPool) {
this.clientPool = clientPool;
}
@Required
public void setClientPool(SftpSessionPool clientPool) {
this.clientPool = clientPool;
}
@SuppressWarnings("ignored")
private boolean copyFromRemoteToLocalDirectory(SftpSession sftpSession, ChannelSftp.LsEntry entry, Resource localDir)
throws Exception {
File fileForLocalDir = localDir.getFile();
@SuppressWarnings("ignored")
private boolean copyFromRemoteToLocalDirectory(SftpSession sftpSession, ChannelSftp.LsEntry entry, Resource localDir)
throws Exception {
File fileForLocalDir = localDir.getFile();
File localFile = new File(fileForLocalDir, entry.getFilename());
File localFile = new File(fileForLocalDir, entry.getFilename());
if (!localFile.exists()) {
InputStream in = null;
FileOutputStream fileOutputStream = null;
if (!localFile.exists()) {
InputStream in = null;
FileOutputStream fileOutputStream = null;
try {
File tmpLocalTarget = new File(localFile.getAbsolutePath() +
AbstractInboundRemoteFileSystemSynchronizingMessageSource.INCOMPLETE_EXTENSION);
try {
File tmpLocalTarget = new File(localFile.getAbsolutePath() +
AbstractInboundRemoteFileSystemSynchronizingMessageSource.INCOMPLETE_EXTENSION);
fileOutputStream = new FileOutputStream(tmpLocalTarget);
fileOutputStream = new FileOutputStream(tmpLocalTarget);
String remoteFqPath = this.remotePath + "/" + entry.getFilename();
in = sftpSession.getChannel().get(remoteFqPath);
IOUtils.copy(in, fileOutputStream);
String remoteFqPath = this.remotePath + "/" + entry.getFilename();
in = sftpSession.getChannel().get(remoteFqPath);
IOUtils.copy(in, fileOutputStream);
if (tmpLocalTarget.renameTo(localFile)) {
// last step
this.acknowledge(sftpSession, entry);
}
if (tmpLocalTarget.renameTo(localFile)) {
// last step
this.acknowledge(sftpSession, entry);
}
return true;
} catch (Throwable th) {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(fileOutputStream);
}
} else {
return true;
}
return true;
} catch (Throwable th) {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(fileOutputStream);
}
} else {
return true;
}
return false;
}
return false;
}
@Override
@SuppressWarnings("unchecked")
protected void syncRemoteToLocalFileSystem() throws Exception {
SftpSession session = null;
@Override
@SuppressWarnings("unchecked")
protected void syncRemoteToLocalFileSystem() throws Exception {
SftpSession session = null;
try {
session = clientPool.getSession();
session.start();
try {
session = clientPool.getSession();
session.start();
ChannelSftp channelSftp = session.getChannel();
Collection<ChannelSftp.LsEntry> beforeFilter = channelSftp.ls(remotePath);
ChannelSftp.LsEntry[] entries = (beforeFilter == null) ? new ChannelSftp.LsEntry[0] : beforeFilter.toArray(new ChannelSftp.LsEntry[beforeFilter.size()]);
Collection<ChannelSftp.LsEntry> files = this.filter.filterEntries(entries);
ChannelSftp channelSftp = session.getChannel();
Collection<ChannelSftp.LsEntry> beforeFilter = channelSftp.ls(remotePath);
ChannelSftp.LsEntry[] entries = (beforeFilter == null) ? new ChannelSftp.LsEntry[0] : beforeFilter.toArray(new ChannelSftp.LsEntry[beforeFilter.size()]);
Collection<ChannelSftp.LsEntry> files = this.filter.filterEntries(entries);
for (ChannelSftp.LsEntry lsEntry : files) {
if ((lsEntry != null) && !lsEntry.getAttrs().isDir() && !lsEntry.getAttrs().isLink()) {
copyFromRemoteToLocalDirectory(session, lsEntry, this.localDirectory);
}
}
} catch (IOException e) {
throw new MessagingException("couldn't synchronize remote to local directory", e);
} finally {
if ((session != null) && (clientPool != null)) {
clientPool.release(session);
}
}
}
for (ChannelSftp.LsEntry lsEntry : files) {
if ((lsEntry != null) && !lsEntry.getAttrs().isDir() && !lsEntry.getAttrs().isLink()) {
copyFromRemoteToLocalDirectory(session, lsEntry, this.localDirectory);
}
}
} catch (IOException e) {
throw new MessagingException("couldn't synchronize remote to local directory", e);
} finally {
if ((session != null) && (clientPool != null)) {
clientPool.release(session);
}
}
}
@Override
protected Trigger getTrigger() {
return new PeriodicTrigger(10 * 1000);
}
@Override
protected Trigger getTrigger() {
return new PeriodicTrigger(10 * 1000);
}
class DeletionEntryAcknowledgmentStrategy implements AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy<ChannelSftp.LsEntry> {
public void acknowledge(Object useful, ChannelSftp.LsEntry msg)
throws Exception {
SftpSession sftpSession = (SftpSession) useful;
class DeletionEntryAcknowledgmentStrategy implements AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy<ChannelSftp.LsEntry> {
public void acknowledge(Object useful, ChannelSftp.LsEntry msg)
throws Exception {
SftpSession sftpSession = (SftpSession) useful;
String remoteFqPath = remotePath + "/" + msg.getFilename();
String remoteFqPath = remotePath + "/" + msg.getFilename();
sftpSession.getChannel().rm(remoteFqPath);
sftpSession.getChannel().rm(remoteFqPath);
if (logger.isDebugEnabled()) {
logger.debug("deleted " + msg.getFilename());
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("deleted " + msg.getFilename());
}
}
}
}

View File

@@ -2,11 +2,9 @@ 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.sftp.SftpSession;
import org.springframework.integration.sftp.SftpSessionPool;
import org.springframework.util.Assert;
@@ -16,86 +14,86 @@ import org.springframework.util.Assert;
* @author Josh Long
*/
public class SftpInboundRemoteFileSystemSynchronizingMessageSource extends AbstractInboundRemoteFileSystemSynchronizingMessageSource<ChannelSftp.LsEntry, SftpInboundRemoteFileSystemSynchronizer> {
/**
* the pool of sessions
*/
private volatile SftpSessionPool clientPool;
/**
* the pool of sessions
*/
private volatile SftpSessionPool clientPool;
/**
* the remote path on teh server
*/
private volatile String remotePath;
public void setClientPool(SftpSessionPool clientPool) {
this.clientPool = clientPool;
}
/**
* the remote path on teh server
*/
private volatile String remotePath;
public void setRemotePath(String remotePath) {
this.remotePath = remotePath;
}
public void setClientPool(SftpSessionPool clientPool) {
this.clientPool = clientPool;
}
@Override
protected void doStart() {
this.synchronizer.start();
}
public void setRemotePath(String remotePath) {
this.remotePath = remotePath;
}
@Override
protected void doStop() {
this.synchronizer.stop();
}
@Override
protected void doStart() {
this.synchronizer.start();
}
/**
* there be dragons this way ... This method will check to ensure that the remote directory exists. If the directory
* doesnt exist, and autoCreatePath is 'true,' then this method makes a few reasonably sane attempts
* to create it. Otherwise, it fails fast.
*
* @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 remotePath) {
SftpSession session = null;
ChannelSftp channelSftp = null;
@Override
protected void doStop() {
this.synchronizer.stop();
}
try {
session = this.clientPool.getSession();
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();
/**
* there be dragons this way ... This method will check to ensure that the remote directory exists. If the directory
* doesnt exist, and autoCreatePath is 'true,' then this method makes a few reasonably sane attempts
* to create it. Otherwise, it fails fast.
*
* @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 remotePath) {
SftpSession session = null;
ChannelSftp channelSftp = null;
SftpATTRS attrs = channelSftp.stat(remotePath);
assert (attrs != null) && attrs.isDir() : "attrs can't be null, and should indicate that it's a directory!";
try {
session = this.clientPool.getSession();
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();
return true;
} catch (Throwable th) {
if (this.autoCreateDirectories && (this.clientPool != null) && (session != null)) {
try {
if (channelSftp != null) {
channelSftp.mkdir(remotePath);
SftpATTRS attrs = channelSftp.stat(remotePath);
assert (attrs != null) && attrs.isDir() : "attrs can't be null, and should indicate that it's a directory!";
if (channelSftp.stat(remotePath).isDir()) {
return true;
}
}
} catch (Throwable t) {
return false;
}
}
} finally {
if ((clientPool != null) && (session != null)) {
clientPool.release(session);
}
}
return true;
} catch (Throwable th) {
if (this.autoCreateDirectories && (this.clientPool != null) && (session != null)) {
try {
if (channelSftp != null) {
channelSftp.mkdir(remotePath);
return false;
}
if (channelSftp.stat(remotePath).isDir()) {
return true;
}
}
} catch (Throwable t) {
return false;
}
}
} finally {
if ((clientPool != null) && (session != null)) {
clientPool.release(session);
}
}
@Override
protected void onInit() throws Exception {
super.onInit();
return false;
}
this.checkThatRemotePathExists(this.remotePath);
this.synchronizer.setClientPool(this.clientPool);
}
@Override
protected void onInit() throws Exception {
super.onInit();
this.checkThatRemotePathExists(this.remotePath);
this.synchronizer.setClientPool(this.clientPool);
}
}

View File

@@ -25,164 +25,164 @@ import java.io.File;
* @author Josh Long
*/
public class SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean extends AbstractFactoryBean<SftpInboundRemoteFileSystemSynchronizingMessageSource> implements ResourceLoaderAware {
/**
* injected by the container
*/
private volatile ResourceLoader resourceLoader;
private volatile Resource localDirectoryResource;
private volatile String localDirectoryPath;
private volatile String autoCreateDirectories;
private volatile String autoDeleteRemoteFilesOnSync;
private volatile String filenamePattern;
private volatile EntryListFilter<ChannelSftp.LsEntry> filter;
private int port = 22;
private String host;
private String keyFile;
private String keyFilePassword;
private String password;
private String remoteDirectory;
private String username;
/**
* injected by the container
*/
private volatile ResourceLoader resourceLoader;
private volatile Resource localDirectoryResource;
private volatile String localDirectoryPath;
private volatile String autoCreateDirectories;
private volatile String autoDeleteRemoteFilesOnSync;
private volatile String filenamePattern;
private volatile EntryListFilter<ChannelSftp.LsEntry> filter;
private int port = 22;
private String host;
private String keyFile;
private String keyFilePassword;
private String password;
private String remoteDirectory;
private String username;
@SuppressWarnings("unused")
public void setLocalDirectoryResource(Resource localDirectoryResource) {
this.localDirectoryResource = localDirectoryResource;
}
@SuppressWarnings("unused")
public void setLocalDirectoryResource(Resource localDirectoryResource) {
this.localDirectoryResource = localDirectoryResource;
}
@SuppressWarnings("unused")
public void setLocalDirectoryPath(String localDirectoryPath) {
this.localDirectoryPath = localDirectoryPath;
}
@SuppressWarnings("unused")
public void setLocalDirectoryPath(String localDirectoryPath) {
this.localDirectoryPath = localDirectoryPath;
}
@SuppressWarnings("unused")
public void setAutoCreateDirectories(String autoCreateDirectories) {
this.autoCreateDirectories = autoCreateDirectories;
}
@SuppressWarnings("unused")
public void setAutoCreateDirectories(String autoCreateDirectories) {
this.autoCreateDirectories = autoCreateDirectories;
}
@SuppressWarnings("unused")
public void setAutoDeleteRemoteFilesOnSync(String autoDeleteRemoteFilesOnSync) {
this.autoDeleteRemoteFilesOnSync = autoDeleteRemoteFilesOnSync;
}
@SuppressWarnings("unused")
public void setAutoDeleteRemoteFilesOnSync(String autoDeleteRemoteFilesOnSync) {
this.autoDeleteRemoteFilesOnSync = autoDeleteRemoteFilesOnSync;
}
@SuppressWarnings("unused")
public void setFilenamePattern(String filenamePattern) {
this.filenamePattern = filenamePattern;
}
@SuppressWarnings("unused")
public void setFilenamePattern(String filenamePattern) {
this.filenamePattern = filenamePattern;
}
@SuppressWarnings("unused")
public void setFilter(EntryListFilter<ChannelSftp.LsEntry> filter) {
this.filter = filter;
}
@SuppressWarnings("unused")
public void setFilter(EntryListFilter<ChannelSftp.LsEntry> filter) {
this.filter = filter;
}
@SuppressWarnings("unused")
public void setPort(int port) {
this.port = port;
}
@SuppressWarnings("unused")
public void setPort(int port) {
this.port = port;
}
@SuppressWarnings("unused")
public void setHost(String host) {
this.host = host;
}
@SuppressWarnings("unused")
public void setHost(String host) {
this.host = host;
}
@SuppressWarnings("unused")
public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}
@SuppressWarnings("unused")
public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}
@SuppressWarnings("unused")
public void setKeyFilePassword(String keyFilePassword) {
this.keyFilePassword = keyFilePassword;
}
@SuppressWarnings("unused")
public void setKeyFilePassword(String keyFilePassword) {
this.keyFilePassword = keyFilePassword;
}
@SuppressWarnings("unused")
public void setPassword(String password) {
this.password = password;
}
@SuppressWarnings("unused")
public void setPassword(String password) {
this.password = password;
}
@SuppressWarnings("unused")
public void setRemoteDirectory(String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
@SuppressWarnings("unused")
public void setRemoteDirectory(String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
@SuppressWarnings("unused")
public void setUsername(String username) {
this.username = username;
}
@SuppressWarnings("unused")
public void setUsername(String username) {
this.username = username;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public Class<?> getObjectType() {
return SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.class;
}
@Override
public Class<?> getObjectType() {
return SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.class;
}
@Override
protected SftpInboundRemoteFileSystemSynchronizingMessageSource createInstance()
throws Exception {
boolean autoCreatDirs = Boolean.parseBoolean(this.autoCreateDirectories);
boolean ackRemoteDir = Boolean.parseBoolean(this.autoDeleteRemoteFilesOnSync);
@Override
protected SftpInboundRemoteFileSystemSynchronizingMessageSource createInstance()
throws Exception {
boolean autoCreatDirs = Boolean.parseBoolean(this.autoCreateDirectories);
boolean ackRemoteDir = Boolean.parseBoolean(this.autoDeleteRemoteFilesOnSync);
SftpInboundRemoteFileSystemSynchronizingMessageSource sftpMsgSrc = new SftpInboundRemoteFileSystemSynchronizingMessageSource();
sftpMsgSrc.setAutoCreateDirectories(autoCreatDirs);
SftpInboundRemoteFileSystemSynchronizingMessageSource sftpMsgSrc = new SftpInboundRemoteFileSystemSynchronizingMessageSource();
sftpMsgSrc.setAutoCreateDirectories(autoCreatDirs);
// local directories
if ((this.localDirectoryResource == null) || !StringUtils.hasText(this.localDirectoryPath)) {
File tmp = SystemUtils.getJavaIoTmpDir();
File sftpTmp = new File(tmp, "sftpInbound");
this.localDirectoryPath = "file://" + sftpTmp.getAbsolutePath();
}
// local directories
if ((this.localDirectoryResource == null) || !StringUtils.hasText(this.localDirectoryPath)) {
File tmp = SystemUtils.getJavaIoTmpDir();
File sftpTmp = new File(tmp, "sftpInbound");
this.localDirectoryPath = "file://" + sftpTmp.getAbsolutePath();
}
this.localDirectoryResource = this.fromText(localDirectoryPath);
this.localDirectoryResource = this.fromText(localDirectoryPath);
// remote predicates
SftpEntryNamer sftpEntryNamer = new SftpEntryNamer();
CompositeEntryListFilter<ChannelSftp.LsEntry> compositeFtpFileListFilter = new CompositeEntryListFilter<ChannelSftp.LsEntry>();
// remote predicates
SftpEntryNamer sftpEntryNamer = new SftpEntryNamer();
CompositeEntryListFilter<ChannelSftp.LsEntry> compositeFtpFileListFilter = new CompositeEntryListFilter<ChannelSftp.LsEntry>();
if (StringUtils.hasText(this.filenamePattern)) {
PatternMatchingEntryListFilter<ChannelSftp.LsEntry> ftpFilePatternMatchingEntryListFilter = new PatternMatchingEntryListFilter<ChannelSftp.LsEntry>(sftpEntryNamer, filenamePattern);
compositeFtpFileListFilter.addFilter(ftpFilePatternMatchingEntryListFilter);
}
if (StringUtils.hasText(this.filenamePattern)) {
PatternMatchingEntryListFilter<ChannelSftp.LsEntry> ftpFilePatternMatchingEntryListFilter = new PatternMatchingEntryListFilter<ChannelSftp.LsEntry>(sftpEntryNamer, filenamePattern);
compositeFtpFileListFilter.addFilter(ftpFilePatternMatchingEntryListFilter);
}
if (this.filter != null) {
compositeFtpFileListFilter.addFilter(this.filter);
}
if (this.filter != null) {
compositeFtpFileListFilter.addFilter(this.filter);
}
this.filter = compositeFtpFileListFilter;
this.filter = compositeFtpFileListFilter;
// pools
SftpSessionFactory sessionFactory = SftpSessionUtils.buildSftpSessionFactory(this.host, this.password, this.username, this.keyFile, this.keyFilePassword, this.port);
// pools
SftpSessionFactory sessionFactory = SftpSessionUtils.buildSftpSessionFactory(this.host, this.password, this.username, this.keyFile, this.keyFilePassword, this.port);
QueuedSftpSessionPool pool = new QueuedSftpSessionPool(15, sessionFactory);
pool.afterPropertiesSet();
QueuedSftpSessionPool pool = new QueuedSftpSessionPool(15, sessionFactory);
pool.afterPropertiesSet();
SftpInboundRemoteFileSystemSynchronizer sftpSync = new SftpInboundRemoteFileSystemSynchronizer();
sftpSync.setClientPool(pool);
sftpSync.setLocalDirectory(this.localDirectoryResource);
sftpSync.setShouldDeleteSourceFile(ackRemoteDir);
sftpSync.setFilter(compositeFtpFileListFilter);
sftpSync.setBeanFactory(this.getBeanFactory());
sftpSync.setRemotePath(this.remoteDirectory);
sftpSync.afterPropertiesSet(); // todo is this correct ?
sftpSync.start(); //todo
SftpInboundRemoteFileSystemSynchronizer sftpSync = new SftpInboundRemoteFileSystemSynchronizer();
sftpSync.setClientPool(pool);
sftpSync.setLocalDirectory(this.localDirectoryResource);
sftpSync.setShouldDeleteSourceFile(ackRemoteDir);
sftpSync.setFilter(compositeFtpFileListFilter);
sftpSync.setBeanFactory(this.getBeanFactory());
sftpSync.setRemotePath(this.remoteDirectory);
sftpSync.afterPropertiesSet(); // todo is this correct ?
sftpSync.start(); //todo
sftpMsgSrc.setRemotePredicate(compositeFtpFileListFilter);
sftpMsgSrc.setSynchronizer(sftpSync);
sftpMsgSrc.setClientPool(pool);
sftpMsgSrc.setRemotePath(this.remoteDirectory);
sftpMsgSrc.setLocalDirectory(this.localDirectoryResource);
sftpMsgSrc.setBeanFactory(this.getBeanFactory());
sftpMsgSrc.setAutoStartup(true);
sftpMsgSrc.afterPropertiesSet();
sftpMsgSrc.start();
sftpMsgSrc.setRemotePredicate(compositeFtpFileListFilter);
sftpMsgSrc.setSynchronizer(sftpSync);
sftpMsgSrc.setClientPool(pool);
sftpMsgSrc.setRemotePath(this.remoteDirectory);
sftpMsgSrc.setLocalDirectory(this.localDirectoryResource);
sftpMsgSrc.setBeanFactory(this.getBeanFactory());
sftpMsgSrc.setAutoStartup(true);
sftpMsgSrc.afterPropertiesSet();
sftpMsgSrc.start();
return sftpMsgSrc;
}
return sftpMsgSrc;
}
private Resource fromText(String path) {
ResourceEditor resourceEditor = new ResourceEditor(this.resourceLoader);
resourceEditor.setAsText(path);
private Resource fromText(String path) {
ResourceEditor resourceEditor = new ResourceEditor(this.resourceLoader);
resourceEditor.setAsText(path);
return (Resource) resourceEditor.getValue();
}
return (Resource) resourceEditor.getValue();
}
}

View File

@@ -16,58 +16,57 @@
-->
<xsd:schema xmlns="http://www.springframework.org/schema/integration/sftp"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/sftp"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/sftp"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an outbound-channel-adapter that writes files to a remote SFTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" type="xsd:string"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" type="xsd:string"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
</xsd:complexType>
</xsd:element>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes with a remote SFTP endpoint.
You may configure a <code>poller</code> element to determine at what frequency to scan the remote directory.
@@ -78,51 +77,51 @@
<li> 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.</li>
</ol>
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.ftp.FtpFileListFilter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.ftp.FtpFileListFilter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="local-working-directory" type="xsd:string"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="local-working-directory" type="xsd:string"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" type="xsd:string"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" type="xsd:string"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
<xsd:attribute name="auto-delete-remote-files-on-sync" type="xsd:boolean"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
<xsd:attribute name="auto-delete-remote-files-on-sync" type="xsd:boolean"/>
</xsd:complexType>
</xsd:element>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -7,14 +7,13 @@ import java.io.File;
/**
* @author Josh Long
*
*/
@Component("sftpAnnouncer")
public class SftpFileAnnouncer {
@ServiceActivator
public void announceFile(File file){
System.out.println( "New file from the remote host has arrived: " + file.getAbsolutePath()) ;
}
@ServiceActivator
public void announceFile(File file) {
System.out.println("New file from the remote host has arrived: " + file.getAbsolutePath());
}
}

View File

@@ -7,8 +7,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
*/
public class TestInboundSftp {
static public void main(String [] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("TestInboundSftp.xml");
classPathXmlApplicationContext.start();
}
static public void main(String[] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("TestInboundSftp.xml");
classPathXmlApplicationContext.start();
}
}

View File

@@ -17,16 +17,16 @@
-->
<beans:beans
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
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-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
@@ -34,31 +34,31 @@
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp-2.0.xsd">
<context:component-scan base-package="org.springframework.integration.sftp"/>
<context:property-placeholder
location="file://${user.home}/Desktop/sftp.properties"
ignore-unresolvable="true"/>
<context:component-scan base-package="org.springframework.integration.sftp"/>
<context:property-placeholder
location="file://${user.home}/Desktop/sftp.properties"
ignore-unresolvable="true"/>
<channel id="inboundFilesChannel"/>
<channel id="inboundFilesChannel"/>
<sftp:inbound-channel-adapter
key-file="${sftp.key}"
remote-directory="${sftp.remote-dir}"
channel="inboundFilesChannel"
filename-pattern=".*?jpg"
username="${sftp.username}"
auto-create-directories="true"
auto-delete-remote-files-on-sync="true"
host="${sftp.host}">
<poller>
<interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</poller>
</sftp:inbound-channel-adapter>
<sftp:inbound-channel-adapter
key-file="${sftp.key}"
remote-directory="${sftp.remote-dir}"
channel="inboundFilesChannel"
filename-pattern=".*?jpg"
username="${sftp.username}"
auto-create-directories="true"
auto-delete-remote-files-on-sync="true"
host="${sftp.host}">
<poller>
<interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</poller>
</sftp:inbound-channel-adapter>
<service-activator ref="sftpAnnouncer" input-channel="inboundFilesChannel"/>
<service-activator ref="sftpAnnouncer" input-channel="inboundFilesChannel"/>
</beans:beans>

View File

@@ -16,18 +16,17 @@
-->
<beans:beans
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
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-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
@@ -36,20 +35,20 @@
http://www.springframework.org/schema/integration/sftp
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp-2.0.xsd">
<context:component-scan base-package="org.springframework.integration.sftp"/>
<context:component-scan base-package="org.springframework.integration.sftp"/>
<channel id="inboundFilesChannel"/>
<channel id="inboundFilesChannel"/>
<sftp:outbound-channel-adapter
key-file="/home/user/user.pem"
remote-directory="/home/ubuntu/remote_mount_key"
auto-create-directories="true"
channel="inboundFilesChannel"
username="ubuntu"
host="siteonec2usingubuntuami.com"
/>
<sftp:outbound-channel-adapter
key-file="/home/user/user.pem"
remote-directory="/home/ubuntu/remote_mount_key"
auto-create-directories="true"
channel="inboundFilesChannel"
username="ubuntu"
host="siteonec2usingubuntuami.com"
/>
<service-activator input-channel="inboundFilesChannel" ref="sftpAnnouncer"/>
<service-activator input-channel="inboundFilesChannel" ref="sftpAnnouncer"/>
</beans:beans>
</beans:beans>