Using connection pool with JSCH

Here's an implementation of Ssh Connection pool http://www.javacodegeeks.com/2013/02/pool-of-ssh-connections-using-apache-keyedobjectpool.html

you can use grep4j to use this pool https://code.google.com/p/grep4j/source/browse/trunk/src/main/java/org/grep4j/core/command/linux/SessionFactory.java?r=354

Also make sure you can access the server from the execution machine. For instance if the target server is not in your reach. It'll throw connection timeout.


For that I would prefer commons-pool. ;)


I wold like to share with you our implementation, We have used Session Manager of jsch-extension library

First of all you need to implement pool object factory that is responsible for lifecycle of pooled objects:

public class ChannelSftpConnectionsFactory extends BasePooledObjectFactory<ChannelSftp> {
    private SessionManager sessionManager;

    public ChannelSftpConnectionsFactory(final SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    //Create and open channel
    @Override
    public ChannelSftp create() throws JSchException {
        ChannelSftp channelSftp = (ChannelSftp) sessionManager.getSession().openChannel("sftp");
        channelSftp.connect();

        return channelSftp;
    }

    //wrapping
    @Override
    public PooledObject<ChannelSftp> wrap(final ChannelSftp channelSftp) {
        return new DefaultPooledObject<>(channelSftp);
    }

    @Override
    //disconnect channel on destroy
    public void destroyObject(final PooledObject<ChannelSftp> pooledObject) {
        ChannelSftp sftp = pooledObject.getObject();
        disconnectChannel(sftp);
    }

    void disconnectChannel(final ChannelSftp sftp) {
        if (sftp.isConnected()) {
            sftp.disconnect();
        }
    }

    @Override
    //reset channel current folder to home if someone was walking on another folders
    public void passivateObject(final PooledObject<ChannelSftp> p) {
        ChannelSftp sftp = p.getObject();
        try {
            sftp.cd(sftp.getHome());
        } catch (SftpException ex) {
            log.error("Could not reset channel to home folder, closing it");
            disconnectChannel(sftp);
        }
    }

    @Override
    //validate object before it is borrowed from pool. If false object will be removed from pool
    public boolean validateObject(final PooledObject<ChannelSftp> p) {
        ChannelSftp sftp = p.getObject();
        return sftp.isConnected() && !sftp.isClosed();
    }
}

Now you could create pool using configured factory:

ObjectPool<ChannelSftp> createPool(final SessionManager sessionManager, final GenericObjectPoolConfig<ChannelSftp> poolConfig) {
    return PoolUtils.synchronizedPool(new GenericObjectPool<>(buildFactory(sessionManager), poolConfig));
}


PooledObjectFactory<ChannelSftp> buildFactory(final SessionManager sessionManager) {
    return PoolUtils.synchronizedPooledFactory(new ChannelSftpConnectionsFactory(sessionManager));
}

This java doc would help you to configure pool properly : https://commons.apache.org/proper/commons-pool/api-2.6.0/org/apache/commons/pool2/impl/BaseGenericObjectPool.html

Do not forget about correct borrowing and returning of object into pool: https://commons.apache.org/proper/commons-pool/api-2.6.0/org/apache/commons/pool2/ObjectPool.html

 Object obj = null;

 try {
     obj = pool.borrowObject();
     try {
         //...use the object...
     } catch(Exception e) {
         // invalidate the object
         pool.invalidateObject(obj);
         // do not return the object to the pool twice
         obj = null;
     } finally {
         // make sure the object is returned to the pool
         if(null != obj) {
             pool.returnObject(obj);
        }
     }
 } catch(Exception e) {
       // failed to borrow an object
 }