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