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 " + 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; 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. 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()