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().
Here is the output produced by this example.// 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]); } }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, set the Context.REFERRAL property to "throw" or "follow". See the Referrals lesson for details.com.sun.jndi.ldap.ctl.SortControl@1fa4d711 com.sun.jndi.ldap.ManageReferralControl@1fa4d59d
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.
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.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(); }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.// Create a clone with the request controls set to newCtls LdapContext cloneCtx = ctx.newInstance(newCtls);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.
Here is the output produced by the example.// 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()); }# 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