001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020
021package org.apache.directory.ldap.client.api;
022
023
024import org.apache.commons.pool.impl.GenericObjectPool;
025import org.apache.directory.api.ldap.codec.api.LdapApiService;
026import org.apache.directory.api.ldap.model.exception.LdapException;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030
031/**
032 * A pool implementation for LdapConnection objects.
033 * 
034 * This class is just a wrapper around the commons GenericObjectPool, and has
035 * a more meaningful name to represent the pool type.
036 * 
037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038 */
039public class LdapConnectionPool extends GenericObjectPool<LdapConnection>
040{
041    private static Logger LOG = LoggerFactory.getLogger( LdapConnectionPool.class );
042
043    private PoolableLdapConnectionFactory factory;
044
045
046    /**
047     * Instantiates a new LDAP connection pool.
048     *
049     * @param connectionConfig The connection configuration
050     * @param apiService The api service (codec)
051     * @param timeout The connection timeout in millis
052     */
053    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
054        LdapApiService apiService, long timeout )
055    {
056        this( connectionConfig, apiService, timeout, null );    
057    }
058    
059    
060    /**
061     * Instantiates a new LDAP connection pool.
062     *
063     * @param connectionConfig The connection configuration
064     * @param apiService The api service (codec)
065     * @param timeout The connection timeout in millis
066     * @param poolConfig The pool configuration
067     */
068    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
069        LdapApiService apiService, long timeout, Config poolConfig )
070    {
071        this( newPoolableConnectionFactory( connectionConfig, apiService, timeout ), poolConfig );
072    }
073
074
075    /**
076     * Instantiates a new LDAP connection pool.
077     *
078     * @param factory The LDAP connection factory
079     */
080    public LdapConnectionPool( PoolableLdapConnectionFactory factory )
081    {
082        this( factory, null );
083    }
084
085    /**
086     * Instantiates a new LDAP connection pool.
087     *
088     * @param factory The LDAP connection factory
089     * @param poolConfig The pool configuration
090     */
091    public LdapConnectionPool( PoolableLdapConnectionFactory factory, Config poolConfig )
092    {
093        super( factory, poolConfig == null ? new Config() : poolConfig );
094        this.factory = factory;
095    }
096
097
098    /**
099     * Returns the LdapApiService instance used by this connection pool.
100     *
101     * @return The LdapApiService instance used by this connection pool.
102     */
103    public LdapApiService getLdapApiService()
104    {
105        return factory.getLdapApiService();
106    }
107
108
109    /**
110     * Gives a LdapConnection fetched from the pool.
111     *
112     * @return an LdapConnection object from pool
113     * @throws Exception if an error occurs while obtaining a connection from the factory
114     */
115    public LdapConnection getConnection() throws LdapException
116    {
117        LdapConnection connection;
118        try
119        {
120            connection = super.borrowObject();
121            LOG.trace( "borrowed connection {}", connection );
122        }
123        catch ( LdapException e )
124        {
125            throw ( e );
126        }
127        catch ( RuntimeException e )
128        {
129            throw ( e );
130        }
131        catch ( Exception e )
132        {
133            // wrap in runtime, but this should NEVER happen per published 
134            // contract as it only throws what the makeObject throws and our 
135            // PoolableLdapConnectionFactory only throws LdapException
136            LOG.error( "An unexpected exception was thrown: ", e );
137            throw new RuntimeException( e );
138        }
139        return connection;
140    }
141
142
143    private static PoolableLdapConnectionFactory newPoolableConnectionFactory(
144        LdapConnectionConfig connectionConfig, LdapApiService apiService,
145        long timeout )
146    {
147        DefaultLdapConnectionFactory connectionFactory =
148            new DefaultLdapConnectionFactory( connectionConfig );
149        connectionFactory.setLdapApiService( apiService );
150        connectionFactory.setTimeOut( timeout );
151        return new PoolableLdapConnectionFactory( connectionFactory );
152    }
153
154
155    /**
156     * Places the given LdapConnection back in the pool.
157     * 
158     * @param connection the LdapConnection to be released
159     * @throws Exception if an error occurs while releasing the connection
160     */
161    public void releaseConnection( LdapConnection connection ) throws LdapException
162    {
163        try
164        {
165            super.returnObject( connection );
166            LOG.trace( "returned connection {}", connection );
167        }
168        catch ( LdapException e )
169        {
170            throw ( e );
171        }
172        catch ( RuntimeException e )
173        {
174            throw ( e );
175        }
176        catch ( Exception e )
177        {
178            // wrap in runtime, but this should NEVER happen as it only throws 
179            // what the passivateObject throws and our 
180            // PoolableLdapConnectionFactory only throws LdapException
181            LOG.error( "An unexpected exception was thrown: ", e );
182            throw new RuntimeException( e );
183        }
184    }
185}