Implement support for the virtual list view (VLV) control as defined in
draft-ietf-ldapext-ldapv3-vlv. This can be used to retrieve a specified page
of a search result set. Any result set that can be used with server-side
sorting can also be used with VLV. The ldapsearch tool has also been updated
to support this control.
OpenDS Issue Number: 80
3 files added
13 files modified
| | |
| | | supportedControls.add(OID_PAGED_RESULTS_CONTROL); |
| | | supportedControls.add(OID_MANAGE_DSAIT_CONTROL); |
| | | supportedControls.add(OID_SERVER_SIDE_SORT_REQUEST_CONTROL); |
| | | supportedControls.add(OID_VLV_REQUEST_CONTROL); |
| | | } |
| | | |
| | | |
| | |
| | | import org.opends.server.controls.PagedResultsControl; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.controls.ServerSideSortResponseControl; |
| | | import org.opends.server.controls.VLVRequestControl; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | |
| | | List<Control> controls = searchOperation.getRequestControls(); |
| | | PagedResultsControl pageRequest = null; |
| | | ServerSideSortRequestControl sortRequest = null; |
| | | VLVRequestControl vlvRequest = null; |
| | | if (controls != null) |
| | | { |
| | | for (Control control : controls) |
| | |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessage(), e.getMessageID(), e); |
| | | } |
| | | |
| | | if (vlvRequest != null) |
| | | { |
| | | int msgID = MSGID_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | else if (control.getOID().equals(OID_SERVER_SIDE_SORT_REQUEST_CONTROL)) |
| | |
| | | } |
| | | } |
| | | } |
| | | else if (control.getOID().equals(OID_VLV_REQUEST_CONTROL)) |
| | | { |
| | | // Ignore all but the first VLV request control. |
| | | if (vlvRequest == null) |
| | | { |
| | | try |
| | | { |
| | | vlvRequest = VLVRequestControl.decodeControl(control); |
| | | } |
| | | catch (LDAPException e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | throw new DirectoryException(ResultCode.PROTOCOL_ERROR, |
| | | e.getMessage(), e.getMessageID(), e); |
| | | } |
| | | |
| | | if (pageRequest != null) |
| | | { |
| | | int msgID = MSGID_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | entryIDList = EntryIDSetSorter.sort(this, entryIDList, |
| | | searchOperation, |
| | | sortRequest.getSortOrder()); |
| | | sortRequest.getSortOrder(), |
| | | vlvRequest); |
| | | searchOperation.addResponseControl( |
| | | new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null)); |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import java.util.Map; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | import java.util.TreeMap; |
| | | |
| | | import org.opends.server.controls.VLVRequestControl; |
| | | import org.opends.server.controls.VLVResponseControl; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.types.AttributeValue; |
| | | 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.SortOrder; |
| | |
| | | * @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. |
| | | * @param vlvRequest The VLV request control included in the search |
| | | * request, or {@code null} if there was none. |
| | | * |
| | | * @return A new entry ID set which is a sorted representation of the |
| | | * provided set using the given sort order. |
| | |
| | | public static EntryIDSet sort(EntryContainer entryContainer, |
| | | EntryIDSet entryIDSet, |
| | | SearchOperation searchOperation, |
| | | SortOrder sortOrder) |
| | | SortOrder sortOrder, |
| | | VLVRequestControl vlvRequest) |
| | | throws DirectoryException |
| | | { |
| | | if (! entryIDSet.isDefined()) |
| | |
| | | } |
| | | } |
| | | |
| | | long[] sortedIDs = new long[sortMap.size()]; |
| | | int i=0; |
| | | for (EntryID id : sortMap.values()) |
| | | |
| | | // See if there is a VLV request to further pare down the set of results, |
| | | // and if there is where it should be processed by offset or assertion |
| | | // value. |
| | | long[] sortedIDs; |
| | | if (vlvRequest != null) |
| | | { |
| | | sortedIDs[i++] = id.longValue(); |
| | | int beforeCount = vlvRequest.getBeforeCount(); |
| | | int afterCount = vlvRequest.getAfterCount(); |
| | | |
| | | if (vlvRequest.getTargetType() == VLVRequestControl.TYPE_TARGET_BYOFFSET) |
| | | { |
| | | int targetOffset = vlvRequest.getOffset(); |
| | | int listOffset = targetOffset - 1; // VLV offsets start at 1, not 0. |
| | | int startPos = listOffset - beforeCount; |
| | | if (startPos < 0) |
| | | { |
| | | searchOperation.addResponseControl( |
| | | new VLVResponseControl(targetOffset, sortMap.size(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR)); |
| | | |
| | | int msgID = MSGID_ENTRYIDSORTER_NEGATIVE_START_POS; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException(ResultCode.VIRTUAL_LIST_VIEW_ERROR, |
| | | message, msgID); |
| | | } |
| | | else if (startPos >= sortMap.size()) |
| | | { |
| | | searchOperation.addResponseControl( |
| | | new VLVResponseControl(targetOffset, sortMap.size(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR)); |
| | | |
| | | int msgID = MSGID_ENTRYIDSORTER_OFFSET_TOO_LARGE; |
| | | String message = getMessage(msgID, vlvRequest.getOffset(), |
| | | sortMap.size()); |
| | | throw new DirectoryException(ResultCode.VIRTUAL_LIST_VIEW_ERROR, |
| | | message, msgID); |
| | | } |
| | | |
| | | int count = 1 + beforeCount + afterCount; |
| | | sortedIDs = new long[count]; |
| | | |
| | | int treePos = 0; |
| | | int arrayPos = 0; |
| | | Iterator<EntryID> idIterator = sortMap.values().iterator(); |
| | | while (idIterator.hasNext()) |
| | | { |
| | | EntryID id = idIterator.next(); |
| | | if (treePos++ < startPos) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | sortedIDs[arrayPos++] = id.longValue(); |
| | | if (arrayPos >= count) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (arrayPos < count) |
| | | { |
| | | // We don't have enough entries in the set to meet the requested |
| | | // page size, so we'll need to shorten the array. |
| | | long[] newIDArray = new long[arrayPos]; |
| | | System.arraycopy(sortedIDs, 0, newIDArray, 0, arrayPos); |
| | | sortedIDs = newIDArray; |
| | | } |
| | | |
| | | searchOperation.addResponseControl( |
| | | new VLVResponseControl(targetOffset, sortMap.size(), |
| | | LDAPResultCode.SUCCESS)); |
| | | } |
| | | else |
| | | { |
| | | AttributeValue assertionValue = new |
| | | AttributeValue(sortOrder.getSortKeys()[0].getAttributeType(), |
| | | vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | |
| | | boolean targetFound = false; |
| | | int targetOffset = 0; |
| | | int includedBeforeCount = 0; |
| | | int includedAfterCount = 0; |
| | | int listSize = 0; |
| | | LinkedList<EntryID> idList = new LinkedList<EntryID>(); |
| | | Iterator<Map.Entry<SortValues,EntryID>> mapIterator = |
| | | sortMap.entrySet().iterator(); |
| | | while (mapIterator.hasNext()) |
| | | { |
| | | Map.Entry<SortValues,EntryID> entry = mapIterator.next(); |
| | | SortValues sortValues = entry.getKey(); |
| | | EntryID id = entry.getValue(); |
| | | |
| | | if (targetFound) |
| | | { |
| | | idList.add(id); |
| | | listSize++; |
| | | includedAfterCount++; |
| | | if (includedAfterCount >= afterCount) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | targetFound = (sortValues.compareTo(assertionValue) >= 0); |
| | | targetOffset++; |
| | | |
| | | if (targetFound) |
| | | { |
| | | idList.add(id); |
| | | listSize++; |
| | | } |
| | | else if (beforeCount > 0) |
| | | { |
| | | if (beforeCount > 0) |
| | | { |
| | | idList.add(id); |
| | | includedBeforeCount++; |
| | | if (includedBeforeCount > beforeCount) |
| | | { |
| | | idList.removeFirst(); |
| | | includedBeforeCount--; |
| | | } |
| | | else |
| | | { |
| | | listSize++; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (! targetFound) |
| | | { |
| | | searchOperation.addResponseControl( |
| | | new VLVResponseControl(sortMap.size(), sortMap.size(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR)); |
| | | |
| | | int msgID = MSGID_ENTRYIDSORTER_TARGET_VALUE_NOT_FOUND; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException(ResultCode.VIRTUAL_LIST_VIEW_ERROR, |
| | | message, msgID); |
| | | } |
| | | |
| | | sortedIDs = new long[listSize]; |
| | | Iterator<EntryID> idIterator = idList.iterator(); |
| | | for (int i=0; i < listSize; i++) |
| | | { |
| | | sortedIDs[i] = idIterator.next().longValue(); |
| | | } |
| | | |
| | | searchOperation.addResponseControl( |
| | | new VLVResponseControl(targetOffset, sortMap.size(), |
| | | LDAPResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | sortedIDs = new long[sortMap.size()]; |
| | | int i=0; |
| | | for (EntryID id : sortMap.values()) |
| | | { |
| | | sortedIDs[i++] = id.longValue(); |
| | | } |
| | | } |
| | | |
| | | return new EntryIDSet(sortedIDs, 0, sortedIDs.length); |
| | |
| | | |
| | | |
| | | /** |
| | | * Compares the first element in this set of sort values with the provided |
| | | * assertion value to determine whether the assertion value is greater than or |
| | | * equal to the initial sort value. This is used during VLV processing to |
| | | * find the offset by assertion value. |
| | | * |
| | | * @param assertionValue The assertion value to compare against the first |
| | | * sort value. |
| | | * |
| | | * @return A negative value if the provided assertion value should come |
| | | * before the first sort value, zero if the provided assertion value |
| | | * is equal to the first sort value, or a positive value if the |
| | | * provided assertion value should come after the first sort value. |
| | | */ |
| | | public int compareTo(AttributeValue assertionValue) |
| | | { |
| | | SortKey sortKey = sortOrder.getSortKeys()[0]; |
| | | return sortKey.compareValues(values[0], assertionValue); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this sort values object. |
| | | * |
| | | * @return A string representation of this sort values object. |
| | |
| | | { |
| | | if (i > 0) |
| | | { |
| | | buffer.append(", "); |
| | | buffer.append(","); |
| | | } |
| | | |
| | | if (sortKeys[i].ascending()) |
| | |
| | | |
| | | buffer.append(sortKeys[i].getAttributeType().getNameOrOID()); |
| | | buffer.append("="); |
| | | buffer.append(values[i].getStringValue()); |
| | | if (values[i] == null) |
| | | { |
| | | buffer.append("null"); |
| | | } |
| | | else |
| | | { |
| | | buffer.append(values[i].getStringValue()); |
| | | } |
| | | } |
| | | |
| | | buffer.append(", id="); |
| | | buffer.append(entryID.toString()); |
| | | 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.ASN1Integer; |
| | | 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.ByteString; |
| | | 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 virtual list view request controls as defined in |
| | | * draft-ietf-ldapext-ldapv3-vlv. The ASN.1 description for the control value |
| | | * is: |
| | | * <BR><BR> |
| | | * <PRE> |
| | | * VirtualListViewRequest ::= SEQUENCE { |
| | | * beforeCount INTEGER (0..maxInt), |
| | | * afterCount INTEGER (0..maxInt), |
| | | * target CHOICE { |
| | | * byOffset [0] SEQUENCE { |
| | | * offset INTEGER (1 .. maxInt), |
| | | * contentCount INTEGER (0 .. maxInt) }, |
| | | * greaterThanOrEqual [1] AssertionValue }, |
| | | * contextID OCTET STRING OPTIONAL } |
| | | * </PRE> |
| | | */ |
| | | public class VLVRequestControl |
| | | extends Control |
| | | { |
| | | /** |
| | | * The BER type to use when encoding the byOffset target element. |
| | | */ |
| | | public static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The BER type to use when encoding the greaterThanOrEqual target element. |
| | | */ |
| | | public static final byte TYPE_TARGET_GREATERTHANOREQUAL = (byte) 0x81; |
| | | |
| | | |
| | | |
| | | // The target type for this VLV request control. |
| | | private byte targetType; |
| | | |
| | | // The context ID for this VLV request control. |
| | | private ByteString contextID; |
| | | |
| | | // The greaterThanOrEqual target assertion value for this VLV request control. |
| | | private ByteString greaterThanOrEqual; |
| | | |
| | | // The after count for this VLV request control. |
| | | private int afterCount; |
| | | |
| | | // The before count for this VLV request control. |
| | | private int beforeCount; |
| | | |
| | | // The content count for the byOffset target of this VLV request control. |
| | | private int contentCount; |
| | | |
| | | // The offset for the byOffset target of this VLV request control. |
| | | private int offset; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control with the provided information. |
| | | * |
| | | * @param beforeCount The number of entries before the target offset to |
| | | * retrieve in the results page. |
| | | * @param afterCount The number of entries after the target offset to |
| | | * retrieve in the results page. |
| | | * @param offset The offset in the result set to target for the |
| | | * beginning of the page of results. |
| | | * @param contentCount The content count returned by the server in the last |
| | | * phase of the VLV request, or zero for a new VLV |
| | | * request session. |
| | | */ |
| | | public VLVRequestControl(int beforeCount, int afterCount, int offset, |
| | | int contentCount) |
| | | { |
| | | this(beforeCount, afterCount, offset, contentCount, null); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control with the provided information. |
| | | * |
| | | * @param beforeCount The number of entries before the target offset to |
| | | * retrieve in the results page. |
| | | * @param afterCount The number of entries after the target offset to |
| | | * retrieve in the results page. |
| | | * @param offset The offset in the result set to target for the |
| | | * beginning of the page of results. |
| | | * @param contentCount The content count returned by the server in the last |
| | | * phase of the VLV request, or zero for a new VLV |
| | | * request session. |
| | | * @param contextID The context ID provided by the server in the last |
| | | * VLV response for the same set of criteria, or |
| | | * {@code null} if there was no previous VLV response or |
| | | * the server did not include a context ID in the |
| | | * last response. |
| | | */ |
| | | public VLVRequestControl(int beforeCount, int afterCount, int offset, |
| | | int contentCount, ByteString contextID) |
| | | { |
| | | super(OID_VLV_REQUEST_CONTROL, false, |
| | | encodeControlValue(beforeCount, afterCount, offset, contentCount, |
| | | contextID)); |
| | | |
| | | this.beforeCount = beforeCount; |
| | | this.afterCount = afterCount; |
| | | this.offset = offset; |
| | | this.contentCount = contentCount; |
| | | this.contextID = contextID; |
| | | |
| | | targetType = TYPE_TARGET_BYOFFSET; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control with the provided information. |
| | | * |
| | | * @param beforeCount The number of entries before the target offset |
| | | * to retrieve in the results page. |
| | | * @param afterCount The number of entries after the target offset |
| | | * to retrieve in the results page. |
| | | * @param greaterThanOrEqual The greaterThanOrEqual target assertion value |
| | | * that indicates where to start the page of |
| | | * results. |
| | | */ |
| | | public VLVRequestControl(int beforeCount, int afterCount, |
| | | ByteString greaterThanOrEqual) |
| | | { |
| | | this(beforeCount, afterCount, greaterThanOrEqual, null); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control with the provided information. |
| | | * |
| | | * @param beforeCount The number of entries before the target |
| | | * assertion value. |
| | | * @param afterCount The number of entries after the target |
| | | * assertion value. |
| | | * @param greaterThanOrEqual The greaterThanOrEqual target assertion value |
| | | * that indicates where to start the page of |
| | | * results. |
| | | * @param contextID The context ID provided by the server in the |
| | | * last VLV response for the same set of criteria, |
| | | * or {@code null} if there was no previous VLV |
| | | * response or the server did not include a |
| | | * context ID in the last response. |
| | | */ |
| | | public VLVRequestControl(int beforeCount, int afterCount, |
| | | ByteString greaterThanOrEqual, |
| | | ByteString contextID) |
| | | { |
| | | super(OID_VLV_REQUEST_CONTROL, false, |
| | | encodeControlValue(beforeCount, afterCount, greaterThanOrEqual, |
| | | contextID)); |
| | | |
| | | this.beforeCount = beforeCount; |
| | | this.afterCount = afterCount; |
| | | this.greaterThanOrEqual = greaterThanOrEqual; |
| | | this.contextID = contextID; |
| | | |
| | | targetType = TYPE_TARGET_GREATERTHANOREQUAL; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control with the provided information. |
| | | * |
| | | * @param oid The OID for the control. |
| | | * @param isCritical Indicates whether the control should be |
| | | * considered critical. |
| | | * @param controlValue The pre-encoded value for the control. |
| | | * @param beforeCount The number of entries before the target |
| | | * assertion value. |
| | | * @param afterCount The number of entries after the target |
| | | * assertion value. |
| | | * @param greaterThanOrEqual The greaterThanOrEqual target assertion value |
| | | * that indicates where to start the page of |
| | | * results. |
| | | * @param contextID The context ID provided by the server in the |
| | | * last VLV response for the same set of criteria, |
| | | * or {@code null} if there was no previous VLV |
| | | * response or the server did not include a |
| | | * context ID in the last response. |
| | | */ |
| | | private VLVRequestControl(String oid, boolean isCritical, |
| | | ASN1OctetString controlValue, int beforeCount, |
| | | int afterCount, byte targetType, |
| | | int offset, int contentCount, |
| | | ByteString greaterThanOrEqual, |
| | | ByteString contextID) |
| | | { |
| | | super(oid, isCritical, controlValue); |
| | | |
| | | this.beforeCount = beforeCount; |
| | | this.afterCount = afterCount; |
| | | this.targetType = targetType; |
| | | this.offset = offset; |
| | | this.contentCount = contentCount; |
| | | this.greaterThanOrEqual = greaterThanOrEqual; |
| | | this.contextID = contextID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the number of entries before the target offset or assertion value |
| | | * to include in the results page. |
| | | * |
| | | * @return The number of entries before the target offset to include in the |
| | | * results page. |
| | | */ |
| | | public int getBeforeCount() |
| | | { |
| | | return beforeCount; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the number of entries after the target offset or assertion value |
| | | * to include in the results page. |
| | | * |
| | | * @return The number of entries after the target offset to include in the |
| | | * results page. |
| | | */ |
| | | public int getAfterCount() |
| | | { |
| | | return afterCount; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the BER type for the target that specifies the beginning of the |
| | | * results page. |
| | | * |
| | | * @return {@code TYPE_TARGET_BYOFFSET} if the beginning of the results page |
| | | * should be specified as a nuemric offset, or |
| | | * {@code TYPE_TARGET_GREATERTHANOREQUAL} if it should be specified |
| | | * by an assertion value. |
| | | */ |
| | | public byte getTargetType() |
| | | { |
| | | return targetType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the offset that indicates the beginning of the results page. The |
| | | * return value will only be applicable if the {@code getTargetType} method |
| | | * returns {@code TYPE_TARGET_BYOFFSET}. |
| | | * |
| | | * @return The offset that indicates the beginning of the results page. |
| | | */ |
| | | public int getOffset() |
| | | { |
| | | return offset; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the content count indicating the estimated number of entries in |
| | | * the complete result set. The return value will only be applicable if the |
| | | * {@code getTargetType} method returns {@code TYPE_TARGET_BYOFFSET}. |
| | | * |
| | | * @return The content count indicating the estimated number of entries in |
| | | * the complete result set. |
| | | */ |
| | | public int getContentCount() |
| | | { |
| | | return contentCount; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the assertion value that will be used to locate the beginning of |
| | | * the results page. This will only be applicable if the |
| | | * {@code getTargetType} method returns |
| | | * {@code TYPE_TARGET_GREATERTHANOREQUAL}. |
| | | * |
| | | * @return The assertion value that will be used to locate the beginning of |
| | | * the results page, or {@code null} if the beginning of the results |
| | | * page is to be specified using an offset. |
| | | */ |
| | | public ByteString getGreaterThanOrEqualAssertion() |
| | | { |
| | | return greaterThanOrEqual; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a context ID value that should be used to resume a previous VLV |
| | | * results session. |
| | | * |
| | | * @return A context ID value that should be used to resume a previous VLV |
| | | * results session, or {@code null} if none is available. |
| | | */ |
| | | public ByteString getContextID() |
| | | { |
| | | return contextID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided information in a manner suitable for use as the value |
| | | * of this control. |
| | | * |
| | | * @param beforeCount The number of entries before the target offset to |
| | | * retrieve in the results page. |
| | | * @param afterCount The number of entries after the target offset to |
| | | * retrieve in the results page. |
| | | * @param offset The offset in the result set to target for the |
| | | * beginning of the page of results. |
| | | * @param contentCount The content count returned by the server in the last |
| | | * phase of the VLV request, or zero for a new VLV |
| | | * request session. |
| | | * @param contextID The context ID provided by the server in the last |
| | | * VLV response for the same set of criteria, or |
| | | * {@code null} if there was no previous VLV response or |
| | | * the server did not include a context ID in the |
| | | * last response. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort order. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(int beforeCount, |
| | | int afterCount, int offset, |
| | | int contentCount, ByteString contextID) |
| | | { |
| | | ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4); |
| | | vlvElements.add(new ASN1Integer(beforeCount)); |
| | | vlvElements.add(new ASN1Integer(afterCount)); |
| | | |
| | | ArrayList<ASN1Element> targetElements = new ArrayList<ASN1Element>(2); |
| | | targetElements.add(new ASN1Integer(offset)); |
| | | targetElements.add(new ASN1Integer(contentCount)); |
| | | vlvElements.add(new ASN1Sequence(TYPE_TARGET_BYOFFSET, targetElements)); |
| | | |
| | | if (contextID != null) |
| | | { |
| | | vlvElements.add(contextID.toASN1OctetString()); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(vlvElements).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided information in a manner suitable for use as the value |
| | | * of this control. |
| | | * |
| | | * @param beforeCount The number of entries before the target |
| | | * assertion value. |
| | | * @param afterCount The number of entries after the target |
| | | * assertion value. |
| | | * @param greaterThanOrEqual The greaterThanOrEqual target assertion value |
| | | * that indicates where to start the page of |
| | | * results. |
| | | * @param contextID The context ID provided by the server in the |
| | | * last VLV response for the same set of criteria, |
| | | * or {@code null} if there was no previous VLV |
| | | * response or the server did not include a |
| | | * context ID in the last response. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort order. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(int beforeCount, |
| | | int afterCount, |
| | | ByteString greaterThanOrEqual, |
| | | ByteString contextID) |
| | | { |
| | | ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4); |
| | | vlvElements.add(new ASN1Integer(beforeCount)); |
| | | vlvElements.add(new ASN1Integer(afterCount)); |
| | | |
| | | vlvElements.add(new ASN1OctetString(TYPE_TARGET_GREATERTHANOREQUAL, |
| | | greaterThanOrEqual.value())); |
| | | |
| | | if (contextID != null) |
| | | { |
| | | vlvElements.add(contextID.toASN1OctetString()); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(vlvElements).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV request control from the contents of the provided |
| | | * control. |
| | | * |
| | | * @param control The generic control containing the information to use to |
| | | * create this VLV request control. It must not be |
| | | * {@code null}. |
| | | * |
| | | * @return The VLV request control decoded from the provided control. |
| | | * |
| | | * @throws LDAPException If this control cannot be decoded as a valid VLV |
| | | * request control. |
| | | */ |
| | | public static VLVRequestControl decodeControl(Control control) |
| | | throws LDAPException |
| | | { |
| | | ASN1OctetString controlValue = control.getValue(); |
| | | if (controlValue == null) |
| | | { |
| | | int msgID = MSGID_VLVREQ_CONTROL_NO_VALUE; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | try |
| | | { |
| | | ASN1Sequence vlvSequence = |
| | | ASN1Sequence.decodeAsSequence(controlValue.value()); |
| | | ArrayList<ASN1Element> elements = vlvSequence.elements(); |
| | | |
| | | if ((elements.size() < 3) || (elements.size() > 4)) |
| | | { |
| | | int msgID = MSGID_VLVREQ_CONTROL_INVALID_ELEMENT_COUNT; |
| | | String message = getMessage(msgID, elements.size()); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | int beforeCount = elements.get(0).decodeAsInteger().intValue(); |
| | | int afterCount = elements.get(1).decodeAsInteger().intValue(); |
| | | |
| | | ASN1Element targetElement = elements.get(2); |
| | | int offset = 0; |
| | | int contentCount = 0; |
| | | ASN1OctetString greaterThanOrEqual = null; |
| | | byte targetType = targetElement.getType(); |
| | | switch (targetType) |
| | | { |
| | | case TYPE_TARGET_BYOFFSET: |
| | | ArrayList<ASN1Element> targetElements = |
| | | targetElement.decodeAsSequence().elements(); |
| | | offset = targetElements.get(0).decodeAsInteger().intValue(); |
| | | contentCount = targetElements.get(1).decodeAsInteger().intValue(); |
| | | break; |
| | | |
| | | case TYPE_TARGET_GREATERTHANOREQUAL: |
| | | greaterThanOrEqual = targetElement.decodeAsOctetString(); |
| | | break; |
| | | |
| | | default: |
| | | int msgID = MSGID_VLVREQ_CONTROL_INVALID_TARGET_TYPE; |
| | | String message = getMessage(msgID, byteToHex(targetType)); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, |
| | | message); |
| | | } |
| | | |
| | | ASN1OctetString contextID = null; |
| | | if (elements.size() == 4) |
| | | { |
| | | contextID = elements.get(3).decodeAsOctetString(); |
| | | } |
| | | |
| | | return new VLVRequestControl(control.getOID(), control.isCritical(), |
| | | controlValue, beforeCount, afterCount, |
| | | targetType, offset, contentCount, |
| | | greaterThanOrEqual, contextID); |
| | | } |
| | | catch (LDAPException le) |
| | | { |
| | | throw le; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_VLVREQ_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 VLV request control. |
| | | * |
| | | * @return A string representation of this VLV request control. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this VLV request control to the provided |
| | | * buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("VLVRequestControl(beforeCount="); |
| | | buffer.append(beforeCount); |
| | | buffer.append(", afterCount="); |
| | | buffer.append(afterCount); |
| | | |
| | | if (targetType == TYPE_TARGET_BYOFFSET) |
| | | { |
| | | buffer.append(", offset="); |
| | | buffer.append(offset); |
| | | buffer.append(", contentCount="); |
| | | buffer.append(contentCount); |
| | | } |
| | | else |
| | | { |
| | | buffer.append(", greaterThanOrEqual="); |
| | | buffer.append(greaterThanOrEqual); |
| | | } |
| | | |
| | | if (contextID != null) |
| | | { |
| | | buffer.append(", contextID="); |
| | | buffer.append(contextID); |
| | | } |
| | | |
| | | 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.ASN1Integer; |
| | | 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.ByteString; |
| | | 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 virtual list view response controls as defined in |
| | | * draft-ietf-ldapext-ldapv3-vlv. The ASN.1 description for the control value |
| | | * is: |
| | | * <BR><BR> |
| | | * <PRE> |
| | | * VirtualListViewResponse ::= SEQUENCE { |
| | | * targetPosition INTEGER (0 .. maxInt), |
| | | * contentCount INTEGER (0 .. maxInt), |
| | | * virtualListViewResult ENUMERATED { |
| | | * success (0), |
| | | * operationsError (1), |
| | | * protocolError (3), |
| | | * unwillingToPerform (53), |
| | | * insufficientAccessRights (50), |
| | | * timeLimitExceeded (3), |
| | | * adminLimitExceeded (11), |
| | | * innapropriateMatching (18), |
| | | * sortControlMissing (60), |
| | | * offsetRangeError (61), |
| | | * other(80), |
| | | * ... }, |
| | | * contextID OCTET STRING OPTIONAL } |
| | | * </PRE> |
| | | */ |
| | | public class VLVResponseControl |
| | | extends Control |
| | | { |
| | | // The context ID for this VLV response control. |
| | | private ByteString contextID; |
| | | |
| | | // The content count estimating the total number of entries in the result set. |
| | | private int contentCount; |
| | | |
| | | // The offset of the target entry in the result set. |
| | | private int targetPosition; |
| | | |
| | | // The result code for the VLV operation. |
| | | private int vlvResultCode; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV response control with the provided information. |
| | | * |
| | | * @param targetPosition The position of the target entry in the result set. |
| | | * @param contentCount The content count estimating the total number of |
| | | * entries in the result set. |
| | | * @param vlvResultCode The result code for the VLV operation. |
| | | */ |
| | | public VLVResponseControl(int targetPosition, int contentCount, |
| | | int vlvResultCode) |
| | | { |
| | | this(targetPosition, contentCount, vlvResultCode, null); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV response control with the provided information. |
| | | * |
| | | * @param targetPosition The position of the target entry in the result set. |
| | | * @param contentCount The content count estimating the total number of |
| | | * entries in the result set. |
| | | * @param vlvResultCode The result code for the VLV operation. |
| | | * @param contextID The context ID for this VLV response control. |
| | | */ |
| | | public VLVResponseControl(int targetPosition, int contentCount, |
| | | int vlvResultCode, ByteString contextID) |
| | | { |
| | | super(OID_VLV_RESPONSE_CONTROL, false, |
| | | encodeControlValue(targetPosition, contentCount, vlvResultCode, |
| | | contextID)); |
| | | |
| | | this.targetPosition = targetPosition; |
| | | this.contentCount = contentCount; |
| | | this.vlvResultCode = vlvResultCode; |
| | | this.contextID = contextID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV response control with the provided information. |
| | | * |
| | | * @param oid The OID for the control. |
| | | * @param isCritical Indicates whether the control should be considered |
| | | * critical. |
| | | * @param controlValue The pre-encoded value for the control. |
| | | * @param targetPosition The position of the target entry in the result set. |
| | | * @param contentCount The content count estimating the total number of |
| | | * entries in the result set. |
| | | * @param vlvResultCode The result code for the VLV operation. |
| | | * @param contextID The context ID for this VLV response control. |
| | | */ |
| | | private VLVResponseControl(String oid, boolean isCritical, |
| | | ASN1OctetString controlValue, int targetPosition, |
| | | int contentCount, int vlvResultCode, |
| | | ByteString contextID) |
| | | { |
| | | super(oid, isCritical, controlValue); |
| | | |
| | | this.targetPosition = targetPosition; |
| | | this.contentCount = contentCount; |
| | | this.vlvResultCode = vlvResultCode; |
| | | this.contextID = contextID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the position of the target entry in the result set. |
| | | * |
| | | * @return The position of the target entry in the result set. |
| | | */ |
| | | public int getTargetPosition() |
| | | { |
| | | return targetPosition; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the estimated total number of entries in the result set. |
| | | * |
| | | * @return The estimated total number of entries in the result set. |
| | | */ |
| | | public int getContentCount() |
| | | { |
| | | return contentCount; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the result code for the VLV operation. |
| | | * |
| | | * @return The result code for the VLV operation. |
| | | */ |
| | | public int getVLVResultCode() |
| | | { |
| | | return vlvResultCode; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves a context ID value that should be included in the next request |
| | | * to retrieve a page of the same result set. |
| | | * |
| | | * @return A context ID value that should be included in the next request to |
| | | * retrieve a page of the same result set, or {@code null} if there |
| | | * is no context ID. |
| | | */ |
| | | public ByteString getContextID() |
| | | { |
| | | return contextID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided information in a manner suitable for use as the value |
| | | * of this control. |
| | | * |
| | | * @param targetPosition The position of the target entry in the result set. |
| | | * @param contentCount The content count estimating the total number of |
| | | * entries in the result set. |
| | | * @param vlvResultCode The result code for the VLV operation. |
| | | * @param contextID The context ID for this VLV response control. |
| | | * |
| | | * @return The ASN.1 octet string containing the encoded sort order. |
| | | */ |
| | | private static ASN1OctetString encodeControlValue(int targetPosition, |
| | | int contentCount, int vlvResultCode, |
| | | ByteString contextID) |
| | | { |
| | | ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4); |
| | | vlvElements.add(new ASN1Integer(targetPosition)); |
| | | vlvElements.add(new ASN1Integer(contentCount)); |
| | | vlvElements.add(new ASN1Enumerated(vlvResultCode)); |
| | | |
| | | if (contextID != null) |
| | | { |
| | | vlvElements.add(contextID.toASN1OctetString()); |
| | | } |
| | | |
| | | return new ASN1OctetString(new ASN1Sequence(vlvElements).encode()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new VLV response control from the contents of the provided |
| | | * control. |
| | | * |
| | | * @param control The generic control containing the information to use to |
| | | * create this VLV response control. It must not be |
| | | * {@code null}. |
| | | * |
| | | * @return The VLV response control decoded from the provided control. |
| | | * |
| | | * @throws LDAPException If this control cannot be decoded as a valid VLV |
| | | * response control. |
| | | */ |
| | | public static VLVResponseControl decodeControl(Control control) |
| | | throws LDAPException |
| | | { |
| | | ASN1OctetString controlValue = control.getValue(); |
| | | if (controlValue == null) |
| | | { |
| | | int msgID = MSGID_VLVRES_CONTROL_NO_VALUE; |
| | | String message = getMessage(msgID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | try |
| | | { |
| | | ASN1Sequence vlvSequence = |
| | | ASN1Sequence.decodeAsSequence(controlValue.value()); |
| | | ArrayList<ASN1Element> elements = vlvSequence.elements(); |
| | | |
| | | if ((elements.size() < 3) || (elements.size() > 4)) |
| | | { |
| | | int msgID = MSGID_VLVRES_CONTROL_INVALID_ELEMENT_COUNT; |
| | | String message = getMessage(msgID, elements.size()); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | |
| | | int targetPosition = elements.get(0).decodeAsInteger().intValue(); |
| | | int contentCount = elements.get(1).decodeAsInteger().intValue(); |
| | | int vlvResultCode = elements.get(2).decodeAsEnumerated().intValue(); |
| | | |
| | | ASN1OctetString contextID = null; |
| | | if (elements.size() == 4) |
| | | { |
| | | contextID = elements.get(3).decodeAsOctetString(); |
| | | } |
| | | |
| | | return new VLVResponseControl(control.getOID(), control.isCritical(), |
| | | controlValue, targetPosition, contentCount, |
| | | vlvResultCode, contextID); |
| | | } |
| | | catch (LDAPException le) |
| | | { |
| | | throw le; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_VLVRES_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 VLV request control. |
| | | * |
| | | * @return A string representation of this VLV request control. |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this VLV request control to the provided |
| | | * buffer. |
| | | * |
| | | * @param buffer The buffer to which the information should be appended. |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("VLVResponseControl(targetPosition="); |
| | | buffer.append(targetPosition); |
| | | buffer.append(", contentCount="); |
| | | buffer.append(contentCount); |
| | | buffer.append(", vlvResultCode="); |
| | | buffer.append(vlvResultCode); |
| | | |
| | | if (contextID != null) |
| | | { |
| | | buffer.append(", contextID="); |
| | | buffer.append(contextID); |
| | | } |
| | | |
| | | buffer.append(")"); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the string representation of the result code that will |
| | | * be used for search operations containing the VLV request control that do |
| | | * not also include the server-side sort control. |
| | | */ |
| | | public static final int MSGID_RESULT_SORT_CONTROL_MISSING = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 608; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the string representation of the result code that will |
| | | * be used for search operations containing the VLV request control with an |
| | | * invalid offset or target count. |
| | | */ |
| | | public static final int MSGID_RESULT_OFFSET_RANGE_ERROR = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 609; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the string representation of the result code that will |
| | | * be used for operations that failed because the request would have impacted |
| | | * information in multiple servers or repositories. |
| | | */ |
| | | public static final int MSGID_RESULT_VIRTUAL_LIST_VIEW_ERROR = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 610; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined |
| | | * in this class. |
| | | */ |
| | |
| | | registerMessage(MSGID_RESULT_UNAVAILABLE, "Unavailable"); |
| | | registerMessage(MSGID_RESULT_UNWILLING_TO_PERFORM, "Unwilling to Perform"); |
| | | registerMessage(MSGID_RESULT_LOOP_DETECT, "Loop Detected"); |
| | | registerMessage(MSGID_RESULT_SORT_CONTROL_MISSING, "Sort Control Missing"); |
| | | registerMessage(MSGID_RESULT_OFFSET_RANGE_ERROR, "Offset Range Error"); |
| | | registerMessage(MSGID_RESULT_NAMING_VIOLATION, "Naming Violation"); |
| | | registerMessage(MSGID_RESULT_OBJECTCLASS_VIOLATION, |
| | | "ObjectClass Violation"); |
| | |
| | | "ObjectClass Modifications Prohibited"); |
| | | registerMessage(MSGID_RESULT_AFFECTS_MULTIPLE_DSAS, |
| | | "Affects Multiple DSAs"); |
| | | registerMessage(MSGID_RESULT_VIRTUAL_LIST_VIEW_ERROR, |
| | | "Virtual List View Error"); |
| | | registerMessage(MSGID_RESULT_OTHER, "Other"); |
| | | registerMessage(MSGID_RESULT_CLIENT_SIDE_SERVER_DOWN, "Server Down"); |
| | | registerMessage(MSGID_RESULT_CLIENT_SIDE_LOCAL_ERROR, "Local Error"); |
| | |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 140; |
| | | |
| | | /** |
| | | * The message ID to use if a VLV request has a negative start position. This |
| | | * does not take any arguments. |
| | | */ |
| | | public static final int MSGID_ENTRYIDSORTER_NEGATIVE_START_POS = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 141; |
| | | |
| | | /** |
| | | * The message ID to use if a VLV request has an offset beyond the end of the |
| | | * entry set. This takes two arguments, which are the provided offset and the |
| | | * list size. |
| | | */ |
| | | public static final int MSGID_ENTRYIDSORTER_OFFSET_TOO_LARGE = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 142; |
| | | |
| | | /** |
| | | * The message ID to use if a VLV request specifies a target value that is |
| | | * larger than all values in the sort list. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_ENTRYIDSORTER_TARGET_VALUE_NOT_FOUND = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 143; |
| | | |
| | | |
| | | /** |
| | | * The message ID of an error indicating that the search request included both |
| | | * the paged results control and the VLV control. This does not take any |
| | | * arguments. |
| | | */ |
| | | public static final int MSGID_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV = |
| | | CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 144; |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | "allow it to be replaced"); |
| | | registerMessage(MSGID_JEB_ATTRIBUTE_INDEX_NOT_CONFIGURED, |
| | | "There is no index configured for attribute type '%s'"); |
| | | registerMessage(MSGID_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV, |
| | | "The requested search operation included both the simple " + |
| | | "paged results control and the virtual list view " + |
| | | "control. These controls are mutually exclusive and " + |
| | | "cannot be used together"); |
| | | registerMessage(MSGID_JEB_SEARCH_NO_SUCH_OBJECT, |
| | | "The search base entry '%s' does not exist"); |
| | | registerMessage(MSGID_JEB_SEARCH_CANNOT_SORT_UNINDEXED, |
| | |
| | | registerMessage(MSGID_ENTRYIDSORTER_CANNOT_EXAMINE_ENTRY, |
| | | "Unable to examine the entry with ID %s for sorting " + |
| | | "purposes: %s"); |
| | | registerMessage(MSGID_ENTRYIDSORTER_NEGATIVE_START_POS, |
| | | "Unable to process the virtual list view request because " + |
| | | "the target start position was before the beginning of " + |
| | | "the result set"); |
| | | registerMessage(MSGID_ENTRYIDSORTER_OFFSET_TOO_LARGE, |
| | | "Unable to process the virtual list view request because " + |
| | | "the target offset %d was greater than the total number " + |
| | | "of results in the list (%d)"); |
| | | registerMessage(MSGID_ENTRYIDSORTER_TARGET_VALUE_NOT_FOUND, |
| | | "Unable to prcess the virtual list view request because " + |
| | | "no entry was found in the result set with a sort value " + |
| | | "greater than or equal to the provided assertion value"); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV request control |
| | | * does not have a value. It does not take any arguments. |
| | | */ |
| | | public static final int MSGID_VLVREQ_CONTROL_NO_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 417; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV request control |
| | | * has an invalid number of elements. This takes a single argument, which is |
| | | * the number of elements contained in the control sequence. |
| | | */ |
| | | public static final int MSGID_VLVREQ_CONTROL_INVALID_ELEMENT_COUNT = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 418; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV request control |
| | | * has an invalid BER target type. It takes a single argument, which is the |
| | | * hex representation of the BER target type. |
| | | */ |
| | | public static final int MSGID_VLVREQ_CONTROL_INVALID_TARGET_TYPE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 419; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV request control |
| | | * value cannot be decoded. It takes a single argument, which is a message |
| | | * explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_VLVREQ_CONTROL_CANNOT_DECODE_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 420; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV response |
| | | * control does not have a value. It does not take any arguments. |
| | | */ |
| | | public static final int MSGID_VLVRES_CONTROL_NO_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 421; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV response |
| | | * control has an invalid number of elements. This takes a single argument, |
| | | * which is the number of elements contained in the control sequence. |
| | | */ |
| | | public static final int MSGID_VLVRES_CONTROL_INVALID_ELEMENT_COUNT = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 422; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the VLV response |
| | | * control value cannot be decoded. It takes a single argument, which is a |
| | | * message explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_VLVRES_CONTROL_CANNOT_DECODE_VALUE = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 423; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | "Unable to process the provided server-side sort " + |
| | | "response control because an error occurred while " + |
| | | "attempting to decode the control value: %s"); |
| | | } |
| | | |
| | | |
| | | registerMessage(MSGID_VLVREQ_CONTROL_NO_VALUE, |
| | | "Unable to decode the provided control as a VLV request " + |
| | | "control because it does not include a control value"); |
| | | registerMessage(MSGID_VLVREQ_CONTROL_INVALID_ELEMENT_COUNT, |
| | | "Unable to decode the provided control as a VLV request " + |
| | | "control because it contains an invalid number of " + |
| | | "elements: %d"); |
| | | registerMessage(MSGID_VLVREQ_CONTROL_INVALID_TARGET_TYPE, |
| | | "Unable to decode the provided control as a VLV request " + |
| | | "control because the target element type %s is invalid"); |
| | | registerMessage(MSGID_VLVREQ_CONTROL_CANNOT_DECODE_VALUE, |
| | | "Unable to process the provided VLV request control " + |
| | | "because an error occurred while attempting to decode " + |
| | | "the control value: %s"); |
| | | |
| | | |
| | | registerMessage(MSGID_VLVRES_CONTROL_NO_VALUE, |
| | | "Unable to decode the provided control as a VLV response " + |
| | | "control because it does not include a control value"); |
| | | registerMessage(MSGID_VLVRES_CONTROL_INVALID_ELEMENT_COUNT, |
| | | "Unable to decode the provided control as a VLV response " + |
| | | "control because it contains an invalid number of " + |
| | | "elements: %d"); |
| | | registerMessage(MSGID_VLVRES_CONTROL_CANNOT_DECODE_VALUE, |
| | | "Unable to process the provided VLV 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 |
| | | * virtualListView option for the ldapsearch tool. It does not take any |
| | | * arguments. |
| | | */ |
| | | public static final int MSGID_DESCRIPTION_VLV = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 878; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the user requests a VLV |
| | | * operation without also requesting a server-side sort. This takes two |
| | | * arguments, which are the long identifiers for the virtualListView and |
| | | * sortOrder arguments. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_VLV_REQUIRES_SORT = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 879; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if the user requests a VLV |
| | | * operation with an invalid descriptor. This does not take any arguments. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_VLV_INVALID_DESCRIPTOR = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 880; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to indicate that the |
| | | * requested server-side sort operation was not successful. This takes a |
| | | * single argument, which is a string representation of the associated sort |
| | | * control result code. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_SORT_ERROR = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 881; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to indicate that the |
| | | * server-side sort response control could not be decoded. This takes a |
| | | * single argument, which is a message explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_CANNOT_DECODE_SORT_RESPONSE = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 882; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used display the target offset |
| | | * for the VLV result set. This takes a single argument, which is the target |
| | | * offset. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_VLV_TARGET_OFFSET = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 883; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used display the content count |
| | | * for the VLV result set. This takes a single argument, which is the content |
| | | * count. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_VLV_CONTENT_COUNT = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 884; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to indicate that the |
| | | * requested virtual list view operation was not successful. This takes a |
| | | * single argument, which is a string representation of the associated sort |
| | | * control result code. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_VLV_ERROR = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 885; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used to indicate that the |
| | | * virtual list view response control could not be decoded. This takes a |
| | | * single argument, which is a message explaining the problem that occurred. |
| | | */ |
| | | public static final int MSGID_LDAPSEARCH_CANNOT_DECODE_VLV_RESPONSE = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 886; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | "filter"); |
| | | registerMessage(MSGID_DESCRIPTION_SORT_ORDER, |
| | | "Sort the results using the provided sort order"); |
| | | registerMessage(MSGID_DESCRIPTION_VLV, |
| | | "Use the virtual list view control to retrieve the " + |
| | | "specified results page"); |
| | | 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"); |
| | |
| | | "The provided matched values filter was invalid: %s"); |
| | | registerMessage(MSGID_LDAP_SORTCONTROL_INVALID_ORDER, |
| | | "The provided sort order was invalid: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_VLV_REQUIRES_SORT, |
| | | "If the --%s argument is provided, then the --%s " + |
| | | "argument must also be given"); |
| | | registerMessage(MSGID_LDAPSEARCH_VLV_INVALID_DESCRIPTOR, |
| | | "The provided virtual list view descriptor was invalid. " + |
| | | "It must be a value in the form " + |
| | | "'beforeCount:afterCount:offset:contentCount' (where " + |
| | | "offset specifies the index of the target entry and " + |
| | | "contentCount specifies the estimated total number of " + |
| | | "results or zero if it is not known), or " + |
| | | "'beforeCount:afterCount:assertionValue' (where the " + |
| | | "entry should be the first entry whose primary sort " + |
| | | "value is greater than or equal to the provided " + |
| | | "assertionValue). In either case, beforeCount is the " + |
| | | "number of entries to return before the target value and " + |
| | | "afterCount is the number of entries to return after " + |
| | | "the target value"); |
| | | registerMessage(MSGID_LDAPMODIFY_PREREAD_NO_VALUE, |
| | | "The pre-read response control did not include a value"); |
| | | registerMessage(MSGID_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE, |
| | |
| | | "# The account is locked"); |
| | | registerMessage(MSGID_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_UNLOCK, |
| | | "# Time until the account is unlocked: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_SORT_ERROR, |
| | | "# Server-side sort failed: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_CANNOT_DECODE_SORT_RESPONSE, |
| | | "# Unable to decode the server-side sort response: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_VLV_TARGET_OFFSET, |
| | | "# VLV Target Offset: %d"); |
| | | registerMessage(MSGID_LDAPSEARCH_VLV_CONTENT_COUNT, |
| | | "# VLV Content Count: %d"); |
| | | registerMessage(MSGID_LDAPSEARCH_VLV_ERROR, |
| | | "# Virtual list view processing failed: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_CANNOT_DECODE_VLV_RESPONSE, |
| | | "# Unable to decode the virtual list view response: %s"); |
| | | registerMessage(MSGID_LDAPSEARCH_MATCHING_ENTRY_COUNT, |
| | | "# Total number of matching entries: %d"); |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The LDAP result code for operations that fail because the request included |
| | | * a VLV request control without a server-side sort control. |
| | | */ |
| | | public static final int SORT_CONTROL_MISSING = 60; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The LDAP result code for operations that fail because the request included |
| | | * a VLV request control with an invalid offset. |
| | | */ |
| | | public static final int OFFSET_RANGE_ERROR = 61; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The LDAP result code for operations that fail due to a naming violation. |
| | | */ |
| | | public static final int NAMING_VIOLATION = 64; |
| | |
| | | |
| | | |
| | | /** |
| | | * The LDAP result code for operations that fail due to an error in |
| | | * virtual list view processing. |
| | | */ |
| | | public static final int VIRTUAL_LIST_VIEW_ERROR = 76; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The LDAP result code for use in cases in which none of the other defined |
| | | * result codes are appropriate. |
| | | */ |
| | |
| | | case LOOP_DETECT: |
| | | msgID = MSGID_RESULT_LOOP_DETECT; |
| | | break; |
| | | case SORT_CONTROL_MISSING: |
| | | msgID = MSGID_RESULT_SORT_CONTROL_MISSING; |
| | | break; |
| | | case OFFSET_RANGE_ERROR: |
| | | msgID = MSGID_RESULT_OFFSET_RANGE_ERROR; |
| | | break; |
| | | case NAMING_VIOLATION: |
| | | msgID = MSGID_RESULT_NAMING_VIOLATION; |
| | | break; |
| | |
| | | case AFFECTS_MULTIPLE_DSAS: |
| | | msgID = MSGID_RESULT_AFFECTS_MULTIPLE_DSAS; |
| | | break; |
| | | case VIRTUAL_LIST_VIEW_ERROR: |
| | | msgID = MSGID_RESULT_VIRTUAL_LIST_VIEW_ERROR; |
| | | break; |
| | | case CLIENT_SIDE_SERVER_DOWN: |
| | | msgID = MSGID_RESULT_CLIENT_SIDE_SERVER_DOWN; |
| | | break; |
| | |
| | | import org.opends.server.controls.PersistentSearchChangeType; |
| | | import org.opends.server.controls.PersistentSearchControl; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.controls.ServerSideSortResponseControl; |
| | | import org.opends.server.controls.VLVRequestControl; |
| | | import org.opends.server.controls.VLVResponseControl; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.util.Base64; |
| | | import org.opends.server.util.PasswordReader; |
| | |
| | | import org.opends.server.protocols.ldap.LDAPControl; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.protocols.ldap.LDAPMessage; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.protocols.ldap.SearchRequestProtocolOp; |
| | | import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp; |
| | | import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp; |
| | |
| | | errorMessage = searchOp.getErrorMessage(); |
| | | matchedDN = searchOp.getMatchedDN(); |
| | | |
| | | for (LDAPControl c : responseMessage.getControls()) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | try |
| | | { |
| | | ServerSideSortResponseControl sortResponse = |
| | | ServerSideSortResponseControl.decodeControl( |
| | | c.getControl()); |
| | | int rc = sortResponse.getResultCode(); |
| | | if (rc != LDAPResultCode.SUCCESS) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_SORT_ERROR; |
| | | String msg = getMessage(msgID, |
| | | LDAPResultCode.toString(rc)); |
| | | err.println(msg); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_CANNOT_DECODE_SORT_RESPONSE; |
| | | String msg = getMessage(msgID, getExceptionMessage(e)); |
| | | err.println(msg); |
| | | } |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | try |
| | | { |
| | | VLVResponseControl vlvResponse = |
| | | VLVResponseControl.decodeControl(c.getControl()); |
| | | int rc = vlvResponse.getVLVResultCode(); |
| | | if (rc == LDAPResultCode.SUCCESS) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_TARGET_OFFSET; |
| | | String msg = getMessage(msgID, |
| | | vlvResponse.getTargetPosition()); |
| | | out.println(msg); |
| | | |
| | | msgID = MSGID_LDAPSEARCH_VLV_CONTENT_COUNT; |
| | | msg = getMessage(msgID, vlvResponse.getContentCount()); |
| | | out.println(msg); |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_ERROR; |
| | | String msg = getMessage(msgID, |
| | | LDAPResultCode.toString(rc)); |
| | | err.println(msg); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_CANNOT_DECODE_VLV_RESPONSE; |
| | | String msg = getMessage(msgID, getExceptionMessage(e)); |
| | | err.println(msg); |
| | | } |
| | | } |
| | | } |
| | | |
| | | break; |
| | | default: |
| | | // FIXME - throw exception? |
| | |
| | | StringArgument sortOrder = null; |
| | | StringArgument trustStorePath = null; |
| | | StringArgument trustStorePassword = null; |
| | | StringArgument vlvDescriptor = null; |
| | | |
| | | |
| | | // Create the command-line argument parser for use with this program. |
| | |
| | | MSGID_DESCRIPTION_SORT_ORDER); |
| | | argParser.addArgument(sortOrder); |
| | | |
| | | vlvDescriptor = |
| | | new StringArgument("vlvdescriptor", 'G', "virtualListView", false, |
| | | false, true, |
| | | "{before:after:index:count | before:after:value}", |
| | | null, null, MSGID_DESCRIPTION_VLV); |
| | | argParser.addArgument(vlvDescriptor); |
| | | |
| | | controlStr = |
| | | new StringArgument("control", 'J', "control", false, true, true, |
| | | "{controloid[:criticality[:value|::b64value|:<fileurl]]}", |
| | |
| | | } |
| | | } |
| | | |
| | | if (vlvDescriptor.isPresent()) |
| | | { |
| | | if (! sortOrder.isPresent()) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_REQUIRES_SORT; |
| | | String message = getMessage(msgID, vlvDescriptor.getLongIdentifier(), |
| | | sortOrder.getLongIdentifier()); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | return 1; |
| | | } |
| | | |
| | | StringTokenizer tokenizer = |
| | | new StringTokenizer(vlvDescriptor.getValue(), ":"); |
| | | int numTokens = tokenizer.countTokens(); |
| | | if (numTokens == 3) |
| | | { |
| | | try |
| | | { |
| | | int beforeCount = Integer.parseInt(tokenizer.nextToken()); |
| | | int afterCount = Integer.parseInt(tokenizer.nextToken()); |
| | | ASN1OctetString assertionValue = |
| | | new ASN1OctetString(tokenizer.nextToken()); |
| | | searchOptions.getControls().add( |
| | | new LDAPControl(new VLVRequestControl(beforeCount, afterCount, |
| | | assertionValue))); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_INVALID_DESCRIPTOR; |
| | | String message = getMessage(msgID); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | return 1; |
| | | } |
| | | } |
| | | else if (numTokens == 4) |
| | | { |
| | | try |
| | | { |
| | | int beforeCount = Integer.parseInt(tokenizer.nextToken()); |
| | | int afterCount = Integer.parseInt(tokenizer.nextToken()); |
| | | int offset = Integer.parseInt(tokenizer.nextToken()); |
| | | int contentCount = Integer.parseInt(tokenizer.nextToken()); |
| | | searchOptions.getControls().add( |
| | | new LDAPControl(new VLVRequestControl(beforeCount, afterCount, |
| | | offset, contentCount))); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_INVALID_DESCRIPTOR; |
| | | String message = getMessage(msgID); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | return 1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_LDAPSEARCH_VLV_INVALID_DESCRIPTOR; |
| | | String message = getMessage(msgID); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | // Set the connection options. |
| | | connectionOptions.setSASLExternal(saslExternal.isPresent()); |
| | | if(saslOptions.isPresent()) |
| | |
| | | |
| | | |
| | | /** |
| | | * The result code that indicates that a search request included a |
| | | * VLV request control without a server-side sort control. |
| | | */ |
| | | SORT_CONTROL_MISSING(LDAPResultCode.SORT_CONTROL_MISSING, |
| | | MSGID_RESULT_SORT_CONTROL_MISSING), |
| | | |
| | | |
| | | |
| | | /** |
| | | * The result code that indicates that a search request included a |
| | | * VLV request control with an invalid offset. |
| | | */ |
| | | OFFSET_RANGE_ERROR(LDAPResultCode.OFFSET_RANGE_ERROR, |
| | | MSGID_RESULT_OFFSET_RANGE_ERROR), |
| | | |
| | | |
| | | |
| | | /** |
| | | * The result code that indicates that the requested operation |
| | | * failed because it would have violated the server's naming |
| | | * configuration. |
| | |
| | | |
| | | |
| | | /** |
| | | * The result code that indicates that the operation could not be |
| | | * processed because there was an error while processing the virtual |
| | | * list view control. |
| | | */ |
| | | VIRTUAL_LIST_VIEW_ERROR(LDAPResultCode.VIRTUAL_LIST_VIEW_ERROR, |
| | | MSGID_RESULT_VIRTUAL_LIST_VIEW_ERROR), |
| | | |
| | | |
| | | |
| | | /** |
| | | * The result code that should be used if no other result code is |
| | | * appropriate. |
| | | */ |
| | |
| | | return UNWILLING_TO_PERFORM; |
| | | case LDAPResultCode.LOOP_DETECT: |
| | | return LOOP_DETECT; |
| | | case LDAPResultCode.SORT_CONTROL_MISSING: |
| | | return SORT_CONTROL_MISSING; |
| | | case LDAPResultCode.OFFSET_RANGE_ERROR: |
| | | return OFFSET_RANGE_ERROR; |
| | | case LDAPResultCode.NAMING_VIOLATION: |
| | | return NAMING_VIOLATION; |
| | | case LDAPResultCode.OBJECTCLASS_VIOLATION: |
| | |
| | | return OBJECTCLASS_MODS_PROHIBITED; |
| | | case LDAPResultCode.AFFECTS_MULTIPLE_DSAS: |
| | | return AFFECTS_MULTIPLE_DSAS; |
| | | case LDAPResultCode.VIRTUAL_LIST_VIEW_ERROR: |
| | | return VIRTUAL_LIST_VIEW_ERROR; |
| | | case LDAPResultCode.CLIENT_SIDE_SERVER_DOWN: |
| | | return CLIENT_SIDE_SERVER_DOWN; |
| | | case LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR: |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * The OID for the virtual list view request control. |
| | | */ |
| | | public static final String OID_VLV_REQUEST_CONTROL = |
| | | "2.16.840.1.113730.3.4.9"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The OID for the virtual list view request control. |
| | | */ |
| | | public static final String OID_VLV_RESPONSE_CONTROL = |
| | | "2.16.840.1.113730.3.4.10"; |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * The block length in bytes used when generating an HMAC-MD5 digest. |
| 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.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | 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 virtual list view request |
| | | * and response controls. |
| | | */ |
| | | public class VLVControlTestCase |
| | | 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. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor1() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = new VLVRequestControl(0, 9, 1, 0); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getOffset(), 1); |
| | | assertEquals(vlvRequest.getContentCount(), 0); |
| | | assertNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_BYOFFSET); |
| | | assertNull(vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the second constructor for the request control with a null context |
| | | * ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor2NullContextID() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = new VLVRequestControl(0, 9, 1, 0, null); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getOffset(), 1); |
| | | assertEquals(vlvRequest.getContentCount(), 0); |
| | | assertNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_BYOFFSET); |
| | | assertNull(vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the second constructor for the request control with a non-null |
| | | * context ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor2NonNullContextID() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = |
| | | new VLVRequestControl(0, 9, 1, 0, new ASN1OctetString("foo")); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getOffset(), 1); |
| | | assertEquals(vlvRequest.getContentCount(), 0); |
| | | assertNotNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_BYOFFSET); |
| | | assertNull(vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the third constructor for the request control. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor3() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = |
| | | new VLVRequestControl(0, 9, new ASN1OctetString("a")); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(), |
| | | "a"); |
| | | assertNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the fourth constructor for the request control with a null context |
| | | * ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor4NullContextID() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = |
| | | new VLVRequestControl(0, 9, new ASN1OctetString("a"), null); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(), |
| | | "a"); |
| | | assertNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the fourth constructor for the request control with a non-null |
| | | * context ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRequestConstructor4NonNullContextID() |
| | | throws Exception |
| | | { |
| | | VLVRequestControl vlvRequest = |
| | | new VLVRequestControl(0, 9, new ASN1OctetString("a"), |
| | | new ASN1OctetString("foo")); |
| | | |
| | | assertEquals(vlvRequest.getBeforeCount(), 0); |
| | | assertEquals(vlvRequest.getAfterCount(), 9); |
| | | assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(), |
| | | "a"); |
| | | assertNotNull(vlvRequest.getContextID()); |
| | | assertEquals(vlvRequest.getTargetType(), |
| | | VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL); |
| | | assertNotNull(vlvRequest.toString()); |
| | | |
| | | assertNotNull(vlvRequest.decodeControl(vlvRequest)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the first constructor for the response control. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResponseConstructor1() |
| | | throws Exception |
| | | { |
| | | VLVResponseControl vlvResponse = new VLVResponseControl(0, 15, 0); |
| | | |
| | | assertEquals(vlvResponse.getTargetPosition(), 0); |
| | | assertEquals(vlvResponse.getContentCount(), 15); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertNull(vlvResponse.getContextID()); |
| | | assertNotNull(vlvResponse.toString()); |
| | | |
| | | assertNotNull(vlvResponse.decodeControl(vlvResponse)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the second constructor for the response control with a null context |
| | | * ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResponseConstructor2NullContextID() |
| | | throws Exception |
| | | { |
| | | VLVResponseControl vlvResponse = new VLVResponseControl(0, 15, 0, null); |
| | | |
| | | assertEquals(vlvResponse.getTargetPosition(), 0); |
| | | assertEquals(vlvResponse.getContentCount(), 15); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertNull(vlvResponse.getContextID()); |
| | | assertNotNull(vlvResponse.toString()); |
| | | |
| | | assertNotNull(vlvResponse.decodeControl(vlvResponse)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the second constructor for the response control with a non-null |
| | | * context ID. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testResponseConstructor2NonNullContextID() |
| | | throws Exception |
| | | { |
| | | VLVResponseControl vlvResponse = |
| | | new VLVResponseControl(0, 15, 0, new ASN1OctetString("foo")); |
| | | |
| | | assertEquals(vlvResponse.getTargetPosition(), 0); |
| | | assertEquals(vlvResponse.getContentCount(), 15); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertNotNull(vlvResponse.getContextID()); |
| | | assertNotNull(vlvResponse.toString()); |
| | | |
| | | assertNotNull(vlvResponse.decodeControl(vlvResponse)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an offset of zero. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByOffsetZeroOffset() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, 1, 0)); |
| | | |
| | | 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 |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 1); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using a nonzero offset that still is completely |
| | | * within the bounds of the result set. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByOffsetNonZeroOffset() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, 3, 0)); |
| | | |
| | | 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(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 3); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control with a negative |
| | | * start position. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByOffsetNegativeStartPosition() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(3, 3, 1, 0)); |
| | | |
| | | 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(); |
| | | |
| | | // It will be successful because it's not a critical control. |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control with a start |
| | | * start position beyond the end of the result set. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByOffsetStartPositionTooHigh() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(3, 3, 30, 0)); |
| | | |
| | | 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(); |
| | | |
| | | // It will be successful because it's not a critical control. |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control with a start |
| | | * start position within the bounds of the list but not enough remaining |
| | | * entries to meet the afterCount |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByOffsetIncompleteAfterCount() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, 7, 0)); |
| | | |
| | | 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(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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 7); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an assertion value before any actual value in |
| | | * the list. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByValueBeforeAll() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("a"))); |
| | | |
| | | 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 |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 1); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an assertion value that matches the first value |
| | | * in the list. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByValueMatchesFirst() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, |
| | | new ASN1OctetString("aaccf"))); |
| | | |
| | | 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 |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 1); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an assertion value that matches the third value |
| | | * in the list. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByValueMatchesThird() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(0, 3, |
| | | new ASN1OctetString("albert"))); |
| | | |
| | | 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(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 3); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an assertion value that matches the third value |
| | | * in the list and includes a nonzero before count. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByValueMatchesThirdWithBeforeCount() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("givenName")); |
| | | requestControls.add(new VLVRequestControl(1, 3, |
| | | new ASN1OctetString("albert"))); |
| | | |
| | | 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); // Aaron |
| | | expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID |
| | | expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID |
| | | expectedDNOrder.add(lowercaseMcGeeDN); // lowercase |
| | | expectedDNOrder.add(margaretJonesDN); // Maggie |
| | | |
| | | 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(), 2); |
| | | |
| | | ServerSideSortResponseControl sortResponse = null; |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) |
| | | { |
| | | sortResponse = ServerSideSortResponseControl.decodeControl(c); |
| | | } |
| | | else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | else |
| | | { |
| | | fail("Response control with unexpected OID " + c.getOID()); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(sortResponse); |
| | | assertEquals(sortResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), 0); |
| | | assertEquals(vlvResponse.getTargetPosition(), 3); |
| | | assertEquals(vlvResponse.getContentCount(), 9); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests performing an internal search using the VLV control to retrieve a |
| | | * subset of the entries using an assertion value that is after all values in |
| | | * the list. |
| | | * |
| | | * @throws Exception If an unexpected problem occurred. |
| | | */ |
| | | @Test() |
| | | public void testInternalSearchByValueAfterAll() |
| | | throws Exception |
| | | { |
| | | populateDB(); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | ArrayList<Control> requestControls = new ArrayList<Control>(); |
| | | requestControls.add(new ServerSideSortRequestControl("sn")); |
| | | requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("zz"))); |
| | | |
| | | 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(); |
| | | |
| | | // It will be successful because the control isn't critical. |
| | | assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | List<Control> responseControls = internalSearch.getResponseControls(); |
| | | assertNotNull(responseControls); |
| | | |
| | | VLVResponseControl vlvResponse = null; |
| | | for (Control c : responseControls) |
| | | { |
| | | if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) |
| | | { |
| | | vlvResponse = VLVResponseControl.decodeControl(c); |
| | | } |
| | | } |
| | | |
| | | assertNotNull(vlvResponse); |
| | | assertEquals(vlvResponse.getVLVResultCode(), |
| | | LDAPResultCode.OFFSET_RANGE_ERROR); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the virtual list view control without the server-side sort |
| | | * control. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testVLVWithoutSort() |
| | | throws Exception |
| | | { |
| | | 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", |
| | | "-G", "0:9:1:0", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the server-side sort control with both the simple paged |
| | | * results and virtual list view controls. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortWithVLVAndPagedResults() |
| | | 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,givenName", |
| | | "--simplePageSize", "2", |
| | | "-G", "0:3:1:0", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the virtual list view control with an invalid descriptor |
| | | * with no colons. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testVLVInvalidDescriptorNoColons() |
| | | throws Exception |
| | | { |
| | | 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", |
| | | "-G", "invalid", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the virtual list view control with an invalid descriptor |
| | | * with two colons. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testVLVInvalidDescriptorTwoColons() |
| | | throws Exception |
| | | { |
| | | 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", |
| | | "-G", "invalid:9:invalid", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of the virtual list view control with an invalid descriptor |
| | | * with three colons. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testVLVInvalidDescriptorThreeColons() |
| | | throws Exception |
| | | { |
| | | 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", |
| | | "-G", "invalid:9:1:0", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the use of both the server-side sort control and the virtual list |
| | | * view control. |
| | | * |
| | | * @throws Exception If an unexpectd problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSortWithVLV() |
| | | 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[] 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", |
| | | "-G", "1:3:1:0", |
| | | "(objectClass=*)" |
| | | }; |
| | | |
| | | assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the LDAPSearch tool with the "--help" option. |
| | | */ |
| | | @Test() |