| Controls and Extensions

## Context Request Controls

> You can associate request controls to be sent along with LDAP requests emitted by `Context` methods by using `LdapContext.setRequestControls()`. For example, you can set the context's request controls to include a control that tells the server to sort the results of `Context.list()` and `DirContext.search()`, assuming that the LDAP server supports server-side sorting, as shown in this example.

> >     // Create the initial context with no connection request controls
> >     LdapContext ctx = new InitialLdapContext(env, null);

> >     // Create the critical Sort control that sorts based on "cn"
> >     Control[] ctxCtls = new Control[]{
> >         new SortControl(new String[]{"cn"}, Control.CRITICAL)
> >     };

> >     // Set the context's request controls to be ctxCtls
> >     ctx.setRequestControls(ctxCtls);

> >     // Perform the list, will sort by cn
> >     NamingEnumeration answer = ctx.list("");

> Once set, the controls remain in effect for the `Context` instance until they are replaced by the arguments to another call to `setRequestControls()`. Next, after doing the list, you can perform a search by using the same `Context` instance; the results will still be sorted by the `"cn"` attribute.

> >     // Perform the search, which will still sort by "cn"
> >     // because context request controls are still in effect
> >     answer = ctx.search("ou=People", "(cn=*)", null);

> To tell a `Context` instance not to use any request controls, supply `null` as the argument to `setRequestControls()`.

> >     // Set the context's request controls to be nothing
> >     ctx.setRequestControls(null);

> #### Finding Out the Context Request Controls That Are in Effect

> To find out the request controls that are in effect for a context, you use `LdapContext.getRequestControls()`. Here is an example that sets the request controls to be a Sort control and then checks the controls by using `getRequestControls()`.

> >     // Set the context's request controls to be ctxCtls
> >     ctx.setRequestControls(ctxCtls);

> >     // Check the controls that are in effect for context
> >     Control[] reqCtls = ctx.getRequestControls();
> >     if (reqCtls != null) {
> >         for (int i = 0; i < reqCtls.length; i++) {
> >             System.out.println(reqCtls[i]);
> >         }
> >     }

> Here is the output produced by this example.

> >     com.sun.jndi.ldap.ctl.SortControl@1fa4d711
> >     com.sun.jndi.ldap.ManageReferralControl@1fa4d59d

> This output shows both the control that was added (the Sort control) as well as a Manage Referral control that the LDAP provider sends when referrals are being ignored (that is, the `Context.REFERRAL` environment property is unset or was set to `"ignore"`). To stop the LDAP provider from sending this control, you must set the `Context.REFERRAL` property to `"throw"` or `"follow"`. See the Referrals lesson for details.

> #### Scope

> A context's request controls remain in effect for all operations on the `Context` instance. However, unlike environment properties, a context's request controls are not inherited by contexts derived from this context. For example, if you perform a `Context.lookup()` and get back a context, then that context has no request controls. You must always explicitly set a context's request controls by using `setRequestControls()`, except when `LdapContext.newInstance()` is used, as explained next.

> #### Multithreaded Programming

> Having a context's request controls in effect for all methods invoked on the context poses a bit of a challenge to multiple threads sharing a context handle. As always (independent of controls), such threads must synchronize their access to the context. In addition, they must ensure that the context has the right request controls set.

> For example, to ensure that a method is executed with the right request controls, you might have code that looks as follows.

> >     synchronized(ctx) {
> >         // Set the context's request controls to be myCtls
> >         ctx.setRequestControls(myCtls);

> >         // Perform the list by using the control
> >         NamingEnumeration answer = ctx.list("");

> >         // Do something useful with the answer

> >         // Get any response controls
> >         respCtls = ctx.getResponseControls();
> >     }

> This is cumbersome if you want a thread to have request controls that persist across multiple operations. Instead of doing this, you can use `LdapContext.newInstance()`. This method allows you to create a clone of the existing `Context` instance, with the request controls initialized to those supplied in the argument.

> >     // Create a clone with the request controls set to newCtls
> >     LdapContext cloneCtx = ctx.newInstance(newCtls);

> When you subsequently update the clone's request controls, the updates won't affect the original context, and vice versa. Where appropriate and possible, the clone will share resources with the original context, such as the underlying connection to the LDAP server.

> Here is an example that uses `newInstance()` to create a clone of a context and initializes the clone with a Sort control. It then performs a search in each context. The results from the clone are sorted, whereas those from the original are not.

> >     // Create the initial context with no connection request controls
> >     LdapContext ctx = new InitialLdapContext(env, null);

> >     // Create the critical Sort that sorts based on "cn"
> >     Control[] ctxCtls = new Control[]{
> >         new SortControl(new String[]{"cn"}, Control.CRITICAL)
> >     };

> >     // Create a clone with request controls set to ctxCtls
> >     LdapContext cloneCtx = ctx.newInstance(ctxCtls);

> >     // Perform the search by using the original context
> >     NamingEnumeration answer = ctx.search("", "(cn=*)", null);

> >     // Enumerate the answers (not sorted)
> >     System.out.println("-----> Unsorted");
> >     while (answer.hasMore()) {
> >         System.out.println(((SearchResult)answer.next()).getName());
> >     }

> >     // Perform the search by using a clone context; sort by "cn"
> >     answer = cloneCtx.search("", "(cn=*)", null);

> >     System.out.println("-----> Sorted");
> >     // Enumerate the answers (sorted)
> >     while (answer.hasMore()) {
> >         System.out.println(((SearchResult)answer.next()).getName());
> >     }

> Here is the output produced by the example.

> >     # java NewInstance
> >     -----> Unsorted
> >     cn=Button
> >     cn=Choice
> >     cn=CheckboxGroup
> >     cn=TextField
> >     cn=CorbaHello
> >     cn=RemoteHello
> >     cn=RefHello
> >     cn=Custom
> >     cn=John Smith
> >     -----> Sorted
> >     cn=Button
> >     cn=CheckboxGroup
> >     cn=Choice
> >     cn=CorbaHello
> >     cn=Custom
> >     cn=John Smith
> >     cn=RefHello
> >     cn=RemoteHello
> >     cn=TextField

| Controls and Extensions