From 82977c03ecd4a686dc25fd6071348da34b00e224 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Mon, 07 May 2012 13:27:36 +0000
Subject: [PATCH] Additional content for controls chapter
---
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java | 152 ++++++++++++++++++++-
opendj3/src/site/resources/Example.ldif | 77 ++++++++--
opendj3/src/main/docbkx/dev-guide/chap-controls.xml | 174 +++++++++++++++++++++++-
3 files changed, 368 insertions(+), 35 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
index cf464fe..ce17ea2 100644
--- a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
+++ b/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 > Manage Indexes > 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;
diff --git a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml b/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
index a9a665e..e43f98a 100644
--- a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
+++ b/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 && 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 && 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 > Manage Indexes > 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">
diff --git a/opendj3/src/site/resources/Example.ldif b/opendj3/src/site/resources/Example.ldif
index 71bc402..578e04b 100644
--- a/opendj3/src/site/resources/Example.ldif
+++ b/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
+
--
Gitblit v1.10.0