9. Pooling Support

9.1. Introduction

Pooling LDAP connections helps mitigate the overhead of creating a new LDAP connection for each LDAP interaction. While Java LDAP pooling support exists it is limited in its configuration options and features, such as connection validation and pool maintenance. Spring LDAP provides support for detailed pool configuration on a per- ContextSource basis.

Pooling support is provided by PoolingContextSource which can wrap any ContextSource and pool both read-only and read-write DirContext objects. Jakarta Commons-Pool is used to provide the underlying pool implementation.

9.2. DirContext Validation

Validation of pooled connections is the primary motivation for using a custom pooling library versus the JDK provided LDAP pooling functionality. Validation allows pooled DirContext connections to be checked to ensure they are still properly connected and configured when checking them out of the pool, in to the pool or while idle in the pool

The DirContextValidator interface is used by the PoolingContextSource for validation and DefaultDirContextValidator is provided as the default validation implementation. DefaultDirContextValidator does a DirContext.search(String, String, SearchControls) , with an empty name, a filter of "objectclass=*" and SearchControls set to limit a single result with the only the objectclass attribute and a 500ms timeout. If the returned NamingEnumeration has results the DirContext passes validation, if no results are returned or an exception is thrown the DirContext fails validation. The DefaultDirContextValidator should work with no configuration changes on most LDAP servers and provide the fastest way to validate the DirContext .

9.3. Pool Properties

The following properties are available on the PoolingContextSource for configuration of the DirContext pool. The contextSource property must be set and the dirContextValidator property must be set if validation is enabled, all other properties are optional.

Table 9.1. Pooling Configuration Properties

ParameterDefaultDescription
contextSource null The ContextSource implementation to get DirContext s from to populate the pool.
dirContextValidator null The DirContextValidator implementation to use when validating connections. This is required if testOnBorrow , testOnReturn , or testWhileIdle options are set to true .
maxActive 8 The maximum number of active connections of each type (read-only|read-write) that can be allocated from this pool at the same time, or non-positive for no limit.
maxTotal -1 The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time, or non-positive for no limit.
maxIdle 8 The maximum number of active connections of each type (read-only|read-write) that can remain idle in the pool, without extra ones being released, or non-positive for no limit.
minIdle 0 The minimum number of active connections of each type (read-only|read-write) that can remain idle in the pool, without extra ones being created, or zero to create none.
maxWait -1 The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or non-positive to wait indefinitely.
whenExhaustedAction 1 (BLOCK) Specifies the behaviour when the pool is exhausted.
  • The FAIL (0) option will throw a NoSuchElementException when the pool is exhausted.

  • The BLOCK (1) option will wait until a new object is available. If maxWait is positive a NoSuchElementException is thrown if no new object is available after the maxWait time expires.

  • The GROW (2) option will create and return a new object (essentially making maxActive meaningless).

testOnBorrow false The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made.
testOnReturn false The indication of whether objects will be validated before being returned to the pool.
testWhileIdle false The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool.
timeBetweenEvictionRunsMillis -1 The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run.
numTestsPerEvictionRun 3 The number of objects to examine during each run of the idle object evictor thread (if any).
minEvictableIdleTimeMillis 1000 * 60 * 30 The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any).

9.4. Configuration

Configuring pooling should look very familiar if you're used to Jakarta Commons-Pool or Commons-DBCP. You will first create a normal ContextSource then wrap it in a PoolingContextSource .

<beans>
   ...
   <bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">
      <property name="contextSource" ref="contextSourceTarget" />
   </bean>
    
   <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
      <property name="url" value="ldap://localhost:389" />
      <property name="base" value="dc=example,dc=com" />
      <property name="userDn" value="cn=Manager" />
      <property name="password" value="secret" />
      <property name="pooled" value="false"/>
   </bean>
   ...
</beans>

In a real world example you would probably configure the pool options and enable connection validation; the above serves as an example to demonstrate the general idea.

[Note]Note

Ensure that the pooled property is set to false on any ContextSource that will be wrapped in a PoolingContextSource . The PoolingContextSource must be able to create new connections when needed and if pooled is set to true that may not be possible.

[Note]Note

You'll notice that the actual ContextSource gets an id with a "Target" suffix. The bean you will actually refer to is the PoolingContextSource that wraps the target contextSource

9.4.1. Validation Configuration

Adding validation and a few pool configuration tweaks to the above example is straight forward. Inject a DirContextValidator and set when validation should occur and the pool is ready to go.

<beans>
   ...
   <bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">
      <property name="contextSource" ref="contextSourceTarget" />
      <property name="dirContextValidator" ref="dirContextValidator" />
      <property name="testOnBorrow" value="true" />
      <property name="testWhileIdle" value="true" />
   </bean>

   <bean id="dirContextValidator"
         class="org.springframework.ldap.pool.validation.DefaultDirContextValidator" />
    
   <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
      <property name="url" value="ldap://localhost:389" />
      <property name="base" value="dc=example,dc=com" />
      <property name="userDn" value="cn=Manager" />
      <property name="password" value="secret" />
      <property name="pooled" value="false"/>
   </bean>
   ...
</beans>

The above example will test each DirContext before it is passed to the client application and test DirContext s that have been sitting idle in the pool.

9.5. Known Issues

9.5.1. Custom Authentication

The PoolingContextSource assumes that all DirContext objects retrieved from ContextSource.getReadOnlyContext() will have the same environment and likewise that all DirContext objects retrieved from ContextSource.getReadWriteContext() will have the same environment. This means that wrapping a LdapContextSource configured with an AuthenticationSource in a PoolingContextSource will not function as expected. The pool would be populated using the credentials of the first user and unless new connections were needed subsequent context requests would not be filled for the user specified by the AuthenticationSource for the requesting thread.