| | |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugCaught; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; |
| | | import org.opends.server.types.*; |
| | | import static org.opends.server.util.ServerConstants.OID_SUBTREE_DELETE_CONTROL; |
| | | import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL; |
| | | import static org.opends.server.util.ServerConstants.OID_MANAGE_DSAIT_CONTROL; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import org.opends.server.admin.std.server.JEBackendCfg; |
| | | import org.opends.server.admin.std.meta.JEBackendCfgDefn; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | |
| | | supportedControls.add(OID_SUBTREE_DELETE_CONTROL); |
| | | supportedControls.add(OID_PAGED_RESULTS_CONTROL); |
| | | supportedControls.add(OID_MANAGE_DSAIT_CONTROL); |
| | | supportedControls.add(OID_SERVER_SIDE_SORT_REQUEST_CONTROL); |
| | | } |
| | | |
| | | |
| | |
| | | import org.opends.server.core.ModifyDNOperation; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.controls.PagedResultsControl; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.controls.ServerSideSortResponseControl; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.Iterator; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugCaught; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugJEAccess; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugVerbose; |
| | | import static org.opends.server.util.ServerConstants.OID_SUBTREE_DELETE_CONTROL; |
| | | import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | |
| | | /** |
| | | * Storage container for LDAP entries. Each base DN of a JE backend is given |
| | |
| | | |
| | | List<Control> controls = searchOperation.getRequestControls(); |
| | | PagedResultsControl pageRequest = null; |
| | | ServerSideSortRequestControl sortRequest = null; |
| | | if (controls != null) |
| | | { |
| | | for (Control control : controls) |
| | |
| | | } |
| | | } |
| | | } |
| | | else if (control.getOID().equals(OID_SERVER_SIDE_SORT_REQUEST_CONTROL)) |
| | | { |
| | | // Ignore all but the first sort request control. |
| | | if (sortRequest == null) |
| | | { |
| | | try |
| | | { |
| | | sortRequest = ServerSideSortRequestControl.decodeControl(control); |
| | | } |
| | | catch (LDAPException e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessage(), e.getMessageID(), e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | if (entryIDList.isDefined()) |
| | | { |
| | | if (sortRequest != null) |
| | | { |
| | | try |
| | | { |
| | | entryIDList = EntryIDSetSorter.sort(this, entryIDList, |
| | | searchOperation, |
| | | sortRequest.getSortOrder()); |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null)); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl( |
| | | de.getResultCode().getIntValue(), null)); |
| | | |
| | | if (sortRequest.isCritical()) |
| | | { |
| | | throw de; |
| | | } |
| | | } |
| | | } |
| | | |
| | | searchIndexed(entryIDList, candidatesAreInScope, searchOperation, |
| | | pageRequest); |
| | | } |
| | | else |
| | | { |
| | | if (sortRequest != null) |
| | | { |
| | | // FIXME -- Add support for sorting unindexed searches using indexes |
| | | // like DSEE currently does. |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl( |
| | | LDAPResultCode.UNWILLING_TO_PERFORM, null)); |
| | | |
| | | if (sortRequest.isCritical()) |
| | | { |
| | | int msgID = MSGID_JEB_SEARCH_CANNOT_SORT_UNINDEXED; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException( |
| | | ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | searchNotIndexed(searchOperation, pageRequest); |
| | | } |
| | | } |
| | |
| | | if (continueSearch) |
| | | { |
| | | List<Lock> lockList = new ArrayList<Lock>(); |
| | | for (EntryID id : entryIDList) |
| | | Iterator<EntryID> iterator = entryIDList.iterator(begin); |
| | | while (iterator.hasNext()) |
| | | { |
| | | EntryID id = iterator.next(); |
| | | Entry entry = null; |
| | | Entry cacheEntry = null; |
| | | |
| | | // Skip entry IDs in pages already returned. |
| | | if (begin != null && id.compareTo(begin) < 0) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | // Try the entry cache first. Note no need to take a lock. |
| | | lockList.clear(); |
| | | cacheEntry = entryCache.getEntry(backend, id.longValue(), |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Create an iterator over the set or an empty iterator |
| | | * if the set is not defined. |
| | | * |
| | | * @param begin The entry ID of the first entry to return in the list. |
| | | * |
| | | * @return An EntryID iterator. |
| | | */ |
| | | public Iterator<EntryID> iterator(EntryID begin) |
| | | { |
| | | if (values == null) |
| | | { |
| | | // The set is not defined. |
| | | return new IDSetIterator(new long[0]); |
| | | } |
| | | else |
| | | { |
| | | // The set is defined. |
| | | return new IDSetIterator(values, begin); |
| | | } |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | |
| | | |
| | | import java.util.TreeMap; |
| | | |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.SearchFilter; |
| | | import org.opends.server.types.SearchScope; |
| | | import org.opends.server.types.SortOrder; |
| | | |
| | | import static org.opends.server.messages.JebMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides a mechanism for sorting the contents of an entry ID set |
| | | * based on a given sort order. |
| | | */ |
| | | public class EntryIDSetSorter |
| | | { |
| | | /** |
| | | * Creates a new entry ID set which is a sorted representation of the provided |
| | | * set using the given sort order. |
| | | * |
| | | * @param entryContainer The entry container with which the ID list is |
| | | * associated. |
| | | * @param entryIDSet The entry ID set to be sorted. |
| | | * @param searchOperation The search operation being processed. |
| | | * @param sortOrder The sort order to use for the entry ID set. |
| | | * |
| | | * @return A new entry ID set which is a sorted representation of the |
| | | * provided set using the given sort order. |
| | | * |
| | | * @throws DirectoryException If an error occurs while performing the sort. |
| | | */ |
| | | public static EntryIDSet sort(EntryContainer entryContainer, |
| | | EntryIDSet entryIDSet, |
| | | SearchOperation searchOperation, |
| | | SortOrder sortOrder) |
| | | throws DirectoryException |
| | | { |
| | | if (! entryIDSet.isDefined()) |
| | | { |
| | | return new EntryIDSet(); |
| | | } |
| | | |
| | | ID2Entry id2Entry = entryContainer.getID2Entry(); |
| | | DN baseDN = searchOperation.getBaseDN(); |
| | | SearchScope scope = searchOperation.getScope(); |
| | | SearchFilter filter = searchOperation.getFilter(); |
| | | |
| | | TreeMap<SortValues,EntryID> sortMap = new TreeMap<SortValues,EntryID>(); |
| | | for (EntryID id : entryIDSet) |
| | | { |
| | | try |
| | | { |
| | | Entry e = id2Entry.get(null, id); |
| | | |
| | | if ((! e.matchesBaseAndScope(baseDN, scope)) || |
| | | (! filter.matchesEntry(e))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | sortMap.put(new SortValues(id, e, sortOrder), id); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_ENTRYIDSORTER_CANNOT_EXAMINE_ENTRY; |
| | | String message = getMessage(msgID, String.valueOf(id), |
| | | getExceptionMessage(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | } |
| | | |
| | | long[] sortedIDs = new long[sortMap.size()]; |
| | | int i=0; |
| | | for (EntryID id : sortMap.values()) |
| | | { |
| | | sortedIDs[i++] = id.longValue(); |
| | | } |
| | | |
| | | return new EntryIDSet(sortedIDs, 0, sortedIDs.length); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Create a new iterator for a given array of entry IDs. |
| | | * @param entryIDList An array of IDs in order or ID. |
| | | * @param begin The entry ID of the first entry that should be returned, or |
| | | * {@code null} if it should start at the beginning of the list. |
| | | */ |
| | | public IDSetIterator(long[] entryIDList, EntryID begin) |
| | | { |
| | | this.entryIDList = entryIDList; |
| | | |
| | | if (begin == null) |
| | | { |
| | | i = 0; |
| | | } |
| | | else |
| | | { |
| | | for (i=0; i < entryIDList.length; i++) |
| | | { |
| | | if (entryIDList[i] == begin.longValue()) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (i >= entryIDList.length) |
| | | { |
| | | i = 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns <tt>true</tt> if the iteration has more elements. (In other |
| | | * words, returns <tt>true</tt> if <tt>next</tt> would return an element |
| | | * rather than throwing an exception.) |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | |
| | | |
| | | import java.util.List; |
| | | |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.SortKey; |
| | | import org.opends.server.types.SortOrder; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class defines a data structure that holds a set of attribute values that |
| | | * are associated with a sort order for a given entry. Any or all of the |
| | | * attribute values may be {@code null} if the entry does not include any values |
| | | * for the attribute type targeted by the corresponding sort key. |
| | | * <BR><BR> |
| | | * This class implements the {@code Comparable} interface and may therefore be |
| | | * used to order the elements in components like {@code TreeMap} and |
| | | * {@code TreeSet}. |
| | | */ |
| | | public class SortValues |
| | | implements Comparable<SortValues> |
| | | { |
| | | // The set of sort keys in this sort order. |
| | | private AttributeValue[] values; |
| | | |
| | | // The entry ID for the entry associated with this sort values. |
| | | private EntryID entryID; |
| | | |
| | | // The sort order for this set of sort values. |
| | | private SortOrder sortOrder; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new sort values object with the provided information. |
| | | * |
| | | * @param entryID The entry ID for the entry associated with this set of |
| | | * values. |
| | | * @param entry The entry containing the values to extract and use when |
| | | * sorting. |
| | | * @param sortOrder The sort order to use to obtain the necessary values. |
| | | */ |
| | | public SortValues(EntryID entryID, Entry entry, SortOrder sortOrder) |
| | | { |
| | | this.entryID = entryID; |
| | | this.sortOrder = sortOrder; |
| | | |
| | | SortKey[] sortKeys = sortOrder.getSortKeys(); |
| | | values = new AttributeValue[sortKeys.length]; |
| | | for (int i=0; i < sortKeys.length; i++) |
| | | { |
| | | SortKey sortKey = sortKeys[i]; |
| | | AttributeType attrType = sortKey.getAttributeType(); |
| | | List<Attribute> attrList = entry.getAttribute(attrType); |
| | | if (attrList != null) |
| | | { |
| | | AttributeValue sortValue = null; |
| | | |
| | | // There may be multiple versions of this attribute in the target entry |
| | | // (e.g., with different sets of options), and it may also be a |
| | | // multivalued attribute. In that case, we need to find the value that |
| | | // is the best match for the corresponding sort key (i.e., for sorting |
| | | // in ascending order, we want to find the lowest value; for sorting in |
| | | // descending order, we want to find the highest value). This is |
| | | // handled by the SortKey.compareValues method. |
| | | for (Attribute a : attrList) |
| | | { |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | if (sortValue == null) |
| | | { |
| | | sortValue = v; |
| | | } |
| | | else if (sortKey.compareValues(v, sortValue) < 0) |
| | | { |
| | | sortValue = v; |
| | | } |
| | | } |
| | | } |
| | | |
| | | values[i] = sortValue; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Compares this set of sort values with the provided set of values to |
| | | * determine their relative order in a sorted list. |
| | | * |
| | | * @param sortValues The set of values to compare against this sort values. |
| | | * It must also have the same sort order as this set of |
| | | * values. |
| | | * |
| | | * @return A negative value if this sort values object should come before the |
| | | * provided values in a sorted list, a positive value if this sort |
| | | * values object should come after the provided values in a sorted |
| | | * list, or zero if there is no significant difference in their |
| | | * relative order. |
| | | */ |
| | | public int compareTo(SortValues sortValues) |
| | | { |
| | | SortKey[] sortKeys = sortOrder.getSortKeys(); |
| | | |
| | | for (int i=0; i < values.length; i++) |
| | | { |
| | | int compareValue = sortKeys[i].compareValues(values[i], |
| | | sortValues.values[i]); |
| | | if (compareValue != 0) |
| | | { |
| | | return compareValue; |
| | | } |
| | | } |
| | | |
| | | // If we've gotten here, then we can't tell a difference between the sets of |
| | | // sort values, so sort based on entry ID. |
| | | long idDifference = (entryID.longValue() - sortValues.entryID.longValue()); |
| | | if (idDifference < 0) |
| | | { |
| | | return -1; |
| | | } |
| | | else if (idDifference > 0) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this sort values object. |
| | | * |
| | | * @return A string representation of this sort values object. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this sort values object to the provided |
| | | * buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("SortValues("); |
| | | |
| | | SortKey[] sortKeys = sortOrder.getSortKeys(); |
| | | for (int i=0; i < sortKeys.length; i++) |
| | | { |
| | | if (i > 0) |
| | | { |
| | | buffer.append(", "); |
| | | } |
| | | |
| | | if (sortKeys[i].ascending()) |
| | | { |
| | | buffer.append("+"); |
| | | } |
| | | else |
| | | { |
| | | buffer.append("-"); |
| | | } |
| | | |
| | | buffer.append(sortKeys[i].getAttributeType().getNameOrOID()); |
| | | buffer.append("="); |
| | | buffer.append(values[i].getStringValue()); |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.controls; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.StringTokenizer; |
| | | |
| | | import org.opends.server.api.OrderingMatchingRule; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.protocols.asn1.ASN1Boolean; |
| | | import org.opends.server.protocols.asn1.ASN1Element; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.asn1.ASN1Sequence; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.LDAPException; |
| | | import org.opends.server.types.SortKey; |
| | | import org.opends.server.types.SortOrder; |
| | | |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.messages.ProtocolMessages.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class implements the server-side sort request control as defined in RFC |
| | | * 2891 section 1.1. The ASN.1 description for the control value is: |
| | | * <BR><BR> |
| | | * <PRE> |
| | | * SortKeyList ::= SEQUENCE OF SEQUENCE { |
| | | * attributeType AttributeDescription, |
| | | * orderingRule [0] MatchingRuleId OPTIONAL, |
| | | * reverseOrder [1] BOOLEAN DEFAULT FALSE } |
| | | * </PRE> |
| | | */ |
| | | public class ServerSideSortRequestControl |
| | | extends Control |
| | | { |
| | | /** |
| | | * The BER type to use when encoding the orderingRule element. |
| | | */ |
| | | private static final byte TYPE_ORDERING_RULE_ID = (byte) 0x80; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The BER type to use when encoding the reverseOrder element. |
| | | */ |
| | | private static final byte TYPE_REVERSE_ORDER = (byte) 0x81; |
| | | |
| | | |
| | | |
| | | // The sort order associated with this control. |
| | | private SortOrder sortOrder; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort request control based on the provided sort |
| | | * order. |
| | | * |
| | | * @param sortOrder The sort order to use for this control. |
| | | */ |
| | | public ServerSideSortRequestControl(SortOrder sortOrder) |
| | | { |
| | | super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, false, |
| | | encodeControlValue(sortOrder)); |
| | | |
| | | this.sortOrder = sortOrder; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort request control based on the definition in |
| | | * the provided sort order string. This is only intended for client-side use, |
| | | * and controls created with this constructor should not attempt to use the |
| | | * generated sort order for any purpose. |
| | | * |
| | | * @param sortOrderString The string representation of the sort order to use |
| | | * for the control. |
| | | * |
| | | * @throws LDAPException If the provided sort order string could not be |
| | | * decoded. |
| | | */ |
| | | public ServerSideSortRequestControl(String sortOrderString) |
| | | throws LDAPException |
| | | { |
| | | super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, false, |
| | | encodeControlValue(sortOrderString)); |
| | | |
| | | this.sortOrder = null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort request control with the provided |
| | | * information. |
| | | * |
| | | * @param oid The OID to use for this control. |
| | | * @param isCritical Indicates whether support for this control should be |
| | | * considered a critical part of the server processing. |
| | | * @param controlValue The encoded value for this control. |
| | | * @param sortOrder sort order associated with this server-side sort |
| | | * control. |
| | | */ |
| | | private ServerSideSortRequestControl(String oid, boolean isCritical, |
| | | ASN1OctetString controlValue, |
| | | SortOrder sortOrder) |
| | | { |
| | | super(oid, isCritical, controlValue); |
| | | |
| | | this.sortOrder = sortOrder; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the sort order for this server-side sort request control. |
| | | * |
| | | * @return The sort order for this server-side sort request control. |
| | | */ |
| | | public SortOrder getSortOrder() |
| | | { |
| | | return sortOrder; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided sort order object in a manner suitable for use as the |
| | | * value of this control. |
| | | * |
| | | * @param sortOrder The sort order to be encoded. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort order. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(SortOrder sortOrder) |
| | | { |
| | | SortKey[] sortKeys = sortOrder.getSortKeys(); |
| | | ArrayList<ASN1Element> keyList = |
| | | new ArrayList<ASN1Element>(sortKeys.length); |
| | | for (SortKey sortKey : sortKeys) |
| | | { |
| | | ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3); |
| | | elementList.add(new ASN1OctetString( |
| | | sortKey.getAttributeType().getNameOrOID())); |
| | | |
| | | if (sortKey.getOrderingRule() != null) |
| | | { |
| | | elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID, |
| | | sortKey.getOrderingRule().getNameOrOID())); |
| | | } |
| | | |
| | | if (! sortKey.ascending()) |
| | | { |
| | | elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, false)); |
| | | } |
| | | |
| | | keyList.add(new ASN1Sequence(elementList)); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(keyList).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided sort order string in a manner suitable for use as the |
| | | * value of this control. |
| | | * |
| | | * @param sortOrderString The sort order string to be encoded. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort order. |
| | | * |
| | | * @throws LDAPException If the provided sort order string cannot be decoded |
| | | * to create the control value. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(String sortOrderString) |
| | | throws LDAPException |
| | | { |
| | | StringTokenizer tokenizer = new StringTokenizer(sortOrderString, ","); |
| | | |
| | | ArrayList<ASN1Element> keyList = new ArrayList<ASN1Element>(); |
| | | while (tokenizer.hasMoreTokens()) |
| | | { |
| | | String token = tokenizer.nextToken().trim(); |
| | | boolean reverseOrder = false; |
| | | if (token.startsWith("-")) |
| | | { |
| | | reverseOrder = true; |
| | | token = token.substring(1); |
| | | } |
| | | else if (token.startsWith("+")) |
| | | { |
| | | token = token.substring(1); |
| | | } |
| | | |
| | | int colonPos = token.indexOf(':'); |
| | | if (colonPos < 0) |
| | | { |
| | | if (token.length() == 0) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_ATTR_NAME; |
| | | String message = getMessage(msgID, sortOrderString); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | |
| | | if (reverseOrder) |
| | | { |
| | | ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(2); |
| | | elementList.add(new ASN1OctetString(token)); |
| | | elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, reverseOrder)); |
| | | keyList.add(new ASN1Sequence(elementList)); |
| | | } |
| | | else |
| | | { |
| | | ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(1); |
| | | elementList.add(new ASN1OctetString(token)); |
| | | keyList.add(new ASN1Sequence(elementList)); |
| | | } |
| | | } |
| | | else if (colonPos == 0) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_ATTR_NAME; |
| | | String message = getMessage(msgID, sortOrderString); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | else if (colonPos == (token.length() - 1)) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_MATCHING_RULE; |
| | | String message = getMessage(msgID, sortOrderString); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | else |
| | | { |
| | | String attrName = token.substring(0, colonPos); |
| | | String ruleID = token.substring(colonPos+1); |
| | | |
| | | if (reverseOrder) |
| | | { |
| | | ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3); |
| | | elementList.add(new ASN1OctetString(attrName)); |
| | | elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID, ruleID)); |
| | | elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, reverseOrder)); |
| | | keyList.add(new ASN1Sequence(elementList)); |
| | | } |
| | | else |
| | | { |
| | | ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(2); |
| | | elementList.add(new ASN1OctetString(attrName)); |
| | | elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID, ruleID)); |
| | | keyList.add(new ASN1Sequence(elementList)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (keyList.isEmpty()) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_SORT_KEYS; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(keyList).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort request control from the contents of the |
| | | * provided control. |
| | | * |
| | | * @param control The generic control containing the information to use to |
| | | * create this server-side sort request control. It must not |
| | | * be {@code null}. |
| | | * |
| | | * @return The server-side sort request control decoded from the provided |
| | | * control. |
| | | * |
| | | * @throws LDAPException If this control cannot be decoded as a valid |
| | | * server-side sort request control. |
| | | */ |
| | | public static ServerSideSortRequestControl decodeControl(Control control) |
| | | throws LDAPException |
| | | { |
| | | ASN1OctetString controlValue = control.getValue(); |
| | | if (controlValue == null) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_VALUE; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | try |
| | | { |
| | | ASN1Sequence orderSequence = |
| | | ASN1Sequence.decodeAsSequence(controlValue.value()); |
| | | ArrayList<ASN1Element> orderElements = orderSequence.elements(); |
| | | SortKey[] sortKeys = new SortKey[orderElements.size()]; |
| | | if (sortKeys.length == 0) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_SORT_KEYS; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | for (int i=0; i < sortKeys.length; i++) |
| | | { |
| | | ASN1Sequence keySequence = orderElements.get(i).decodeAsSequence(); |
| | | ArrayList<ASN1Element> keyElements = keySequence.elements(); |
| | | |
| | | String attrName = |
| | | keyElements.get(0).decodeAsOctetString().stringValue(). |
| | | toLowerCase(); |
| | | AttributeType attrType = DirectoryServer.getAttributeType(attrName, |
| | | false); |
| | | if (attrType == null) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_UNDEFINED_ATTR; |
| | | String message = getMessage(msgID, attrName); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | |
| | | OrderingMatchingRule orderingRule = null; |
| | | boolean ascending = true; |
| | | |
| | | for (int j=1; j < keyElements.size(); j++) |
| | | { |
| | | ASN1Element e = keyElements.get(j); |
| | | switch (e.getType()) |
| | | { |
| | | case TYPE_ORDERING_RULE_ID: |
| | | String orderingRuleID = |
| | | e.decodeAsOctetString().stringValue().toLowerCase(); |
| | | orderingRule = |
| | | DirectoryServer.getOrderingMatchingRule(orderingRuleID); |
| | | if (orderingRule == null) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE; |
| | | String message = getMessage(msgID, orderingRuleID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | break; |
| | | |
| | | case TYPE_REVERSE_ORDER: |
| | | ascending = ! e.decodeAsBoolean().booleanValue(); |
| | | break; |
| | | |
| | | default: |
| | | int msgID = MSGID_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE; |
| | | String message = getMessage(msgID, byteToHex(e.getType())); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | } |
| | | |
| | | if ((orderingRule == null) && |
| | | (attrType.getOrderingMatchingRule() == null)) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR; |
| | | String message = getMessage(msgID, attrName); |
| | | throw new LDAPException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID, |
| | | message); |
| | | } |
| | | |
| | | sortKeys[i] = new SortKey(attrType, ascending, orderingRule); |
| | | } |
| | | |
| | | return new ServerSideSortRequestControl(control.getOID(), |
| | | control.isCritical(), |
| | | controlValue, |
| | | new SortOrder(sortKeys)); |
| | | } |
| | | catch (LDAPException le) |
| | | { |
| | | throw le; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_SORTREQ_CONTROL_CANNOT_DECODE_VALUE; |
| | | String message = getMessage(msgID, getExceptionMessage(e)); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message, e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this server-side sort request control. |
| | | * |
| | | * @return A string representation of this server-side sort request control. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this server-side sort request control |
| | | * to the provided buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("ServerSideSortRequestControl("); |
| | | |
| | | if (sortOrder != null) |
| | | { |
| | | buffer.append(sortOrder); |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.controls; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | |
| | | import org.opends.server.protocols.asn1.ASN1Element; |
| | | import org.opends.server.protocols.asn1.ASN1Enumerated; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.asn1.ASN1Sequence; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.LDAPException; |
| | | |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.messages.ProtocolMessages.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class implements the server-side sort response control as defined in RFC |
| | | * 2891 section 1.2. The ASN.1 description for the control value is: |
| | | * <BR><BR> |
| | | * <PRE> |
| | | * SortResult ::= SEQUENCE { |
| | | * sortResult ENUMERATED { |
| | | * success (0), -- results are sorted |
| | | * operationsError (1), -- server internal failure |
| | | * timeLimitExceeded (3), -- timelimit reached before |
| | | * -- sorting was completed |
| | | * strongAuthRequired (8), -- refused to return sorted |
| | | * -- results via insecure |
| | | * -- protocol |
| | | * adminLimitExceeded (11), -- too many matching entries |
| | | * -- for the server to sort |
| | | * noSuchAttribute (16), -- unrecognized attribute |
| | | * -- type in sort key |
| | | * inappropriateMatching (18), -- unrecognized or |
| | | * -- inappropriate matching |
| | | * -- rule in sort key |
| | | * insufficientAccessRights (50), -- refused to return sorted |
| | | * -- results to this client |
| | | * busy (51), -- too busy to process |
| | | * unwillingToPerform (53), -- unable to sort |
| | | * other (80) |
| | | * }, |
| | | * attributeType [0] AttributeDescription OPTIONAL } |
| | | * </PRE> |
| | | */ |
| | | public class ServerSideSortResponseControl |
| | | extends Control |
| | | { |
| | | /** |
| | | * The BER type to use when encoding the attribute type element. |
| | | */ |
| | | private static final byte TYPE_ATTRIBUTE_TYPE = (byte) 0x80; |
| | | |
| | | |
| | | |
| | | // The result code for the sort result. |
| | | private int resultCode; |
| | | |
| | | // The attribute type for the sort result. |
| | | private String attributeType; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort response control based on the provided |
| | | * result code and attribute type. |
| | | * |
| | | * @param resultCode The result code for the sort result. |
| | | * @param attributeType The attribute type for the sort result (or |
| | | * {@code null} if there is none). |
| | | */ |
| | | public ServerSideSortResponseControl(int resultCode, String attributeType) |
| | | { |
| | | super(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL, false, |
| | | encodeControlValue(resultCode, attributeType)); |
| | | |
| | | this.resultCode = resultCode; |
| | | this.attributeType = attributeType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort response control with the provided |
| | | * information. |
| | | * |
| | | * @param oid The OID to use for this control. |
| | | * @param isCritical Indicates whether support for this control should be |
| | | * considered a critical part of the server processing. |
| | | * @param controlValue The encoded value for this control. |
| | | * @param resultCode The result code for the sort result. |
| | | * @param attributeType The attribute type for the sort result. |
| | | */ |
| | | private ServerSideSortResponseControl(String oid, boolean isCritical, |
| | | ASN1OctetString controlValue, |
| | | int resultCode, |
| | | String attributeType) |
| | | { |
| | | super(oid, isCritical, controlValue); |
| | | |
| | | this.resultCode = resultCode; |
| | | this.attributeType = attributeType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the result code for this sort result. |
| | | * |
| | | * @return The result code for this sort result. |
| | | */ |
| | | public int getResultCode() |
| | | { |
| | | return resultCode; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the attribute type for this sort result. |
| | | * |
| | | * @return The attribute type for this sort result, or {@code null} if there |
| | | * is none. |
| | | */ |
| | | public String getAttributeType() |
| | | { |
| | | return attributeType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided set of result codes and attribute types in a manner |
| | | * suitable for use as the value of this control. |
| | | * |
| | | * @param resultCode The result code for the sort result. |
| | | * @param attributeType The attribute type for the sort result, or |
| | | * {@code null} if there is none. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort result. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(int resultCode, |
| | | String attributeType) |
| | | { |
| | | ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); |
| | | elements.add(new ASN1Enumerated(resultCode)); |
| | | |
| | | if (attributeType != null) |
| | | { |
| | | elements.add(new ASN1OctetString(TYPE_ATTRIBUTE_TYPE, attributeType)); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(elements).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server-side sort response control from the contents of the |
| | | * provided control. |
| | | * |
| | | * @param control The generic control containing the information to use to |
| | | * create this server-side sort response control. It must |
| | | * not be {@code null}. |
| | | * |
| | | * @return The server-side sort response control decoded from the provided |
| | | * control. |
| | | * |
| | | * @throws LDAPException If this control cannot be decoded as a valid |
| | | * server-side sort response control. |
| | | */ |
| | | public static ServerSideSortResponseControl decodeControl(Control control) |
| | | throws LDAPException |
| | | { |
| | | ASN1OctetString controlValue = control.getValue(); |
| | | if (controlValue == null) |
| | | { |
| | | int msgID = MSGID_SORTRES_CONTROL_NO_VALUE; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | try |
| | | { |
| | | ArrayList<ASN1Element> elements = |
| | | ASN1Sequence.decodeAsSequence(control.getValue().value()).elements(); |
| | | int resultCode = elements.get(0).decodeAsEnumerated().intValue(); |
| | | |
| | | String attributeType = null; |
| | | if (elements.size() > 1) |
| | | { |
| | | attributeType = elements.get(1).decodeAsOctetString().stringValue(); |
| | | } |
| | | |
| | | return new ServerSideSortResponseControl(control.getOID(), |
| | | control.isCritical(), |
| | | control.getValue(), resultCode, |
| | | attributeType); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_SORTRES_CONTROL_CANNOT_DECODE_VALUE; |
| | | String message = getMessage(msgID, getExceptionMessage(e)); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message, e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this server-side sort response |
| | | * control. |
| | | * |
| | | * @return A string representation of this server-side sort response control. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this server-side sort response control |
| | | * to the provided buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("ServerSideSortResponseControl(resultCode="); |
| | | buffer.append(resultCode); |
| | | |
| | | if (attributeType != null) |
| | | { |
| | | buffer.append(", attributeType="); |
| | | buffer.append(attributeType); |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort key string |
| | | * has an invalid order indicator. This takes a single argument, which is the |
| | | * sort key string. |
| | | */ |
| | | public static final int MSGID_SORTKEY_INVALID_ORDER_INDICATOR = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 603; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort key string |
| | | * has an undefined attribute type. This takes two arguments, which are the |
| | | * sort key string and the name of the attribute type. |
| | | */ |
| | | public static final int MSGID_SORTKEY_UNDEFINED_TYPE = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 604; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort key string |
| | | * has an attribute type with no ordering matching rule. This takes two |
| | | * arguments, which are the sort key string and the name of the attribute |
| | | * type. |
| | | */ |
| | | public static final int MSGID_SORTKEY_NO_ORDERING_RULE = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 605; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort key string |
| | | * has an undefined ordering rule. This takes two arguments, which are the |
| | | * sort key string and the name of the ordering rule. |
| | | */ |
| | | public static final int MSGID_SORTKEY_UNDEFINED_ORDERING_RULE = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 606; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort order string |
| | | * does not include any sort keys. This takes a single argument, which is the |
| | | * sort order string. |
| | | */ |
| | | public static final int MSGID_SORTORDER_DECODE_NO_KEYS = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 607; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined |
| | | * in this class. |
| | | */ |
| | |
| | | registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES, |
| | | "You do not have sufficient privileges to use the " + |
| | | "proxied authorization control"); |
| | | |
| | | |
| | | registerMessage(MSGID_SORTKEY_INVALID_ORDER_INDICATOR, |
| | | "The provided sort key value %s is invalid because it " + |
| | | "does not start with either '+' (to indicate sorting in " + |
| | | "ascending order) or '-' (to indicate sorting in " + |
| | | "descending order)"); |
| | | registerMessage(MSGID_SORTKEY_UNDEFINED_TYPE, |
| | | "The provided sort key value %s is invalid because it " + |
| | | "references undefined attribute type %s"); |
| | | registerMessage(MSGID_SORTKEY_NO_ORDERING_RULE, |
| | | "The provided sort key value %s is invalid because " + |
| | | "attribute type %s does not have a default ordering " + |
| | | "matching rule and no specific rule was provided"); |
| | | registerMessage(MSGID_SORTKEY_UNDEFINED_ORDERING_RULE, |
| | | "The provided sort key value %s is invalid because " + |
| | | "it references undefined ordering matching rule %s"); |
| | | |
| | | |
| | | registerMessage(MSGID_SORTORDER_DECODE_NO_KEYS, |
| | | "The provided sort order string \"%s\" is invalid " + |
| | | "because it does not contain any sort keys"); |
| | | } |
| | | } |
| | | |
| | |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_SEVERE_ERROR | 138; |
| | | |
| | | /** |
| | | * The message ID to use if an error occurs while attempting to retrieve an |
| | | * entry to examine while sorting. This takes two arguments, which are a |
| | | * string representation of the entry ID and a message explaining the |
| | | * problem that occurred. |
| | | */ |
| | | public static final int MSGID_ENTRYIDSORTER_CANNOT_EXAMINE_ENTRY = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_SEVERE_ERROR | 139; |
| | | |
| | | /** |
| | | * The message ID of an error indicating that the base entry of a search |
| | | * operation does not exist. This message takes one string argument which is |
| | | * the DN of the search base entry. |
| | | */ |
| | | public static final int MSGID_JEB_SEARCH_CANNOT_SORT_UNINDEXED = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 140; |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | "There is no index configured for attribute type '%s'"); |
| | | registerMessage(MSGID_JEB_SEARCH_NO_SUCH_OBJECT, |
| | | "The search base entry '%s' does not exist"); |
| | | registerMessage(MSGID_JEB_SEARCH_CANNOT_SORT_UNINDEXED, |
| | | "The search results cannot be sorted because the given " + |
| | | "search request is not indexed"); |
| | | registerMessage(MSGID_JEB_ADD_NO_SUCH_OBJECT, |
| | | "The entry '%s' cannot be added because its parent " + |
| | | "entry does not exist"); |
| | |
| | | registerMessage(MSGID_JEB_REBUILD_BACKEND_ONLINE, |
| | | "Rebuilding system index(es) must be done with the " + |
| | | "backend containing the base DN disabled"); |
| | | |
| | | |
| | | registerMessage(MSGID_ENTRYIDSORTER_CANNOT_EXAMINE_ENTRY, |
| | | "Unable to examine the entry with ID %s for sorting " + |
| | | "purposes: %s"); |
| | | } |
| | | } |
| | |
| | | public static final int MSGID_LDAP_CONNHANDLER_NO_TRUSTMANAGER_DN = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 403; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used as the description of the |
| | | * configuration attribute specifying whether to enable the LDAPS |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * request control does not have a value. It does not take any arguments. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_NO_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 406; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * request control references an undefined attribute type. This takes a |
| | | * single argument, which is the name of the attribute type. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_UNDEFINED_ATTR = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 407; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * request control references an undefined matching rule. This takes a |
| | | * single argument, which is the name of the matching rule. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 408; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * request control value sequence has an element with an invalid type. This |
| | | * takes a single argument, which is the hex representation of the unsupported |
| | | * type value. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 409; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * decoding the server-side sort request control value. This takes a single |
| | | * argument, which is a message explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_CANNOT_DECODE_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 410; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * response control does not have a value. It does not take any arguments. |
| | | */ |
| | | public static final int MSGID_SORTRES_CONTROL_NO_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 411; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * decoding the server-side sort response control value. This takes a single |
| | | * argument, which is a message explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_SORTRES_CONTROL_CANNOT_DECODE_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 412; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort order string |
| | | * has a zero-length attribute name. This takes a single argument, which is |
| | | * the sort order string. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_NO_ATTR_NAME = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 413; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a sort order string |
| | | * has a zero-length matching rule name. This takes a single argument, which |
| | | * is the sort order string. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_NO_MATCHING_RULE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 414; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * control does not have any sort keys. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_NO_SORT_KEYS = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 415; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the server-side sort |
| | | * control includes an attribute for which no ordering rule is available. |
| | | * This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 416; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | registerMessage(MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR, |
| | | "Cannot decode the provided address mask because the it has an" + |
| | | "invalid format"); |
| | | |
| | | |
| | | registerMessage(MSGID_SORTREQ_CONTROL_NO_VALUE, |
| | | "Unable to decode the provided control as a server-side " + |
| | | "sort request control because it does not include a " + |
| | | "control value"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_UNDEFINED_ATTR, |
| | | "Unable to process the provided server-side sort " + |
| | | "request control because it references attribute " + |
| | | "type %s which is not defined in the server schema"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE, |
| | | "Unable to process the provided server-side sort request " + |
| | | "control because it references undefined ordering " + |
| | | "matching rule %s"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE, |
| | | "Unable to process the provided server-side sort request " + |
| | | "control because the value sequence contains an element " + |
| | | "with an unsupported type of %s"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_CANNOT_DECODE_VALUE, |
| | | "Unable to process the provided server-side sort request " + |
| | | "control because an error occurred while attempting to " + |
| | | "decode the control value: %s"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_NO_ATTR_NAME, |
| | | "Unable to process the provided server-side sort " + |
| | | "request control because the sort order string \"%s\" " + |
| | | "included a sort key with no attribute name"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_NO_MATCHING_RULE, |
| | | "Unable to process the provided server-side sort " + |
| | | "request control because the sort order string \"%s\" " + |
| | | "included a sort key with a colon but no matching rule " + |
| | | "name"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_NO_SORT_KEYS, |
| | | "Unable to process the provided server-side sort " + |
| | | "request control because it did not contain any sort keys"); |
| | | registerMessage(MSGID_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR, |
| | | "Unable to process the provided server-side sort " + |
| | | "request control because it included attribute %s which " + |
| | | "does not have a default ordering matching rule and no " + |
| | | "ordering rule was specified in the sort key"); |
| | | |
| | | |
| | | registerMessage(MSGID_SORTRES_CONTROL_NO_VALUE, |
| | | "Unable to decode the provided control as a server-side " + |
| | | "sort response control because it does not include a " + |
| | | "control value"); |
| | | registerMessage(MSGID_SORTRES_CONTROL_CANNOT_DECODE_VALUE, |
| | | "Unable to process the provided server-side sort " + |
| | | "response control because an error occurred while " + |
| | | "attempting to decode the control value: %s"); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used as the description of the |
| | | * sortOrder option for the ldapsearch tool. It does not take any arguments. |
| | | */ |
| | | public static final int MSGID_DESCRIPTION_SORT_ORDER = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 876; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the provided sort order |
| | | * is invalid. This takes a single argument, which is a message explaining |
| | | * the problem that occurred. |
| | | */ |
| | | public static final int MSGID_LDAP_SORTCONTROL_INVALID_ORDER = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 877; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | registerMessage(MSGID_DESCRIPTION_MATCHED_VALUES_FILTER, |
| | | "Use the LDAP matched values control with the provided " + |
| | | "filter"); |
| | | registerMessage(MSGID_DESCRIPTION_SORT_ORDER, |
| | | "Sort the results using the provided sort order"); |
| | | registerMessage(MSGID_COMPARE_CANNOT_BASE64_DECODE_ASSERTION_VALUE, |
| | | "The assertion value was indicated to be base64-encoded, " + |
| | | "but an error occurred while trying to decode the value"); |
| | |
| | | "control was invalid: %s"); |
| | | registerMessage(MSGID_LDAP_MATCHEDVALUES_INVALID_FILTER, |
| | | "The provided matched values filter was invalid: %s"); |
| | | registerMessage(MSGID_LDAP_SORTCONTROL_INVALID_ORDER, |
| | | "The provided sort order was invalid: %s"); |
| | | registerMessage(MSGID_LDAPMODIFY_PREREAD_NO_VALUE, |
| | | "The pre-read response control did not include a value"); |
| | | registerMessage(MSGID_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE, |
| | |
| | | import org.opends.server.controls.PagedResultsControl; |
| | | import org.opends.server.controls.PersistentSearchChangeType; |
| | | import org.opends.server.controls.PersistentSearchControl; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.util.Base64; |
| | | import org.opends.server.util.PasswordReader; |
| | |
| | | StringArgument pSearchInfo = null; |
| | | StringArgument saslOptions = null; |
| | | StringArgument searchScope = null; |
| | | StringArgument sortOrder = null; |
| | | StringArgument trustStorePath = null; |
| | | StringArgument trustStorePassword = null; |
| | | |
| | |
| | | MSGID_DESCRIPTION_MATCHED_VALUES_FILTER); |
| | | argParser.addArgument(matchedValuesFilter); |
| | | |
| | | sortOrder = new StringArgument("sortorder", 'S', "sortOrder", false, |
| | | false, true, "{sortOrder}", null, null, |
| | | MSGID_DESCRIPTION_SORT_ORDER); |
| | | argParser.addArgument(sortOrder); |
| | | |
| | | controlStr = |
| | | new StringArgument("control", 'J', "control", false, true, true, |
| | | "{controloid[:criticality[:value|::b64value|:<fileurl]]}", |
| | |
| | | searchOptions.getControls().add(new LDAPControl(mvc)); |
| | | } |
| | | |
| | | if (sortOrder.isPresent()) |
| | | { |
| | | try |
| | | { |
| | | searchOptions.getControls().add( |
| | | new LDAPControl(new ServerSideSortRequestControl( |
| | | sortOrder.getValue()))); |
| | | } |
| | | catch (LDAPException le) |
| | | { |
| | | int msgID = MSGID_LDAP_SORTCONTROL_INVALID_ORDER; |
| | | String message = getMessage(msgID, le.getErrorMessage()); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | // Set the connection options. |
| | | connectionOptions.setSASLExternal(saslExternal.isPresent()); |
| | | if(saslOptions.isPresent()) |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | |
| | | |
| | | import org.opends.server.api.OrderingMatchingRule; |
| | | |
| | | import static org.opends.server.messages.CoreMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class defines a data structure that may be used as a sort key. |
| | | * It includes an attribute type and a boolean value that indicates |
| | | * whether the sort should be ascending or descending. It may also |
| | | * contain a specific ordering matching rule that should be used for |
| | | * the sorting process, although if none is provided it will use the |
| | | * default ordering matching rule for the attribute type. |
| | | */ |
| | | public class SortKey |
| | | { |
| | | // The attribute type for this sort key. |
| | | private AttributeType attributeType; |
| | | |
| | | // The indication of whether the sort should be ascending. |
| | | private boolean ascending; |
| | | |
| | | // The ordering matching rule to use with this sort key. |
| | | private OrderingMatchingRule orderingRule; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new sort key with the provided information. |
| | | * |
| | | * @param attributeType The attribute type for this sort key. |
| | | * @param ascending Indicates whether the sort should be in |
| | | * ascending order rather than descending. |
| | | */ |
| | | public SortKey(AttributeType attributeType, boolean ascending) |
| | | { |
| | | this.attributeType = attributeType; |
| | | this.ascending = ascending; |
| | | |
| | | orderingRule = null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new sort key with the provided information. |
| | | * |
| | | * @param attributeType The attribute type for this sort key. |
| | | * @param ascending Indicates whether the sort should be in |
| | | * ascending order rather than descending. |
| | | * @param orderingRule The ordering matching rule to use with |
| | | * this sort key. |
| | | */ |
| | | public SortKey(AttributeType attributeType, boolean ascending, |
| | | OrderingMatchingRule orderingRule) |
| | | { |
| | | this.attributeType = attributeType; |
| | | this.ascending = ascending; |
| | | this.orderingRule = orderingRule; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the attribute type for this sort key. |
| | | * |
| | | * @return The attribute type for this sort key. |
| | | */ |
| | | public AttributeType getAttributeType() |
| | | { |
| | | return attributeType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether the specified attribute should be sorted in |
| | | * ascending order. |
| | | * |
| | | * @return {@code true} if the attribute should be sorted in |
| | | * ascending order, or {@code false} if it should be sorted |
| | | * in descending order. |
| | | */ |
| | | public boolean ascending() |
| | | { |
| | | return ascending; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the ordering matching rule to use with this sort key. |
| | | * |
| | | * @return The ordering matching rule to use with this sort key. |
| | | */ |
| | | public OrderingMatchingRule getOrderingRule() |
| | | { |
| | | return orderingRule; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Compares the provided values using this sort key. |
| | | * |
| | | * @param value1 The first value to be compared. |
| | | * @param value2 The second value to be compared. |
| | | * |
| | | * @return A negative value if the first value should come before |
| | | * the second in a sorted list, a positive value if the |
| | | * first value should come after the second in a sorted |
| | | * list, or zero if there is no relative difference between |
| | | * the values. |
| | | */ |
| | | public int compareValues(AttributeValue value1, |
| | | AttributeValue value2) |
| | | { |
| | | // A null value will always come after a non-null value. |
| | | if (value1 == null) |
| | | { |
| | | if (value2 == null) |
| | | { |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | return 1; |
| | | } |
| | | } |
| | | else if (value2 == null) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | // Use the ordering matching rule if one is provided. Otherwise, |
| | | // fall back on the default ordering rule for the attribute type. |
| | | if (orderingRule == null) |
| | | { |
| | | try |
| | | { |
| | | OrderingMatchingRule rule = |
| | | attributeType.getOrderingMatchingRule(); |
| | | if (rule == null) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | if (ascending) |
| | | { |
| | | return rule.compareValues(value1.getNormalizedValue(), |
| | | value2.getNormalizedValue()); |
| | | } |
| | | else |
| | | { |
| | | return rule.compareValues(value2.getNormalizedValue(), |
| | | value1.getNormalizedValue()); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | if (ascending) |
| | | { |
| | | return orderingRule.compareValues( |
| | | orderingRule.normalizeValue(value1.getValue()), |
| | | orderingRule.normalizeValue(value2.getValue())); |
| | | } |
| | | else |
| | | { |
| | | return orderingRule.compareValues( |
| | | orderingRule.normalizeValue(value2.getValue()), |
| | | orderingRule.normalizeValue(value1.getValue())); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this sort key. |
| | | * |
| | | * @return A string representation of this sort key. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this sort key to the |
| | | * provided buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be |
| | | * appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("SortKey("); |
| | | if (ascending) |
| | | { |
| | | buffer.append("+"); |
| | | } |
| | | else |
| | | { |
| | | buffer.append("-"); |
| | | } |
| | | buffer.append(attributeType.getNameOrOID()); |
| | | |
| | | if (orderingRule != null) |
| | | { |
| | | buffer.append(":"); |
| | | buffer.append(orderingRule.getNameOrOID()); |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | |
| | | |
| | | import static org.opends.server.messages.CoreMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class defines a data structure that defines a set of sort |
| | | * criteria that may be used to order entries in a set of search |
| | | * results. The sort order object is comprised of one or more sort |
| | | * keys, which indicate which attribute types should be used to |
| | | * perform the sort and information about the ordering to use for |
| | | * those attributes. If the sort order has multiple sort keys, then |
| | | * the first sort key will be used as the primary sort criteria, and |
| | | * the second will only be used in cases where the values of the |
| | | * attribute associated with the first sort key are equal, the third |
| | | * will only be used if the first and second values are equal, etc. |
| | | * If all of the sort key attributes for two entries are identical, |
| | | * then the relative order for those entries is undefined. |
| | | */ |
| | | public class SortOrder |
| | | { |
| | | // The set of sort keys in this sort order. |
| | | private SortKey[] sortKeys; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new sort order with a single key. |
| | | * |
| | | * @param sortKey The sort key to use in this sort order. |
| | | */ |
| | | public SortOrder(SortKey sortKey) |
| | | { |
| | | this.sortKeys = new SortKey[] { sortKey }; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new sort order with the provided set of sort keys. |
| | | * |
| | | * @param sortKeys The set of sort keys to use for this sort |
| | | * order. |
| | | */ |
| | | public SortOrder(SortKey[] sortKeys) |
| | | { |
| | | this.sortKeys = new SortKey[sortKeys.length]; |
| | | System.arraycopy(sortKeys, 0, this.sortKeys, 0, sortKeys.length); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the sort keys for this sort order. |
| | | * |
| | | * @return The sort keys for this sort order. |
| | | */ |
| | | public SortKey[] getSortKeys() |
| | | { |
| | | return sortKeys; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this sort order. |
| | | * |
| | | * @return A string representation of this sort order. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this sort order to the |
| | | * provided buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be |
| | | * appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("SortOrder("); |
| | | |
| | | if (sortKeys.length > 0) |
| | | { |
| | | sortKeys[0].toString(buffer); |
| | | |
| | | for (int i=1; i < sortKeys.length; i++) |
| | | { |
| | | buffer.append(","); |
| | | sortKeys[i].toString(buffer); |
| | | } |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The OID for the server-side sort request control. |
| | | */ |
| | | public static final String OID_SERVER_SIDE_SORT_REQUEST_CONTROL = |
| | | "1.2.840.113556.1.4.473"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The OID for the server-side sort response control. |
| | | */ |
| | | public static final String OID_SERVER_SIDE_SORT_RESPONSE_CONTROL = |
| | | "1.2.840.113556.1.4.474"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The IANA-assigned OID for the feature allowing the use of LDAP true and |
| | | * false filters. |
| | | */ |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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 |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.controls; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.Control; |
| | | import org.opends.server.types.DereferencePolicy; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.ResultCode; |
| | | import org.opends.server.types.SearchFilter; |
| | | import org.opends.server.types.SearchScope; |
| | | import org.opends.server.types.SortKey; |
| | | import org.opends.server.types.SortOrder; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class contains a number of test cases for the server side sort request |
| | | * and response controls. |
| | | */ |
| | | public class ServerSideSortControlTestCase |
| | | extends ControlsTestCase |
| | | { |
| | | // The givenName attribute type. |
| | | private AttributeType givenNameType; |
| | | |
| | | // The sn attribute type. |
| | | private AttributeType snType; |
| | | |
| | | // The DN for "Aaccf Johnson" |
| | | DN aaccfJohnsonDN; |
| | | |
| | | // The DN for "Aaron Zimmerman" |
| | | DN aaronZimmermanDN; |
| | | |
| | | // The DN for "Albert Smith" |
| | | DN albertSmithDN; |
| | | |
| | | // The DN for "Albert Zimmerman" |
| | | DN albertZimmermanDN; |
| | | |
| | | // The DN for "lowercase mcgee" |
| | | DN lowercaseMcGeeDN; |
| | | |
| | | // The DN for "Mararet Jones" |
| | | DN margaretJonesDN; |
| | | |
| | | // The DN for "Mary Jones" |
| | | DN maryJonesDN; |
| | | |
| | | // The DN for "Sam Zweck" |
| | | DN samZweckDN; |
| | | |
| | | // The DN for "Zorro" |
| | | DN zorroDN; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Make sure that the server is running. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @BeforeClass() |
| | | public void startServer() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | givenNameType = DirectoryServer.getAttributeType("givenname", false); |
| | | assertNotNull(givenNameType); |
| | | |
| | | snType = DirectoryServer.getAttributeType("sn", false); |
| | | assertNotNull(snType); |
| | | |
| | | aaccfJohnsonDN = DN.decode("uid=aaccf.johnson,dc=example,dc=com"); |
| | | aaronZimmermanDN = DN.decode("uid=aaron.zimmerman,dc=example,dc=com"); |
| | | albertSmithDN = DN.decode("uid=albert.smith,dc=example,dc=com"); |
| | | albertZimmermanDN = DN.decode("uid=albert.zimmerman,dc=example,dc=com"); |
| | | lowercaseMcGeeDN = DN.decode("uid=lowercase.mcgee,dc=example,dc=com"); |
| | | margaretJonesDN = DN.decode("uid=margaret.jones,dc=example,dc=com"); |
| | | maryJonesDN = DN.decode("uid=mary.jones,dc=example,dc=com"); |
| | | samZweckDN = DN.decode("uid=sam.zweck,dc=example,dc=com"); |
| | | zorroDN = DN.decode("uid=zorro,dc=example,dc=com"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Populates the JE DB with a set of test data. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | private void populateDB() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman", |
| | | "", |
| | | "dn: uid=mary.jones,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: mary.jones", |
| | | "givenName: Mary", |
| | | "sn: Jones", |
| | | "cn: Mary Jones", |
| | | "", |
| | | "dn: uid=margaret.jones,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: margaret.jones", |
| | | "givenName: Margaret", |
| | | "givenName: Maggie", |
| | | "sn: Jones", |
| | | "sn: Smith", |
| | | "cn: Maggie Jones-Smith", |
| | | "", |
| | | "dn: uid=aaccf.johnson,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: aaccf.johnson", |
| | | "givenName: Aaccf", |
| | | "sn: Johnson", |
| | | "cn: Aaccf Johnson", |
| | | "", |
| | | "dn: uid=sam.zweck,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: sam.zweck", |
| | | "givenName: Sam", |
| | | "sn: Zweck", |
| | | "cn: Sam Zweck", |
| | | "", |
| | | "dn: uid=lowercase.mcgee,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: lowercase.mcgee", |
| | | "givenName: lowercase", |
| | | "sn: mcgee", |
| | | "cn: lowercase mcgee", |
| | | "", |
| | | "dn: uid=zorro,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: zorro", |
| | | "sn: Zorro", |
| | | "cn: Zorro" |
| | | ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the first constructor for the request control with different sort |
| | | * order values. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor1() |
| | | throws Exception |
| | | { |
| | | SortKey sortKey = new SortKey(givenNameType, true); |
| | | SortOrder sortOrder = new SortOrder(sortKey); |
| | | new ServerSideSortRequestControl(sortOrder).toString(); |
| | | sortKey.toString(); |
| | | sortOrder.toString(); |
| | | |
| | | sortKey = new SortKey(givenNameType, false); |
| | | sortOrder = new SortOrder(sortKey); |
| | | new ServerSideSortRequestControl(sortOrder).toString(); |
| | | sortKey.toString(); |
| | | sortOrder.toString(); |
| | | |
| | | SortKey[] sortKeys = |
| | | { |
| | | new SortKey(snType, true), |
| | | new SortKey(givenNameType, true) |
| | | }; |
| | | sortOrder = new SortOrder(sortKeys); |
| | | new ServerSideSortRequestControl(sortOrder).toString(); |
| | | sortOrder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the second constructor for the request control with different sort |
| | | * order strings. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor2() |
| | | throws Exception |
| | | { |
| | | new ServerSideSortRequestControl("givenName").toString(); |
| | | new ServerSideSortRequestControl("givenName:caseIgnoreOrderingMatch"). |
| | | toString(); |
| | | new ServerSideSortRequestControl("+givenName").toString(); |
| | | new ServerSideSortRequestControl("-givenName").toString(); |
| | | new ServerSideSortRequestControl("givenName,sn").toString(); |
| | | new ServerSideSortRequestControl("givenName,+sn").toString(); |
| | | new ServerSideSortRequestControl("givenName,-sn").toString(); |
| | | new ServerSideSortRequestControl("+givenName,sn").toString(); |
| | | new ServerSideSortRequestControl("+givenName,+sn").toString(); |
| | | new ServerSideSortRequestControl("+givenName,-sn").toString(); |
| | | new ServerSideSortRequestControl("-givenName").toString(); |
| | | new ServerSideSortRequestControl("-givenName,+sn").toString(); |
| | | new ServerSideSortRequestControl("-givenName,-sn").toString(); |
| | | new ServerSideSortRequestControl("-givenName,-sn:caseExactOrderingMatch"). |
| | | toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of ascending givenName values. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameAscending() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(aaronZimmermanDN); // Aaron |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of ascending givenName values using a specific |
| | | * ordering matching rule. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameAscendingCaseExact() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl( |
| | | "givenName:caseExactOrderingMatch")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(aaronZimmermanDN); // Aaron |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of descending givenName values. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameDescending() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("-givenName")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(aaronZimmermanDN); // Zeke |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(margaretJonesDN); // Margaret |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of descending givenName values using a specific |
| | | * ordering matching rule. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameDescendingCaseExact() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl( |
| | | "-givenName:caseExactOrderingMatch")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(aaronZimmermanDN); // Zeke |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(margaretJonesDN); // Margaret |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of ascending givenName and ascending sn values. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameAscendingSnAscending() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName,sn")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(aaronZimmermanDN); // Aaron |
| | | expectedDNOrder.add(albertSmithDN); // Albert, lower sn |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, higher sn |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control to |
| | | * sort the entries in order of ascending givenName and descending sn values. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchGivenNameAscendingSnDescending() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName,-sn")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); |
| | | expectedDNOrder.add(aaccfJohnsonDN); // Aaccf |
| | | expectedDNOrder.add(aaronZimmermanDN); // Aaron |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, higher sn |
| | | expectedDNOrder.add(albertSmithDN); // Albert, lower sn |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | expectedDNOrder.add(maryJonesDN); // Mary |
| | | expectedDNOrder.add(samZweckDN); // Sam |
| | | expectedDNOrder.add(zorroDN); // No first name |
| | | |
| | | ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); |
| | | for (Entry e : internalSearch.getSearchEntries()) |
| | | { |
| | | returnedDNOrder.add(e.getDN()); |
| | | } |
| | | |
| | | assertEquals(returnedDNOrder, expectedDNOrder); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | assertEquals(responseControls.size(), 1); |
| | | |
| | | ServerSideSortResponseControl responseControl = |
| | | ServerSideSortResponseControl.decodeControl(responseControls.get(0)); |
| | | assertEquals(responseControl.getResultCode(), 0); |
| | | assertNull(responseControl.getAttributeType()); |
| | | responseControl.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control with |
| | | * an undefined attribute type. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchUndefinedAttribute() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("undefined")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertFalse(internalSearch.getResultCode() == ResultCode.SUCCESS); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the server-side sort control with |
| | | * an undefined ordering rule. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchUndefinedOrderingRule() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl( |
| | | "givenName:undefinedOrderingMatch")); |
| | | |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), requestControls, |
| | | DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=person)"), |
| | | null, null); |
| | | internalSearch.run(); |
| | | assertFalse(internalSearch.getResultCode() == ResultCode.SUCCESS); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of both the server-side sort control and the simple paged |
| | | * results control. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortWithPagedResults() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman", |
| | | "", |
| | | "dn: uid=mary.jones,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: mary.jones", |
| | | "givenName: Mary", |
| | | "sn: Jones", |
| | | "cn: Mary Jones", |
| | | "", |
| | | "dn: uid=margaret.jones,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: margaret.jones", |
| | | "givenName: Margaret", |
| | | "givenName: Maggie", |
| | | "sn: Jones", |
| | | "sn: Smith", |
| | | "cn: Maggie Jones-Smith", |
| | | "", |
| | | "dn: uid=aaccf.johnson,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: aaccf.johnson", |
| | | "givenName: Aaccf", |
| | | "sn: Johnson", |
| | | "cn: Aaccf Johnson", |
| | | "", |
| | | "dn: uid=sam.zweck,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: sam.zweck", |
| | | "givenName: Sam", |
| | | "sn: Zweck", |
| | | "cn: Sam Zweck", |
| | | "", |
| | | "dn: uid=lowercase.mcgee,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: lowercase.mcgee", |
| | | "givenName: lowercase", |
| | | "sn: mcgee", |
| | | "cn: lowercase mcgee", |
| | | "", |
| | | "dn: uid=zorro,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: zorro", |
| | | "sn: Zorro", |
| | | "cn: Zorro"); |
| | | |
| | | String[] pagedArgs = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "givenName", |
| | | "--simplePageSize", "2", |
| | | "--countEntries", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | String[] unpagedArgs = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "givenName", |
| | | "--countEntries", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(pagedArgs, false, null, System.err), |
| | | LDAPSearch.mainSearch(unpagedArgs, false, null, System.err)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with valid sort criteria. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortValidGivenNameAscending() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "givenName", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with valid sort criteria. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortValidGivenNameDescending() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "-givenName", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with valid sort criteria. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortValidGivenNameAscendingCaseExactOrderingMatch() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "givenName:caseExactOrderingMatch", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with valid sort criteria. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortValidSnAscendingGivenNameAscending() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "sn,givenName", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with valid sort criteria. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortValidSnAscendingGivenNameDescending() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: uid=albert.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Albert", |
| | | "sn: Zimmerman", |
| | | "cn: Albert Zimmerman", |
| | | "", |
| | | "dn: uid=albert.smith,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.smith", |
| | | "givenName: Albert", |
| | | "sn: Smith", |
| | | "cn: Albert Smith", |
| | | "", |
| | | "dn: uid=aaron.zimmerman,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: albert.zimmerman", |
| | | "givenName: Aaron", |
| | | "givenName: Zeke", |
| | | "sn: Zimmerman", |
| | | "cn: Aaron Zimmerman"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "sn,-givenName", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with an empty sort order. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortEmptySortOrder() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with a sort order containing |
| | | * a key with no attribute type. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortSortOrderMissingType() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "-,sn", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with a sort order containing |
| | | * a key with a colon but no matching rule. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortSortOrderMissingMatchingRule() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "-sn:", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with an undefined attribute. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortUndefinedAttribute() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "undefined", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with an undefined ordering |
| | | * rule. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortUndefinedOrderingRule() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-b", "dc=example,dc=com", |
| | | "-s", "sub", |
| | | "-S", "givenName:undefined", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the LDAPSearch tool with the "--help" option. |
| | | */ |
| | | @Test() |