From 97a278742576929ec8c6e63d570a1cc00f38c543 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Mon, 05 Feb 2007 04:13:38 +0000
Subject: [PATCH] Update the ldapsearch tool to provide support for using the simple paged results control.

---
 opendj-sdk/opends/src/server/org/opends/server/tools/LDAPSearch.java                                 |  111 ++++++++++++++++++++++++++-
 opendj-sdk/opends/src/server/org/opends/server/tools/LDAPToolOptions.java                            |   12 ++
 opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java                            |   53 +++++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java |   57 ++++++++++++++
 4 files changed, 224 insertions(+), 9 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index 0244cc9..37731ce 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7518,6 +7518,47 @@
 
 
   /**
+   * The message ID for the message that will be used as the description for the
+   * command-line option that includes the simple paged results control in the
+   * request.  This does not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_SIMPLE_PAGE_SIZE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 790;
+
+
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * use the simple paged results control in conjunction with multiple search
+   * filters.  This does not take any arguments.
+   */
+  public static final int MSGID_PAGED_RESULTS_REQUIRES_SINGLE_FILTER =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 791;
+
+
+
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * attempting to decode the simple paged results response control from the
+   * server.  This takes a single argument, which is a message explaining the
+   * problem that occurred.
+   */
+  public static final int MSGID_PAGED_RESULTS_CANNOT_DECODE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 792;
+
+
+
+  /**
+   * The message ID for the message that will be used if the simple paged
+   * results control is not found in the response from the server.  This does
+   * not take any arguments.
+   */
+  public static final int MSGID_PAGED_RESULTS_RESPONSE_NOT_FOUND =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 793;
+
+
+
+  /**
    * Associates a set of generic messages with the message IDs defined in this
    * class.
    */
@@ -7949,6 +7990,9 @@
                     "authorization ID");
     registerMessage(MSGID_DESCRIPTION_PSEARCH_INFO,
                     "Use the persistent search control");
+    registerMessage(MSGID_DESCRIPTION_SIMPLE_PAGE_SIZE,
+                    "Use the simple paged results control with the given " +
+                    "page size");
     registerMessage(MSGID_DESCRIPTION_REPORT_AUTHZID,
                     "Use the authorization identity control");
     registerMessage(MSGID_DESCRIPTION_USE_PWP_CONTROL,
@@ -8279,6 +8323,15 @@
                     "Invalid scope %s specified for the search request.");
     registerMessage(MSGID_SEARCH_NO_FILTERS,
                     "No filters specified for the search request.");
+    registerMessage(MSGID_PAGED_RESULTS_REQUIRES_SINGLE_FILTER,
+                    "The simple paged results control may only be used with " +
+                    "a single search filter.");
+    registerMessage(MSGID_PAGED_RESULTS_CANNOT_DECODE,
+                    "Unable to decode the simple paged results control from " +
+                    "the search response:  %s.");
+    registerMessage(MSGID_PAGED_RESULTS_RESPONSE_NOT_FOUND,
+                    "The simple paged results response control was not found " +
+                    "in the search result done message from the server.");
     registerMessage(MSGID_PSEARCH_MISSING_DESCRIPTOR,
                     "The request to use the persistent search control did " +
                     "not include a descriptor that indicates the options to " +
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPSearch.java b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPSearch.java
index fd9a4ad..cfde1b7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPSearch.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
 
@@ -42,6 +42,7 @@
 import org.opends.server.controls.EntryChangeNotificationControl;
 import org.opends.server.controls.MatchedValuesControl;
 import org.opends.server.controls.MatchedValuesFilter;
+import org.opends.server.controls.PagedResultsControl;
 import org.opends.server.controls.PersistentSearchChangeType;
 import org.opends.server.controls.PersistentSearchControl;
 import org.opends.server.core.DirectoryServer;
@@ -93,6 +94,9 @@
 
 
 
+  // The set of response controls for the search.
+  private ArrayList<LDAPControl> responseControls;
+
   // The message ID counter to use for requests.
   private AtomicInteger nextMessageID;
 
@@ -117,6 +121,7 @@
     this.nextMessageID = nextMessageID;
     this.out           = out;
     this.err           = err;
+    responseControls   = new ArrayList<LDAPControl>();
   }
 
 
@@ -175,14 +180,14 @@
           ASN1Element element = connection.getASN1Reader().readElement();
           LDAPMessage responseMessage =
                LDAPMessage.decode(ASN1Sequence.decodeAsSequence(element));
-          ArrayList<LDAPControl> controls = responseMessage.getControls();
+          responseControls = responseMessage.getControls();
 
 
           opType = responseMessage.getProtocolOpType();
           switch(opType)
           {
             case OP_TYPE_SEARCH_RESULT_ENTRY:
-              for (LDAPControl c : controls)
+              for (LDAPControl c : responseControls)
               {
                 if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION))
                 {
@@ -287,6 +292,7 @@
                    responseMessage.getSearchResultDoneProtocolOp();
               resultCode = searchOp.getResultCode();
               errorMessage = searchOp.getErrorMessage();
+
               break;
             default:
               // FIXME - throw exception?
@@ -462,6 +468,18 @@
   }
 
   /**
+   * Retrieves the set of response controls included in the last search result
+   * done message.
+   *
+   * @return  The set of response controls included in the last search result
+   *          done message.
+   */
+  public ArrayList<LDAPControl> getResponseControls()
+  {
+    return responseControls;
+  }
+
+  /**
    * The main method for LDAPSearch tool.
    *
    * @param  args  The command-line arguments provided to this program.
@@ -554,6 +572,7 @@
     FileBasedArgument keyStorePasswordFile     = null;
     FileBasedArgument trustStorePasswordFile   = null;
     IntegerArgument   port                     = null;
+    IntegerArgument   simplePageSize           = null;
     IntegerArgument   sizeLimit                = null;
     IntegerArgument   timeLimit                = null;
     IntegerArgument   version                  = null;
@@ -706,6 +725,13 @@
                               null, null, MSGID_DESCRIPTION_PSEARCH_INFO);
       argParser.addArgument(pSearchInfo);
 
+      simplePageSize = new IntegerArgument("simplepagesize", null,
+                                           "simplePageSize", false, false, true,
+                                           "{numEntries}", 1000, null, true, 1,
+                                           false, 0,
+                                           MSGID_DESCRIPTION_SIMPLE_PAGE_SIZE);
+      argParser.addArgument(simplePageSize);
+
       assertionFilter = new StringArgument("assertionfilter", null,
                                            "assertionFilter", false, false,
                                            true, "{filter}", null, null,
@@ -1297,10 +1323,81 @@
                                       connectionOptions, out, err);
       connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
 
-      LDAPSearch ldapSearch = new LDAPSearch(nextMessageID, out, err);
-      int matchingEntries = ldapSearch.executeSearch(connection, baseDNValue,
-                                                     filters, attributes,
-                                                     searchOptions, wrapColumn);
+      int matchingEntries = 0;
+      if (simplePageSize.isPresent())
+      {
+        if (filters.size() > 1)
+        {
+          int    msgID   = MSGID_PAGED_RESULTS_REQUIRES_SINGLE_FILTER;
+          String message = getMessage(msgID);
+          throw new LDAPException(CLIENT_SIDE_PARAM_ERROR, msgID, message);
+        }
+
+        int pageSize = simplePageSize.getIntValue();
+        ASN1OctetString cookieValue = new ASN1OctetString();
+        ArrayList<LDAPControl> origControls = searchOptions.getControls();
+
+        while (true)
+        {
+          ArrayList<LDAPControl> newControls =
+               new ArrayList<LDAPControl>(origControls.size()+1);
+          newControls.addAll(origControls);
+          newControls.add(new LDAPControl(
+               new PagedResultsControl(true, pageSize, cookieValue)));
+          searchOptions.setControls(newControls);
+
+          LDAPSearch ldapSearch = new LDAPSearch(nextMessageID, out, err);
+          matchingEntries += ldapSearch.executeSearch(connection, baseDNValue,
+                                                      filters, attributes,
+                                                      searchOptions,
+                                                      wrapColumn);
+
+          ArrayList<LDAPControl> responseControls =
+               ldapSearch.getResponseControls();
+          boolean responseFound = false;
+          for (LDAPControl c  :responseControls)
+          {
+            if (c.getOID().equals(OID_PAGED_RESULTS_CONTROL))
+            {
+              try
+              {
+                PagedResultsControl control =
+                     new PagedResultsControl(c.isCritical(), c.getValue());
+                responseFound = true;
+                cookieValue = control.getCookie();
+                break;
+              }
+              catch (LDAPException le)
+              {
+                int    msgID   = MSGID_PAGED_RESULTS_CANNOT_DECODE;
+                String message = getMessage(msgID, le.getMessage());
+                throw new LDAPException(CLIENT_SIDE_DECODING_ERROR, msgID,
+                                        message, le);
+              }
+            }
+          }
+
+          if (! responseFound)
+          {
+            int msgID = MSGID_PAGED_RESULTS_RESPONSE_NOT_FOUND;
+            String message = getMessage(msgID);
+            throw new LDAPException(CLIENT_SIDE_CONTROL_NOT_FOUND, msgID,
+                                    message);
+          }
+          else if (cookieValue.value().length == 0)
+          {
+            break;
+          }
+        }
+      }
+      else
+      {
+        LDAPSearch ldapSearch = new LDAPSearch(nextMessageID, out, err);
+        matchingEntries = ldapSearch.executeSearch(connection, baseDNValue,
+                                                   filters, attributes,
+                                                   searchOptions, wrapColumn);
+      }
+
       if (countEntries.isPresent())
       {
         return matchingEntries;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPToolOptions.java b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
index 1fdda1f..5a9165f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
 
@@ -141,6 +141,16 @@
   }
 
   /**
+   * Specifies the set of controls to apply to the operation.
+   *
+   * @param  controls  The set of controls to apply to the operation.
+   */
+  public void setControls(ArrayList<LDAPControl> controls)
+  {
+    this.controls = controls;
+  }
+
+  /**
    * Set the encoding.
    *
    * @param  encodingStr  The encoding to use for string values.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java
index 46f47aa..522bf5a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPSearchTestCase.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
 
@@ -1471,6 +1471,61 @@
 
 
   /**
+   * Tests the use of the simple paged results control.
+   *
+   * @throws  Exception  If an unexpectd problem occurs.
+   */
+  @Test()
+  public void testSimplePagedResults()
+         throws Exception
+  {
+    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
+
+    TestCaseUtils.addEntries(
+      "dn: cn=device 1,dc=example,dc=com",
+      "objectClass: top",
+      "objectClass: device",
+      "cn: device 1",
+      "",
+      "dn: cn=device 2,dc=example,dc=com",
+      "objectClass: top",
+      "objectClass: device",
+      "cn: device 2",
+      "",
+      "dn: cn=device 3,dc=example,dc=com",
+      "objectClass: top",
+      "objectClass: device",
+      "cn: device 3",
+      "",
+      "dn: cn=device 4,dc=example,dc=com",
+      "objectClass: top",
+      "objectClass: device",
+      "cn: device 4",
+      "",
+      "dn: cn=device 5,dc=example,dc=com",
+      "objectClass: top",
+      "objectClass: device",
+      "cn: device 5");
+
+    String[] args =
+    {
+      "-h", "127.0.0.1",
+      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+      "-D", "cn=Directory Manager",
+      "-w", "password",
+      "-b", "dc=example,dc=com",
+      "-s", "one",
+      "--simplePageSize", "2",
+      "--countEntries",
+      "(objectClass=*)"
+    };
+
+    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 5);
+  }
+
+
+
+  /**
    * Tests the LDAPSearch tool with the "--help" option.
    */
   @Test()

--
Gitblit v1.10.0