001 /*
002 * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.naming.ldap;
027
028 import java.io.IOException;
029 import com.sun.jndi.ldap.Ber;
030 import com.sun.jndi.ldap.BerEncoder;
031
032 /**
033 * Requests that the results of a search operation be sorted by the LDAP server
034 * before being returned.
035 * The sort criteria are specified using an ordered list of one or more sort
036 * keys, with associated sort parameters.
037 * Search results are sorted at the LDAP server according to the parameters
038 * supplied in the sort control and then returned to the requestor. If sorting
039 * is not supported at the server (and the sort control is marked as critical)
040 * then the search operation is not performed and an error is returned.
041 * <p>
042 * The following code sample shows how the class may be used:
043 * <pre>
044 *
045 * // Open an LDAP association
046 * LdapContext ctx = new InitialLdapContext();
047 *
048 * // Activate sorting
049 * String sortKey = "cn";
050 * ctx.setRequestControls(new Control[]{
051 * new SortControl(sortKey, Control.CRITICAL) });
052 *
053 * // Perform a search
054 * NamingEnumeration results =
055 * ctx.search("", "(objectclass=*)", new SearchControls());
056 *
057 * // Iterate over search results
058 * while (results != null && results.hasMore()) {
059 * // Display an entry
060 * SearchResult entry = (SearchResult)results.next();
061 * System.out.println(entry.getName());
062 * System.out.println(entry.getAttributes());
063 *
064 * // Handle the entry's response controls (if any)
065 * if (entry instanceof HasControls) {
066 * // ((HasControls)entry).getControls();
067 * }
068 * }
069 * // Examine the sort control response
070 * Control[] controls = ctx.getResponseControls();
071 * if (controls != null) {
072 * for (int i = 0; i < controls.length; i++) {
073 * if (controls[i] instanceof SortResponseControl) {
074 * SortResponseControl src = (SortResponseControl)controls[i];
075 * if (! src.isSorted()) {
076 * throw src.getException();
077 * }
078 * } else {
079 * // Handle other response controls (if any)
080 * }
081 * }
082 * }
083 *
084 * // Close the LDAP association
085 * ctx.close();
086 * ...
087 *
088 * </pre>
089 * <p>
090 * This class implements the LDAPv3 Request Control for server-side sorting
091 * as defined in
092 * <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
093 *
094 * The control's value has the following ASN.1 definition:
095 * <pre>
096 *
097 * SortKeyList ::= SEQUENCE OF SEQUENCE {
098 * attributeType AttributeDescription,
099 * 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)
134 throws IOException {
135
136 super (OID, criticality, null);
137 super .value = setEncodedValue(new SortKey[] { new SortKey(
138 sortBy) });
139 }
140
141 /**
142 * Constructs a control to sort on a list of attributes in ascending order.
143 * Sorting will be performed using the ordering matching rule defined
144 * for use with each of the specified attributes.
145 *
146 * @param sortBy A non-null list of attribute IDs to sort by.
147 * The list is in order of highest to lowest sort key
148 * precedence.
149 * @param criticality If true then the server must honor the control
150 * and return the search results sorted as
151 * requested or refuse to perform the search.
152 * If false, then the server need not honor the
153 * control.
154 * @exception IOException If an error was encountered while encoding the
155 * supplied arguments into a control.
156 */
157 public SortControl(String[] sortBy, boolean criticality)
158 throws IOException {
159
160 super (OID, criticality, null);
161 SortKey[] sortKeys = new SortKey[sortBy.length];
162 for (int i = 0; i < sortBy.length; i++) {
163 sortKeys[i] = new SortKey(sortBy[i]);
164 }
165 super .value = setEncodedValue(sortKeys);
166 }
167
168 /**
169 * Constructs a control to sort on a list of sort keys.
170 * Each sort key specifies the sort order and ordering matching rule to use.
171 *
172 * @param sortBy A non-null list of keys to sort by.
173 * The list is in order of highest to lowest sort key
174 * precedence.
175 * @param criticality If true then the server must honor the control
176 * and return the search results sorted as
177 * requested or refuse to perform the search.
178 * If false, then the server need not honor the
179 * control.
180 * @exception IOException If an error was encountered while encoding the
181 * supplied arguments into a control.
182 */
183 public SortControl(SortKey[] sortBy, boolean criticality)
184 throws IOException {
185
186 super (OID, criticality, null);
187 super .value = setEncodedValue(sortBy);
188 }
189
190 /*
191 * Encodes the sort control's value using ASN.1 BER.
192 * The result includes the BER tag and length for the control's value but
193 * does not include the control's object identifer and criticality setting.
194 *
195 * @param sortKeys A non-null list of keys to sort by.
196 * @return A possibly null byte array representing the ASN.1 BER encoded
197 * value of the sort control.
198 * @exception IOException If a BER encoding error occurs.
199 */
200 private byte[] setEncodedValue(SortKey[] sortKeys)
201 throws IOException {
202
203 // build the ASN.1 BER encoding
204 BerEncoder ber = new BerEncoder(30 * sortKeys.length + 10);
205 String matchingRule;
206
207 ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
208
209 for (int i = 0; i < sortKeys.length; i++) {
210 ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
211 ber.encodeString(sortKeys[i].getAttributeID(), true); // v3
212
213 if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) {
214 ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0),
215 true);
216 }
217 if (!sortKeys[i].isAscending()) {
218 ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1));
219 }
220 ber.endSeq();
221 }
222 ber.endSeq();
223
224 return ber.getTrimmedBuf();
225 }
226 }
|