diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/inbound/SftpInboundSynchronizer.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/inbound/SftpInboundSynchronizer.java index be9631b940..7370636016 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/inbound/SftpInboundSynchronizer.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/inbound/SftpInboundSynchronizer.java @@ -123,7 +123,7 @@ public class SftpInboundSynchronizer extends AbstractInboundRemoteFileSystemSych try { session = sessionPool.getSession(); logger.trace("Pooled SftpSession " + this.sessionPool + " from the pool"); - session.start(); + session.connect(); this.checkThatRemotePathExists(remotePath, session); ChannelSftp channelSftp = session.getChannel(); Collection beforeFilter = channelSftp.ls(remotePath); diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandler.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandler.java index ac719d0901..f9a71cd2a2 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandler.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandler.java @@ -171,7 +171,7 @@ public class SftpSendingMessageHandler extends AbstractMessageHandler { } InputStream fileInputStream = null; try { - session.start(); + session.connect(); ChannelSftp sftp = session.getChannel(); fileInputStream = new FileInputStream(file); String baseOfRemotePath = ""; diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/DefaultSftpSession.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/DefaultSftpSession.java new file mode 100644 index 0000000000..48565e3945 --- /dev/null +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/DefaultSftpSession.java @@ -0,0 +1,165 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.sftp.session; + +import java.io.InputStream; + +import org.apache.commons.lang.StringUtils; + +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.UserInfo; + +/** + * Default SftpSession implementation. + * + * @author Josh Long + * @author Mario Gray + * @author Mark Fisher + * @since 2.0 + */ +public class DefaultSftpSession implements SftpSession { + + private volatile ChannelSftp channel; + + private volatile Session targetSession; + + 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 DefaultSftpSession(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; + } + this.privateKey = privateKey; + this.privateKeyPassphrase = pvKeyPassPhrase; + if (!StringUtils.isEmpty(knownHostsFile)) { + jSch.setKnownHosts(knownHostsFile); + } + else if (null != knownHostsInputStream) { + jSch.setKnownHosts(knownHostsInputStream); + } + // private key + if (privateKey != null) { + if (!StringUtils.isEmpty(privateKeyPassphrase)) { + jSch.addIdentity(this.privateKey, privateKeyPassphrase); + } + else { + jSch.addIdentity(this.privateKey); + } + } + this.targetSession = jSch.getSession(userName, hostName, port); + if (!StringUtils.isEmpty(userPassword)) { + this.targetSession.setPassword(userPassword); + } + this.userInfo = new OptimisticUserInfoImpl(userPassword); + this.targetSession.setUserInfo(userInfo); + this.targetSession.connect(); + this.channel = (ChannelSftp) this.targetSession.openChannel("sftp"); + } + + public ChannelSftp getChannel() { + return channel; + } + + public void connect() { + if (!channel.isConnected()) { + try { + channel.connect(); + } + catch (JSchException e) { + throw new IllegalStateException("failed to connect", e); + } + } + } + + public void disconnect() { + if (targetSession.isConnected()) { + targetSession.disconnect(); + } + } + + + /** + * 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 password; + + public OptimisticUserInfoImpl(String password) { + this.password = password; + } + + public String getPassphrase() { + return null; // pass + } + + public String getPassword() { + return password; + } + + public boolean promptPassphrase(String string) { + return true; + } + + public boolean promptPassword(String string) { + return true; + } + + public boolean promptYesNo(String string) { + return true; + } + + public void showMessage(String string) { + } + } + +} diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/QueuedSftpSessionPool.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/QueuedSftpSessionPool.java index f97c077577..bbc9309ab4 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/QueuedSftpSessionPool.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/QueuedSftpSessionPool.java @@ -25,7 +25,6 @@ import org.springframework.context.SmartLifecycle; import org.springframework.util.Assert; import com.jcraft.jsch.Channel; -import com.jcraft.jsch.Session; /** * This approach - of having a SessionPool ({@link SftpSessionPool}) that has an @@ -120,10 +119,7 @@ public class QueuedSftpSessionPool implements SftpSessionPool, SmartLifecycle { if (channel.isConnected()) { channel.disconnect(); } - Session session = sftpSession.getSession(); - if (session.isConnected()) { - session.disconnect(); - } + sftpSession.disconnect(); } } catch (Throwable e) { diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java index f03276c373..58ebfde1bb 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java @@ -16,14 +16,7 @@ package org.springframework.integration.sftp.session; -import java.io.InputStream; - -import org.apache.commons.lang.StringUtils; - import com.jcraft.jsch.ChannelSftp; -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.Session; -import com.jcraft.jsch.UserInfo; /** * There are many ways to create a {@link SftpSession} just as there are many ways to SSH into a remote system. @@ -36,125 +29,12 @@ import com.jcraft.jsch.UserInfo; * @author Mario Gray * @since 2.0 */ -public class SftpSession { +public interface SftpSession { - private volatile ChannelSftp channel; + ChannelSftp getChannel(); - private volatile Session session; + void connect(); - 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(); - if (port <= 0) { - port = 22; - } - this.privateKey = privateKey; - this.privateKeyPassphrase = pvKeyPassPhrase; - if (!StringUtils.isEmpty(knownHostsFile)) { - jSch.setKnownHosts(knownHostsFile); - } - else if (null != knownHostsInputStream) { - jSch.setKnownHosts(knownHostsInputStream); - } - // private key - if (privateKey != null) { - if (!StringUtils.isEmpty(privateKeyPassphrase)) { - jSch.addIdentity(this.privateKey, privateKeyPassphrase); - } - else { - jSch.addIdentity(this.privateKey); - } - } - this.session = jSch.getSession(userName, hostName, port); - if (!StringUtils.isEmpty(userPassword)) { - this.session.setPassword(userPassword); - } - this.userInfo = new OptimisticUserInfoImpl(userPassword); - this.session.setUserInfo(userInfo); - this.session.connect(); - this.channel = (ChannelSftp) this.session.openChannel("sftp"); - } - - public ChannelSftp getChannel() { - return channel; - } - - public Session getSession() { - return session; - } - - 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 password; - - public OptimisticUserInfoImpl(String password) { - this.password = password; - } - - public String getPassphrase() { - return null; // pass - } - - public String getPassword() { - return password; - } - - public boolean promptPassphrase(String string) { - return true; - } - - public boolean promptPassword(String string) { - return true; - } - - public boolean promptYesNo(String string) { - return true; - } - - public void showMessage(String string) { - } - } + void disconnect(); } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SimpleSftpSessionFactory.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SimpleSftpSessionFactory.java index e90b2d53e4..8d3f2de9f0 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SimpleSftpSessionFactory.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SimpleSftpSessionFactory.java @@ -84,7 +84,7 @@ public class SimpleSftpSessionFactory implements SftpSessionFactory { if (privateKey != null){ privateKeyToPass = privateKey.getFile().getAbsolutePath(); } - return new SftpSession(this.user, this.host, this.password, this.port, this.knownHosts, null, privateKeyToPass, this.privateKeyPassphrase); + return new DefaultSftpSession(this.user, this.host, this.password, this.port, this.knownHosts, null, privateKeyToPass, this.privateKeyPassphrase); } catch (Exception e) { throw new IllegalStateException("failed to create SFTP Session", e);