/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.cqcis.com</a>
 */
package com.crunii.micro.common.ftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

/**
 * @author 田平 create 2016-6-14上午11:48:47
 */
@Slf4j
@Configuration
public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp> implements DisposableBean, InitializingBean {

	private String host;
	private int port = 22;
	private String username;
	private String password;
	private int connectTimeout = 60000;// 连接超时时间
	private Properties config = new Properties();
	private static JSch jsch = new JSch();
	private Session session;

	/**
	 * @see BasePooledObjectFactory#create()
	 */
	@Override
	public ChannelSftp create() throws Exception {
		ChannelSftp channelSftp = null;
		synchronized (session) {
			if (!session.isConnected()) {
				session = createSession();
			}
			// session.openChannel is not thread safe
			channelSftp = (ChannelSftp) session.openChannel("sftp");
			channelSftp.connect(connectTimeout);
		}
		return channelSftp;
	}

	@Override
	public void destroyObject(final PooledObject<ChannelSftp> p) throws Exception {
		if (p.getObject() != null) {
			p.getObject().disconnect();
		}
	}

	@Override
	public boolean validateObject(final PooledObject<ChannelSftp> p) {
		if (p.getObject() != null) {
			return p.getObject().isConnected();
		} else {
			return false;
		}
	}

	/**
	 * @see BasePooledObjectFactory#wrap(Object)
	 */
	@Override
	public PooledObject<ChannelSftp> wrap(ChannelSftp obj) {
		return new DefaultPooledObject<ChannelSftp>(obj);
	}

	/**
	 * @return the host
	 */
	public String getHost() {
		return host;
	}

	/**
	 * @param host the host to set
	 */
	public void setHost(String host) {
		this.host = host;
	}

	/**
	 * @return the port
	 */
	public int getPort() {
		return port;
	}

	/**
	 * @param port the port to set
	 */
	public void setPort(int port) {
		this.port = port;
	}

	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the connectTimeout
	 */
	public int getConnectTimeout() {
		return connectTimeout;
	}

	/**
	 * @param connectTimeout the connectTimeout to set
	 */
	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}

	/**
	 * @return the config
	 */
	public Properties getConfig() {
		return config;
	}

	/**
	 * @param config the config to set
	 */
	public void setConfig(Properties config) {
		this.config = config;
	}

	/**
	 * @see InitializingBean#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		session = createSession();
	}

	/**
	 * @see DisposableBean#destroy()
	 */
	@Override
	public void destroy() throws Exception {
		if (session != null) {
			session.disconnect();
		}
	}

	private synchronized Session createSession() {
		Session session = null;
		try {
			session = jsch.getSession(username, host, port);// 根据用户名，主机ip和端口获取一个Session对象
			session.setPassword(password); // 设置密码
			config.put("StrictHostKeyChecking", "no");
			session.setConfig(config);// 为Session对象设置properties
			session.connect(connectTimeout);// 通过Session建立连接
			log.info("SSH connect to {}:{} with user {}!", host, port, username);
			return session;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
