Previous | Next | Trail Map | Tips for LDAP Users | Controls and Extensions

Context Request Controls

You can associate request controls to be sent along with LDAP requests emitted by context methods using LdapContext.setRequestControls()(in the API reference documentation) . For example, if you want the results of a Context.list()(in the API reference documentation) or DirContext.search()(in the API reference documentation) to be sorted, and the LDAP server supports server-side sorting, you can set the context's request controls to include a control for doing that, as shown in this example:
// Create initial context with no connection request controls
LdapContext ctx = new InitialLdapContext(env, null);

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

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

// Perform 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 another call to setRequestControls(). In the above example, after doing the list, you can perform a search using the same context instance and the results will be still be sorted by CN:

// Perform search, 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 context's request controls to be nothing
ctx.setRequestControls(null);

Finding Out the Context Request Controls In Effect

To find out the request controls in effect for a context, you use the LdapContext.getRequestControls()(in the API reference documentation) method. Here is an example that sets the request controls to be a sort control and then checks the controls using getRequestControls():
// Set context's request controls to be ctxCtls
ctx.setRequestControls(ctxCtls);

// Check what controls 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
It shows both the control that we've added (the sort control), and a "manage referral" control that the LDAP provider sends when referrals are being ignored (that is, the Context.REFERRAL(in the API reference documentation)environment property is unset or has been set to "ignore"). To stop the LDAP provider from sending this control, you must set the Context.REFERRAL property to "throw" or "follow".

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()(in the API reference documentation) and got back a context, that context has no request controls. A context's request controls must always be explicitly set using setRequestControls() except when LdapContext.newInstance()(in the API reference documentation) is used, as explained next.

Multithreaded Programming

The fact that a context's request controls are 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, the threads must ensure that the context has the right request controls set. For example, to make sure that a method is executed with the right request controls, you might have code that looks as follows:
synchronized(ctx) {
    // Set context's request controls to be myCtls
    ctx.setRequestControls(myCtls);

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

    // Do something useful with 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()(in the API reference documentation) . 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 clone with request controls set to newCtls
LdapContext cloneCtx = ctx.newInstance(newCtls);
When you subsequently update the request controls of the clone, 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 while those from the original are not.

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

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

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

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

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

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

System.out.println("-----> Sorted");
// Enumerate 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


Previous | Next | Trail Map | Tips for LDAP Users | Controls and Extensions