Mozilla LDAP SDK Programmer's Guide/Writing Asynchronous Clients With LDAP Java SDK

From MozillaWiki
Jump to: navigation, search

This section shows how to use the asynchronous interface to LDAP in Java applications.

Synchronous and Asynchronous Connections With LDAP Java SDK

Most operations with LDAP Java SDK are performed synchronously.

A connection is established, a request is sent, the results are returned. Then the application resumes. Though the LDAP Java SDK can deliver one search result at a time, other operations block until completion when accessing an LDAP server.

Sometimes, initiating a new request while another request executes can be useful. An additional interface is provided to access the built-in support in LDAP Java SDK for these asynchronous requests. By returning control to an application before obtaining a response, the asynchronous interface allows you to perform complex operations requiring access to low-level LDAP mechanisms.

LDAPConnection methods support both asynchronous requests and synchronous requests. Synchronous methods wait for response messages from a server and then process the responses for you. Asynchronous methods require that you check for the messages. You then perform the processing in your code. This mechanism allows you to make additional LDAP requests while waiting for results to return.

Common Uses for the Asynchronous Interface With LDAP Java SDK

Since using the asynchronous interface involves managing more complex code in an application, use the asynchronous methods only when required. The most common use is for merging the results of searches that involve multiple servers or that are executed simultaneously on different subtrees. This method is sometimes referred to as multiplexing.

A search that multiplexes servers can make a request to an array of hosts. A search that multiplexes query statements can make different requests to different subtrees of a server. If you combine these search methods, you can perform complex searches across a number of servers without having to wait for individual responses.

The following example illustrates a practical use of multiplexed searches and the asynchronous interface.

Suppose event notification must be implemented as a generic service with LDAP persistent search. Synchronous methods require a new thread for every request to the service. This solution is not scalable and can exhaust system resources very quickly.

After the search is rewritten using the asynchronous interface, performance improves dramatically. Since asynchronous searches do not block until completion, the persistent search results can be multiplexed into one queue and then processed on a single thread.

Classes in the Asynchronous Interface for LDAP Java SDK

LDAP Java SDK handles asynchronous communication through the LDAPAsynchronousConnection interface and its dependent classes. These files collectively form the asynchronous extensions to the LDAP API.

LDAPAsynchronousConnection defines methods for authenticating to a server, as well as for searching, modifying, comparing, and deleting entries in the directory.

When you call a method of LDAPAsynchronousConnection, the method returns a listener object. This object acts as a message queue. The object accepts search results and server-generated responses to LDAP requests. The LDAP client has the responsibility to read and process these messages. LDAPAsynchronousConnection incorporates the following classes for handling asynchronous client-server interactions:

  • LDAPMessage, which is the base class for LDAP request and response messages.
  • LDAPResponse, which extends LDAPMessage, represents a message received from an LDAP server in response to a request.
  • LDAPExtendedResponse, which extends LDAPResponse. This response is the response that an LDAP server returns when handling an extended operation request.
  • LDAPResponseListener queues LDAPResponse messages.
  • LDAPSearchResult, which extends LDAPMessage. The response contains a single LDAP entry. The response is one of the responses an LDAP server can return when handling a search request.
  • LDAPSearchResultReference, which extends LDAPMessage. The response contains a referral. The response is one of the responses that an LDAP server can return when handling a search request.
  • LDAPSearchListener queues search results and references.

Performing Asynchronous Searches With LDAP Java SDK

One of the most common uses of the asynchronous interface is for performing multiplexed searches using more than one server or suffix.

To Search Across Multiple Servers

To search on more than one server, perform the following steps.

  1. Connect to all the servers.
  2. Create a response listener for one search.
  3. Share the response listener with all the other searches.
  4. Obtain and process the results.
  5. Disconnect from the servers.

This example demonstrates how to search on two servers at the same time.

import netscape.ldap.*;
import java.util.*;
 
public class MultiplexServers {
    public static void main(String[] args) {
        try {
            LDAPConnection[] ld = new LDAPConnection[2];
            String[] hosts = {"server1", "server2"};
            int[] ports = {389, 389};
            String[] bases = {"dc=example,dc=com", "dc=example,dc=com"};
 
            /* search for all entries with surname of Jensen */
            String MY_FILTER = "(sn=Jensen)";
            for (int i = 0; i  ld.length; i++) {
                ld[i] = new LDAPConnection();
                ld[i].connect(hosts[i], ports[i]);
            }
            /* Get a response listener for one search */
            LDAPSearchListener l = ld[0].search(bases[0], ld[0].SCOPE_SUB,
                MY_FILTER, null, false, (LDAPSearchListener)null);
            /* Share the listener */
            for (int i = 1; i  ld.length; i++) {
                ld[i].search(bases[i], ld[i].SCOPE_SUB,
                    MY_FILTER, null, false, l);
            }
           
            /* Loop on results until finished */
            LDAPMessage msg;
            while ((msg = l.getResponse()) != null) {
                if (msg instanceof LDAPSearchResultReference) {
                    ; // Ignore referrals
                } else if (msg instanceof LDAPSearchResult) {
                    LDAPEntry entry = ((LDAPSearchResult)msg).getEntry();
                    System.out.println("Found entry: " + entry.getDN());
                } else if (msg instanceof LDAPResponse) {
                    int result = ((LDAPResponse)msg).getResultCode();
                    if (result != 0) {
                        System.out.println("Result code: " + result);
                        System.out.println("Error message: " +
                            ((LDAPResponse)msg).getErrorMessage());
                    }
                }
            }
            for (int i = 0; i  ld.length; i++) {
                ld[i].disconnect();
            }
        } catch (LDAPException e) {
            System.err.println(e.toString());
        }
    }
}

To Search Across Multiple Suffixes on a Single Server

To search on more than one suffix, perform the following steps.

  1. Connect to the server.
  2. Create a response listener for one search.
  3. Share (multiplex) the response listener with the other searches.
  4. Obtain and process the results.
  5. Disconnect from the server.

This example demonstrates how to search across two suffixes at the same time.

import netscape.ldap.*;
import java.util.*;
 
public class MultiplexSuffixes {
    public static void main(String[] args) {
        try {
            UserArgs userArgs =
                new UserArgs("MultipleSuffixes", args, false);
            LDAPConnection ld = new LDAPConnection();
            ld.connect(userArgs.getHost(), userArgs.getPort());

            String[] bases = {"dc=example,dc=com",
                "ou=groups,dc=example,dc=com"};
            String MY_FILTER = "(objectclass=*)";
 
            /* Get a response listener for one search */
            LDAPSearchListener l = ld.search(bases[0], ld.SCOPE_ONE,
                MY_FILTER, null, false, (LDAPSearchListener)null);
            /* Share the listener */
            for (int i = 1; i  bases.length; i++) {
                ld.search(bases[i], ld.SCOPE_ONE,
                    MY_FILTER, null, false, l);
            }
           
            /* Loop on results until finished */
            LDAPMessage msg;
            while ((msg = l.getResponse()) != null) {
                if (msg instanceof LDAPSearchResultReference) {
                    ; // Ignore referrals
                } else if (msg instanceof LDAPSearchResult) {
                    LDAPEntry entry = ((LDAPSearchResult)msg).getEntry();
                    System.out.println("Found entry: " + entry.getDN());
                } else if (msg instanceof LDAPResponse) {
                    int result = ((LDAPResponse)msg).getResultCode();
                    if (result != 0) {
                        System.out.println("Result code: " + result);
                        System.out.println("Error message: " +
                            ((LDAPResponse)msg).getErrorMessage());
                    }
                }
            }
            ld.disconnect();
        } catch (LDAPException e) {
            System.err.println(e.toString());
        }
    }
}

Further Reading About the Asynchronous Interface for LDAP Java SDK

The asynchronous interface is defined in an Internet Draft, The Java LDAP Application Programming Interface.