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

Response Controls

A response control allows a server to send more information to the client than is allowed by the operation's response. There need not be a one-to-one mapping between request controls and response controls. That is, a server can accompany any response with response controls--they need not be in response to any client-initiated request control.

Because an LDAP server might send response controls with any response, you might be able to collect response controls after any context method invocation. However, realistically, you would only check for response controls if you were expecting them.

The LdapContext.getResponseControls()(in the API reference documentation) method is used to retrieve a context's response controls. Each time a method that communicates with the server is invoked on a context, the LDAP service provider clears any previously collected response controls and collects all response controls resulting from the current method invocation. For example, the following code fragment examines the response controls after a Context.lookup()(in the API reference documentation) call:

// Perform lookup
Object answer = ctx.lookup("ou=People");

// Retrieve the response controls
Control[] respCtls = ctx.getResponseControls();
If you invoke two context methods and then use getResponseControls(), you will only get the response controls generated by the most recent context method.

Enumerations

Methods such as Context.list(in the API reference documentation) and DirContext.search(in the API reference documentation) return NamingEnumeration(in the API reference documentation) . Each member of a NamingEnumeration might have response controls. A member that has response controls implements the HasControls(in the API reference documentation) interface. Here is an example that shows you how to retrieve the response controls from each member of a NamingEnumeration generated by a search() method:
// Perform search
NamingEnumeration answer = ctx.search("ou=People", "(cn=*)", null);

// examine the response controls (if any)
printControls("After search", ctx.getResponseControls());

// Enumerate answers
while (answer.hasMore()) {
    SearchResult si = (SearchResult)answer.next();
    System.out.println(si);

    // examine the response controls (if any)
    if (si instanceof HasControls) {
        printControls(si.getName(), ((HasControls)si).getControls());
    }
}

// examine the response controls (if any)
printControls("After enumeration", ctx.getResponseControls());
This example defines a method, printControls() that prints out a Control(in the API reference documentation) array. It first performs a search, examines the response controls after the search, and then enumerates the results of the search. For each member of the enumeration, it checks whether the member implements the HasControls interface and if so, displays the response controls associated with the member. After the enumeration has completed, it checks for response controls of the context by using ctx.getResponseControls().

Exceptions

If a context method throws an exception and the LDAP server had sent response controls with the error response that generated the exception, you can retrieve the response controls using ctx.getResponseControls(). Here is an example:
try {
    // Perform lookup
    Object answer = ctx.lookup("ou=People");

    // Retrieve the response controls
    Control[] respCtls = ctx.getResponseControls();

    // Display respCtls
} catch (NamingException e) {
    // Retrieve the response controls
    Control[] respCtls = ctx.getResponseControls();

    // Handle exception
}

Implementations

The Control interface is generic for all request and response controls. Typically, you would be dealing implementation classes that implement this interface rather than directly using the methods in this interface. Such implementation classes typically have type-friendly and accessor methods. After getting the response controls by using getResponseControls(), you can cast the control to its most derived class and use the class-specific accessor methods.

For example, Sun provides classes that implement some popular controls, such as the server-side sorting control. The server-side sorting response control is represented by the SortResponseControl class. You can use the following code to access information about the server-side sorting response control:

if (controls[i] instanceof SortResponseControl) {
    SortResponseControl src = (SortResponseControl)controls[i];
		
    if (src.isSorted()) {
	// result was sorted ...
    }
}
...
In order to do this casting and use specific control classes, you must have some expectation of receiving such a control from the server and have made the control classes available to your program. If either of these is lacking, you can only use the methods in the Control interface to determine the identity of the control and to decode its contents.

Response Control Factories

The JNDI allows an application to use control implementation classes that are produced by any vendor. To help service providers achieve this goal, the JNDI provides a method ControlFactory.getControlInstance(Control, Context, Hashtable)(in the API reference documentation)for service providers to use to transform (that is, to narrow) generic controls received from an LDAP server into control classes made available to the application.

A control factory is an entity that narrows a control. It is represented by the abstract class, ControlFactory(in the API reference documentation) . A control received from an LDAP server starts out life as a Control instance. The LDAP service provider uses the getControlInstance() method to narrow the control instance into a more type-specific one. This method searches the list of ControlFactory class implementations specified in the LdapContext.CONTROL_FACTORIES(in the API reference documentation)("java.naming.factory.control") environment property for a class that can narrow the control.

For example, if an application uses an LDAP server that returns a special response control, the application can define a response control factory to parse the control and provide type-friendly accessor methods. Here is an example of a response control factory:

public  class SampleResponseControlFactory extends ControlFactory {
    public SampleResponseControlFactory() {
    }

    public Control getControlInstance(Control ctl) throws NamingException {
	String id = ctl.getID();

	// See if it's one of ours
	if (id.equals(SampleResponseControl.OID)) {
	    return new SampleResponseControl(id, ctl.isCritical(),
		ctl.getEncodedValue());
	} 

	// Not one of ours; return null and let someone else try
	return null;
    }
}
The factory class must have a public constructor that accepts no arguments. It must also provide an implementation for the abstract method ControlFactory.getControlInstance(Control)(in the API reference documentation) . This method should check whether the input control is one that it can narrow. If so, it should process the control and return an object of a more type-specific class. If it cannot narrow the control, it should return null so that other factories may be tried.


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