[[adding-missing-overloaded-api-methods]] = Adding Missing Overloaded API Methods This section covers how to add your own overloaded API methods to implement new functionality. [[implementing-custom-search-methods]] == 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: ==== [source,java] [subs="verbatim,quotes"] ---- 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: ==== [source,java] [subs="verbatim,quotes"] ---- 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: .A custom search method using `SearchExecutor` and `AttributesMapper` ==== [source,java] [subs="verbatim,quotes"] ---- package com.example.repo; 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: .A custom search method using `SearchExecutor` and `ContextMapper` ==== [source,java] [subs="verbatim,quotes"] ---- package com.example.repo; 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(); } } ---- ==== NOTE: When you use the `ContextMapperCallbackHandler`, you must make sure that you have called `setReturningObjFlag(true)` on your `SearchControls` instance. [[implementing-other-custom-context-methods]] == 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: ==== [source,java] [subs="verbatim,quotes"] ---- 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: ==== [source,java] [subs="verbatim,quotes"] ---- 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: .A custom `DirContext` method using `ContextExecutor` ==== [source,java] [subs="verbatim,quotes"] ---- package com.example.repo; 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.