# Processing the DirContext

## Custom DirContext Pre/Postprocessing

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)

## Implementing a Request Control DirContextProcessor

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:

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

## Paged Search Results

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:

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.