View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  
21  package org.apache.directory.ldap.client.api;
22  
23  
24  import java.lang.reflect.Constructor;
25  
26  import org.apache.commons.pool2.PooledObject;
27  import org.apache.commons.pool2.PooledObjectFactory;
28  import org.apache.commons.pool2.impl.DefaultPooledObject;
29  import org.apache.directory.api.i18n.I18n;
30  import org.apache.directory.api.ldap.codec.api.LdapApiService;
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * An abstract class implementing the PoolableObjectFactory, for LdapConnections.
38   *
39   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
40   */
41  public abstract class AbstractPoolableLdapConnectionFactory implements PooledObjectFactory<LdapConnection>
42  {
43      /** This class logger */
44      private static final Logger LOG = LoggerFactory.getLogger( AbstractPoolableLdapConnectionFactory.class );
45  
46      /** The factory to use to create a new connection */
47      protected LdapConnectionFactory connectionFactory;
48  
49      /** The validator to use */
50      protected LdapConnectionValidator validator = new LookupLdapConnectionValidator();
51  
52      /**
53       * {@inheritDoc}
54       * 
55       * There is nothing to do to activate a connection.
56       */
57      @Override
58      public void activateObject( PooledObject<LdapConnection> connection ) throws LdapException
59      {
60          if ( LOG.isDebugEnabled() )
61          {
62              LOG.debug( I18n.msg( I18n.MSG_04146_ACTIVATING, connection ) );
63          }
64          
65          if ( !connection.getObject().isConnected() || !connection.getObject().isAuthenticated() )
66          {
67              if ( LOG.isDebugEnabled() )
68              {
69                  LOG.debug( I18n.msg( I18n.MSG_04147_REBIND_CONNECTION_DROPPED, connection ) );
70              }
71              
72              connectionFactory.bindConnection( connection.getObject() );
73          }
74      }
75  
76  
77      /**
78       * {@inheritDoc}
79       * 
80       * Destroying a connection will unbind it which will result on a shutdown
81       * of teh underlying protocol.
82       */
83      @Override
84      public void destroyObject( PooledObject<LdapConnection> connection ) throws LdapException
85      {
86          if ( LOG.isDebugEnabled() )
87          {
88              LOG.debug( I18n.msg( I18n.MSG_04148_DESTROYING, connection ) );
89          }
90  
91          try
92          {
93              // https://tools.ietf.org/html/rfc2251#section-4.3
94              // unbind closes the connection so no need to close
95              connection.getObject().unBind();
96          }
97          catch ( LdapException e )
98          {
99              LOG.error( I18n.err( I18n.ERR_04100_UNABLE_TO_UNBIND, e.getMessage() ) );
100 
101             if ( LOG.isDebugEnabled() )
102             {
103                 LOG.debug( I18n.msg( I18n.MSG_04149_UNABLE_TO_UNBIND, e.getMessage() ) );
104             }
105         }
106     }
107 
108 
109     /**
110      * Returns the LdapApiService instance used by this factory.
111      *
112      * @return The LdapApiService instance used by this factory
113      */
114     public LdapApiService getLdapApiService()
115     {
116         return connectionFactory.getLdapApiService();
117     }
118 
119 
120     /**
121      * {@inheritDoc}
122      * Specifically, we are creating a new connection based on the LdapConnection Factory
123      * we used to create this pool of connections. The default is to create bound connections.
124      * 
125      * @throws LdapException If unable to connect.
126      */
127     @Override
128     public PooledObject<LdapConnection> makeObject() throws LdapException
129     {
130         if ( LOG.isDebugEnabled() )
131         {
132             LOG.debug( I18n.msg( I18n.MSG_04150_CREATING_LDAP_CONNECTION ) );
133         }
134         
135         return new DefaultPooledObject<>( connectionFactory.newLdapConnection() );
136     }
137 
138 
139     protected static LdapConnectionFactory newLdapConnectionFactory(
140         LdapConnectionConfig config,
141         Class<? extends LdapConnectionFactory> connectionFactoryClass )
142     {
143         try
144         {
145             Constructor<? extends LdapConnectionFactory> constructor =
146                 connectionFactoryClass.getConstructor( LdapConnectionConfig.class );
147             return constructor.newInstance( config );
148         }
149         catch ( Exception e )
150         {
151             throw new IllegalArgumentException( I18n.err( I18n.ERR_04101_CANNOT_CREATE_LDAP_CONNECTION_FACTORY, e.getMessage(), e ) );
152         }
153     }
154 
155 
156     /**
157      * {@inheritDoc}
158      * 
159      * We don't do anything with the connection. It remains in the state it was before
160      * being used.
161      * 
162      * @throws LdapException If unable to reconfigure and rebind.
163      */
164     @Override
165     public void passivateObject( PooledObject<LdapConnection> connection ) throws LdapException
166     {
167         if ( LOG.isDebugEnabled() )
168         {
169             LOG.debug( I18n.msg( I18n.MSG_04151_PASSIVATING, connection ) );
170         }
171     }
172   
173     
174     /**
175      * Sets the validator to use when validation occurs.  Note that validation
176      * will only occur if the connection pool was configured to validate.  This
177      * means one of:
178      * <ul>
179      * <li>{@link org.apache.commons.pool2.impl.GenericObjectPool#setTestOnBorrow setTestOnBorrow}</li>
180      * <li>{@link org.apache.commons.pool2.impl.GenericObjectPool#setTestWhileIdle setTestWhileIdle}</li>
181      * <li>{@link org.apache.commons.pool2.impl.GenericObjectPool#setTestOnReturn setTestOnReturn}</li>
182      * </ul>
183      * must have been set to true on the pool.  The default validator is 
184      * {@link LookupLdapConnectionValidator}.
185      *
186      * @param validator The validator
187      */
188     public void setValidator( LdapConnectionValidator validator ) 
189     {
190         this.validator = validator;
191     }
192 
193 
194     /**
195      * {@inheritDoc}
196      * 
197      * Validating a connection is done by checking the connection status.
198      */
199     @Override
200     public boolean validateObject( PooledObject<LdapConnection> connection )
201     {
202         if ( LOG.isDebugEnabled() )
203         {
204             LOG.debug( I18n.msg( I18n.MSG_04152_VALIDATING, connection ) );
205         }
206         
207         return validator.validate( connection.getObject() );
208     }
209 }