/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2012-2013 ForgeRock AS * */ package org.forgerock.opendj.examples; import java.io.IOException; import java.util.Collection; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.Connection; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.DecodeOptions; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.ErrorResultException; import org.forgerock.opendj.ldap.ErrorResultIOException; import org.forgerock.opendj.ldap.Filter; import org.forgerock.opendj.ldap.LDAPConnectionFactory; import org.forgerock.opendj.ldap.ModificationType; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.RootDSE; import org.forgerock.opendj.ldap.SearchResultHandler; import org.forgerock.opendj.ldap.SearchResultReferenceIOException; import org.forgerock.opendj.ldap.SearchScope; import org.forgerock.opendj.ldap.SortKey; import org.forgerock.opendj.ldap.controls.AssertionRequestControl; import org.forgerock.opendj.ldap.controls.AuthorizationIdentityRequestControl; import org.forgerock.opendj.ldap.controls.AuthorizationIdentityResponseControl; import org.forgerock.opendj.ldap.controls.EntryChangeNotificationResponseControl; import org.forgerock.opendj.ldap.controls.GetEffectiveRightsRequestControl; import org.forgerock.opendj.ldap.controls.ManageDsaITRequestControl; import org.forgerock.opendj.ldap.controls.MatchedValuesRequestControl; import org.forgerock.opendj.ldap.controls.PasswordExpiredResponseControl; import org.forgerock.opendj.ldap.controls.PasswordExpiringResponseControl; import org.forgerock.opendj.ldap.controls.PasswordPolicyRequestControl; import org.forgerock.opendj.ldap.controls.PasswordPolicyResponseControl; import org.forgerock.opendj.ldap.controls.PermissiveModifyRequestControl; import org.forgerock.opendj.ldap.controls.PersistentSearchChangeType; import org.forgerock.opendj.ldap.controls.PersistentSearchRequestControl; import org.forgerock.opendj.ldap.controls.PostReadRequestControl; import org.forgerock.opendj.ldap.controls.PostReadResponseControl; import org.forgerock.opendj.ldap.controls.PreReadRequestControl; import org.forgerock.opendj.ldap.controls.PreReadResponseControl; import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl; 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; import org.forgerock.opendj.ldap.responses.BindResult; import org.forgerock.opendj.ldap.responses.Result; import org.forgerock.opendj.ldap.responses.SearchResultEntry; import org.forgerock.opendj.ldap.responses.SearchResultReference; import org.forgerock.opendj.ldif.ConnectionEntryReader; import org.forgerock.opendj.ldif.LDIFEntryWriter; /** * This command-line client demonstrates use of LDAP controls. The client takes * as arguments the host and port for the directory server, and expects to find * the entries and access control instructions as defined in Example.ldif. * * This client connects as cn=Directory Manager with password * password. Not a best practice; in real code use application * specific credentials to connect, and ensure that your application has access * to use the LDAP controls needed. */ public final class Controls { /** * Connect to the server, and then try to use some LDAP controls. * * @param args * The command line arguments: host, port */ public static void main(final String[] args) { if (args.length != 2) { System.err.println("Usage: host port"); System.err.println("For example: localhost 1389"); System.exit(1); } final String host = args[0]; final int port = Integer.parseInt(args[1]); final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); checkSupportedControls(connection); final String user = "cn=Directory Manager"; final char[] password = "password".toCharArray(); connection.bind(user, password); // Uncomment a method to run one of the examples. //useAssertionControl(connection); useAuthorizationIdentityRequestControl(connection); // For the EntryChangeNotificationResponseControl see // usePersistentSearchRequestControl() //useGetEffectiveRightsRequestControl(connection); //useManageDsaITRequestControl(connection); //useMatchedValuesRequestControl(connection); //usePasswordExpiredResponseControl(connection); //usePasswordExpiringResponseControl(connection); //usePasswordPolicyRequestControl(connection); //usePermissiveModifyRequestControl(connection); //usePersistentSearchRequestControl(connection); //usePostReadRequestControl(connection); //usePreReadRequestControl(connection); //useProxiedAuthV2RequestControl(connection); //useServerSideSortRequestControl(connection); //useSimplePagedResultsControl(connection); //useSubentriesRequestControl(connection); //useSubtreeDeleteRequestControl(connection); //useVirtualListViewRequestControl(connection); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } } } /** * Use the LDAP assertion control to modify Babs Jensen's description if * her entry does not have a description, yet. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useAssertionControl(Connection connection) throws ErrorResultException { // --- JCite assertion --- if (isSupported(AssertionRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(AssertionRequestControl.newControl( true, Filter.valueOf("!(description=*)"))) .addModification(ModificationType.ADD, "description", "Created using LDAP assertion control"); connection.modify(request); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(connection.readEntry(dn, "description")); writer.close(); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("AssertionRequestControl not supported."); } // --- JCite assertion --- } /** * Use the LDAP Authorization Identity Controls to get the authorization ID. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useAuthorizationIdentityRequestControl(Connection connection) throws ErrorResultException { // --- JCite authzid --- if (isSupported(AuthorizationIdentityRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); System.out.println("Binding as " + dn); final BindRequest request = Requests.newSimpleBindRequest(dn, pwd) .addControl(AuthorizationIdentityRequestControl.newControl(true)); final BindResult result = connection.bind(request); try { final AuthorizationIdentityResponseControl control = result.getControl(AuthorizationIdentityResponseControl.DECODER, new DecodeOptions()); System.out.println("Authorization ID returned: " + control.getAuthorizationID()); } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } else { System.err.println("AuthorizationIdentityRequestControl not supported."); } // --- JCite authzid --- } /** * Use the GetEffectiveRights Request Control to determine what sort of * access a user has to particular attributes on an entry. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useGetEffectiveRightsRequestControl(Connection connection) throws ErrorResultException { // --- JCite effective rights --- if (isSupported(GetEffectiveRightsRequestControl.OID)) { final String authDN = "uid=kvaughan,ou=People,dc=example,dc=com"; final SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(uid=bjensen)", "cn", "aclRights", "aclRightsInfo") .addControl(GetEffectiveRightsRequestControl.newControl( true, authDN, "cn")); final ConnectionEntryReader reader = connection.search(request); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { while (reader.hasNext()) { if (!reader.isReference()) { final SearchResultEntry entry = reader.readEntry(); writer.writeEntry(entry); } } writer.close(); } catch (final ErrorResultIOException e) { System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("GetEffectiveRightsRequestControl not supported."); } // --- JCite effective rights --- } /** * Use the ManageDsaIT Request Control to show the difference between a * referral accessed with and without use of the control. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useManageDsaITRequestControl(Connection connection) throws ErrorResultException { // --- JCite manage DsaIT --- if (isSupported(ManageDsaITRequestControl.OID)) { 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.SUBORDINATES, "(objectclass=*)", ""); final ConnectionEntryReader reader = connection.search(request); while (reader.hasNext()) { if (reader.isReference()) { final SearchResultReference ref = reader.readReference(); System.out.println("Reference: " + ref.getURIs().toString()); } } System.out.println("Referral with the ManageDsaIT control."); request.addControl(ManageDsaITRequestControl.newControl(true)); final SearchResultEntry entry = connection.searchSingleEntry(request); writer.writeEntry(entry); writer.close(); } catch (final ErrorResultIOException e) { System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("ManageDsaITRequestControl not supported."); } // --- JCite manage DsaIT --- } /** * Use the Matched Values Request Control to show read only one attribute * value. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useMatchedValuesRequestControl(Connection connection) throws ErrorResultException { // --- JCite matched values --- if (isSupported(MatchedValuesRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final SearchRequest request = Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, "(objectclass=*)", "cn") .addControl(MatchedValuesRequestControl.newControl( true, "(cn=Babs Jensen)")); final SearchResultEntry entry = connection.searchSingleEntry(request); System.out.println("Reading entry with matched values request."); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.close(); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("MatchedValuesRequestControl not supported."); } // --- JCite matched values --- } /** * Check the Password Expired Response Control. To get this code to output * something, you must first set up an appropriate password policy and wait * for Barbara Jensen's password to expire. * * @param connection * Active connection to LDAP server containing Example.ldif content. */ static void usePasswordExpiredResponseControl(Connection connection) { // --- JCite password expired --- if (isSupported(PasswordExpiredResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); try { connection.bind(dn, pwd); } catch (final ErrorResultException e) { final Result result = e.getResult(); try { final PasswordExpiredResponseControl control = result.getControl(PasswordExpiredResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && control.hasValue()) { System.out.println("Password expired for " + dn); } } catch (final DecodeException de) { System.err.println(de.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } } else { System.err.println("PasswordExpiredResponseControl not supported."); } // --- JCite password expired --- } /** * Check the Password Expiring Response Control. To get this code to output * something, you must first set up an appropriate password policy and wait * for Barbara Jensen's password to get old enough that the server starts * warning about expiration. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void usePasswordExpiringResponseControl(Connection connection) throws ErrorResultException { // --- JCite password expiring --- if (isSupported(PasswordExpiringResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); final BindResult result = connection.bind(dn, pwd); try { final PasswordExpiringResponseControl control = result.getControl(PasswordExpiringResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && control.hasValue()) { System.out.println("Password for " + dn + " expires in " + control.getSecondsUntilExpiration() + " seconds."); } } catch (final DecodeException de) { System.err.println(de.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } else { System.err.println("PasswordExpiringResponseControl not supported"); } // --- JCite password expiring --- } /** * Use the Password Policy Request and Response Controls. To get this code * to output something, you must first set up an appropriate password policy * and wait for Barbara Jensen's password to get old enough that the server * starts warning about expiration, or for the password to expire. * * @param connection * Active connection to LDAP server containing Example.ldif content. */ static void usePasswordPolicyRequestControl(Connection connection) { // --- JCite password policy --- if (isSupported(PasswordPolicyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); try { final BindRequest request = Requests.newSimpleBindRequest(dn, pwd) .addControl(PasswordPolicyRequestControl.newControl(true)); final BindResult result = connection.bind(request); final PasswordPolicyResponseControl control = result.getControl(PasswordPolicyResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && !(control.getWarningType() == null)) { System.out.println("Password policy warning " + control.getWarningType().toString() + ", value " + control.getWarningValue() + " for " + dn); } } catch (final ErrorResultException e) { final Result result = e.getResult(); try { final PasswordPolicyResponseControl control = result.getControl(PasswordPolicyResponseControl.DECODER, new DecodeOptions()); if (!(control == null)) { System.out.println("Password policy error " + control.getErrorType().toString() + " for " + dn); } } catch (final DecodeException de) { System.err.println(de.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } else { System.err.println("PasswordPolicyRequestControl not supported"); } // --- JCite password policy --- } /** * Use Permissive Modify Request Control to try to add an attribute that * already exists. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void usePermissiveModifyRequestControl(Connection connection) throws ErrorResultException { // --- JCite permissive modify --- if (isSupported(PermissiveModifyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PermissiveModifyRequestControl.newControl(true)) .addModification(ModificationType.ADD, "uid", "bjensen"); connection.modify(request); System.out.println("Permissive modify did not complain about " + "attempt to add uid: bjensen to " + dn + "."); } else { System.err.println("PermissiveModifyRequestControl not supported"); } // --- JCite permissive modify --- } /** * Use the LDAP PersistentSearchRequestControl to set up a persistent * search. Also use the Entry Change Notification Response Control to get * details about why an entry was returned for a persistent search. * * After you set this up, use another application to make changes to user * entries under dc=example,dc=com. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void usePersistentSearchRequestControl(Connection connection) throws ErrorResultException { // --- JCite psearch --- if (isSupported(PersistentSearchRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(objectclass=inetOrgPerson)", "cn") .addControl(PersistentSearchRequestControl.newControl( true, true, true, // isCritical, changesOnly, returnECs PersistentSearchChangeType.ADD, PersistentSearchChangeType.DELETE, PersistentSearchChangeType.MODIFY, PersistentSearchChangeType.MODIFY_DN)); final ConnectionEntryReader reader = connection.search(request); try { while (reader.hasNext()) { if (!reader.isReference()) { final SearchResultEntry entry = reader.readEntry(); System.out.println("Entry changed: " + entry.getName().toString()); final EntryChangeNotificationResponseControl control = entry.getControl( EntryChangeNotificationResponseControl.DECODER, new DecodeOptions()); final PersistentSearchChangeType type = control.getChangeType(); System.out.println("Change type: " + type.toString()); if (type.equals(PersistentSearchChangeType.MODIFY_DN)) { System.out.println("Previous DN: " + control.getPreviousName().toString()); } System.out.println("Change number: " + control.getChangeNumber()); System.out.println(); // Add a blank line. } } } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } catch (final ErrorResultIOException e) { System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } } else { System.err.println("PersistentSearchRequestControl not supported."); } // --- JCite psearch --- } /** * Use Post Read Controls to get entry content after a modification. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void usePostReadRequestControl(Connection connection) throws ErrorResultException { // --- JCite post read --- if (isSupported(PostReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PostReadRequestControl.newControl(true, "description")) .addModification(ModificationType.REPLACE, "description", "Using the PostReadRequestControl"); final Result result = connection.modify(request); try { final PostReadResponseControl control = result.getControl(PostReadResponseControl.DECODER, new DecodeOptions()); final Entry entry = control.getEntry(); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); writer.writeEntry(entry); writer.close(); } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("PostReadRequestControl not supported"); } // --- JCite post read --- } /** * Use Pre Read Controls to get entry content before a modification. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void usePreReadRequestControl(Connection connection) throws ErrorResultException { // --- JCite pre read --- if (isSupported(PreReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PreReadRequestControl.newControl(true, "mail")) .addModification( ModificationType.REPLACE, "mail", "modified@example.com"); final Result result = connection.modify(request); try { final PreReadResponseControl control = result.getControl(PreReadResponseControl.DECODER, new DecodeOptions()); final Entry entry = control.getEntry(); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); writer.writeEntry(entry); writer.close(); } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("PreReadRequestControl not supported"); } // --- JCite pre read --- } /** * Use proxied authorization to modify an identity as another user. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useProxiedAuthV2RequestControl(Connection connection) throws ErrorResultException { // --- JCite proxied authzv2 --- if (isSupported(ProxiedAuthV2RequestControl.OID)) { final String bindDN = "cn=My App,ou=Apps,dc=example,dc=com"; final String targetDn = "uid=bjensen,ou=People,dc=example,dc=com"; final String authzId = "dn:uid=kvaughan,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(targetDn) .addControl(ProxiedAuthV2RequestControl.newControl(authzId)) .addModification(ModificationType.REPLACE, "description", "Done with proxied authz"); connection.bind(bindDN, "password".toCharArray()); connection.modify(request); final Entry entry = connection.readEntry(targetDn, "description"); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.close(); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("ProxiedAuthV2RequestControl not supported"); } // --- JCite proxied authzv2 --- } /** * Use the server-side sort controls. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ // --- JCite server-side sort --- static void useServerSideSortRequestControl(Connection connection) throws ErrorResultException { if (isSupported(ServerSideSortRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("ou=People,dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn") .addControl(ServerSideSortRequestControl.newControl( true, new SortKey("cn"))); final SearchResultHandler resultHandler = new MySearchResultHandler(); final Result result = connection.search(request, resultHandler); try { final ServerSideSortResponseControl control = result.getControl(ServerSideSortResponseControl.DECODER, new DecodeOptions()); if (control != null && control.getResult() == ResultCode.SUCCESS) { System.out.println("# Entries are sorted."); } else { System.out.println("# Entries not necessarily sorted"); } } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } else { System.err.println("ServerSideSortRequestControl not supported"); } } private static class MySearchResultHandler implements SearchResultHandler { @Override public void handleErrorResult(ErrorResultException error) { // Ignore. } @Override public void handleResult(Result result) { // Ignore. } @Override public boolean handleEntry(SearchResultEntry entry) { final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.flush(); } catch (final IOException e) { System.err.println(e.getMessage()); return false; } return true; } @Override public boolean handleReference(SearchResultReference reference) { System.out.println("Got a reference: " + reference.toString()); return false; } } // --- JCite server-side sort --- /** * Use the simple paged results mechanism. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useSimplePagedResultsControl(Connection connection) throws ErrorResultException { // --- JCite simple paged results --- if (isSupported(SimplePagedResultsControl.OID)) { ByteString cookie = ByteString.empty(); SearchRequest request; final SearchResultHandler resultHandler = new MySearchResultHandler(); Result result; int page = 1; do { System.out.println("# Simple paged results: Page " + page); request = Requests.newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn") .addControl(SimplePagedResultsControl.newControl( true, 3, cookie)); result = connection.search(request, resultHandler); try { SimplePagedResultsControl control = result.getControl(SimplePagedResultsControl.DECODER, new DecodeOptions()); cookie = control.getCookie(); } catch (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } ++page; } while (cookie.length() != 0); } else { System.err.println("SimplePagedResultsControl not supported"); } // --- JCite simple paged results --- } /** * Use the subentries request control. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useSubentriesRequestControl(Connection connection) throws ErrorResultException { // --- JCite subentries --- if (isSupported(SubentriesRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "cn=*Class of Service", "cn", "subtreeSpecification") .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 (final ErrorResultIOException e) { System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); } } else { System.err.println("SubentriesRequestControl not supported"); } // --- JCite subentries --- } /** * Use the subtree delete control. * * @param connection * Active connection to LDAP server containing Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useSubtreeDeleteRequestControl(Connection connection) throws ErrorResultException { // --- JCite tree delete --- 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.err.println("Result: " + result.getDiagnosticMessage()); } } else { System.err.println("SubtreeDeleteRequestControl not supported"); } // --- JCite tree delete --- } /** * 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 Example.ldif content. * @throws ErrorResultException * Operation failed. */ static void useVirtualListViewRequestControl(Connection connection) throws ErrorResultException { // --- JCite vlv --- 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 (final DecodeException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_DECODING_ERROR.intValue()); } } else { System.err.println("VirtualListViewRequestControl not supported"); } // --- JCite vlv --- } // --- JCite check support --- /** * Controls supported by the LDAP server. */ private static Collection controls; /** * Populate the list of supported LDAP control OIDs. * * @param connection * Active connection to the LDAP server. * @throws ErrorResultException * Failed to get list of controls. */ static void checkSupportedControls(Connection connection) throws ErrorResultException { controls = RootDSE.readRootDSE(connection).getSupportedControls(); } /** * Check whether a control is supported. Call {@code checkSupportedControls} * first. * * @param control * Check support for this control, provided by OID. * @return True if the control is supported. */ static boolean isSupported(final String control) { if (controls != null && !controls.isEmpty()) { return controls.contains(control); } return false; } // --- JCite check support --- /** * Constructor not used. */ private Controls() { // Not used. } }