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 java.lang.reflect.Constructor;
025
026import org.apache.commons.pool.PoolableObjectFactory;
027import org.apache.directory.api.ldap.codec.api.LdapApiService;
028import org.apache.directory.api.ldap.model.exception.LdapException;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032
033/**
034 * An abstract class implementing the PoolableObjectFactory, for LdapConnections.
035 *
036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037 */
038public abstract class AbstractPoolableLdapConnectionFactory implements PoolableObjectFactory<LdapConnection>
039{
040    /** This class logger */
041    private static final Logger LOG = LoggerFactory.getLogger( AbstractPoolableLdapConnectionFactory.class );
042
043    /** The factory to use to create a new connection */
044    protected LdapConnectionFactory connectionFactory;
045
046    /** The validator to use */
047    protected LdapConnectionValidator validator = new LookupLdapConnectionValidator();
048
049    /**
050     * {@inheritDoc}
051     * 
052     * There is nothing to do to activate a connection.
053     */
054    public void activateObject( LdapConnection connection ) throws LdapException
055    {
056        LOG.debug( "Activating {}", connection );
057        if ( !connection.isConnected() || !connection.isAuthenticated() )
058        {
059            LOG.debug( "rebind due to connection dropped on {}", connection );
060            connectionFactory.bindConnection( connection );
061        }
062    }
063
064
065    /**
066     * {@inheritDoc}
067     * 
068     * Destroying a connection will unbind it which will result on a shutdown
069     * of teh underlying protocol.
070     */
071    public void destroyObject( LdapConnection connection ) throws LdapException
072    {
073        LOG.debug( "Destroying {}", connection );
074
075        try
076        {
077            // https://tools.ietf.org/html/rfc2251#section-4.3
078            // unbind closes the connection so no need to close
079            connection.unBind();
080        }
081        catch ( LdapException e )
082        {
083            LOG.error( "unable to unbind connection: {}", e.getMessage() );
084            LOG.debug( "unable to unbind connection:", e );
085        }
086    }
087
088
089    /**
090     * Returns the LdapApiService instance used by this factory.
091     *
092     * @return The LdapApiService instance used by this factory
093     */
094    public LdapApiService getLdapApiService()
095    {
096        return connectionFactory.getLdapApiService();
097    }
098
099
100    /**
101     * {@inheritDoc}
102     * Specifically, we are creating a new connection based on the LdapConnection Factory
103     * we used to create this pool of connections. The default is to create bound connections.
104     * 
105     * @throws LdapException If unable to connect.
106     */
107    public LdapConnection makeObject() throws LdapException
108    {
109        LOG.debug( "Creating a LDAP connection" );
110        return connectionFactory.newLdapConnection();
111    }
112
113
114    protected static LdapConnectionFactory newLdapConnectionFactory(
115        LdapConnectionConfig config,
116        Class<? extends LdapConnectionFactory> connectionFactoryClass )
117    {
118        try
119        {
120            Constructor<? extends LdapConnectionFactory> constructor =
121                connectionFactoryClass.getConstructor( LdapConnectionConfig.class );
122            return constructor.newInstance( config );
123        }
124        catch ( Exception e )
125        {
126            throw new IllegalArgumentException( "unable to create LdapConnectionFactory" + e.getMessage(), e );
127        }
128    }
129
130
131    /**
132     * {@inheritDoc}
133     * 
134     * We don't do anything with the connection. It remains in the state it was before
135     * being used.
136     * 
137     * @throws LdapException If unable to reconfigure and rebind.
138     */
139    public void passivateObject( LdapConnection connection ) throws LdapException
140    {
141        LOG.debug( "Passivating {}", connection );
142    }
143  
144    
145    /**
146     * Sets the validator to use when validation occurs.  Note that validation
147     * will only occur if the connection pool was configured to validate.  This
148     * means one of:
149     * <ul>
150     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestOnBorrow setTestOnBorrow}</li>
151     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestWhileIdle setTestWhileIdle}</li>
152     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestOnReturn setTestOnReturn}</li>
153     * </ul>
154     * must have been set to true on the pool.  The default validator is 
155     * {@link LookupLdapConnectionValidator}.
156     *
157     * @param validator The validator
158     */
159    public void setValidator( LdapConnectionValidator validator ) 
160    {
161        this.validator = validator;
162    }
163
164
165    /**
166     * {@inheritDoc}
167     * 
168     * Validating a connection is done by checking the connection status.
169     */
170    public boolean validateObject( LdapConnection connection )
171    {
172        LOG.debug( "Validating {}", connection );
173        return validator.validate( connection );
174    }
175}