# LDAP Controls With &DirectorySDKForJava;

This chapter explains how LDAP controls work and how to use the LDAP controls.

This chapter covers the following topics:

- How LDAP Controls Work With Directory SDK for Java

- Using Controls in the LDAP Java Classes

- Determining the Controls Supported the Server With Directory SDK for Java

- Using the Server-Side Sorting Control With Directory SDK for Java

- Using the Persistent Search Control With Directory SDK for Java

- Using the Entry Change Notification Control With Directory SDK for Java

- Using the Virtual List Control With Directory SDK for Java

- Using the Manage DSA IT Control With Directory SDK for Java

- Using Password Policy Controls With Directory SDK for Java

- Using the Proxied Authorization Control With Directory SDK for Java

## How LDAP Controls Work With &DirectorySDKForJava;

LDAP v3 allows clients and servers to use controls as a mechanism for extending an LDAP operation. A control is a way to specify additional information as part of a request and a response.

For example, a client can send a control to a server as part of a search request. The control indicates that the server should sort the search results before sending the results back to the client.

Servers can also send controls back to clients. For example, the server can send a control back to a client during the authentication process. The control can indicate that the client password has expired. The control can alternatively indicate that the client password is going to expire.

A control specifies the following information:

- A unique object identifier (OID)

- An indication of whether the control is critical to the operation

- Optional data related to the control, such as the server-side sorting control, where attributes used for sorting search results are needed

The OID identifies the control. If you plan to use a control, you need to make sure that the server supports the control. Refer to Determining the Controls Supported the Server With Directory SDK for Java for instructions.

When your client includes a control in a request for an LDAP operation, the server can respond in one of the following ways:

- If the server supports this control and if the control is appropriate, the server should use the control when performing the operation.

- If the server does not support the control type or if the control is not appropriate, the server should do one of the following:

  - If the control is marked as critical to the operation, the server should not perform the operation. Instead, the server should send an unavailable critical extension result code. When receiving this result code, your client returns an `LDAPException` with the result code LDAPException.UNAVAILABLE_CRITICAL_EXTENSION.

  - If the control is marked as not critical to the operation, the server should ignore the control. The server should proceed to perform the operation.

Servers can also send controls back to clients.

Two types of controls exist:

- Server controls can be included in requests sent by clients and in responses sent by servers.

- Client controls affect the behavior of the LDAP Java classes only and are never sent to the server.

  &DirectorySDKForJava; does not support client controls.

## Using Controls in the LDAP Java Classes

This section describes how controls are implemented in the LDAP Java classes. This section also describes which methods to use to create, send, and parse data from LDAP controls.

In the LDAP Java classes, a control is represented by an object of the `LDAPControl` class.

To include a control in a request, do the following:

1. Invoke the `getSearchConstraints` method of the `LDAPConnection` object to get a clone of `LDAPSearchConstraints` for this connection.

2. Invoke the `setServerControls` method of the cloned constraints object, passing in the `LDAPControl` object that represents the control to include.

3. Invoke the appropriate method to perform the LDAP operation, passing in the constraints object.

   For example, if you are performing a search, invoke the `search` method. Pass the search constraints as an argument.

You can also include controls by invoking the `setServerControls` method for the default set of search constraints. Alternatively, invoke the `setOption` method to set the `LDAPv3.SERVERCONTROLS` option. These controls are sent to the server with every request, however. In general, controls tend to be specific to a type of operation. Include a control in a request only for the operation to which the control applies.

You can then retrieve data from the returned controls through accessor methods in the `LDAPControl` object.

## Determining the Controls Supported the Server With &DirectorySDKForJava;

LDAP v3 states that servers should list any controls that servers support in the `supportedControl` attribute in the root DSE. The following OIDs have corresponding constants that are defined in the LDAP Java classes.

`1.2.840.113556.1.4.473`

`netscape.ldap.controls.LDAPSortControl.SORTREQUEST`

- For instructions on using this control, refer to Using the Server-Side Sorting Control With Directory SDK for Java.

`2.16.840.1.113730.3.4.2`

`netscape.ldap.LDAPControl.MANAGEDSAIT`

- For instructions on using this control, refer to Using the Manage DSA IT Control With Directory SDK for Java.

`2.16.840.1.113730.3.4.3`

`netscape.ldap.controls.LDAPPersistSearchControl.PERSISTENTSEARCH`

- For instructions on using this control, refer to Using the Persistent Search Control With Directory SDK for Java.

`2.16.840.1.113730.3.4.4`

`netscape.ldap.LDAPControl.PWEXPIRED`

- For instructions on using this control, refer to Using Password Policy Controls With Directory SDK for Java.

`2.16.840.1.113730.3.4.5`

`netscape.ldap.LDAPControl.PWEXPIRING`

- For instructions on using this control, refer to Using Password Policy Controls With Directory SDK for Java.

`2.16.840.1.113730.3.4.9`

`netscape.ldap.controls.LDAPVirtualListControl.VIRTUALLIST`

- For instructions on using this control, refer to Using the Virtual List Control With Directory SDK for Java.

`2.16.840.1.113730.3.4.12`

`netscape.ldap.controls.LDAPProxiedAuthControl.PROXIEDAUTHREQUEST`

- For instructions on using this control, refer to Using the Proxied Authorization Control With Directory SDK for Java.

The following example searches for the root DSE. Then the example prints the values of the `supportedControl` attribute.

    import netscape.ldap.*;
    import netscape.ldap.controls.*;
    import java.util.*;

    public class ListCtrl {
        public static void main(String[] args) {

            /* Hashtable mapping OIDs of controls to a description */
            Hashtable knownControls = new Hashtable();
            knownControls.put(LDAPSortControl.SORTREQUEST,
                "Sort control");
            knownControls.put(LDAPControl.MANAGEDSAIT,
                "ManageDsaIT control");
            knownControls.put(LDAPPersistSearchControl.PERSISTENTSEARCH,
                "Persistent Search control");
            knownControls.put(LDAPControl.PWEXPIRED,
                "Password Expiration Notification control");
            knownControls.put(LDAPControl.PWEXPIRING,
                "Password Expiration Warning control");
            knownControls.put(LDAPVirtualListControl.VIRTUALLIST,
                "Virtual List View control");
            knownControls.put(LDAPProxiedAuthControl.PROXIEDAUTHREQUEST,
                "Proxied Authorization control");

            try {
                UserArgs userArgs = new UserArgs("ListCtrl", args, false);
                LDAPConnection ld = new LDAPConnection();
                ld.connect(userArgs.getHost(), userArgs.getPort());

                /* Retreive the list of supported controls from the DSE. */
                String getAttrs[] = {"supportedControl"};
                LDAPSearchResults res = ld.search("", LDAPv3.SCOPE_BASE,
                    "(objectclass=*)", getAttrs, false);
                LDAPEntry DSE = (LDAPEntry)res.nextElement();
                LDAPAttributeSet findAttrs = DSE.getAttributeSet();
                Enumeration enumAttrs = findAttrs.getAttributes();

                while (enumAttrs.hasMoreElements()) {
                    LDAPAttribute anAttr =
                        (LDAPAttribute)enumAttrs.nextElement();
                    String attrName = anAttr.getName();
                    System.out.println(attrName);

                    Enumeration enumVals = anAttr.getStringValues();
                    if (enumVals == null) {
                        System.out.println("\tNo values.");
                        continue;
                    }
                    while (enumVals.hasMoreElements()) {
                        String aVal = (String)enumVals.nextElement();
                        /*
                         * Each value should be the OID of a control.
                         * Look up its description in the hash table.
                         */
                        String aDesc = (String)knownControls.get(aVal);
                        if (aDesc != null) {
                            System.out.println("\t" + aDesc+ " (" + aVal + ")");
                        } else {
                            System.out.println("\t" + aVal);
                        }
                    }
                }

                ld.disconnect();
            } catch(LDAPException e) {
                System.out.println("Error: " + e.toString());
            }
        }
    }

## Using the Server-Side Sorting Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.LDAPControl.SORTREQUEST` is a server-side sorting control. The server-side sorting control is defined in RFC 2891. When you send a search request with this control to the server, the server should sort the results before sending them back to you.

### Specifying the Server-Side Sort Order With Directory SDK for Java

To specify the sort order of the results, construct one or more `LDAPSortKey` objects. Each object represents a sort key that is generated from a string in the following format:

    [-]attrName[:matchingRuleOID
    ]

Here, `attrName` represents the name of the attribute to use for sorting. `matchingRuleOID` represents the optional OID of the matching rule to use for sorting. The optional minus sign (`-`) indicates that the results should be sorted in reverse order for that attribute.

For example, the following string specifies that results should be sorted by first name (`givenname`) in descending order:

    -givenname

Pass this string to the `LDAPSortKey` constructor to create a sort key:

    LDAPSortKey reverseSortByFirstName = new LDAPSortKey("-givenname");

To sort by more than one attribute, construct more than one `LDAPSortKey` object and create an array of the objects.

For example, suppose you want to sort the result by last name (`sn`) in ascending order. If two or more entries have the same last name, you want to sort the result by first name (`givenname`) in ascending order. To specify this sort order, you construct two `LDAPSortKey` objects. Then create an array:

    LDAPSortKey sortByLastName = new LDAPSortKey("sn");
    LDAPSortKey sortByFirstName = new LDAPSortKey("givenname");
    LDAPSortKey[] sortOrder = { sortByLastName, sortByFirstName };

### Creating the Server-Side Sorting Control With &DirectorySDKForJava;

Next, to create the server-side sorting control, construct a new `LDAPSortControl` object. Pass the `LDAPSortKey` object, or the array of `LDAPSortKey` objects, to the `LDAPSortControl` constructor.

In the constructor, you can also specify whether or not the control is critical to the search operation. The control can be marked as critical, but the server cannot sort the results. If the situation occurs, the server should not send back any entries.

For example, the following section of code creates a server-side sorting control. Also, the code specifies that the control is critical to the search operation:

    LDAPSortKey sortOrder = new LDAPSortKey("-givenname");
    LDAPSortControl sortCtrl = new LDAPSortControl(sortOrder, true);

### Performing the Server—Side Sort With &DirectorySDKForJava;

To specify that you want the server to sort the results, do the following:

1. Get a clone of `LDAPSearchConstraints` for the current connection by invoking the `getSearchConstraints` method of the `LDAPConnection` object.

2. Invoke the `setServerControls` method for the copied `LDAPSearchConstraints` object, and pass in the `LDAPSortControl` object that you have constructed.

3. Invoke the `search` method of the `LDAPConnection` object, passing in the `LDAPSearchConstraints` object.

   The server returns a result for the search operation and a response control. The response control indicates the success or failure of the sorting.

4. Invoke the `getResponseControls` method of the `LDAPSearchResults` object to retrieve any controls sent back by the server in response to the search.

   Response controls are passed back as an array of `LDAPControl` objects.

5. Examine the type of each returned control.

If a control is an instance of `LDAPSortControl`, you can read the result code for the sorting operation with the `getResultCode` method.

If the sorting operation failed, the server can also return the name of the attribute that caused the failure. You can read the name of this attribute with the `getFailedAttribute` method.

The server can return the following result codes that apply to the sorting operation.

LDAPException.ADMIN_LIMIT_EXCEEDED

- Too many entries exist for the server to sort.

LDAPException.BUSY

- The server is too busy to sort the results.

LDAPException.INAPPROPRIATE_MATCHING

- The sort key list specifies a matching rule that is not recognized or appropriate.

LDAPException.INSUFFICIENT_ACCESS_RIGHTS

- The server did not send the sorted results because the client has insufficient access rights.

LDAPException.NO_SUCH_ATTRIBUTE

- The sort key list specifies an attribute that does not exist.

LDAPException.OPERATION_ERROR

- An internal server error occurred.

LDAPException.OTHER

- This general result code indicates that the server failed to sort the results for a reason other than the results listed here.

LDAPException.STRONG_AUTH_REQUIRED

- The server refused to send back the sorted search results because the server requires that you use a stronger authentication method.

LDAPException.SUCCESS

- The results were sorted successfully.

LDAPException.TIME_LIMIT_EXCEEDED

- The maximum time allowed for a search was exceeded before the server finished sorting the results.

LDAPException.UNWILLING_TO_PERFORM

- The server is unable to sort the results.

### Interpreting the Server-Side Sort Results With &DirectorySDKForJava;

The following table shows the kinds of results to expect from the LDAP server under different conditions.

### Server Responses to Sort Controls

Supports sort control? | Sort control marked critical? | Any other conditions? | Results From LDAP Server
Server does not support sort control. | Control is not marked as critical. | Not applicable | The server ignores the sorting control. The server returns the entries unsorted.
Server does not support sort control. | Control is marked as critical. | Not applicable | The server does not send back any entries.
Server does support sort control. | Control is not marked as critical. | The server cannot sort the results with the specified sort key list. | The server returns the entries unsorted. The server sends back the sorting response control. The response control specifies the result code of the sort attempt and, optionally, the attribute type that caused the error.
Server does support sort control. | Control is marked as critical. | The server cannot sort the results with the specified sort key list. | The server does not return any entries. The server sends back the sorting response control. The response control specifies the result code of the sort attempt and, optionally, the attribute type that caused the error.
Server does support sort control. | has no effect on results | The search failed. | The server returns a result code for the search operation. The server does not send back the sorting response control.
Server does support sort control. | has no effect on results | The server successfully sorted the entries. | The server returns the entries in sorted order. The server sends back the sorting response control, which specifies the result code of the sort attempt as LDAPException.SUCCESS .

### Example of Using Server-Side Sorting With &DirectorySDKForJava;

The following sample program uses the server-side sorting control to get a list of all users in the directory. The list is sorted in ascending order by last name, then in descending order by first name.

    import netscape.ldap.*;
    import netscape.ldap.controls.*;
    import java.util.*;

    public class SrchSort {
        public static void main(String[] args) {
            try {
                UserArgs userArgs = new UserArgs("SrchSort", args, false);
                LDAPConnection ld = new LDAPConnection();
                ld.connect(userArgs.getHost(), userArgs.getPort());
                ld.authenticate(3, null, null); // Anonymous bind, LDAP v3

                String filter = "sn=Jen*";
                String baseDN = "ou=People,dc=example,dc=com";
                String[] attrs = {"sn", "givenname"};

                /* Sort by last name, then in reverse by first name. */
                LDAPSortKey sortByLastName = new LDAPSortKey("sn");
                LDAPSortKey sortByFirstName = new LDAPSortKey("-givenname");
                LDAPSortKey[] sortOrder = {sortByLastName, sortByFirstName};

                LDAPSortControl sortCtrl = new LDAPSortControl(sortOrder, true);
                LDAPSearchConstraints cons = ld.getSearchConstraints();
                cons.setServerControls(sortCtrl);

                /* Perform the search using the control. */
                LDAPSearchResults res = ld.search(baseDN, LDAPv3.SCOPE_SUB,
                    filter, attrs, false, cons);

                /* Display the results. */
                System.out.println("Sorted results from server");
                System.out.println("==========================");
                while (res.hasMoreElements()) {
                    LDAPEntry resEntry = null;
                    try {
                        resEntry = res.next();
                    } catch (LDAPReferralException e) {
                        continue; // Skip referrals for now.
                    } catch (LDAPException e) {
                        System.err.println("Error:" + e.toString());
                        continue;
                    }

                    LDAPAttributeSet resAttrs = resEntry.getAttributeSet();
                    Enumeration enumAttrs = resAttrs.getAttributes();

                    while (enumAttrs.hasMoreElements()) {
                        LDAPAttribute attr =
                            (LDAPAttribute)enumAttrs.nextElement();
                        Enumeration enumVals =  attr.getStringValues();
                        if (enumVals == null) {
                            System.out.println("\tNo values.");
                            continue;
                        }
                        while (enumVals.hasMoreElements()) {
                            String val = (String)enumVals.nextElement();
                            System.out.print(val);
                        }
                        System.out.print(", ");
                    }
                    System.out.println("");
                }

                /* Check whether the server sent back a control. */
                LDAPControl[] returnedControls = res.getResponseControls();
                if (returnedControls != null) {
                    for (int i = 0; i < returnedControls.length; ++i) {
                        if (!(returnedControls[i] instanceof LDAPSortControl)) {
                            continue;
                        }
                        LDAPSortControl sortRsp =
                            (LDAPSortControl)returnedControls[i];
                        int resultCode = sortRsp.getResultCode();

                        /* Check the result for errors. */
                        if (resultCode != 0) {
                            System.err.println("Result code: " + resultCode);
                            System.err.println(
                                LDAPException.errorCodeToString(resultCode));

                            /* Report attribute that caused the failure. */
                            String failedAttr = sortRsp.getFailedAttribute();
                            if (failedAttr != null) {
                                System.err.println("Failed on: " + failedAttr);
                            } else {
                                System.err.println("Server did not indicate " +
                                    "which attribute caused sorting to fail.");
                            }
                        }
                    }
                }

                ld.disconnect();
            } catch(LDAPException e) {
                System.out.println("Error: " + e.toString());
            }
        }
    }

## Using the Persistent Search Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.LDAPControl.PERSISTENTSEARCH` is a persistent search control. A persistent search, an ongoing search operation, allows your LDAP client to get notification of changes to the directory.

To use persistent searching for change notification, you create a persistent search control that specifies the types of changes that you want to track. You include the control in a search request. If an entry in the directory is changed, the server determines if the entry matches the search criteria in your request. The server also determines if the change is the type of change that you are tracking. If both of the conditions are true, the server sends the entry to your client.

You can use this control in conjunction with an entry change notification control, as described in Using the Entry Change Notification Control With Directory SDK for Java.

### Creating the Persistent Search Control With Directory SDK for Java

To create a persistent search control, you construct a new `LDAPPersistSearchControl` object. When invoking the `LDAPPersistSearchControl` constructor, you can specify the following information:

- The type of change you want to track. You can specify any of the following, or any combination of the following, using a bitwise OR (`|`) operator:

  - `ADD` indicates that you want to track added entries.

  - `DELETE` indicates that you want to track deleted entries.

  - `MODDN` indicates that you want to track renamed entries.

  - `MODIFY` indicates that you want to track modified entries.

- A preference indicating whether you want the server to return all entries that initially matched the search criteria

- A preference indicating whether or not you want entry change notification controls included with every modified entry returned by the server

This code excerpt shows an example of creating a persistent search control.

    /* Track all types of changes. */
    int op = LDAPPersistSearchControl.ADD |
        LDAPPersistSearchControl.MODIFY |
        LDAPPersistSearchControl.DELETE |
        LDAPPersistSearchControl.MODDN;

    /* Return only entries that have changed. */
    boolean changesOnly = true;

    /* Return an entry change notification control. */
    boolean returnControls = true;

    /* Mark the control as critical. */
    boolean isCritical = true;

    /* Create the control. */
    LDAPPersistSearchControl persistCtrl =
        new LDAPPersistSearchControl(
            op, changesOnly, returnControls, isCritical);

### Performing the Persistent Search With Directory SDK for Java

To specify that you want to start a persistent search, do the following:

1. Get a clone of `LDAPSearchConstraints` for the current connection by invoking the `getSearchConstraints` method of the `LDAPConnection` object.

2. Invoke the `setServerControls` method for the cloned `LDAPSearchConstraints` object, and pass in the `LDAPPersistSearchControl` object that you have constructed.

3. Invoke the search method of the `LDAPConnection` object, passing in the `LDAPSearchConstraints` object.

   The server returns entries that match as the entries change. If you specified that you wanted an entry change notification control included with each entry, you can get these controls from the server's results. For instructions, refer to Using the Entry Change Notification Control With Directory SDK for Java.

To end the persistent search, invoke the `abandon` method of the `LDAPConnection` object. Alternatively, invoke the `disconnect` method to disconnect from the server.

### Example of Using the Persistent Search Control With Directory SDK for Java

The following example performs a persistent search. The example receives entry change notification controls from the server.

    import netscape.ldap.*;
    import netscape.ldap.controls.*;
    import java.util.*;

    public class SrchPrst implements Runnable {
        private static String [] cliArgs;
        public static void main(String[] args) {
            cliArgs = args;
            /* Start up a new thread. */
            Thread th = new Thread(new SrchPrst(), "mainConn");
            th.start();
            System.out.println("Main thread started.");
        }

        public void run() {
            try {
                UserArgs userArgs = new UserArgs("SrchPrst", cliArgs, true);
                LDAPConnection ld = new LDAPConnection();
                ld.connect(userArgs.getHost(), userArgs.getPort());
                ld.authenticate(3, userArgs.getBindDN(),userArgs.getPassword());

                /* Create the control and search constraints. */
                int op = LDAPPersistSearchControl.ADD |
                    LDAPPersistSearchControl.MODIFY |
                    LDAPPersistSearchControl.DELETE |
                    LDAPPersistSearchControl.MODDN;
                boolean changesOnly = true;
                boolean returnControls = true;
                boolean isCritical = true;
                LDAPPersistSearchControl persistCtrl =
                    new LDAPPersistSearchControl(op, changesOnly,
                        returnControls, isCritical);
                LDAPSearchConstraints cons = ld.getSearchConstraints();
                cons.setServerControls(persistCtrl);

                /* Track changes on all entries. */
                String filter = "(objectclass=*)";
                String baseDN = "dc=example,dc=com";
                /* Start the search. */
                LDAPSearchResults res =
                    ld.search(
                        baseDN, LDAPv3.SCOPE_SUB, filter, null, false, cons);

                /* Loop through the results until finished. */
                while (res.hasMoreElements()) {
                    System.out.println("\n===== Changed Entry =====");
                    LDAPEntry findEntry = res.next();
                    LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
                    Enumeration enumAttrs = findAttrs.getAttributes();
                    while (enumAttrs.hasMoreElements()) {
                        LDAPAttribute anAttr =
                            (LDAPAttribute)enumAttrs.nextElement();
                        String attrName = anAttr.getName();
                        System.out.println("\t" + attrName);

                        Enumeration enumVals = anAttr.getStringValues();
                        while (enumVals.hasMoreElements()) {
                            String aVal = (String)enumVals.nextElement();
                            System.out.println("\t\t" + aVal);
                        }
                    }

                    /* Get any entry change controls. */
                    LDAPControl[] responseCtrls = res.getResponseControls();
                    if (responseCtrls != null) {
                        for (int i=0; i < responseCtrls.length; i++){
                            if (!(responseCtrls[i] instanceof
                                  LDAPEntryChangeControl)) {
                                continue;
                            }

                            LDAPEntryChangeControl entryCtrl =
                                (LDAPEntryChangeControl) responseCtrls[i];

                            /* Get information on the type of change */
                            int changeType = entryCtrl.getChangeType();
                            if (changeType != -1) {
                                System.out.print("Change made: ");
                                switch (changeType) {
                                    case LDAPPersistSearchControl.ADD:
                                        System.out.println("Added new entry.");
                                        break;
                                    case LDAPPersistSearchControl.MODIFY:
                                        System.out.println("Modified entry.");
                                        break;
                                    case LDAPPersistSearchControl.DELETE:
                                        System.out.println("Deleted entry.");
                                        break;
                                    case LDAPPersistSearchControl.MODDN:
                                        System.out.println("Renamed entry.");
                                        break;
                                    default:
                                        System.out.println(
                                             "Unknown change type.");
                                        break;
                                }
                            }

                            /* Get the change log number, if present */
                            int changeNumber = entryCtrl.getChangeNumber();
                            if (changeNumber != -1) {
                                System.out.println(
                                    "Change log number: " + changeNumber);
                            }

                            /* Get the previous DN of the entry, if
                               a rename operation was performed. */
                            String oldDN = entryCtrl.getPreviousDN();
                            if (oldDN != null) {
                                System.out.println("Previous DN: " + oldDN);
                            }
                        }
                        System.out.println("\n");
                    }
                }
            } catch(LDAPException e) {
                System.out.println("Error: " + e.toString());
            }
        }
    }

## Using the Entry Change Notification Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.LDAPEntryChangeControl.ENTRYCHANGED` is an entry change notification control. These types of controls can be included with entries sent back from the server during a persistent search.

### Getting the Entry Change Notification Control With Directory SDK for Java

To get an entry change notification control that is included with an entry, do the following:

1. As you retrieve each entry, invoke the `getResponseControls` method of the `LDAPConnection` object to retrieve any response controls sent back from the server.

   Response controls are passed back as an array of `LDAPControl` objects.

2. Pass this array of `LDAPControl` objects as an argument to the `LDAPPersistSearchControl.parseResponse` static method to retrieve the entry change notification control.

An entry change notification control is represented by an object of the `LDAPEntryChangeControl` class. To get data from this control, you can invoke the accessor methods, such as `getChangeNumber` , `getChangeType`, and `getPreviousDN`.

### Working With Change Log Numbers With Directory SDK for Java

If the directory server is set up to be a supplier, the server is capable of replicating changes in the directory to other servers. The server therefore keeps a record of the changes made to the directory in a change log. Each record of a change has a number that identifies the change in the log.

You can get the change number for a modified entry from the `LDAPEntryChangeControl` object.

To look up the record for a particular change log number to get more information about the change that took place, search for the record. With Directory Server, the change log is represented by an entry in the directory. Individual change records are represented by entries in a subtree beneath the change log entry.

To determine the DN for the change log entry, search the root DSE to retrieve the `changelog` attribute. For example, the value of this attribute might be `cn=changelog`, which is the DN for the change log entry.

Each change log record is an entry under the change log entry. The change log number is the value of the `changenumber` attribute of the record. To get a specific change log record, search with base DN `cn=changelog` and filter `changenumber=``value`. Here, `value` is the change number of the record.

## Using the Virtual List Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.controls.LDAPVirtualListControl.VIRTUALLIST` is a virtual list control. When you send a search request with this control and with a server-side sorting control to the server, the server should sort the results and return the specified subset of entries back to your client.

After you set the list size with the `setListSize` method of the `LDAPVirtualListControl` object, invoke the `setRange` method. The method recreates the control with the new data. `setRange` generates the BER-encoded request to be sent to the server. `setListSize` does not generate the request.

## Using the Manage DSA IT Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.controls.LDAPControl.MANAGEDSAIT` is a manage DSA IT control. The control is for managing search references in the directory and is defined in RFC 3296.

To create this control, construct a new `LDAPControl` object. In the `LDAPControl` constructor, set the OID of the control to `netscape.ldap.controls.LDAPControl.MANAGEDSAIT`.

Add this control to the array of `LDAPControl` objects. When you pass the array to a method that performs an LDAP operation, the server treats search references as ordinary entries.

Rather than returning a reference to you, the server returns the entry that contains the reference. This mechanism allows your client application to manage search references in the directory.

## Using Password Policy Controls With &DirectorySDKForJava;

&cnDirectoryServer; uses two server response controls to send information back to a client after an LDAP bind operation.

- The control represented with the OID that corresponds to the constant `netscape.ldap.controls.LDAPControl.PWEXPIRED` is the expired password control.

  This control is used if the server is configured to require users to change their passwords on first login. The control is also used whenever the passwords are reset.

  The user might be logging in for the first time. The user password might have been reset. In either circumstance, the server sends the control to indicate that the client needs to change the password immediately. When receiving this control, the only operation that the client can perform is to change the user's password. If the client requests any other LDAP operation, the server sends back an LDAP_UNWILLING_TO_PERFORM result code with an expired password control.

- The control represented with the OID that corresponds to the constant `netscape.ldap.controls.LDAPControl.PWEXPIRING` is the password expiring warning control.

  This control is used if the server is configured to expire user passwords after a certain amount of time.

  The server sends this control back to the client if the client binds with a password that is soon to expire. If you invoke the `getValue` method for this `LDAPControl` object, the method returns the number of seconds before the password expires.

To get these server response controls when binding, invoke the `getResponseControls` method of the `LDAPConnection` object after you attempt to authenticate to the server.

## Using the Proxied Authorization Control With &DirectorySDKForJava;

The control represented with the OID that corresponds to the constant `netscape.ldap.controls.LDAPProxiedAuthControl.PROXIEDAUTHREQUEST` is a proxied authorization control. It allows LDAP clients to use different credentials, without rebinding, when executing LDAP operations.

For example, suppose a messaging server stores its user profiles on an LDAP server. For certain types of requests the messaging server needs to use a DN and password other than its own. To use another DN and password without proxied authorization requires the messaging server to rebind, using the different credentials, before executing each operation.

If the messaging server uses the proxied authorization control, the server can act as the user when executing an operation. The messaging server maintains only its own binding to the LDAP server. This mechanism drastically improves performance, especially when processing a large number of requests.