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