1 /* 2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.naming.ldap; 27 28 import java.io.IOException; 29 import com.sun.jndi.ldap.Ber; 30 import com.sun.jndi.ldap.BerEncoder; 31 32 /** 33 * Requests that the results of a search operation be sorted by the LDAP server 34 * before being returned. 35 * The sort criteria are specified using an ordered list of one or more sort 36 * keys, with associated sort parameters. 37 * Search results are sorted at the LDAP server according to the parameters 38 * supplied in the sort control and then returned to the requestor. If sorting 39 * is not supported at the server (and the sort control is marked as critical) 40 * then the search operation is not performed and an error is returned. 41 * <p> 42 * The following code sample shows how the class may be used: 43 * <pre>{@code 44 * 45 * // Open an LDAP association 46 * LdapContext ctx = new InitialLdapContext(); 47 * 48 * // Activate sorting 49 * String sortKey = "cn"; 50 * ctx.setRequestControls(new Control[]{ 51 * new SortControl(sortKey, Control.CRITICAL) }); 52 * 53 * // Perform a search 54 * NamingEnumeration results = 55 * ctx.search("", "(objectclass=*)", new SearchControls()); 56 * 57 * // Iterate over search results 58 * while (results != null && results.hasMore()) { 59 * // Display an entry 60 * SearchResult entry = (SearchResult)results.next(); 61 * System.out.println(entry.getName()); 62 * System.out.println(entry.getAttributes()); 63 * 64 * // Handle the entry's response controls (if any) 65 * if (entry instanceof HasControls) { 66 * // ((HasControls)entry).getControls(); 67 * } 68 * } 69 * // Examine the sort control response 70 * Control[] controls = ctx.getResponseControls(); 71 * if (controls != null) { 72 * for (int i = 0; i < controls.length; i++) { 73 * if (controls[i] instanceof SortResponseControl) { 74 * SortResponseControl src = (SortResponseControl)controls[i]; 75 * if (! src.isSorted()) { 76 * throw src.getException(); 77 * } 78 * } else { 79 * // Handle other response controls (if any) 80 * } 81 * } 82 * } 83 * 84 * // Close the LDAP association 85 * ctx.close(); 86 * ... 87 * 88 * }</pre> 89 * <p> 90 * This class implements the LDAPv3 Request Control for server-side sorting 91 * as defined in 92 * <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>. 93 * 94 * The control's value has the following ASN.1 definition: 95 * <pre> 96 * 97 * SortKeyList ::= SEQUENCE OF SEQUENCE { 98 * attributeType AttributeDescription, 99 * orderingRule [0] MatchingRuleId OPTIONAL, 100 * reverseOrder [1] BOOLEAN DEFAULT FALSE } 101 * 102 * </pre> 103 * 104 * @since 1.5 105 * @see SortKey 106 * @see SortResponseControl 107 * @author Vincent Ryan 108 */ 109 final public class SortControl extends BasicControl { 110 111 /** 112 * The server-side sort control's assigned object identifier 113 * is 1.2.840.113556.1.4.473. 114 */ 115 public static final String OID = "1.2.840.113556.1.4.473"; 116 117 private static final long serialVersionUID = -1965961680233330744L; 118 119 /** 120 * Constructs a control to sort on a single attribute in ascending order. 121 * Sorting will be performed using the ordering matching rule defined 122 * for use with the specified attribute. 123 * 124 * @param sortBy An attribute ID to sort by. 125 * @param criticality If true then the server must honor the control 126 * and return the search results sorted as 127 * requested or refuse to perform the search. 128 * If false, then the server need not honor the 129 * control. 130 * @exception IOException If an error was encountered while encoding the 131 * supplied arguments into a control. 132 */ 133 public SortControl(String sortBy, boolean criticality) throws IOException { 134 135 super(OID, criticality, null); 136 super.value = setEncodedValue(new SortKey[]{ new SortKey(sortBy) }); 137 } 138 139 /** 140 * Constructs a control to sort on a list of attributes in ascending order. 141 * Sorting will be performed using the ordering matching rule defined 142 * for use with each of the specified attributes. 143 * 144 * @param sortBy A non-null list of attribute IDs to sort by. 145 * The list is in order of highest to lowest sort key 146 * precedence. 147 * @param criticality If true then the server must honor the control 148 * and return the search results sorted as 149 * requested or refuse to perform the search. 150 * If false, then the server need not honor the 151 * control. 152 * @exception IOException If an error was encountered while encoding the 153 * supplied arguments into a control. 154 */ 155 public SortControl(String[] sortBy, boolean criticality) 156 throws IOException { 157 158 super(OID, criticality, null); 159 SortKey[] sortKeys = new SortKey[sortBy.length]; 160 for (int i = 0; i < sortBy.length; i++) { 161 sortKeys[i] = new SortKey(sortBy[i]); 162 } 163 super.value = setEncodedValue(sortKeys); 164 } 165 166 /** 167 * Constructs a control to sort on a list of sort keys. 168 * Each sort key specifies the sort order and ordering matching rule to use. 169 * 170 * @param sortBy A non-null list of keys to sort by. 171 * The list is in order of highest to lowest sort key 172 * precedence. 173 * @param criticality If true then the server must honor the control 174 * and return the search results sorted as 175 * requested or refuse to perform the search. 176 * If false, then the server need not honor the 177 * control. 178 * @exception IOException If an error was encountered while encoding the 179 * supplied arguments into a control. 180 */ 181 public SortControl(SortKey[] sortBy, boolean criticality) 182 throws IOException { 183 184 super(OID, criticality, null); 185 super.value = setEncodedValue(sortBy); 186 } 187 188 /* 189 * Encodes the sort control's value using ASN.1 BER. 190 * The result includes the BER tag and length for the control's value but 191 * does not include the control's object identifer and criticality setting. 192 * 193 * @param sortKeys A non-null list of keys to sort by. 194 * @return A possibly null byte array representing the ASN.1 BER encoded 195 * value of the sort control. 196 * @exception IOException If a BER encoding error occurs. 197 */ 198 private byte[] setEncodedValue(SortKey[] sortKeys) throws IOException { 199 200 // build the ASN.1 BER encoding 201 BerEncoder ber = new BerEncoder(30 * sortKeys.length + 10); 202 String matchingRule; 203 204 ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); 205 206 for (int i = 0; i < sortKeys.length; i++) { 207 ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); 208 ber.encodeString(sortKeys[i].getAttributeID(), true); // v3 209 210 if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) { 211 ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0), true); 212 } 213 if (! sortKeys[i].isAscending()) { 214 ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1)); 215 } 216 ber.endSeq(); 217 } 218 ber.endSeq(); 219 220 return ber.getTrimmedBuf(); 221 } 222 }