Pooling Support

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 supplying a <ldap:pooling /> child element to the <ldap:context-source /> element in the application context configuration. Read-only and read-write DirContext objects are pooled separately (if anonymous-read-only is specified). Jakarta Commons-Pool is used to provide the underlying pool implementation.

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 that they are still properly connected and configured when checking them out of the pool, checking them into the pool, or while they are idle in the pool.

If connection validation is configured, pooled connections are validated by using DefaultDirContextValidator. 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 default settings should work with no configuration changes on most LDAP servers and provide the fastest way to validate the DirContext. If you need customization, you can do so by using the validation configuration attributes, described in Pool Configuration.

Connections are automatically invalidated if they throw an exception that is considered non-transient. For example, if a DirContext instance throws a javax.naming.CommunicationException, it is interpreted as a non-transient error and the instance is automatically invalidated, without the overhead of an additional testOnReturn operation. The exceptions that are interpreted as non-transient are configured by using the nonTransientExceptions property of the PoolingContextSource.

Pool Configuration

The following attributes are available on the <ldap:pooling /> element for configuration of the DirContext pool:

Table 1. Pooling Configuration Attributes
Attribute Default Description

max-active

8

The maximum number of active connections of each type (read-only or read-write) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-total

-1

The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-idle

8

The maximum number of active connections of each type (read-only or read-write) that can remain idle in the pool without extra connections being released. You can use a non-positive number for no limit.

min-idle

0

The minimum number of active connections of each type (read-only or read-write) that can remain idle in the pool without extra connections being created. You can use zero (the default) to create none.

max-wait

-1

The maximum number of milliseconds that the pool waits (when no connections are available) for a connection to be returned before throwing an exception. You can use a non-positive number to wait indefinitely.

when-exhausted

BLOCK

Specifies the behavior when the pool is exhausted.

  • The FAIL option throws NoSuchElementException when the pool is exhausted.

  • The BLOCK option waits until a new object is available. If max-wait is positive and no new object is available after the max-wait time expires, NoSuchElementException is thrown.

  • The GROW option creates and returns a new object (essentially making max-active meaningless).

test-on-borrow

false

Whether objects are validated before being borrowed from the pool. If the object fails to validate, it is dropped from the pool, and an attempt to borrow another is made.

test-on-return

false

Whether objects are validated before being returned to the pool.

test-while-idle

false

Whether objects are validated by the idle object evictor (if any). If an object fails to validate, it is dropped from the pool.

eviction-run-interval-millis

-1

The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread is run.

tests-per-eviction-run

3

The number of objects to examine during each run of the idle object evictor thread (if any).

min-evictable-time-millis

1000 * 60 * 30 (30 minutes)

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).

validation-query-base

LdapUtils.emptyName()

The search base to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified.

validation-query-filter

objectclass=*

The search filter to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified.

validation-query-search-controls-ref

null; default search control settings are described above.

The ID of a SearchControls instance to be used when validating connections. Only used if test-on-borrow, test-on-return, or test-while-idle is specified.

non-transient-exceptions

javax.naming.CommunicationException

Comma-separated list of Exception classes. The listed exceptions are considered non-transient with regards to eager invalidation. Should any of the listed exceptions (or subclasses of them) be thrown by a call to a pooled DirContext instance, that object is automatically invalidated without any additional testOnReturn operation.

Pool2 Configuration

The following attributes are available on the <ldap:pooling2 /> element for configuring the DirContext pool:

Table 2. Pooling Configuration Attributes
Attribute Default Description

max-total

-1

The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-total-per-key

8

The limit on the number of object instances allocated by the pool (checked out or idle), per key. When the limit is reached, the sub-pool is exhausted. A negative value indicates no limit.

max-idle-per-key

8

The maximum number of active connections of each type (read-only or read-write) that can remain idle in the pool, without extra connections being released. A negative value indicates no limit.

min-idle-per-key

0

The minimum number of active connections of each type (read-only or read-write) that can remain idle in the pool, without extra connections being created. You can use zero (the default) to create none.

max-wait

-1

The maximum number of milliseconds that the pool waits (when there are no available connections) for a connection to be returned before throwing an exception. You can use a non-positive number to wait indefinitely.

block-when-exhausted

true

Whether to wait until a new object is available. If max-wait is positive, a NoSuchElementException is thrown if no new object is available after the maxWait time expires.

test-on-create

false

Whether objects are validated before borrowing. If the object fails to validate, then borrowing fails.

test-on-borrow

false

The indicator for whether objects are validated before being borrowed from the pool. If the object fails to validate, it is dropped from the pool, and an attempt to borrow another is made.

test-on-return

false

The indicator for whether objects are validated before being returned to the pool.

test-while-idle

false

The indicator for whether objects are validated by the idle object evictor (if any). If an object fails to validate, it is dropped from the pool.

eviction-run-interval-millis

-1

The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread is run.

tests-per-eviction-run

3

The number of objects to examine during each run of the idle object evictor thread (if any).

min-evictable-time-millis

1000 * 60 * 30 (30 minutes)

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).

soft-min-evictable-time-millis

-1

The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor, with the extra condition that at least the minimum number of object instances per key remain in the pool. This setting is overridden by min-evictable-time-millis if it is set to a positive value.

eviction-policy-class

org.apache.commons.pool2.impl.DefaultEvictionPolicy

The eviction policy implementation that is used by this pool. The pool tries to load the class by using the thread context class loader. If that fails, the pool tries to load the class by using the class loader that loaded this class.

fairness

false

The pool serves threads that are waiting to borrow connections fairly. true means that waiting threads are served as if waiting in a FIFO queue.

jmx-enable

true

JMX is enabled with the platform MBean server for the pool.

jmx-name-base

null

The JMX name base that is used as part of the name assigned to JMX enabled pools.

jmx-name-prefix

pool

The JMX name prefix that is used as part of the name assigned to JMX enabled pools.

lifo

true

The indicator for whether the pool has LIFO (last in, first out) behavior with respect to idle objects or as a FIFO (first in, first out) queue. LIFO always returns the most recently used object from the pool, while FIFO always returns the oldest object in the idle object pool

validation-query-base

LdapUtils.emptyPath()

The base DN to use for validation searches.

validation-query-filter

objectclass=*

The filter to use for validation queries.

validation-query-search-controls-ref

null; default search control settings are described above.

The ID of a SearchControls instance to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified

non-transient-exceptions

javax.naming.CommunicationException

Comma-separated list of Exception classes. The listed exceptions are considered non-transient with regards to eager invalidation. Should any of the listed exceptions (or subclasses of them) be thrown by a call to a pooled DirContext instance, that object is automatically invalidated without any additional testOnReturn operation.

Configuration

Configuring pooling requires adding an <ldap:pooling> element nested in the <ldap:context-source> element, as follows:

<beans>
   ...
    <ldap:context-source
        password="secret" url="ldap://localhost:389" username="cn=Manager">
        <ldap:pooling />
    </ldap:context-source>
   ...
</beans>

In a real-world situation, you would probably configure the pool options and enable connection validation. The preceding example demonstrates the general idea.

Validation Configuration

The following example tests each DirContext before it is passed to the client application and tests DirContext objects that have been sitting idle in the pool:

<beans>
   ...
    <ldap:context-source
        username="cn=Manager" password="secret" url="ldap://localhost:389" >
        <ldap:pooling
            test-on-borrow="true"
            test-while-idle="true" />
    </ldap:context-source>
   ...
</beans>

Known Issues

This section describes issues that sometimes arise when people use Spring LDAP. At present, it covers the following issues:

Custom Authentication

The PoolingContextSource assumes that all DirContext objects retrieved from ContextSource.getReadOnlyContext() have the same environment and, likewise, that all DirContext objects retrieved from ContextSource.getReadWriteContext() have the same environment. This means that wrapping an LdapContextSource configured with an AuthenticationSource in a PoolingContextSource does not function as expected. The pool would be populated by 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.