From 30f5175327333dcfaaeafb02560697bcdce6166d Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Mon, 30 Apr 2007 16:24:15 +0000
Subject: [PATCH] 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/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java | 181 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java b/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
index 768b3b2..5b685a5 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
@@ -28,13 +28,21 @@
+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;
@@ -60,6 +68,8 @@
* @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.
@@ -69,7 +79,8 @@
public static EntryIDSet sort(EntryContainer entryContainer,
EntryIDSet entryIDSet,
SearchOperation searchOperation,
- SortOrder sortOrder)
+ SortOrder sortOrder,
+ VLVRequestControl vlvRequest)
throws DirectoryException
{
if (! entryIDSet.isDefined())
@@ -107,11 +118,171 @@
}
}
- 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);
--
Gitblit v1.10.0