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; 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"> 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