Adding Missing Overloaded API Methods

This section covers how to add your own overloaded API methods to implement new functionality.

Implementing Custom Search Methods

LdapTemplate contains several overloaded versions of the most common operations in DirContext. However, we have not provided an alternative for each and every method signature, mostly because there are so many of them. We have, however, provided a means to call whichever DirContext method you want and still get the benefits that LdapTemplate provides.

Suppose you want to call the following DirContext method:

NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls ctls)

There is no corresponding overloaded method in LdapTemplate. The way to solve this is to use a custom SearchExecutor implementation, as follows:

public interface SearchExecutor {
   public NamingEnumeration executeSearch(DirContext ctx) throws NamingException;
}

In your custom executor, you have access to a DirContext object, which you can use to call the method you want. You can then provide a handler that is responsible for mapping attributes and collecting the results. You can, for example, use one of the available implementations of CollectingNameClassPairCallbackHandler, which collects the mapped results in an internal list. In order to actually perform the search, you need to call the search method in LdapTemplate that takes an executor and a handler as arguments. Finally, you need to return whatever your handler has collected. The following example shows how to do all of that:

Example 1. A custom search method using SearchExecutor and AttributesMapper
public class PersonRepoImpl implements PersonRepo {
   ...
   public List search(final Name base, final String filter, final String[] params,
         final SearchControls ctls) {
      SearchExecutor executor = new SearchExecutor() {
         public NamingEnumeration executeSearch(DirContext ctx) {
            return ctx.search(base, filter, params, ctls);
         }
      };

      CollectingNameClassPairCallbackHandler handler =
         new AttributesMapperCallbackHandler(new PersonAttributesMapper());

      ldapTemplate.search(executor, handler);
      return handler.getList();
   }
}

If you prefer the ContextMapper to the AttributesMapper, the following example shows what it would look like:

Example 2. A custom search method using SearchExecutor and ContextMapper
public class PersonRepoImpl implements PersonRepo {
   ...
   public List search(final Name base, final String filter, final String[] params,
         final SearchControls ctls) {
      SearchExecutor executor = new SearchExecutor() {
         public NamingEnumeration executeSearch(DirContext ctx) {
            return ctx.search(base, filter, params, ctls);
         }
      };

      CollectingNameClassPairCallbackHandler handler =
         new ContextMapperCallbackHandler(new PersonContextMapper());

      ldapTemplate.search(executor, handler);
      return handler.getList();
   }
}
When you use the ContextMapperCallbackHandler, you must make sure that you have called setReturningObjFlag(true) on your SearchControls instance.

Implementing Other Custom Context Methods

In the same manner as for custom search methods, you can actually call any method in DirContext by using a ContextExecutor, as follows:

public interface ContextExecutor {
   public Object executeWithContext(DirContext ctx) throws NamingException;
}

When implementing a custom ContextExecutor, you can choose between using the executeReadOnly() or the executeReadWrite() method. Suppose you want to call the following method:

Object lookupLink(Name name)

The method is available in DirContext, but there is no matching method in LdapTemplate. It is a lookup method, so it should be read-only. We can implement it as follows:

Example 3. A custom DirContext method using ContextExecutor
public class PersonRepoImpl implements PersonRepo {
   ...
   public Object lookupLink(final Name name) {
      ContextExecutor executor = new ContextExecutor() {
         public Object executeWithContext(DirContext ctx) {
            return ctx.lookupLink(name);
         }
      };

      return ldapTemplate.executeReadOnly(executor);
   }
}

In the same manner, you can perform a read-write operation by using the executeReadWrite() method.