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   *     http://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 org.apache.directory.api.asn1.util.Oid;
25  import org.apache.directory.api.ldap.model.exception.LdapException;
26  import org.apache.directory.api.ldap.model.message.BindRequest;
27  import org.apache.directory.api.ldap.model.message.ExtendedRequest;
28  import org.apache.directory.api.ldap.model.name.Dn;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  
33  /**
34   * A factory for creating LdapConnection objects managed by LdapConnectionPool. 
35   * A bind operation is executed upon return if any of the following operations 
36   * were performed on the connection while it was checked out:
37   * 
38   * <ul>
39   * <li>{@link LdapConnection#bind() bind()}</li>
40   * <li>{@link LdapConnection#anonymousBind() anonymousBind()}</li>
41   * <li>{@link LdapConnection#bind(String) bind(String)}</li>
42   * <li>{@link LdapConnection#bind(String, String) bind(String, String)}</li>
43   * <li>{@link LdapConnection#bind(Dn) bind(Dn)}</li>
44   * <li>{@link LdapConnection#bind(Dn, String) bind(Dn, String)}</li>
45   * <li>{@link LdapConnection#bind(BindRequest) bind(BindRequest)}</li>
46   * <li>{@link LdapConnection#extended(String) extended(String)} <i>where oid is StartTLS</i></li>
47   * <li>{@link LdapConnection#extended(String, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li>
48   * <li>{@link LdapConnection#extended(Oid) extended(String)} <i>where oid is StartTLS</i></li>
49   * <li>{@link LdapConnection#extended(Oid, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li>
50   * <li>{@link LdapConnection#extended(ExtendedRequest) extended(ExtendedRequest)} <i>where ExtendedRequest is StartTLS</i></li>
51   * </ul>
52   * 
53   * This is a <i>MOSTLY</i> safe way to handle connections in a pool. If one 
54   * would like to use a slightly less expensive pool factory, the 
55   * {@link DefaultPoolableLdapConnectionFactory} may be the right choice.
56   * 
57   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
58   */
59  public class ValidatingPoolableLdapConnectionFactory extends AbstractPoolableLdapConnectionFactory
60  {
61      /** This class logger */
62      private static final Logger LOG = LoggerFactory.getLogger( ValidatingPoolableLdapConnectionFactory.class );
63  
64  
65      /**
66       * Creates a new instance of ValidatingPoolableLdapConnectionFactory.
67       *
68       * @param config the configuration for creating LdapConnections
69       */
70      public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config )
71      {
72          this( new DefaultLdapConnectionFactory( config ) );
73      }
74  
75  
76      /**
77       * Creates a new instance of ValidatingPoolableLdapConnectionFactory.  The
78       * <code>connectionFactoryClass</code> must have a public constructor accepting
79       * an <code>LdapConnectionConfig</code> object or an 
80       * <code>IllegalArgumentException</code> will be thrown.
81       *
82       * @param config the configuration for creating LdapConnections
83       * @param connectionFactoryClass An implementation class of for the 
84       * LDAP connection factory.
85       * @throws IllegalArgumentException If the instantiation of an instance of 
86       * the <code>connectionFactoryClass</code> fails.
87       */
88      public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config,
89          Class<? extends LdapConnectionFactory> connectionFactoryClass )
90      {
91          this( newLdapConnectionFactory( config, connectionFactoryClass ) );
92      }
93  
94  
95      /**
96       * Creates a new instance of ValidatingPoolableLdapConnectionFactory.
97       *
98       * @param connectionFactory the connection factory for creating LdapConnections
99       */
100     public ValidatingPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
101     {
102         this.connectionFactory = connectionFactory;
103     }
104 
105 
106     /**
107      * {@inheritDoc}
108      * 
109      * There is nothing to do to activate a connection.
110      */
111     @Override
112     public void activateObject( LdapConnection connection ) throws LdapException
113     {
114         LOG.debug( "Activating {}", connection );
115         super.activateObject( connection );
116 
117         // clear the monitors
118         ( ( MonitoringLdapConnection ) connection ).resetMonitors();
119     }
120 
121 
122     /**
123      * {@inheritDoc}
124      * 
125      * Specifically, we are creating a new connection based on the LdapConnection Factory
126      * we used to create this pool of connections. The default is to create bound connections.
127      * 
128      * @throws LdapException If unable to connect.
129      */
130     @Override
131     public MonitoringLdapConnection makeObject() throws LdapException
132     {
133         LOG.debug( "Creating a LDAP connection" );
134         return new MonitoringLdapConnection( connectionFactory.newLdapConnection() );
135     }
136 
137 
138     /**
139      * {@inheritDoc}
140      * 
141      * Here, passivating a connection means we re-bind it, so that the existing LDAPSession
142      * is reset.
143      * 
144      * @throws LdapException If unable to reconfigure and rebind.
145      */
146     @Override
147     public void passivateObject( LdapConnection connection ) throws LdapException
148     {
149         LOG.debug( "Passivating {}", connection );
150 
151         if ( !connection.isConnected() || !connection.isAuthenticated()
152             || ( ( MonitoringLdapConnection ) connection ).bindCalled() )
153         {
154             LOG.debug( "rebind due to bind on connection {}", connection );
155             connectionFactory.bindConnection( connection );
156         }
157         if ( ( ( MonitoringLdapConnection ) connection ).startTlsCalled() )
158         {
159             LOG.debug( "unbind/rebind due to startTls on {}", connection );
160             // unbind to clear the tls
161             connection.unBind();
162             connectionFactory.bindConnection( connection );
163         }
164 
165         // in case connection had configuration changed
166         connectionFactory.configureConnection( connection );
167     }
168 }