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.
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
.
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
Parameter | Default | Description |
---|---|---|
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.
|
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). |
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 | |
---|---|
Ensure that the
|
Note | |
---|---|
You'll notice that the actual
|
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.
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.