1. /*
  2. * @(#)SortControl.java 1.3 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.naming.ldap;
  8. import java.io.IOException;
  9. import com.sun.jndi.ldap.Ber;
  10. import com.sun.jndi.ldap.BerEncoder;
  11. /**
  12. * Requests that the results of a search operation be sorted by the LDAP server
  13. * before being returned.
  14. * The sort criteria are specified using an ordered list of one or more sort
  15. * keys, with associated sort parameters.
  16. * Search results are sorted at the LDAP server according to the parameters
  17. * supplied in the sort control and then returned to the requestor. If sorting
  18. * is not supported at the server (and the sort control is marked as critical)
  19. * then the search operation is not performed and an error is returned.
  20. * <p>
  21. * The following code sample shows how the class may be used:
  22. * <pre>
  23. *
  24. * // Open an LDAP association
  25. * LdapContext ctx = new InitialLdapContext();
  26. *
  27. * // Activate sorting
  28. * String sortKey = "cn";
  29. * ctx.setRequestControls(new Control[]{
  30. * new SortControl(sortKey, Control.CRITICAL) });
  31. *
  32. * // Perform a search
  33. * NamingEnumeration results =
  34. * ctx.search("", "(objectclass=*)", new SearchControls());
  35. *
  36. * // Iterate over search results
  37. * while (results != null && results.hasMore()) {
  38. * // Display an entry
  39. * SearchResult entry = (SearchResult)results.next();
  40. * System.out.println(entry.getName());
  41. * System.out.println(entry.getAttributes());
  42. *
  43. * // Handle the entry's response controls (if any)
  44. * if (entry instanceof HasControls) {
  45. * // ((HasControls)entry).getControls();
  46. * }
  47. * }
  48. * // Examine the sort control response
  49. * Control[] controls = ctx.getResponseControls();
  50. * if (controls != null) {
  51. * for (int i = 0; i < controls.length; i++) {
  52. * if (controls[i] instanceof SortResponseControl) {
  53. * SortResponseControl src = (SortResponseControl)controls[i];
  54. * if (! src.isSorted()) {
  55. * throw src.getException();
  56. * }
  57. * } else {
  58. * // Handle other response controls (if any)
  59. * }
  60. * }
  61. * }
  62. *
  63. * // Close the LDAP association
  64. * ctx.close();
  65. * ...
  66. *
  67. * </pre>
  68. * <p>
  69. * This class implements the LDAPv3 Request Control for server-side sorting
  70. * as defined in
  71. * <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
  72. *
  73. * The control's value has the following ASN.1 definition:
  74. * <pre>
  75. *
  76. * SortKeyList ::= SEQUENCE OF SEQUENCE {
  77. * attributeType AttributeDescription,
  78. * orderingRule [0] MatchingRuleId OPTIONAL,
  79. * reverseOrder [1] BOOLEAN DEFAULT FALSE }
  80. *
  81. * </pre>
  82. *
  83. * @since 1.5
  84. * @see SortKey
  85. * @see SortResponseControl
  86. * @author Vincent Ryan
  87. */
  88. final public class SortControl extends BasicControl {
  89. /**
  90. * The server-side sort control's assigned object identifier
  91. * is 1.2.840.113556.1.4.473.
  92. */
  93. public static final String OID = "1.2.840.113556.1.4.473";
  94. private static final long serialVersionUID = -1965961680233330744L;
  95. /**
  96. * Constructs a control to sort on a single attribute in ascending order.
  97. * Sorting will be performed using the ordering matching rule defined
  98. * for use with the specified attribute.
  99. *
  100. * @param sortBy An attribute ID to sort by.
  101. * @param criticality If true then the server must honor the control
  102. * and return the search results sorted as
  103. * requested or refuse to perform the search.
  104. * If false, then the server need not honor the
  105. * control.
  106. * @exception IOException If an error was encountered while encoding the
  107. * supplied arguments into a control.
  108. */
  109. public SortControl(String sortBy, boolean criticality) throws IOException {
  110. super(OID, criticality, null);
  111. super.value = setEncodedValue(new SortKey[]{ new SortKey(sortBy) });
  112. }
  113. /**
  114. * Constructs a control to sort on a list of attributes in ascending order.
  115. * Sorting will be performed using the ordering matching rule defined
  116. * for use with each of the specified attributes.
  117. *
  118. * @param sortBy A non-null list of attribute IDs to sort by.
  119. * The list is in order of highest to lowest sort key
  120. * precedence.
  121. * @param criticality If true then the server must honor the control
  122. * and return the search results sorted as
  123. * requested or refuse to perform the search.
  124. * If false, then the server need not honor the
  125. * control.
  126. * @exception IOException If an error was encountered while encoding the
  127. * supplied arguments into a control.
  128. */
  129. public SortControl(String[] sortBy, boolean criticality)
  130. throws IOException {
  131. super(OID, criticality, null);
  132. SortKey[] sortKeys = new SortKey[sortBy.length];
  133. for (int i = 0; i < sortBy.length; i++) {
  134. sortKeys[i] = new SortKey(sortBy[i]);
  135. }
  136. super.value = setEncodedValue(sortKeys);
  137. }
  138. /**
  139. * Constructs a control to sort on a list of sort keys.
  140. * Each sort key specifies the sort order and ordering matching rule to use.
  141. *
  142. * @param sortBy A non-null list of keys to sort by.
  143. * The list is in order of highest to lowest sort key
  144. * precedence.
  145. * @param criticality If true then the server must honor the control
  146. * and return the search results sorted as
  147. * requested or refuse to perform the search.
  148. * If false, then the server need not honor the
  149. * control.
  150. * @exception IOException If an error was encountered while encoding the
  151. * supplied arguments into a control.
  152. */
  153. public SortControl(SortKey[] sortBy, boolean criticality)
  154. throws IOException {
  155. super(OID, criticality, null);
  156. super.value = setEncodedValue(sortBy);
  157. }
  158. /*
  159. * Encodes the sort control's value using ASN.1 BER.
  160. * The result includes the BER tag and length for the control's value but
  161. * does not include the control's object identifer and criticality setting.
  162. *
  163. * @param sortKeys A non-null list of keys to sort by.
  164. * @return A possibly null byte array representing the ASN.1 BER encoded
  165. * value of the sort control.
  166. * @exception IOException If a BER encoding error occurs.
  167. */
  168. private byte[] setEncodedValue(SortKey[] sortKeys) throws IOException {
  169. // build the ASN.1 BER encoding
  170. BerEncoder ber = new BerEncoder(30 * sortKeys.length + 10);
  171. String matchingRule;
  172. ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
  173. for (int i = 0; i < sortKeys.length; i++) {
  174. ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
  175. ber.encodeString(sortKeys[i].getAttributeID(), true); // v3
  176. if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) {
  177. ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0), true);
  178. }
  179. if (! sortKeys[i].isAscending()) {
  180. ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1));
  181. }
  182. ber.endSeq();
  183. }
  184. ber.endSeq();
  185. return ber.getTrimmedBuf();
  186. }
  187. }