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, 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