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.PoolableObjectFactory;
025import org.apache.commons.pool.impl.GenericObjectPool;
026import org.apache.directory.api.ldap.codec.api.LdapApiService;
027import org.apache.directory.api.ldap.model.exception.LdapException;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031
032/**
033 * A pool implementation for LdapConnection objects.
034 * 
035 * This class is just a wrapper around the commons GenericObjectPool, and has
036 * a more meaningful name to represent the pool type.
037 * 
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 */
040public class LdapConnectionPool extends GenericObjectPool<LdapConnection>
041{
042    private static Logger LOG = LoggerFactory.getLogger( LdapConnectionPool.class );
043
044    private PoolableObjectFactory<LdapConnection> factory;
045
046
047    /**
048     * Instantiates a new LDAP connection pool.
049     *
050     * @param connectionConfig The connection configuration
051     * @param apiService The api service (codec)
052     * @param timeout The connection timeout in millis
053     */
054    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
055        LdapApiService apiService, long timeout )
056    {
057        this( connectionConfig, apiService, timeout, null );
058    }
059
060
061    /**
062     * Instantiates a new LDAP connection pool.
063     *
064     * @param connectionConfig The connection configuration
065     * @param apiService The api service (codec)
066     * @param timeout The connection timeout in millis
067     * @param poolConfig The pool configuration
068     */
069    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
070        LdapApiService apiService, long timeout, Config poolConfig )
071    {
072        this( newPoolableConnectionFactory( connectionConfig, apiService, timeout ), poolConfig );
073    }
074
075
076    /**
077     * Instantiates a new LDAP connection pool.
078     *
079     * @param factory The LDAP connection factory
080     */
081    public LdapConnectionPool( PoolableObjectFactory<LdapConnection> factory )
082    {
083        this( factory, null );
084    }
085
086
087    /**
088     * Instantiates a new LDAP connection pool.
089     *
090     * @param factory The LDAP connection factory
091     * @param poolConfig The pool configuration
092     */
093    public LdapConnectionPool( PoolableObjectFactory<LdapConnection> factory, Config poolConfig )
094    {
095        super( factory, poolConfig == null ? new Config() : poolConfig );
096        this.factory = factory;
097    }
098
099
100    /**
101     * Returns the LdapApiService instance used by this connection pool.
102     *
103     * @return The LdapApiService instance used by this connection pool.
104     */
105    public LdapApiService getLdapApiService()
106    {
107        return ( ( AbstractPoolableLdapConnectionFactory ) factory ).getLdapApiService();
108    }
109
110
111    /**
112     * Gives a LdapConnection fetched from the pool.
113     *
114     * @return an LdapConnection object from pool
115     * @throws Exception if an error occurs while obtaining a connection from the factory
116     */
117    public LdapConnection getConnection() throws LdapException
118    {
119        LdapConnection connection;
120
121        try
122        {
123            connection = super.borrowObject();
124            LOG.trace( "borrowed connection {}", connection );
125        }
126        catch ( LdapException e )
127        {
128            throw ( e );
129        }
130        catch ( RuntimeException e )
131        {
132            throw ( e );
133        }
134        catch ( Exception e )
135        {
136            // wrap in runtime, but this should NEVER happen per published 
137            // contract as it only throws what the makeObject throws and our 
138            // PoolableLdapConnectionFactory only throws LdapException
139            LOG.error( "An unexpected exception was thrown: ", e );
140            throw new RuntimeException( e );
141        }
142
143        return connection;
144    }
145
146
147    private static ValidatingPoolableLdapConnectionFactory newPoolableConnectionFactory(
148        LdapConnectionConfig connectionConfig, LdapApiService apiService,
149        long timeout )
150    {
151        DefaultLdapConnectionFactory connectionFactory =
152            new DefaultLdapConnectionFactory( connectionConfig );
153        connectionFactory.setLdapApiService( apiService );
154        connectionFactory.setTimeOut( timeout );
155        return new ValidatingPoolableLdapConnectionFactory( connectionFactory );
156    }
157
158
159    /**
160     * Places the given LdapConnection back in the pool.
161     * 
162     * @param connection the LdapConnection to be released
163     * @throws Exception if an error occurs while releasing the connection
164     */
165    public void releaseConnection( LdapConnection connection ) throws LdapException
166    {
167        try
168        {
169            super.returnObject( connection );
170            LOG.trace( "returned connection {}", connection );
171        }
172        catch ( LdapException e )
173        {
174            throw ( e );
175        }
176        catch ( RuntimeException e )
177        {
178            throw ( e );
179        }
180        catch ( Exception e )
181        {
182            // wrap in runtime, but this should NEVER happen as it only throws 
183            // what the passivateObject throws and our 
184            // PoolableLdapConnectionFactory only throws LdapException
185            LOG.error( "An unexpected exception was thrown: ", e );
186            throw new RuntimeException( e );
187        }
188    }
189}