<!--

Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.

The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.

See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.

-->
<chapter id="asynchronous"><title>Writing Asynchronous Clients With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter shows how to use the asynchronous interface to LDAP in
Java applications.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="async-vs-sync">Synchronous and Asynchronous Connections With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-using">Common Uses for the Asynchronous Interface With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-new">Classes in the Asynchronous Interface for Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-search">Performing Asynchronous Searches With Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="async-further">Further Reading About the Asynchronous Interface for Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="async-vs-sync"><title>Synchronous and Asynchronous Connections
With Directory SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>explained</secondary>
</indexterm><indexterm>
<primary>synchronous interface</primary>
<secondary>explained</secondary>
</indexterm>
<para>Most operations with &DirectorySDKForJava; are performed synchronously.
A connection is established, a request is sent, the results are returned.
Then the application resumes. Though the &DirectorySDKForJava; can deliver
one search result at a time, other operations block until completion when
accessing an LDAP server.</para>
<para>Sometimes, initiating a new request while another request executes can
be useful. An additional interface is provided to access the built-in support
in &DirectorySDKForJava; 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.</para>
<para><classname>LDAPConnection</classname> 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.</para></sect1>
<sect1 id="async-using"><title>Common Uses for the Asynchronous Interface
With Directory SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>common uses</secondary>
</indexterm>
<para>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 <firstterm>multiplexing</firstterm>.</para>
<para>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.</para>
<para>The following example illustrates a practical use of multiplexed searches
and the asynchronous interface.</para>
<para>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.</para>
<para>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.</para></sect1>
<sect1 id="async-new"><title>Classes in the Asynchronous Interface for Directory
SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>classes</secondary>
</indexterm>
<para>&DirectorySDKForJava; handles asynchronous communication through
the <classname>LDAPAsynchronousConnection</classname> interface and its dependent
classes. These files collectively form the asynchronous extensions to the
LDAP API.</para>
<para><classname>LDAPAsynchronousConnection</classname> defines methods for
authenticating to a server, as well as for searching, modifying, comparing,
and deleting entries in the directory.</para>
<para>When you call a method of <classname>LDAPAsynchronousConnection</classname>,
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.</para>
<itemizedlist>
<para><classname>LDAPAsynchronousConnection</classname> incorporates the following
classes for handling asynchronous client-server interactions:</para>
<listitem><para><classname>LDAPMessage</classname>, which is the base class
for LDAP request and response messages.</para></listitem>
<listitem><para><classname>LDAPResponse</classname>, which extends <classname>LDAPMessage
</classname>, represents a message received from an LDAP server in response
to a request.</para></listitem>
<listitem><para><classname>LDAPExtendedResponse</classname>, which extends <classname>
LDAPResponse</classname>. This response is the response that an LDAP server
returns when handling an extended operation request.</para></listitem>
<listitem><para><classname>LDAPResponseListener</classname> queues <classname>LDAPResponse
</classname> messages.</para></listitem>
<listitem><para><classname>LDAPSearchResult</classname>, which extends <classname>
LDAPMessage</classname>. The response contains a single LDAP entry. The response
is one of the responses an LDAP server can return when handling a search request.
</para></listitem>
<listitem><para><classname>LDAPSearchResultReference</classname>, which extends <classname>
LDAPMessage</classname>. The response contains a referral. The response is
one of the responses that an LDAP server can return when handling a search
request.</para></listitem>
<listitem><para><classname>LDAPSearchListener</classname> queues search results
and references.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="async-search"><title>Performing Asynchronous Searches With Directory
SDK for Java</title>
<para>One of the most common uses of the asynchronous interface is for performing
multiplexed searches using more than one server or suffix.</para>
<task id="async-search-mult-servers"><title>To Search Across Multiple Servers</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>search multiple servers</secondary>
</indexterm>
<tasksummary>
<para>To search on more than one server, perform the following steps.</para>
</tasksummary>
<procedure>
<step><para>Connect to all the servers.</para></step>
<step><para>Create a response listener for one search.</para></step>
<step><para>Share the response listener with all the other searches.</para>
</step>
<step><para>Obtain and process the results.</para></step>
<step><para>Disconnect from the servers.</para></step>
</procedure>
<example id="async-search-mult-servers-example">
<title>Searching Across Multiple Servers</title>
<para>This example demonstrates how to search on two servers at the same time.</para>
<programlisting>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 &lt; 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 &lt; 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 &lt; ld.length; i++) {
                ld[i].disconnect();
            }
        } catch (LDAPException e) {
            System.err.println(e.toString());
        }
    }
}</programlisting>
</example>
</task>
<task id="async-search-mult-suffixes"><title>To Search Across Multiple Suffixes
on a Single Server</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>search multiple suffixes</secondary>
</indexterm>
<tasksummary>
<para>To search on more than one suffix, perform the following steps.</para>
</tasksummary>
<procedure>
<step><para>Connect to the server.</para></step>
<step><para>Create a response listener for one search.</para></step>
<step><para>Share (multiplex) the response listener with the other searches.</para>
</step>
<step><para>Obtain and process the results.</para></step>
<step><para>Disconnect from the server.</para></step>
</procedure>
<example id="async-search-mult-suffixes-example">
<title>Searching Across Multiple Suffixes</title>
<para>This example demonstrates how to search across two suffixes at the same
time.</para>
<programlisting>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 &lt; 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());
        }
    }
}</programlisting>
</example>
</task>
</sect1>
<sect1 id="async-further"><title>Further Reading About the Asynchronous Interface
for Directory SDK for Java</title>
<para>The asynchronous interface is defined in an Internet Draft, <citetitle>The
Java LDAP Application Programming Interface</citetitle>.</para></sect1>
</chapter>
