mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Mark Craig
07.27.2012 82977c03ecd4a686dc25fd6071348da34b00e224
Additional content for controls chapter
3 files modified
403 ■■■■■ changed files
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java 152 ●●●●● patch | view | raw | blame | history
opendj3/src/main/docbkx/dev-guide/chap-controls.xml 174 ●●●●● patch | view | raw | blame | history
opendj3/src/site/resources/Example.ldif 77 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
@@ -67,7 +67,12 @@
import org.forgerock.opendj.ldap.controls.ServerSideSortRequestControl;
import org.forgerock.opendj.ldap.controls.ServerSideSortResponseControl;
import org.forgerock.opendj.ldap.controls.SimplePagedResultsControl;
import org.forgerock.opendj.ldap.controls.SubentriesRequestControl;
import org.forgerock.opendj.ldap.controls.SubtreeDeleteRequestControl;
import org.forgerock.opendj.ldap.controls.VirtualListViewRequestControl;
import org.forgerock.opendj.ldap.controls.VirtualListViewResponseControl;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
@@ -116,10 +121,10 @@
            final char[] password = "password".toCharArray();
            connection.bind(user, password);
            // Uncomment one of the methods:
            // Uncomment a method to run one of the examples.
            //useAssertionControl(connection);
            //useAuthorizationIdentityRequestControl(connection);
            useAuthorizationIdentityRequestControl(connection);
            // For the EntryChangeNotificationResponseControl see
            // usePersistentSearchRequestControl()
            //useGetEffectiveRightsRequestControl(connection);
@@ -134,8 +139,10 @@
            //usePreReadRequestControl(connection);
            //useProxiedAuthV2RequestControl(connection);
            //useServerSideSortRequestControl(connection);
            useSimplePagedResultsControl(connection);
            // TODO: The rest of the supported controls
            //useSimplePagedResultsControl(connection);
            //useSubentriesRequestControl(connection);
            //useSubtreeDeleteRequestControl(connection);
            //useVirtualListViewRequestControl(connection);
        } catch (final ErrorResultException e) {
            System.err.println(e.getMessage());
@@ -277,14 +284,13 @@
     */
    static void useManageDsaITRequestControl(Connection connection) throws ErrorResultException {
        if (isSupported(ManageDsaITRequestControl.OID)) {
            // This entry is a referral object:
            final String dn = "dc=references,dc=example,dc=com";
            final String dn = "dc=ref,dc=com";
            final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
            try {
                System.out.println("Referral without the ManageDsaIT control.");
                SearchRequest request = Requests.newSearchRequest(dn,
                        SearchScope.BASE_OBJECT, "(objectclass=*)", "");
                        SearchScope.SUBORDINATES, "(objectclass=*)", "");
                final ConnectionEntryReader reader = connection.search(request);
                while (reader.hasNext()) {
                    if (reader.isReference()) {
@@ -690,7 +696,7 @@
    static void useServerSideSortRequestControl(Connection connection) throws ErrorResultException {
        if (isSupported(ServerSideSortRequestControl.OID)) {
            final SearchRequest request =
                    Requests.newSearchRequest("dc=example,dc=com",
                    Requests.newSearchRequest("ou=People,dc=example,dc=com",
                            SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn")
                            .addControl(ServerSideSortRequestControl.newControl(
                                            true, new SortKey("cn")));
@@ -704,7 +710,6 @@
                                new DecodeOptions());
                if (control != null && control.getResult() == ResultCode.SUCCESS) {
                    System.out.println("# Entries are sorted.");
                    // FIXME: But the order is backwards!
                } else {
                    System.out.println("# Entries not necessarily sorted");
                }
@@ -792,6 +797,135 @@
    }
    /**
     * Use the subentries request control.
     *
     * @param connection
     *            Active connection to LDAP server containing <a
     *            href="http://opendj.forgerock.org/Example.ldif"
     *            >Example.ldif</a> content.
     * @throws ErrorResultException
     *             Operation failed.
     */
    static void useSubentriesRequestControl(Connection connection) throws ErrorResultException {
        if (isSupported(SubentriesRequestControl.OID)) {
            final SearchRequest request =
                    Requests.newSearchRequest("dc=example,dc=com",
                                SearchScope.WHOLE_SUBTREE,
                                "cn=*Class of Service", "*", "+")
                            .addControl(SubentriesRequestControl.newControl(
                                true, true));
            final ConnectionEntryReader reader = connection.search(request);
            final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
            try {
                while (reader.hasNext()) {
                    if (reader.isEntry()) {
                        final SearchResultEntry entry = reader.readEntry();
                        writer.writeEntry(entry);
                    }
                }
                writer.close();
            } catch (ErrorResultIOException e) {
                e.printStackTrace();
            } catch (SearchResultReferenceIOException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("SubentriesRequestControl not supported");
        }
    }
    /**
     * Use the subtree delete control.
     *
     * @param connection
     *            Active connection to LDAP server containing <a
     *            href="http://opendj.forgerock.org/Example.ldif"
     *            >Example.ldif</a> content.
     * @throws ErrorResultException
     *             Operation failed.
     */
    static void useSubtreeDeleteRequestControl(Connection connection) throws ErrorResultException {
        if (isSupported(SubtreeDeleteRequestControl.OID)) {
            final String dn = "ou=Apps,dc=example,dc=com";
            final DeleteRequest request =
                    Requests.newDeleteRequest(dn)
                            .addControl(SubtreeDeleteRequestControl.newControl(true));
            final Result result = connection.delete(request);
            if (result.isSuccess()) {
                System.out.println("Successfully deleted " + dn
                        + " and all entries below.");
            } else {
                System.out.println("Result: " + result.getDiagnosticMessage());
            }
        } else {
            System.out.println("SubtreeDeleteRequestControl not supported");
        }
    }
    /**
     * Use the virtual list view controls. In order to set up OpenDJ directory
     * server to produce the following output with the example code, use OpenDJ
     * Control Panel &gt; Manage Indexes &gt; New VLV Index... to set up a
     * virtual list view index for people by last name, using the filter
     * {@code (|(givenName=*)(sn=*))}, and sorting first by surname, {@code sn},
     * in ascending order, then by given name also in ascending order
     *
     * @param connection
     *            Active connection to LDAP server containing <a
     *            href="http://opendj.forgerock.org/Example.ldif"
     *            >Example.ldif</a> content.
     * @throws ErrorResultException
     *             Operation failed.
     */
    static void useVirtualListViewRequestControl(Connection connection) throws ErrorResultException {
        if (isSupported(VirtualListViewRequestControl.OID)) {
            ByteString contextID = ByteString.empty();
            // Add a window of 2 entries on either side of the first sn=Jensen entry.
            final SearchRequest request =
                    Requests.newSearchRequest("ou=People,dc=example,dc=com",
                            SearchScope.WHOLE_SUBTREE, "(sn=*)", "sn", "givenName")
                            .addControl(ServerSideSortRequestControl.newControl(
                                    true, new SortKey("sn")))
                            .addControl(
                                    VirtualListViewRequestControl.newAssertionControl(
                                            true,
                                            ByteString.valueOf("Jensen"),
                                            2, 2, contextID));
            final SearchResultHandler resultHandler = new MySearchResultHandler();
            final Result result = connection.search(request, resultHandler);
            try {
                final ServerSideSortResponseControl sssControl =
                        result.getControl(ServerSideSortResponseControl.DECODER,
                                new DecodeOptions());
                if (sssControl != null && sssControl.getResult() == ResultCode.SUCCESS) {
                    System.out.println("# Entries are sorted.");
                } else {
                    System.out.println("# Entries not necessarily sorted");
                }
                final VirtualListViewResponseControl vlvControl =
                        result.getControl(VirtualListViewResponseControl.DECODER,
                                new DecodeOptions());
                System.out.println("# Position in list: "
                        + vlvControl.getTargetPosition() + "/"
                        + vlvControl.getContentCount());
            } catch (DecodeException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("VirtualListViewRequestControl not supported");
        }
    }
    /**
     * Controls supported by the LDAP server.
     */
    private static Collection<String> controls;
opendj3/src/main/docbkx/dev-guide/chap-controls.xml
@@ -390,14 +390,13 @@
  <programlisting language="java">
if (isSupported(ManageDsaITRequestControl.OID)) {
    // This entry is a referral object:
    final String dn = "dc=references,dc=example,dc=com";
    final String dn = "dc=ref,dc=com";
    final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
    try {
        System.out.println("Referral without the ManageDsaIT control.");
        SearchRequest request = Requests.newSearchRequest(dn,
                SearchScope.BASE_OBJECT, "(objectclass=*)", "");
                SearchScope.SUBORDINATES, "(objectclass=*)", "");
        final ConnectionEntryReader reader = connection.search(request);
        while (reader.hasNext()) {
            if (reader.isReference()) {
@@ -409,7 +408,7 @@
        System.out.println("Referral with the ManageDsaIT control.");
        request.addControl(ManageDsaITRequestControl.newControl(true));
        final SearchResultEntry entry = connection.searchSingleEntry(request);
        writer.writeEntry(entry)
        writer.writeEntry(entry);
        writer.close();
    } catch (final ErrorResultIOException e) {
        e.printStackTrace();
@@ -421,7 +420,14 @@
}
</programlisting>
  <para>OpenDJ directory server supports the ManageDsaIT Request Control.</para>
  <para>OpenDJ directory server supports the ManageDsaIT Request Control. To use
  the example entry create a new base DN, <literal>dc=ref,dc=com</literal>
  before you import the data:</para>
  <programlisting>Referral without the ManageDsaIT control.
Reference: [ldap:///dc=example,dc=com??sub?]
Referral with the ManageDsaIT control.
dn: dc=references,dc=ref,dc=com</programlisting>
 </section>
 <section xml:id="use-matched-values-request-control">
@@ -791,7 +797,7 @@
        throws ErrorResultException {
    if (isSupported(ServerSideSortRequestControl.OID)) {
        final SearchRequest request =
                Requests.newSearchRequest("dc=example,dc=com",
                Requests.newSearchRequest("ou=People,dc=example,dc=com",
                        SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn")
                        .addControl(ServerSideSortRequestControl.newControl(
                                        true, new SortKey("cn")));
@@ -805,7 +811,6 @@
                            new DecodeOptions());
            if (control != null &amp;&amp; control.getResult() == ResultCode.SUCCESS) {
                System.out.println("# Entries are sorted.");
                // FIXME: But the order is backwards!
            } else {
                System.out.println("# Entries not necessarily sorted");
            }
@@ -958,18 +963,165 @@
 </section>
 <section xml:id="use-subentry-request-control">
  <title>Sub-entries Request Control</title>
  <para>TODO</para>
  <title>Subentries Request Control</title>
  <para>RFC 3672, <link xlink:href="http://tools.ietf.org/html/rfc3672"
  xlink:show="new"><citetitle>Subentries in LDAP</citetitle></link>, describes
  subentries and also the subentries request control. When you perform a search
  without the control and visibility set to <literal>TRUE</literal>, subentries
  are only visible in searches with
  <literal>SearchScope.BASE_OBJECT</literal>.</para>
  <programlisting language="java">
if (isSupported(SubentriesRequestControl.OID)) {
    final SearchRequest request =
            Requests.newSearchRequest("dc=example,dc=com",
                        SearchScope.WHOLE_SUBTREE,
                        "cn=*Class of Service", "*", "+")
                    .addControl(SubentriesRequestControl.newControl(
                        true, true));
    final ConnectionEntryReader reader = connection.search(request);
    final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
    try {
        while (reader.hasNext()) {
            if (reader.isEntry()) {
                final SearchResultEntry entry = reader.readEntry();
                writer.writeEntry(entry);
            }
        }
        writer.close();
    } catch (ErrorResultIOException e) {
        e.printStackTrace();
    } catch (SearchResultReferenceIOException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
</programlisting>
  <para>OpenDJ directory server supports the control.</para>
  <programlisting>TODO: pending OPENDJ-486</programlisting>
 </section>
 <section xml:id="use-subtree-delete-control">
  <title>Subtree Delete Request Control</title>
  <para>TODO</para>
  <para>The subtree delete request control, described in the Internet-Draft
  <link xlink:href="http://tools.ietf.org/html/draft-armijo-ldap-treedelete"
  xlink:show="new"><citetitle>Tree Delete Control</citetitle></link>, lets
  your application delete an entire branch of entries starting with the entry
  you target for deletion.</para>
  <programlisting language="java">
if (isSupported(SubtreeDeleteRequestControl.OID)) {
    final String dn = "ou=Apps,dc=example,dc=com";
    final DeleteRequest request =
            Requests.newDeleteRequest(dn)
                    .addControl(SubtreeDeleteRequestControl.newControl(true));
    final Result result = connection.delete(request);
    if (result.isSuccess()) {
        System.out.println("Successfully deleted " + dn
                + " and all entries below.");
    } else {
        System.out.println("Result: " + result.getDiagnosticMessage());
    }
}
</programlisting>
  <para>OpenDJ directory server supports the subtree delete control:</para>
  <programlisting
  >Successfully deleted ou=Apps,dc=example,dc=com and all entries below.</programlisting>
 </section>
 <section xml:id="use-vlv-control">
  <title>Virtual List View Controls</title>
  <para>TODO</para>
  <para>The virtual list view controls are intended to be used by applications
  that let users browse lists of directory entries. The Internet-Draft <link
  xlink:href="http://tools.ietf.org/html/draft-ietf-ldapext-ldapv3-vlv"
  xlink:show="new"><citetitle>LDAP Extensions for Scrolling View Browsing of
  Search Results</citetitle></link> describes the controls. The virtual list
  view request control is used in conjunction with the server-side sort
  control such that the subset of entries the directory server returns from
  a search are a window into the full sorted list.</para>
  <programlisting language="java">
if (isSupported(VirtualListViewRequestControl.OID)) {
    ByteString contextID = ByteString.empty();
    // Add a window of 2 entries on either side of the first sn=Jensen entry.
    final SearchRequest request =
            Requests.newSearchRequest("ou=People,dc=example,dc=com",
                    SearchScope.WHOLE_SUBTREE, "(sn=*)", "sn", "givenName")
                    .addControl(ServerSideSortRequestControl.newControl(
                            true, new SortKey("sn")))
                    .addControl(
                            VirtualListViewRequestControl.newAssertionControl(
                                    true,
                                    ByteString.valueOf("Jensen"),
                                    2, 2, contextID));
    final SearchResultHandler resultHandler = new MySearchResultHandler();
    final Result result = connection.search(request, resultHandler);
    try {
        final ServerSideSortResponseControl sssControl =
                result.getControl(ServerSideSortResponseControl.DECODER,
                        new DecodeOptions());
        if (sssControl != null &amp;&amp; sssControl.getResult() == ResultCode.SUCCESS){
            System.out.println("# Entries are sorted.");
        } else {
            System.out.println("# Entries not necessarily sorted");
        }
        final VirtualListViewResponseControl vlvControl =
                result.getControl(VirtualListViewResponseControl.DECODER,
                        new DecodeOptions());
        System.out.println("# Position in list: "
                + vlvControl.getTargetPosition() + "/"
                + vlvControl.getContentCount());
    } catch (DecodeException e) {
        e.printStackTrace();
    }
}
</programlisting>
  <para>OpenDJ directory server supports the virtual list view controls.
  In order to set up OpenDJ directory server to produce the following output
  with the example code, use OpenDJ Control Panel &gt; Manage Indexes &gt; New
  VLV Index... to set up a virtual list view index for people by last name,
  using the filter <literal>(|(givenName=*)(sn=*))</literal>, and sorting first
  by surname, <literal>sn</literal>, in ascending order, then by given name
  also in ascending order.</para>
  <programlisting language="ldif">dn: uid=skellehe,ou=People,dc=example,dc=com
givenName: Sue
sn: Kelleher
dn: uid=ejohnson,ou=People,dc=example,dc=com
givenName: Emanuel
sn: Johnson
dn: uid=ajensen,ou=People,dc=example,dc=com
givenName: Allison
sn: Jensen
dn: uid=bjense2,ou=People,dc=example,dc=com
givenName: Bjorn
sn: Jensen
dn: uid=bjensen,ou=People,dc=example,dc=com
givenName: Barbara
sn: Jensen
# Entries are sorted.
# Position in list: 92/150</programlisting>
 </section>
 <section xml:id="custom-control">
opendj3/src/site/resources/Example.ldif
@@ -25,13 +25,6 @@
#
# dc=com sample LDIF file
#
# Notes:
#   161 total entries.
#     2 (objectclass=domain) entries (dc=example,dc=com).
#     4 (objectclass=organizationalunit) entries.
#     5 (objectclass=groupofuniquenames) entries.
#   150 (objectclass=person) entries (all under ou=people,dc=example,dc=com).
#
# Schema definition for use with Class of Service collective attributes:
#
#dn: cn=schema
@@ -42,10 +35,24 @@
# SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE user
# Applications X-ORIGIN 'OpenDJ Documentation Examples' )
#-
#add: attributeTypes
#attributeTypes: ( example-class-of-service-disk-quota NAME 'diskQuota
# ' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR case
# IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE user
# Applications X-ORIGIN 'OpenDJ Documentation Examples' )
#-
#add: attributeTypes
#attributeTypes: ( example-class-of-service-mail-quota NAME 'mailQuota
# ' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR case
# IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE user
# Applications X-ORIGIN 'OpenDJ Documentation Examples' )
#-
#add: objectClasses
#objectClasses: ( example-class-of-service-object-class NAME 'cos' SUP top AUX
# ILIARY MAY classOfService X-ORIGIN 'OpenDJ Documentation Examples' )
# ILIARY MAY classOfService $ diskQuota $ mailQuota X-ORIGIN 'OpenDJ Doc
# umentation Examples' )
#
dn: dc=com
objectClass: domain
objectClass: top
@@ -3746,19 +3753,46 @@
uidNumber: 1109
gidNumber: 1000
# Quotas by class of service
dn: cn=Bronze Class of Service,dc=example,dc=com
objectClass: collectiveAttributeSubentry
objectClass: extensibleObject
objectClass: subentry
objectClass: top
cn: Bronze Class of Service
diskQuota;collective: 10 GB
mailQuota;collective: 1 GB
subtreeSpecification: { base "ou=People", specificationFilter "(classOfService=
 bronze)" }
dn: cn=Silver Class of Service,dc=example,dc=com
objectClass: collectiveAttributeSubentry
objectClass: extensibleObject
objectClass: subentry
objectClass: top
cn: Silver Class of Service
diskQuota;collective: 50 GB
mailQuota;collective: 5 GB
subtreeSpecification: { base "ou=People", specificationFilter "(classOfService=
 silver)" }
dn: cn=Gold Class of Service,dc=example,dc=com
objectClass: collectiveAttributeSubentry
objectClass: extensibleObject
objectClass: subentry
objectClass: top
cn: Gold Class of Service
diskQuota;collective: 100 GB
mailQuota;collective: 10 GB
subtreeSpecification: { base "ou=People", specificationFilter "(classOfService=
 gold)" }
dn: ou=Special Users,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
description: Special Administrative Accounts
ou: Special Users
dn: dc=references,dc=example,dc=com
dc: references
objectClass: extensibleObject
objectClass: referral
objectClass: top
ref: ldap:///ou=People,dc=example,dc=com
dn: ou=Apps,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
@@ -3774,3 +3808,16 @@
userPassword: password
ds-privilege-name: proxied-auth
# Create a new base DN, dc=ref,dc=com, before importing these entries:
dn: dc=ref,dc=com
objectClass: domain
objectClass: top
dc: ref
dn: dc=references,dc=ref,dc=com
dc: references
objectClass: extensibleObject
objectClass: referral
objectClass: top
ref: ldap:///dc=example,dc=com