In some situations, one would like to perform operations on the
DirContext
before and after the search operation. The
interface that is used for this is called
DirContextProcessor
:
public interface DirContextProcessor { public void preProcess(DirContext ctx) throws NamingException; public void postProcess(DirContext ctx) throws NamingException; }
The LdapTemplate
class has a search method that
takes a DirContextProcessor
:
public void search(SearchExecutor se, NameClassPairCallbackHandler handler, DirContextProcessor processor) throws DataAccessException;
Before the search operation, the preProcess
method is called on the given DirContextProcessor
instance. After the search has been executed and the resulting
NamingEnumeration
has been processed, the
postProcess
method is called. This enables a user to
perform operations on the DirContext
to be used in the
search, and to check the DirContext
when the search has
been performed. This can be very useful for example when handling request
and response controls.
There are also a few convenience methods for those that don't need a
custom SearchExecutor
:
public void search(Name base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) public void search(Name base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) public void search(Name base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) public void search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor)
The LDAPv3 protocol uses Controls to send and receive additional
data to affect the behavior of predefined operations. In order to simplify
the implementation of a request control
DirContextProcessor
, Spring LDAP provides the base
class AbstractRequestControlDirContextProcessor
. This
class handles the retrieval of the current request controls from the
LdapContext
, calls a template method for creating a
request control, and adds it to the LdapContext
. All
you have to do in the subclass is to implement the template method
createRequestControl
, and of course the
postProcess
method for performing whatever you need to
do after the search.
public abstract class AbstractRequestControlDirContextProcessor implements DirContextProcessor { public void preProcess(DirContext ctx) throws NamingException { ... } public abstract Control createRequestControl(); }
A typical DirContextProcessor
will be similar to the following:
Example 5.1. A request control DirContextProcessor implementation
package com.example.control; public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor { private static final boolean CRITICAL_CONTROL = true; private MyCoolCookie cookie; ... public MyCoolCookie getCookie() { return cookie; } public Control createRequestControl() { return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL); } public void postProcess(DirContext ctx) throws NamingException { LdapContext ldapContext = (LdapContext) ctx; Control[] responseControls = ldapContext.getResponseControls(); for (int i = 0; i < responseControls.length; i++) { if (responseControls[i] instanceof SomeCoolResponseControl) { SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i]; this.cookie = new MyCoolCookie(control.getCookie()); } } } }
Make sure you use LdapContextSource
when you
use Controls. The Control
interface is specific for LDAPv3 and requires that
LdapContext
is used instead of
DirContext
. If an
AbstractRequestControlDirContextProcessor
subclass is
called with an argument that is not an LdapContext
,
it will throw an IllegalArgumentException
.
Some searches may return large numbers of results. When there is no easy way to filter out a smaller amount, it would be convenient to have the server return only a certain number of results each time it is called. This is known as paged search results. Each "page" of the result could then be displayed at the time, with links to the next and previous page. Without this functionality, the client must either manually limit the search result into pages, or retrieve the whole result and then chop it into pages of suitable size. The former would be rather complicated, and the latter would be consuming unnecessary amounts of memory.
Some LDAP servers have support for the
PagedResultsControl
, which requests that the results of
a search operation are returned by the LDAP server in pages of a specified
size. The user controls the rate at which the pages are returned, simply
by the rate at which the searches are called. However, the user must keep
track of a cookie between the calls. The server uses
this cookie to keep track of where it left off the previous time it was
called with a paged results request.
Spring LDAP provides support for paged results by leveraging the
concept for pre- and postprocessing of an LdapContext
that was discussed
in the previous sections. It does so by providing two classes:
PagedResultsRequestControl
and
PagedResultsCookie
. The
PagedResultsRequestControl
class creates a
PagedResultsControl
with the requested page size and
adds it to the LdapContext
. After the search, it gets
the PagedResultsResponseControl
and retrieves two
pieces of information from it: the estimated total result size and a
cookie. This cookie is a byte array containing information that the server
needs the next time it is called with a
PagedResultsControl
. In order to make it easy to store
this cookie between searches, Spring LDAP provides the wrapper class
PagedResultsCookie
.
Below is an example of how the paged search results functionality may be used:
Example 5.2. Paged results using PagedResultsRequestControl
public PagedResult getAllPersons(PagedResultsCookie cookie) { PagedResultsRequestControl control = new PagedResultsRequestControl(PAGE_SIZE, cookie); SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); List persons = ldapTemplate.search("", "objectclass=person", searchControls, control); return new PagedResult(persons, control.getCookie()); }
In the first call to this method, null
will be supplied as
the cookie parameter. On subsequent calls the client will need to supply the cookie from
the last search (returned wrapped in the PagedResult
) each time the
method is called. When the actual cookie is null
(i.e.
pagedResult.getCookie().getCookie()
returns null
),
the last batch has been returned from the search.