From a1db2514d6a1bf75e851a44e649a7986e95d2cc9 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 06 Jul 2007 21:39:40 +0000
Subject: [PATCH] Update the way that the server handles the VLV request control to be more forgiving with target ranges that are out of the bounds of the actual result set. Negative target offsets will still result in errors, but a target offset of zero will be treated as if it were one. If beforeCount is greater than or equal to the target offset, then it will now be truncated. If the target offset or assertion value is beyond the end of the result set, then only the before count entries will be returned and the target position will be set to one greater than the content count.
---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java | 167 ++++++++++++++++++++++++++++++++++++++---
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java | 50 +++++++-----
2 files changed, 185 insertions(+), 32 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
index 5b685a5..fd4b3dc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
@@ -131,10 +131,10 @@
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)
+ if (targetOffset < 0)
{
+ // The client specified a negative target offset. This should never
+ // be allowed.
searchOperation.addResponseControl(
new VLVResponseControl(targetOffset, sortMap.size(),
LDAPResultCode.OFFSET_RANGE_ERROR));
@@ -144,17 +144,32 @@
throw new DirectoryException(ResultCode.VIRTUAL_LIST_VIEW_ERROR,
message, msgID);
}
+ else if (targetOffset == 0)
+ {
+ // This is an easy mistake to make, since VLV offsets start at 1
+ // instead of 0. We'll assume the client meant to use 1.
+ targetOffset = 1;
+ }
+
+ int listOffset = targetOffset - 1; // VLV offsets start at 1, not 0.
+ int startPos = listOffset - beforeCount;
+ if (startPos < 0)
+ {
+ // This can happen if beforeCount >= offset, and in this case we'll
+ // just adjust the start position to ignore the range of beforeCount
+ // that doesn't exist.
+ startPos = 0;
+ beforeCount = listOffset;
+ }
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);
+ // The start position is beyond the end of the list. In this case,
+ // we'll assume that the start position was one greater than the
+ // size of the list and will only return the beforeCount entries.
+ targetOffset = sortMap.size() + 1;
+ listOffset = sortMap.size();
+ startPos = listOffset - beforeCount;
+ afterCount = 0;
}
int count = 1 + beforeCount + afterCount;
@@ -253,14 +268,9 @@
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);
+ // No entry was found to be greater than or equal to the sort key, so
+ // the target offset will be one greater than the content count.
+ targetOffset = sortMap.size() + 1;
}
sortedIDs = new long[listSize];
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
index abe7e45..c417505 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
@@ -469,12 +469,12 @@
/**
* Tests performing an internal search using the VLV control to retrieve a
- * subset of the entries using an offset of zero.
+ * subset of the entries using an offset of one.
*
* @throws Exception If an unexpected problem occurred.
*/
@Test()
- public void testInternalSearchByOffsetZeroOffset()
+ public void testInternalSearchByOffsetOneOffset()
throws Exception
{
populateDB();
@@ -546,13 +546,91 @@
/**
* 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.
+ * subset of the entries using an offset of zero, which should be treated like
+ * an offset of one.
*
* @throws Exception If an unexpected problem occurred.
*/
@Test()
- public void testInternalSearchByOffsetNonZeroOffset()
+ 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, 0, 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 an offset that isn't at the beginning of the
+ * result set but is still completely within the bounds of that set.
+ *
+ * @throws Exception If an unexpected problem occurred.
+ */
+ @Test()
+ public void testInternalSearchByOffsetThreeOffset()
throws Exception
{
populateDB();
@@ -624,7 +702,58 @@
/**
* Tests performing an internal search using the VLV control with a negative
- * start position.
+ * target offset.
+ *
+ * @throws Exception If an unexpected problem occurred.
+ */
+ @Test()
+ public void testInternalSearchByOffsetNegativeOffset()
+ 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();
+
+ // 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 an offset of
+ * one but a beforeCount that puts the start position at a negative value.
*
* @throws Exception If an unexpected problem occurred.
*/
@@ -667,8 +796,7 @@
}
assertNotNull(vlvResponse);
- assertEquals(vlvResponse.getVLVResultCode(),
- LDAPResultCode.OFFSET_RANGE_ERROR);
+ assertEquals(vlvResponse.getVLVResultCode(), LDAPResultCode.SUCCESS);
}
@@ -702,9 +830,21 @@
internalSearch.run();
- // It will be successful because it's not a critical control.
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);
@@ -718,8 +858,9 @@
}
assertNotNull(vlvResponse);
- assertEquals(vlvResponse.getVLVResultCode(),
- LDAPResultCode.OFFSET_RANGE_ERROR);
+ assertEquals(vlvResponse.getVLVResultCode(), LDAPResultCode.SUCCESS);
+ assertEquals(vlvResponse.getTargetPosition(), 10);
+ assertEquals(vlvResponse.getContentCount(), 9);
}
@@ -1164,7 +1305,9 @@
assertNotNull(vlvResponse);
assertEquals(vlvResponse.getVLVResultCode(),
- LDAPResultCode.OFFSET_RANGE_ERROR);
+ LDAPResultCode.SUCCESS);
+ assertEquals(vlvResponse.getTargetPosition(), 10);
+ assertEquals(vlvResponse.getContentCount(), 9);
}
}
--
Gitblit v1.10.0