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        }
122        catch ( LdapException e )
123        {
124            throw ( e );
125        }
126        catch ( RuntimeException e )
127        {
128            throw ( e );
129        }
130        catch ( Exception e )
131        {
132            // wrap in runtime, but this should NEVER happen per published 
133            // contract as it only throws what the makeObject throws and our 
134            // PoolableLdapConnectionFactory only throws LdapException
135            LOG.error( "An unexpected exception was thrown: ", e );
136            throw new RuntimeException( e );
137        }
138        return connection;
139    }
140
141
142    /**
143     * Returns an LdapConnection from the pool that is not bound to an
144     * identity.  This type of connection is useful when you want to bind
145     * yourself for authentication/authorization purposes.
146     *
147     * @return An unbound LdapConnection from the pool
148     * @throws Exception If an error occurs while obtaining a connection 
149     * from the factory
150     */
151    public LdapConnection getUnboundConnection() throws LdapException
152    {
153        LdapConnection connection = getConnection();
154        connection.unBind();
155        return connection;
156    }
157
158
159    private static PoolableLdapConnectionFactory newPoolableConnectionFactory(
160        LdapConnectionConfig connectionConfig, LdapApiService apiService,
161        long timeout )
162    {
163        DefaultLdapConnectionFactory connectionFactory =
164            new DefaultLdapConnectionFactory( connectionConfig );
165        connectionFactory.setLdapApiService( apiService );
166        connectionFactory.setTimeOut( timeout );
167        return new PoolableLdapConnectionFactory( connectionFactory );
168    }
169
170
171    /**
172     * Places the given LdapConnection back in the pool.
173     * 
174     * @param connection the LdapConnection to be released
175     * @throws Exception if an error occurs while releasing the connection
176     */
177    public void releaseConnection( LdapConnection connection ) throws LdapException
178    {
179        try
180        {
181            super.returnObject( connection );
182        }
183        catch ( LdapException e )
184        {
185            throw ( e );
186        }
187        catch ( RuntimeException e )
188        {
189            throw ( e );
190        }
191        catch ( Exception e )
192        {
193            // wrap in runtime, but this should NEVER happen as it only throws 
194            // what the passivateObject throws and our 
195            // PoolableLdapConnectionFactory only throws LdapException
196            LOG.error( "An unexpected exception was thrown: ", e );
197            throw new RuntimeException( e );
198        }
199    }
200}