edu.amc.sakai.user.PoolingLdapConnectionManager.java Source code

Java tutorial

Introduction

Here is the source code for edu.amc.sakai.user.PoolingLdapConnectionManager.java

Source

/**********************************************************************************
 * $URL$
 * $Id$
 ***********************************************************************************
 *
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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 edu.amc.sakai.user;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;

import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPException;

/**
 * Allocates connected, constrained, bound and optionally secure <code>LDAPConnection</code>s.
 * Uses commons-pool to provide a pool of connections instead of creating a new
 * connection for each request.  Originally tried implementing this with
 * <code>om.novell.ldap.connectionpool.PoolManager</code>, but it did not handle
 * recovering connections that had suffered a network error or connections that
 * were never returned but dropped out of scope.
 * @see LdapConnectionManagerConfig
 * @see PooledLDAPConnection
 * @see PooledLDAPConnectionFactory
 * @author John Lewis, Unicon Inc
 */
public class PoolingLdapConnectionManager extends SimpleLdapConnectionManager {

    /** Class-specific logger */
    private static Log log = LogFactory.getLog(PoolingLdapConnectionManager.class);

    /** LDAP connection pool */
    private ObjectPool pool;

    private PooledLDAPConnectionFactory factory;

    /** How long to block waiting for an available connection before throwing an exception */
    private static final int POOL_MAX_WAIT = 60000;

    /**
     * {@inheritDoc}
     */
    public void init() {
        super.init();

        if (pool != null) {
            return;
        }

        if (factory == null) {
            factory = new PooledLDAPConnectionFactory();
        }
        factory.setConnectionManager(this);

        Config poolConfig = new Config();
        poolConfig.maxActive = getConfig().getPoolMaxConns();
        poolConfig.maxIdle = getConfig().getPoolMaxConns();
        poolConfig.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
        poolConfig.maxWait = POOL_MAX_WAIT;
        poolConfig.testOnBorrow = true;
        poolConfig.testOnReturn = false;

        pool = new GenericObjectPool(factory, poolConfig);
    }

    /**
     * {@inheritDoc}
     */
    public LDAPConnection getConnection() throws LDAPException {
        if (log.isDebugEnabled())
            log.debug("getConnection(): attempting to borrow connection from pool");
        try {
            LDAPConnection conn = (LDAPConnection) pool.borrowObject();
            if (log.isDebugEnabled())
                log.debug("getConnection(): successfully to borrowed connection from pool");
            return conn;
        } catch (Exception e) {
            if (e instanceof LDAPException)
                throw (LDAPException) e;
            throw new RuntimeException("failed to get pooled connection", e);
        }
    }

    public LDAPConnection getBoundConnection(String dn, String pw) throws LDAPException {
        if (log.isDebugEnabled())
            log.debug("getBoundConnection():dn=[" + dn
                    + "] attempting to borrow connection from pool and bind to dn");
        LDAPConnection conn = null;
        try {
            conn = (LDAPConnection) pool.borrowObject();
            if (log.isDebugEnabled())
                log.debug("getBoundConnection():dn=[" + dn + "] successfully borrowed connection from pool");
            conn.bind(LDAPConnection.LDAP_V3, dn, pw.getBytes("UTF8"));
            if (log.isDebugEnabled())
                log.debug("getBoundConnection():dn=[" + dn + "] successfully bound to dn");
            return conn;
        } catch (Exception e) {
            if (conn != null) {
                try {
                    if (log.isDebugEnabled())
                        log.debug("getBoundConnection():dn=[" + dn
                                + "]; error occurred, returning connection to pool");
                    returnConnection(conn);
                } catch (Exception ee) {
                    if (log.isDebugEnabled())
                        log.debug("getBoundConnection():dn=[" + dn + "] failed to return connection to pool", ee);
                }
            }
            if (e instanceof LDAPException)
                throw (LDAPException) e;
            throw new RuntimeException("failed to get pooled connection", e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void returnConnection(LDAPConnection conn) {
        if (conn == null) {
            if (log.isDebugEnabled())
                log.debug("returnConnection() received null connection; nothing to do");
            return;
        } else {
            if (log.isDebugEnabled())
                log.debug("returnConnection(): attempting to return connection to the pool");
        }

        try {
            pool.returnObject(conn);
            if (log.isDebugEnabled())
                log.debug("returnConnection(): successfully returned connection to pool");
        } catch (Exception e) {
            throw new RuntimeException("failed to return pooled connection", e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void destroy() {
        try {
            if (log.isDebugEnabled())
                log.debug("destroy(): closing connection pool");
            pool.close();
            if (log.isDebugEnabled())
                log.debug("destroy(): successfully closed connection pool");
        } catch (Exception e) {
            throw new RuntimeException("failed to shutdown connection pool", e);
        }
        if (log.isDebugEnabled())
            log.debug("destroy(): delegating to parent destroy() impl");
        super.destroy();
    }

    public PooledLDAPConnectionFactory getFactory() {
        return factory;
    }

    public void setFactory(PooledLDAPConnectionFactory factory) {
        this.factory = factory;
    }

    /**
     * Assign a pool implementation. If not specified, one will
     * be constructed by {@link #init()}. If specified,
     * {@link #setFactory(PooledLDAPConnectionFactory)} will have
     * no effect.
     * 
     * <p>This method exists almost entirely for testing purposes.</p>
     * 
     * @param pool the pool to cache; accepts <code>null</code>
     */
    protected void setPool(ObjectPool pool) {
        this.pool = pool;
    }

}