Home » Java » Enterprise Java » Pool of ssh connections using Apache KeyedObjectPool

About Marco Castigliego

Pool of ssh connections using Apache KeyedObjectPool

I found the org.apache.commons.pool extremely useful and robust, but not well documented. So, I’ll try to help a bit here explaining how to use an Apache KeyedObjectPool. What is a KeyedObjectPool? It’s a map that contains a pool of instances of multiple types. Each type may be accessed using an arbitrary key. In this example I’ll create a pool of JSch ssh connections and I will use a simple getter setter object called ServerDetails as a key. Basically for each server I want to have a pool of 10 reusable ssh connections. So first thing to do is to create a Sessionfactory, a class in charge of creating the actual object you want to store in the pool. In our example that would be an ssh connection.
 
 
 
Sessionfactory needs to extend the BaseKeyedPoolableObjectFactory<K,V> where K is the type of keys in this pool and V is the type of objects held in this pool. All you need to do is implement the  makeObject method where you need to actually create the object in the pool and destroyObject where obviously you need to implement the code when the object is released and put back in the pool.

package org.grep4j.core.command.linux;
import org.apache.commons.pool.BaseKeyedPoolableObjectFactory;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
/**
 * This class is used to handle ssh Session inside the pool.
 * 
 * @author Marco Castigliego
 *
 */
public class SessionFactory extends BaseKeyedPoolableObjectFactory<ServerDetails, Session> {

        /**
         * This creates a Session if not already present in the pool.
         */
        @Override
        public Session makeObject(ServerDetails serverDetails) throws Exception {
                Session session = null;
                try {
                        JSch jsch = new JSch();
                        session = jsch.getSession(serverDetails.getUser(), serverDetails.getHost(), serverDetails.getPort());
                        session.setConfig('StrictHostKeyChecking', 'no'); // 
                        UserInfo userInfo = new JschUserInfo(serverDetails.getUser(), serverDetails.getPassword());
                        session.setUserInfo(userInfo);
                        session.setTimeout(60000);
                        session.setPassword(serverDetails.getPassword());
                        session.connect();
                } catch (Exception e) {
                        throw new RuntimeException(
                                        'ERROR: Unrecoverable error when trying to connect to serverDetails :  ' + serverDetails, e);
                }
                return session;
        }

        /**
         * This is called when closing the pool object
         */
        @Override
        public void destroyObject(ServerDetails serverDetails, Session session) {
                session.disconnect();
        }
}

Second thing you need to do, is to create the actual keyed pool Object. In our example we create a singleton that holds a StackKeyedObjectPool. The number 10 is a cap on the number of ‘sleeping’ instances in the pool. If 11 clients try to obtain an ssh connection for the same server, the 11th will wait until one of the first 10 will release his connection.

package org.grep4j.core.command.linux;
import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.impl.StackKeyedObjectPool;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.Session;
/**
 * Pool controller. This class exposes the org.apache.commons.pool.KeyedObjectPool class.
 * 
 * @author Marco Castigliego
 *
 */
public class StackSessionPool {

        private KeyedObjectPool<ServerDetails, Session> pool;

        private static class SingletonHolder {
                public static final StackSessionPool INSTANCE = new StackSessionPool();
        }

        public static StackSessionPool getInstance() {
                return SingletonHolder.INSTANCE;
        }

        private StackSessionPool()
        {
                startPool();
        }

        /**
         * 
         * @return the org.apache.commons.pool.KeyedObjectPool class
         */
        public KeyedObjectPool<ServerDetails, Session> getPool() {
                return pool;
        }

        /**
         * 
         * @return the org.apache.commons.pool.KeyedObjectPool class
         */
        public void startPool() {
                pool = new StackKeyedObjectPool<ServerDetails, Session>(new SessionFactory(), 10);
        }
}

How to use it, it’s simple and straightforward. To obtain a ssh connection from the pool, we just need to call:

StackSessionPool.getInstance().getPool().borrowObject(serverDetails)

where serverDetails is our key (we want a pool of ssh connections per server).

When the connection is not needed anymore we put it back on the pool with :

StackSessionPool.getInstance().getPool().returnObject(serverDetails, session);
package org.grep4j.core.command.linux;

import org.grep4j.core.command.ExecutableCommand;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.Session;
/**
 * The SshCommandExecutor uses the net.schmizz.sshj library to execute remote
 * commands.
 * 
 * <ol>
 * <li>Establish a connection using the credential in the {@link serverDetails}</li>
 * <li>Opens a session channel</li>
 * <li>Execute a command on the session</li>
 * <li>Closes the session</li>
 * <li>Disconnects</li>
 * </ol>
 * 
 * @author Marco Castigliego
 * 
 */
public class JschCommandExecutor extends CommandExecutor {

        public JschCommandExecutor(ServerDetails serverDetails) {
                super(serverDetails);
        }

        @Override
        public CommandExecutor execute(ExecutableCommand command) {
                Session session = null;
                Channel channel = null;
                try {

                        session = StackSessionPool.getInstance().getPool()
                                        .borrowObject(serverDetails);
                        //...do stuff
                } catch (Exception e) {
                        throw new RuntimeException(
                                        'ERROR: Unrecoverable error when performing remote command '
                                                        + e.getMessage(), e);
                } finally {
                        if (null != channel && channel.isConnected()) {
                                channel.disconnect();
                        }
                        if (null != session) {
                                try {
                                        StackSessionPool.getInstance().getPool()
                                                        .returnObject(serverDetails, session);
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                }

                return this;
        }
}

Remember to close the pool when you don’t need it anymore with StackSessionPool.getInstance().getPool().close();
 

Reference: Pool of ssh connections using Apache KeyedObjectPool from our JCG partner Marco Castigliego at the Remove duplication and fix bad names blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

One comment

  1. StackSessionPool.getInstance().getPool().borrowObject(serverDetails);

    StackSessionPool.getInstance().startPool();

    StackSessionPool.getInstance().getPool().borrowObject(serverDetails);

    Isn’t it possible to overwrite the pool all the time!?

Leave a Reply

Your email address will not be published. Required fields are marked *

*


+ 2 = six

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Do you want to know how to develop your skillset and become a ...

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!
Get ready to Rock!
To download the books, please verify your email address by following the instructions found on the email we just sent you.

THANK YOU!

Close