/* | 
|
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package javax.naming.ldap;  | 
|
import java.io.IOException;  | 
|
import com.sun.jndi.ldap.Ber;  | 
|
import com.sun.jndi.ldap.BerEncoder;  | 
|
/** | 
|
 * Requests that the results of a search operation be sorted by the LDAP server | 
|
 * before being returned. | 
|
 * The sort criteria are specified using an ordered list of one or more sort | 
|
 * keys, with associated sort parameters. | 
|
 * Search results are sorted at the LDAP server according to the parameters | 
|
 * supplied in the sort control and then returned to the requestor. If sorting | 
|
 * is not supported at the server (and the sort control is marked as critical) | 
|
 * then the search operation is not performed and an error is returned. | 
|
 * <p> | 
|
 * The following code sample shows how the class may be used: | 
|
 * <pre>{@code | 
|
 * | 
|
 *     // Open an LDAP association | 
|
 *     LdapContext ctx = new InitialLdapContext(); | 
|
 * | 
|
 *     // Activate sorting | 
|
 *     String sortKey = "cn"; | 
|
 *     ctx.setRequestControls(new Control[]{ | 
|
 *         new SortControl(sortKey, Control.CRITICAL) }); | 
|
 * | 
|
 *     // Perform a search | 
|
 *     NamingEnumeration results = | 
|
 *         ctx.search("", "(objectclass=*)", new SearchControls()); | 
|
 * | 
|
 *     // Iterate over search results | 
|
 *     while (results != null && results.hasMore()) { | 
|
 *         // Display an entry | 
|
 *         SearchResult entry = (SearchResult)results.next(); | 
|
 *         System.out.println(entry.getName()); | 
|
 *         System.out.println(entry.getAttributes()); | 
|
 * | 
|
 *         // Handle the entry's response controls (if any) | 
|
 *         if (entry instanceof HasControls) { | 
|
 *             // ((HasControls)entry).getControls(); | 
|
 *         } | 
|
 *     } | 
|
 *     // Examine the sort control response | 
|
 *     Control[] controls = ctx.getResponseControls(); | 
|
 *     if (controls != null) { | 
|
 *         for (int i = 0; i < controls.length; i++) { | 
|
 *             if (controls[i] instanceof SortResponseControl) { | 
|
 *                 SortResponseControl src = (SortResponseControl)controls[i]; | 
|
 *                 if (! src.isSorted()) { | 
|
 *                     throw src.getException(); | 
|
 *                 } | 
|
 *             } else { | 
|
 *                 // Handle other response controls (if any) | 
|
 *             } | 
|
 *         } | 
|
 *     } | 
|
 * | 
|
 *     // Close the LDAP association | 
|
 *     ctx.close(); | 
|
 *     ... | 
|
 * | 
|
 * }</pre> | 
|
 * <p> | 
|
 * This class implements the LDAPv3 Request Control for server-side sorting | 
|
 * as defined in | 
|
 * <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>. | 
|
 * | 
|
 * The control's value has the following ASN.1 definition: | 
|
 * <pre> | 
|
 * | 
|
 *     SortKeyList ::= SEQUENCE OF SEQUENCE { | 
|
 *         attributeType     AttributeDescription, | 
|
 *         orderingRule  [0] MatchingRuleId OPTIONAL, | 
|
 *         reverseOrder  [1] BOOLEAN DEFAULT FALSE } | 
|
 * | 
|
 * </pre> | 
|
 * | 
|
 * @since 1.5 | 
|
 * @see SortKey | 
|
 * @see SortResponseControl | 
|
 * @author Vincent Ryan | 
|
*/  | 
|
final public class SortControl extends BasicControl {  | 
|
    /** | 
|
     * The server-side sort control's assigned object identifier | 
|
     * is 1.2.840.113556.1.4.473. | 
|
*/  | 
|
public static final String OID = "1.2.840.113556.1.4.473";  | 
|
private static final long serialVersionUID = -1965961680233330744L;  | 
|
    /** | 
|
     * Constructs a control to sort on a single attribute in ascending order. | 
|
     * Sorting will be performed using the ordering matching rule defined | 
|
     * for use with the specified attribute. | 
|
     * | 
|
     * @param   sortBy  An attribute ID to sort by. | 
|
     * @param   criticality     If true then the server must honor the control | 
|
     *                          and return the search results sorted as | 
|
     *                          requested or refuse to perform the search. | 
|
     *                          If false, then the server need not honor the | 
|
     *                          control. | 
|
     * @exception IOException If an error was encountered while encoding the | 
|
     *                        supplied arguments into a control. | 
|
*/  | 
|
public SortControl(String sortBy, boolean criticality) throws IOException {  | 
|
super(OID, criticality, null);  | 
|
super.value = setEncodedValue(new SortKey[]{ new SortKey(sortBy) });  | 
|
}  | 
|
    /** | 
|
     * Constructs a control to sort on a list of attributes in ascending order. | 
|
     * Sorting will be performed using the ordering matching rule defined | 
|
     * for use with each of the specified attributes. | 
|
     * | 
|
     * @param   sortBy  A non-null list of attribute IDs to sort by. | 
|
     *                  The list is in order of highest to lowest sort key | 
|
     *                  precedence. | 
|
     * @param   criticality     If true then the server must honor the control | 
|
     *                          and return the search results sorted as | 
|
     *                          requested or refuse to perform the search. | 
|
     *                          If false, then the server need not honor the | 
|
     *                          control. | 
|
     * @exception IOException If an error was encountered while encoding the | 
|
     *                        supplied arguments into a control. | 
|
*/  | 
|
public SortControl(String[] sortBy, boolean criticality)  | 
|
throws IOException {  | 
|
super(OID, criticality, null);  | 
|
SortKey[] sortKeys = new SortKey[sortBy.length];  | 
|
for (int i = 0; i < sortBy.length; i++) {  | 
|
sortKeys[i] = new SortKey(sortBy[i]);  | 
|
}  | 
|
super.value = setEncodedValue(sortKeys);  | 
|
}  | 
|
    /** | 
|
     * Constructs a control to sort on a list of sort keys. | 
|
     * Each sort key specifies the sort order and ordering matching rule to use. | 
|
     * | 
|
     * @param   sortBy      A non-null list of keys to sort by. | 
|
     *                      The list is in order of highest to lowest sort key | 
|
     *                      precedence. | 
|
     * @param   criticality     If true then the server must honor the control | 
|
     *                          and return the search results sorted as | 
|
     *                          requested or refuse to perform the search. | 
|
     *                          If false, then the server need not honor the | 
|
     *                          control. | 
|
     * @exception IOException If an error was encountered while encoding the | 
|
     *                        supplied arguments into a control. | 
|
*/  | 
|
public SortControl(SortKey[] sortBy, boolean criticality)  | 
|
throws IOException {  | 
|
super(OID, criticality, null);  | 
|
super.value = setEncodedValue(sortBy);  | 
|
}  | 
|
    /* | 
|
     * Encodes the sort control's value using ASN.1 BER. | 
|
     * The result includes the BER tag and length for the control's value but | 
|
     * does not include the control's object identifer and criticality setting. | 
|
     * | 
|
     * @param   sortKeys    A non-null list of keys to sort by. | 
|
     * @return A possibly null byte array representing the ASN.1 BER encoded | 
|
     *         value of the sort control. | 
|
     * @exception IOException If a BER encoding error occurs. | 
|
*/  | 
|
private byte[] setEncodedValue(SortKey[] sortKeys) throws IOException {  | 
|
        // build the ASN.1 BER encoding | 
|
BerEncoder ber = new BerEncoder(30 * sortKeys.length + 10);  | 
|
String matchingRule;  | 
|
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);  | 
|
for (int i = 0; i < sortKeys.length; i++) {  | 
|
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);  | 
|
ber.encodeString(sortKeys[i].getAttributeID(), true); // v3  | 
|
if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) {  | 
|
ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0), true);  | 
|
}  | 
|
if (! sortKeys[i].isAscending()) {  | 
|
ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1));  | 
|
}  | 
|
ber.endSeq();  | 
|
}  | 
|
ber.endSeq();  | 
|
return ber.getTrimmedBuf();  | 
|
}  | 
|
}  |