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 two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Pool of ssh connections using Apache KeyedObjectPool"

  1. Franz Ebner says:

    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


× seven = 63



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

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

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close