diff --git a/spring-integration-sftp/pom.xml b/spring-integration-sftp/pom.xml index 9f412137d1..1c83cd8685 100644 --- a/spring-integration-sftp/pom.xml +++ b/spring-integration-sftp/pom.xml @@ -1,99 +1,99 @@ - 4.0.0 - - org.springframework.integration - spring-integration-parent - 2.0.0.BUILD-SNAPSHOT - - org.springframework.integration - spring-integration-sftp - jar - Spring Integration SFTP Support - - - javax.activation - activation - 1.1.1 - true - - - org.springframework.integration - spring-integration-file - ${project.version} - - - com.jcraft - jsch - 0.1.42 - - - cglib - cglib-nodep - ${cglib.version} - test - - - org.easymock - easymock - ${org.easymock.version} - test - - - org.easymock - easymockclassextension - ${org.easymock.version} - test - - - junit - junit - ${junit.version} - test - - - org.springframework - spring-context-support - ${org.springframework.version} - compile - - - org.springframework - spring-test - ${org.springframework.version} - test - - - org.springframework.integration - spring-integration-stream - ${project.version} - compile - - - org.springframework.integration - spring-integration-core - ${project.version} - compile - - - commons-lang - commons-lang - 2.5 - - - commons-io - commons-io - 1.4 - - - - - + 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"> + 4.0.0 + + org.springframework.integration + spring-integration-parent + 2.0.0.BUILD-SNAPSHOT + + org.springframework.integration + spring-integration-sftp + jar + Spring Integration SFTP Support + + + javax.activation + activation + 1.1.1 + true + + + org.springframework.integration + spring-integration-file + ${project.version} + + + com.jcraft + jsch + 0.1.42 + + + cglib + cglib-nodep + ${cglib.version} + test + + + org.easymock + easymock + ${org.easymock.version} + test + + + org.easymock + easymockclassextension + ${org.easymock.version} + test + + + junit + junit + ${junit.version} + test + + + org.springframework + spring-context-support + ${org.springframework.version} + compile + + + org.springframework + spring-test + ${org.springframework.version} + test + + + org.springframework.integration + spring-integration-stream + ${project.version} + compile + + + org.springframework.integration + spring-integration-core + ${project.version} + compile + + + commons-lang + commons-lang + 2.5 + + + commons-io + commons-io + 1.4 + + + + + diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/QueuedSftpSessionPool.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/QueuedSftpSessionPool.java index 4cd55d898d..af4395c1f6 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/QueuedSftpSessionPool.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/QueuedSftpSessionPool.java @@ -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 queue; - private final SftpSessionFactory sftpSessionFactory; - private int maxPoolSize; + public static final int DEFAULT_POOL_SIZE = 10; + private Queue 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(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(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 session was finished! - } else { - dispose(session); - } - } + public void release(SftpSession session) { + if (queue.size() < maxPoolSize) { + queue.add(session); // somehow one snuck in before session 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(); + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpConstants.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpConstants.java index 662e9ec473..7ae153a82e 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpConstants.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpConstants.java @@ -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"; } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpEntryNamer.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpEntryNamer.java index 404c93510b..b55d142ad4 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpEntryNamer.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpEntryNamer.java @@ -8,9 +8,9 @@ import org.springframework.integration.file.entries.EntryNamer; * * @author Josh Long */ -public class SftpEntryNamer implements EntryNamer{ +public class SftpEntryNamer implements EntryNamer { - public String nameOf(ChannelSftp.LsEntry entry) { - return entry.getFilename() ; - } + public String nameOf(ChannelSftp.LsEntry entry) { + return entry.getFilename(); + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSendingMessageHandler.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSendingMessageHandler.java index 3c2538b1d6..5494168266 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSendingMessageHandler.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSendingMessageHandler.java @@ -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); + } + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSession.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSession.java index a25bfa9db0..7ed42d4a19 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSession.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSession.java @@ -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. - * + *

* 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 ssh 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 foo.com work, where - * http://foo.com 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 not 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: /home/user/.ssh/known_hosts - * @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: /home/user/.ssh/known_hosts. Note - * that you may specify this or 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 - * .pem 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 foo.com work, where + * http://foo.com 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 not 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: /home/user/.ssh/known_hosts + * @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: /home/user/.ssh/known_hosts. Note + * that you may specify this or 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 + * .pem 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) { + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionFactory.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionFactory.java index 8d9ed4c071..9b346e7f03 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionFactory.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionFactory.java @@ -30,59 +30,59 @@ import org.springframework.util.StringUtils; * @author Mario Gray */ public class SftpSessionFactory implements FactoryBean, 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 getObjectType() { - return SftpSession.class; - } + public Class 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; + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionPool.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionPool.java index a81c9e0354..da5f02da93 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionPool.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/SftpSessionPool.java @@ -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 (session - * ,channel).disconnect() ? - * - * @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 (session + * ,channel).disconnect() ? + * + * @param session the session to relinquish / renew + */ + void release(SftpSession session); } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpMessageSendingConsumerFactoryBean.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpMessageSendingConsumerFactoryBean.java index 40dfc1e623..f5ffbc19e6 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpMessageSendingConsumerFactoryBean.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpMessageSendingConsumerFactoryBean.java @@ -28,66 +28,66 @@ import org.springframework.integration.sftp.SftpSessionFactory; * @author Josh Long */ public class SftpMessageSendingConsumerFactoryBean implements FactoryBean { - 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 getObjectType() { - return SftpSendingMessageHandler.class; - } + public Class 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; + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpNamespaceHandler.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpNamespaceHandler.java index ec2cc9aada..4e2cbe8960 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpNamespaceHandler.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpNamespaceHandler.java @@ -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()); + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpSessionUtils.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpSessionUtils.java index 908239a35c..1e9c0b5c44 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpSessionUtils.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/config/SftpSessionUtils.java @@ -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 anything - */ - 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 anything + */ + 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; + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizer.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizer.java index 203d6c7f29..e564c1bc27 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizer.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizer.java @@ -26,117 +26,117 @@ import java.util.Collection; * @author Josh Long */ public class SftpInboundRemoteFileSystemSynchronizer extends AbstractInboundRemoteFileSystemSychronizer { - /** - * 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 beforeFilter = channelSftp.ls(remotePath); - ChannelSftp.LsEntry[] entries = (beforeFilter == null) ? new ChannelSftp.LsEntry[0] : beforeFilter.toArray(new ChannelSftp.LsEntry[beforeFilter.size()]); - Collection files = this.filter.filterEntries(entries); + ChannelSftp channelSftp = session.getChannel(); + 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.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 { - public void acknowledge(Object useful, ChannelSftp.LsEntry msg) - throws Exception { - SftpSession sftpSession = (SftpSession) useful; + class DeletionEntryAcknowledgmentStrategy implements AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy { + 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()); + } + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizingMessageSource.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizingMessageSource.java index f45177b690..ba9b45251c 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizingMessageSource.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpInboundRemoteFileSystemSynchronizingMessageSource.java @@ -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 { - /** - * 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); + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.java index 5bbd0854c5..e34844c1b5 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/impl/SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean.java @@ -25,164 +25,164 @@ import java.io.File; * @author Josh Long */ public class SftpRemoteFileSystemSynchronizingMessageSourceFactoryBean extends AbstractFactoryBean 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 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 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 filter) { - this.filter = filter; - } + @SuppressWarnings("unused") + public void setFilter(EntryListFilter 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 compositeFtpFileListFilter = new CompositeEntryListFilter(); + // remote predicates + SftpEntryNamer sftpEntryNamer = new SftpEntryNamer(); + CompositeEntryListFilter compositeFtpFileListFilter = new CompositeEntryListFilter(); - if (StringUtils.hasText(this.filenamePattern)) { - PatternMatchingEntryListFilter ftpFilePatternMatchingEntryListFilter = new PatternMatchingEntryListFilter(sftpEntryNamer, filenamePattern); - compositeFtpFileListFilter.addFilter(ftpFilePatternMatchingEntryListFilter); - } + if (StringUtils.hasText(this.filenamePattern)) { + PatternMatchingEntryListFilter ftpFilePatternMatchingEntryListFilter = new PatternMatchingEntryListFilter(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(); + } } diff --git a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd index 122986609c..766d933e91 100644 --- a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd +++ b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd @@ -16,58 +16,57 @@ --> + 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"> - - - + + + - - - - + + - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - - + + + + - - - + + + - - - + + poller element to determine at what frequency to scan the remote directory. @@ -78,51 +77,51 @@

  • 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.
  • ]]> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - + - - - - + + + + - - - - + + + + - - + + - - + + diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/SftpFileAnnouncer.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/SftpFileAnnouncer.java index 47b7e6bc2e..48b4eac96b 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/SftpFileAnnouncer.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/SftpFileAnnouncer.java @@ -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()); + } } 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 index dd13f032e4..a07ed529c8 100644 --- 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 @@ -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(); + } } diff --git a/spring-integration-sftp/src/test/resources/TestInboundSftp.xml b/spring-integration-sftp/src/test/resources/TestInboundSftp.xml index aa6efb21db..f031d7d131 100644 --- a/spring-integration-sftp/src/test/resources/TestInboundSftp.xml +++ b/spring-integration-sftp/src/test/resources/TestInboundSftp.xml @@ -17,16 +17,16 @@ --> - - - + + + - + - - - - - + + + + + - + diff --git a/spring-integration-sftp/src/test/resources/TestOutboundSftp.xml b/spring-integration-sftp/src/test/resources/TestOutboundSftp.xml index 78a5ecc7f8..132c0eca34 100644 --- a/spring-integration-sftp/src/test/resources/TestOutboundSftp.xml +++ b/spring-integration-sftp/src/test/resources/TestOutboundSftp.xml @@ -16,18 +16,17 @@ --> - - + - + - + - + - \ No newline at end of file +