Revision: 1534
http://sourceforge.net/p/ldap-sdk/code/1534
Author: dirmgr
Date: 2022-04-04 23:23:00 +0000 (Mon, 04 Apr 2022)
Log Message:
-----------
JSON control support for ldapsearch & ldapmodify
Updated the ldapsearch and ldapmodify command-line tools to add
support for JSON-formatted request and response controls. If the
--useJSONFormattedRequestControls argument is provided, requests
sent to the server will include a JSON-formatted request control
with appropriate encodings for any other request controls to be
included in the request. Any JSON-formatted response control
received from the server will automatically have its embedded
controls extracted and processed as if they had been returned with
their regular LDAP encodings.
Modified Paths:
--------------
trunk/docs/release-notes.html
trunk/messages/unboundid-ldapsdk-tools.properties
trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModify.java
trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearch.java
trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtils.java
trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModifyTestCase.java
trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearchTestCase.java
trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtilsTestCase.java
Modified: trunk/docs/release-notes.html
===================================================================
--- trunk/docs/release-notes.html 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/docs/release-notes.html 2022-04-04 23:23:00 UTC (rev 1534)
@@ -40,6 +40,18 @@
</li>
<li>
+ Updated the ldapsearch and ldapmodify command-line tools to add support for
+ JSON-formatted request and response controls. If the
+ --useJSONFormattedRequestControls argument is provided, requests sent to the
+ server will include a JSON-formatted request control with appropriate encodings
+ for any other request controls to be included in the request. Any
+ JSON-formatted response control received from the server will automatically have
+ its embedded controls extracted and processed as if they had been returned with
+ their regular LDAP encodings.
+ <br><br>
+ </li>
+
+ <li>
Fixed an issue with the way the parallel-update tool created assured replication
request controls when an explicit local or remote assurance level was specified.
Previously, it would only specify a minimum assurance level without specifying a
Modified: trunk/messages/unboundid-ldapsdk-tools.properties
===================================================================
--- trunk/messages/unboundid-ldapsdk-tools.properties 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/messages/unboundid-ldapsdk-tools.properties 2022-04-04 23:23:00 UTC (rev 1534)
@@ -1059,6 +1059,8 @@
INFO_RESULT_UTILS_JOIN_MATCHED_DN=Join Matched DN: {0}
INFO_RESULT_UTILS_JOIN_REFERRAL_URL=Join Referral URL: {0}
INFO_RESULT_UTILS_JOINED_WITH_ENTRY_HEADER=Joined With Entry:
+INFO_RESULT_UTILS_JSON_FORMATTED_HEADER=JSON-Formatted Response Control:
+INFO_RESULT_UTILS_JSON_FORMATTED_EMBEDDED_CONTROL_HEADER=Embedded Control JSON:
INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_HEADER=Matching Entry Count Response \
Control:
INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_TYPE_EXAMINED=Count Type: Examined
@@ -2140,6 +2142,12 @@
search operation even if it cannot do so efficiently using server indexes. \
The requester must have either the unindexed-search or \
unindexed-search-with-control privilege.
+INFO_LDAPSEARCH_ARG_DESCRIPTION_USE_JSON_FORMATTED_CONTROLS=Indicates that \
+ any request controls should be encapsulated in a JSON-formatted request \
+ control. Even if there wouldn''t otherwise be any request controls, an \
+ empty JSON-formatted request control will be included to indicate that the \
+ server should encapsulate any response controls in a JSON-formatted \
+ response control.
INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_ATTRIBUTE=Specifies the name or OID \
of an attribute that should be excluded from search result entries. This \
argument may be provided multiple times to specify multiple attributes to \
@@ -3978,6 +3986,12 @@
all modify requests.
INFO_PARALLEL_UPDATE_ARG_DESC_MODIFY_DN_CONTROL=Include the specified control \
in all modify DN requests.
+INFO_LDAPMODIFY_ARG_DESCRIPTION_USE_JSON_FORMATTED_CONTROLS=Indicates that \
+ any request controls should be encapsulated in a JSON-formatted request \
+ control. Even if there wouldn''t otherwise be any request controls, an \
+ empty JSON-formatted request control will be included to indicate that the \
+ server should encapsulate any response controls in a JSON-formatted \
+ response control.
ERR_PARALLEL_UPDATE_CANNOT_CREATE_POOL=ERROR: Unable to create the \
connection pool to use for processing requests: {0}
ERR_PARALLEL_UPDATE_ERROR_CREATING_LOG_WRITER=ERROR: Unable to create the \
Modified: trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModify.java
===================================================================
--- trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModify.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModify.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -112,6 +112,10 @@
import com.unboundid.ldap.sdk.unboundidds.controls.
IgnoreNoUserModificationRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
+ JSONFormattedControlDecodeBehavior;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedRequestControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.
NameWithEntryUUIDRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.NoOpRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
@@ -315,6 +319,7 @@
@Nullable private BooleanArgument serverSideSubtreeDelete = null;
@Nullable private BooleanArgument suppressReferentialIntegrityUpdates = null;
@Nullable private BooleanArgument useAdministrativeSession = null;
+ @Nullable private BooleanArgument useJSONFormattedRequestControls = null;
@Nullable private BooleanArgument usePasswordPolicyControl = null;
@Nullable private BooleanArgument useTransaction = null;
@Nullable private BooleanArgument verbose = null;
@@ -1282,6 +1287,20 @@
parser.addArgument(modifyDNControl);
+ useJSONFormattedRequestControls = new BooleanArgument(null,
+ "useJSONFormattedRequestControls", 1,
+ INFO_LDAPMODIFY_ARG_DESCRIPTION_USE_JSON_FORMATTED_CONTROLS.get());
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "use-json-formatted-request-controls", true);
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "useJSONFormattedControls", true);
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "use-json-formatted-controls", true);
+ useJSONFormattedRequestControls.setArgumentGroupName(
+ INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
+ parser.addArgument(useJSONFormattedRequestControls);
+
+
ratePerSecond = new IntegerArgument('r', "ratePerSecond", false, 1,
INFO_PLACEHOLDER_NUM.get(),
INFO_LDAPMODIFY_ARG_DESCRIPTION_RATE_PER_SECOND.get(), 1,
@@ -1593,6 +1612,14 @@
suppressTypes));
}
+ if (useJSONFormattedRequestControls.isPresent())
+ {
+ final JSONFormattedRequestControl jsonFormattedRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, bindControls);
+ bindControls.clear();
+ bindControls.add(jsonFormattedRequestControl);
+ }
+
return bindControls;
}
@@ -2612,7 +2639,9 @@
}
}
+ searchResult = LDAPSearch.handleJSONEncodedResponseControls(searchResult);
+
// If we've gotten here, then the search was successful. Check to see if
// any of the modifications failed, and if so then update the result code
// accordingly.
@@ -3245,6 +3274,36 @@
modifyControls.add(c);
modifyDNControls.add(c);
}
+
+
+ if (useJSONFormattedRequestControls.isPresent())
+ {
+ final JSONFormattedRequestControl jsonFormattedAddRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, addControls);
+ addControls.clear();
+ addControls.add(jsonFormattedAddRequestControl);
+
+ final JSONFormattedRequestControl jsonFormattedDeleteRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, deleteControls);
+ deleteControls.clear();
+ deleteControls.add(jsonFormattedDeleteRequestControl);
+
+ final JSONFormattedRequestControl jsonFormattedModifyRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, modifyControls);
+ modifyControls.clear();
+ modifyControls.add(jsonFormattedModifyRequestControl);
+
+ final JSONFormattedRequestControl jsonFormattedModifyDNRequestControl =
+ JSONFormattedRequestControl.createWithControls(true,
+ modifyDNControls);
+ modifyDNControls.clear();
+ modifyDNControls.add(jsonFormattedModifyDNRequestControl);
+
+ final JSONFormattedRequestControl jsonFormattedSearchRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, searchControls);
+ searchControls.clear();
+ searchControls.add(jsonFormattedSearchRequestControl);
+ }
}
@@ -3514,7 +3573,9 @@
addResult = le.toLDAPResult();
}
+ addResult = handleJSONEncodedResponseControls(addResult);
+
// Display information about the result.
displayResult(addResult, useTransaction.isPresent());
@@ -3641,7 +3702,9 @@
deleteResult = le.toLDAPResult();
}
+ deleteResult = handleJSONEncodedResponseControls(deleteResult);
+
// Display information about the result.
displayResult(deleteResult, useTransaction.isPresent());
@@ -3727,7 +3790,7 @@
// Evaluate the result of the subtree delete.
- final LDAPResult finalResult;
+ LDAPResult finalResult;
if (subtreeDeleterResult.completelySuccessful())
{
final long entriesDeleted = subtreeDeleterResult.getEntriesDeleted();
@@ -3828,7 +3891,9 @@
StaticUtils.NO_STRINGS, StaticUtils.NO_CONTROLS);
}
+ finalResult = handleJSONEncodedResponseControls(finalResult);
+
// Display information about the final result.
displayResult(finalResult, useTransaction.isPresent());
@@ -3969,7 +4034,9 @@
modifyResult = le.toLDAPResult();
}
+ modifyResult = handleJSONEncodedResponseControls(modifyResult);
+
// Display information about the result.
displayResult(modifyResult, useTransaction.isPresent());
@@ -4156,7 +4223,9 @@
modifyDNResult = le.toLDAPResult();
}
+ modifyDNResult = handleJSONEncodedResponseControls(modifyDNResult);
+
// Display information about the result.
displayResult(modifyDNResult, useTransaction.isPresent());
@@ -4382,6 +4451,62 @@
/**
+ * Examines the provided LDAP result to see if it includes a JSONf-formatted
+ * response control. If so, then its embedded controls will be extracted and
+ * a new LDAP result will be returned with those extracted controls instead
+ * of the JSON-formatted response control. Otherwise, the provided LDAP
+ * result will be returned.
+ *
+ * @param ldapResult The LDAP result to be handled. It must not be
+ * {@code null}.
+ *
+ * @return A new LDAP result with the controls extracted from a
+ * JSON-formatted response control, or the original LDAP result if
+ * it did not include a JSON-formatted response control.
+ */
+ @NotNull()
+ static LDAPResult handleJSONEncodedResponseControls(
+ @NotNull final LDAPResult ldapResult)
+ {
+ try
+ {
+ final JSONFormattedResponseControl jsonFormattedResponseControl =
+ JSONFormattedResponseControl.get(ldapResult);
+ if (jsonFormattedResponseControl == null)
+ {
+ return ldapResult;
+ }
+
+ final JSONFormattedControlDecodeBehavior decodeBehavior =
+ new JSONFormattedControlDecodeBehavior();
+ decodeBehavior.setThrowOnUnparsableObject(false);
+ decodeBehavior.setThrowOnInvalidCriticalControl(false);
+ decodeBehavior.setThrowOnInvalidNonCriticalControl(false);
+ decodeBehavior.setThrowOnInvalidNonCriticalControl(false);
+ decodeBehavior.setAllowEmbeddedJSONFormattedControl(true);
+ decodeBehavior.setStrict(false);
+
+ final List<Control> decodedControls =
+ jsonFormattedResponseControl.decodeEmbeddedControls(
+ decodeBehavior, null);
+
+ return new LDAPResult(ldapResult.getMessageID(),
+ ldapResult.getResultCode(),
+ ldapResult.getDiagnosticMessage(),
+ ldapResult.getMatchedDN(),
+ ldapResult.getReferralURLs(),
+ StaticUtils.toArray(decodedControls, Control.class));
+ }
+ catch (final LDAPException e)
+ {
+ Debug.debugException(e);
+ return ldapResult;
+ }
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override()
Modified: trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearch.java
===================================================================
--- trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearch.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearch.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -111,6 +111,10 @@
import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
GetUserResourceLimitsRequestControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.
+ JSONFormattedControlDecodeBehavior;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedRequestControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinBaseDN;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestValue;
@@ -234,6 +238,7 @@
@Nullable private BooleanArgument suppressBase64EncodedValueComments = null;
@Nullable private BooleanArgument teeResultsToStandardOut = null;
@Nullable private BooleanArgument useAdministrativeSession = null;
+ @Nullable private BooleanArgument useJSONFormattedRequestControls = null;
@Nullable private BooleanArgument usePasswordPolicyControl = null;
@Nullable private BooleanArgument terse = null;
@Nullable private BooleanArgument typesOnly = null;
@@ -1177,6 +1182,19 @@
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(virtualListView);
+ useJSONFormattedRequestControls = new BooleanArgument(null,
+ "useJSONFormattedRequestControls", 1,
+ INFO_LDAPSEARCH_ARG_DESCRIPTION_USE_JSON_FORMATTED_CONTROLS.get());
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "use-json-formatted-request-controls", true);
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "useJSONFormattedControls", true);
+ useJSONFormattedRequestControls.addLongIdentifier(
+ "use-json-formatted-controls", true);
+ useJSONFormattedRequestControls.setArgumentGroupName(
+ INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
+ parser.addArgument(useJSONFormattedRequestControls);
+
excludeAttribute = new StringArgument(null, "excludeAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_ATTRIBUTE.get());
@@ -1458,6 +1476,14 @@
suppressTypes));
}
+ if (useJSONFormattedRequestControls.isPresent())
+ {
+ final JSONFormattedRequestControl jsonFormattedRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, bindControls);
+ bindControls.clear();
+ bindControls.add(jsonFormattedRequestControl);
+ }
+
return bindControls;
}
@@ -3008,6 +3034,8 @@
searchResult = pool.search(searchRequest);
}
+ searchResult = handleJSONEncodedResponseControls(searchResult);
+
if (searchResult.getEntryCount() > 0)
{
totalEntries += searchResult.getEntryCount();
@@ -3365,6 +3393,14 @@
controls.add(new PermitUnindexedSearchRequestControl());
}
+ if (useJSONFormattedRequestControls.isPresent())
+ {
+ final JSONFormattedRequestControl jsonFormattedRequestControl =
+ JSONFormattedRequestControl.createWithControls(true, controls);
+ controls.clear();
+ controls.add(jsonFormattedRequestControl);
+ }
+
return controls;
}
@@ -3525,6 +3561,66 @@
/**
+ * Examines the provided search result to see if it includes a JSONf-formatted
+ * response control. If so, then its embedded controls will be extracted and
+ * a new search result will be returned with those extracted controls instead
+ * of the JSON-formatted response control. Otherwise, the provided search
+ * result will be returned.
+ *
+ * @param searchResult The search result to be handled. It must not be
+ * {@code null}.
+ *
+ * @return A new search result with the controls extracted from a
+ * JSON-formatted response control, or the original search result if
+ * it did not include a JSON-formatted response control.
+ */
+ @NotNull()
+ static SearchResult handleJSONEncodedResponseControls(
+ @NotNull final SearchResult searchResult)
+ {
+ try
+ {
+ final JSONFormattedResponseControl jsonFormattedResponseControl =
+ JSONFormattedResponseControl.get(searchResult);
+ if (jsonFormattedResponseControl == null)
+ {
+ return searchResult;
+ }
+
+ final JSONFormattedControlDecodeBehavior decodeBehavior =
+ new JSONFormattedControlDecodeBehavior();
+ decodeBehavior.setThrowOnUnparsableObject(false);
+ decodeBehavior.setThrowOnInvalidCriticalControl(false);
+ decodeBehavior.setThrowOnInvalidNonCriticalControl(false);
+ decodeBehavior.setThrowOnInvalidNonCriticalControl(false);
+ decodeBehavior.setAllowEmbeddedJSONFormattedControl(true);
+ decodeBehavior.setStrict(false);
+
+ final List<Control> decodedControls =
+ jsonFormattedResponseControl.decodeEmbeddedControls(
+ decodeBehavior, null);
+
+ return new SearchResult(searchResult.getMessageID(),
+ searchResult.getResultCode(),
+ searchResult.getDiagnosticMessage(),
+ searchResult.getMatchedDN(),
+ searchResult.getReferralURLs(),
+ searchResult.getSearchEntries(),
+ searchResult.getSearchReferences(),
+ searchResult.getEntryCount(),
+ searchResult.getReferenceCount(),
+ StaticUtils.toArray(decodedControls, Control.class));
+ }
+ catch (final LDAPException e)
+ {
+ Debug.debugException(e);
+ return searchResult;
+ }
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override()
Modified: trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtils.java
===================================================================
--- trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtils.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtils.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -102,6 +102,7 @@
IntermediateClientResponseValue;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinedEntry;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinResultControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
MatchingEntryCountResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyErrorType;
@@ -133,6 +134,7 @@
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
+import com.unboundid.util.json.JSONObject;
import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;
@@ -813,6 +815,11 @@
{
addJoinResultControl(lines, c, prefix, maxWidth);
}
+ else if (oid.equals(
+ JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID))
+ {
+ addJSONFormattedResponseControl(lines, c, prefix, maxWidth);
+ }
else if (oid.equals(MatchingEntryCountResponseControl.
MATCHING_ENTRY_COUNT_RESPONSE_OID))
{
@@ -2568,6 +2575,58 @@
/**
* Adds a multi-line string representation of the provided control, which is
+ * expected to be a JSON-formatted response control, to the given list.
+ *
+ * @param lines The list to which the lines should be added.
+ * @param c The control to be formatted.
+ * @param prefix The prefix to use for each line.
+ * @param maxWidth The maximum length of each line in characters, including
+ * the comment prefix and indent.
+ */
+ private static void addJSONFormattedResponseControl(
+ @NotNull final List<String> lines,
+ @NotNull final Control c,
+ @NotNull final String prefix,
+ final int maxWidth)
+ {
+ final JSONFormattedResponseControl decoded;
+ try
+ {
+ decoded = new JSONFormattedResponseControl(c.getOID(), c.isCritical(),
+ c.getValue());
+ }
+ catch (final Exception e)
+ {
+ Debug.debugException(e);
+ addGenericResponseControl(lines, c, prefix, maxWidth);
+ return;
+ }
+
+ wrap(lines, INFO_RESULT_UTILS_JSON_FORMATTED_HEADER.get(), prefix,
+ maxWidth);
+
+ final String indentPrefix = prefix + " ";
+ final String doubleIndentPrefix = indentPrefix + " ";
+ wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
+ indentPrefix, maxWidth);
+
+ for (final JSONObject responseControlObject : decoded.getControlObjects())
+ {
+ wrap(lines,
+ INFO_RESULT_UTILS_JSON_FORMATTED_EMBEDDED_CONTROL_HEADER.get(),
+ indentPrefix, maxWidth);
+ for (final String jsonLine :
+ StaticUtils.stringToLines(responseControlObject.toMultiLineString()))
+ {
+ lines.add(doubleIndentPrefix + jsonLine);
+ }
+ }
+ }
+
+
+
+ /**
+ * Adds a multi-line string representation of the provided control, which is
* expected to be a matching entry count response control, to the given list.
*
* @param lines The list to which the lines should be added.
Modified: trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModifyTestCase.java
===================================================================
--- trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModifyTestCase.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModifyTestCase.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -48,15 +48,20 @@
import org.testng.annotations.Test;
+import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSDKTestCase;
import com.unboundid.ldap.sdk.OperationType;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.extensions.NoticeOfDisconnectionExtendedResult;
+import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDResponseControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
PasswordUpdateBehaviorRequestControl;
import com.unboundid.ldap.sdk.unboundidds.extensions.
@@ -1866,7 +1871,8 @@
"--usePasswordPolicyControl",
"--suppressOperationalAttributeUpdates", "last-access-time",
"--suppressOperationalAttributeUpdates", "last-login-time",
- "--suppressOperationalAttributeUpdates", "last-login-ip");
+ "--suppressOperationalAttributeUpdates", "last-login-ip",
+ "--useJSONFormattedRequestControls");
}
@@ -1915,7 +1921,8 @@
"--replicationRepair",
"--operationPurpose", "testAddControls",
"--getPasswordValidationDetails",
- "--allowUndelete");
+ "--allowUndelete",
+ "--useJSONFormattedRequestControls");
}
@@ -1956,7 +1963,8 @@
"--replicationRepair",
"--hardDelete",
"--serverSideSubtreeDelete",
- "--operationPurpose", "testAddControls");
+ "--operationPurpose", "testAddControls",
+ "--useJSONFormattedRequestControls");
}
@@ -1999,7 +2007,8 @@
"--softDelete",
"--operationPurpose", "testAddControls",
"--retireCurrentPassword",
- "--getPasswordValidationDetails");
+ "--getPasswordValidationDetails",
+ "--useJSONFormattedRequestControls");
in = getInputStream(
@@ -2053,7 +2062,8 @@
"--assuredReplicationRemoteLevel", "processed-all-remote-servers",
"--assuredReplicationTimeout", "30s",
"--replicationRepair",
- "--operationPurpose", "testAddControls");
+ "--operationPurpose", "testAddControls",
+ "--useJSONFormattedRequestControls");
}
@@ -3220,4 +3230,182 @@
"--routeToBackendSet", "malformed",
"--ldifFile", ldifFile.getAbsolutePath());
}
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for an LDAP result that does not have any controls.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsNoControls()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final LDAPResult originalResult = new LDAPResult(1, ResultCode.SUCCESS,
+ "diagnosticMessage", "dc=matched,dc=dn", referralURLs,
+ StaticUtils.NO_CONTROLS);
+
+ final LDAPResult processedResult =
+ LDAPModify.handleJSONEncodedResponseControls(originalResult);
+
+ assertNotNull(processedResult);
+
+ assertEquals(processedResult.getMessageID(), 1);
+
+ assertEquals(processedResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedResult.getDiagnosticMessage(), "diagnosticMessage");
+
+ assertEquals(processedResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedResult.getResponseControls().length, 0);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for an LDAP result that includes a control that isn't a JSON-formatted
+ * response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsNonJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final LDAPResult originalResult = new LDAPResult(1, ResultCode.SUCCESS,
+ "diagnosticMessage", "dc=matched,dc=dn", referralURLs,
+ new Control[] { new GetServerIDResponseControl("serverID") });
+
+ final LDAPResult processedResult =
+ LDAPModify.handleJSONEncodedResponseControls(originalResult);
+
+ assertNotNull(processedResult);
+
+ assertEquals(processedResult.getMessageID(), 1);
+
+ assertEquals(processedResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedResult.getDiagnosticMessage(), "diagnosticMessage");
+
+ assertEquals(processedResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedResult.getResponseControls()[0].getOID(),
+ GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for an LDAP result that includes a control that is a valid JSON-formatted
+ * response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsValidJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final Control[] originalResponseControls =
+ {
+ JSONFormattedResponseControl.createWithControls(
+ new GetServerIDResponseControl("serverID"))
+ };
+
+ final LDAPResult originalResult = new LDAPResult(1, ResultCode.SUCCESS,
+ "diagnosticMessage", "dc=matched,dc=dn", referralURLs,
+ originalResponseControls);
+
+ final LDAPResult processedResult =
+ LDAPModify.handleJSONEncodedResponseControls(originalResult);
+
+ assertNotNull(processedResult);
+
+ assertEquals(processedResult.getMessageID(), 1);
+
+ assertEquals(processedResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedResult.getDiagnosticMessage(), "diagnosticMessage");
+
+ assertEquals(processedResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedResult.getResponseControls()[0].getOID(),
+ GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for an LDAP result that includes a control that is a malformed
+ * JSON-formatted response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsInvalidJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final Control[] originalResponseControls =
+ {
+ new Control(JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID,
+ false, new ASN1OctetString("this is a malformed value"))
+ };
+
+ final LDAPResult originalResult = new LDAPResult(1, ResultCode.SUCCESS,
+ "diagnosticMessage", "dc=matched,dc=dn", referralURLs,
+ originalResponseControls);
+
+ final LDAPResult processedResult =
+ LDAPModify.handleJSONEncodedResponseControls(originalResult);
+
+ assertNotNull(processedResult);
+
+ assertEquals(processedResult.getMessageID(), 1);
+
+ assertEquals(processedResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedResult.getDiagnosticMessage(), "diagnosticMessage");
+
+ assertEquals(processedResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedResult.getResponseControls()[0].getOID(),
+ JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID);
+ }
}
Modified: trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearchTestCase.java
===================================================================
--- trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearchTestCase.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearchTestCase.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -50,15 +50,20 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DeleteRequest;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPSDKTestCase;
import com.unboundid.ldap.sdk.ResultCode;
+import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl;
import com.unboundid.ldap.sdk.extensions.NoticeOfDisconnectionExtendedResult;
+import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDResponseControl;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldif.LDIFReader;
import com.unboundid.util.PassphraseEncryptedInputStream;
import com.unboundid.util.PasswordReader;
@@ -452,6 +457,7 @@
"--suppressOperationalAttributeUpdates", "last-access-time",
"--suppressOperationalAttributeUpdates", "last-login-time",
"--suppressOperationalAttributeUpdates", "last-login-ip",
+ "--useJSONFormattedRequestControls",
"--dontWrap",
"--dereferencePolicy", "always",
"(objectClass=*)",
@@ -512,6 +518,7 @@
"--suppressOperationalAttributeUpdates", "lastmod",
"--realAttributesOnly",
"--rejectUnindexedSearch",
+ "--useJSONFormattedRequestControls",
"--wrapColumn", "0",
"--dereferencePolicy", "search",
"(objectClass=*)",
@@ -2522,4 +2529,209 @@
"(uid=nonexistent)");
assertEquals(resultCode, ResultCode.NO_RESULTS_RETURNED);
}
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for a search result that does not have any controls.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsNoControls()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final SearchResult originalSearchResult = new SearchResult(1,
+ ResultCode.SUCCESS, "diagnosticMessage", "dc=matched,dc=dn",
+ referralURLs, 1, 2, StaticUtils.NO_CONTROLS);
+
+ final SearchResult processedSearchResult =
+ LDAPSearch.handleJSONEncodedResponseControls(originalSearchResult);
+
+ assertNotNull(processedSearchResult);
+
+ assertEquals(processedSearchResult.getMessageID(), 1);
+
+ assertEquals(processedSearchResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedSearchResult.getDiagnosticMessage(),
+ "diagnosticMessage");
+
+ assertEquals(processedSearchResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedSearchResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedSearchResult.getEntryCount(), 1);
+
+ assertEquals(processedSearchResult.getReferenceCount(), 2);
+
+ assertEquals(processedSearchResult.getResponseControls().length, 0);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for a search result that includes a control that isn't a JSON-formatted
+ * response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsNonJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final SearchResult originalSearchResult = new SearchResult(1,
+ ResultCode.SUCCESS, "diagnosticMessage", "dc=matched,dc=dn",
+ referralURLs, 1, 2,
+ new Control[] { new GetServerIDResponseControl("serverID") });
+
+ final SearchResult processedSearchResult =
+ LDAPSearch.handleJSONEncodedResponseControls(originalSearchResult);
+
+ assertNotNull(processedSearchResult);
+
+ assertEquals(processedSearchResult.getMessageID(), 1);
+
+ assertEquals(processedSearchResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedSearchResult.getDiagnosticMessage(),
+ "diagnosticMessage");
+
+ assertEquals(processedSearchResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedSearchResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedSearchResult.getEntryCount(), 1);
+
+ assertEquals(processedSearchResult.getReferenceCount(), 2);
+
+ assertEquals(processedSearchResult.getResponseControls().length, 1);
+
+ assertEquals(processedSearchResult.getResponseControls()[0].getOID(),
+ GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for a search result that includes a control that is a valid JSON-formatted
+ * response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsValidJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final Control[] originalResponseControls =
+ {
+ JSONFormattedResponseControl.createWithControls(
+ new GetServerIDResponseControl("serverID"))
+ };
+
+ final SearchResult originalSearchResult = new SearchResult(1,
+ ResultCode.SUCCESS, "diagnosticMessage", "dc=matched,dc=dn",
+ referralURLs, 1, 2, originalResponseControls);
+
+ final SearchResult processedSearchResult =
+ LDAPSearch.handleJSONEncodedResponseControls(originalSearchResult);
+
+ assertNotNull(processedSearchResult);
+
+ assertEquals(processedSearchResult.getMessageID(), 1);
+
+ assertEquals(processedSearchResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedSearchResult.getDiagnosticMessage(),
+ "diagnosticMessage");
+
+ assertEquals(processedSearchResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedSearchResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedSearchResult.getEntryCount(), 1);
+
+ assertEquals(processedSearchResult.getReferenceCount(), 2);
+
+ assertEquals(processedSearchResult.getResponseControls().length, 1);
+
+ assertEquals(processedSearchResult.getResponseControls()[0].getOID(),
+ GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID);
+ }
+
+
+
+ /**
+ * Tests the behavior of the {@code handleJSONEncodedResponseControls} method
+ * for a search result that includes a control that is a malformed
+ * JSON-formatted response control.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testHandleJSONEncodedResponseControlsInvalidJSONFormattedControl()
+ throws Exception
+ {
+ final String[] referralURLs =
+ {
+ "ldap://ds1.example.com:389/",
+ "ldap://ds2.example.com:389/"
+ };
+
+ final Control[] originalResponseControls =
+ {
+ new Control(JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID,
+ false, new ASN1OctetString("this is a malformed value"))
+ };
+
+ final SearchResult originalSearchResult = new SearchResult(1,
+ ResultCode.SUCCESS, "diagnosticMessage", "dc=matched,dc=dn",
+ referralURLs, 1, 2, originalResponseControls);
+
+ final SearchResult processedSearchResult =
+ LDAPSearch.handleJSONEncodedResponseControls(originalSearchResult);
+
+ assertNotNull(processedSearchResult);
+
+ assertEquals(processedSearchResult.getMessageID(), 1);
+
+ assertEquals(processedSearchResult.getResultCode(), ResultCode.SUCCESS);
+
+ assertEquals(processedSearchResult.getDiagnosticMessage(),
+ "diagnosticMessage");
+
+ assertEquals(processedSearchResult.getMatchedDN(), "dc=matched,dc=dn");
+
+ assertEquals(processedSearchResult.getReferralURLs(), referralURLs);
+
+ assertEquals(processedSearchResult.getEntryCount(), 1);
+
+ assertEquals(processedSearchResult.getReferenceCount(), 2);
+
+ assertEquals(processedSearchResult.getResponseControls().length, 1);
+
+ assertEquals(processedSearchResult.getResponseControls()[0].getOID(),
+ JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID);
+ }
}
Modified: trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtilsTestCase.java
===================================================================
--- trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtilsTestCase.java 2022-04-04 14:57:54 UTC (rev 1533)
+++ trunk/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/ResultUtilsTestCase.java 2022-04-04 23:23:00 UTC (rev 1534)
@@ -106,6 +106,7 @@
IntermediateClientResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
IntermediateClientResponseValue;
+import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinedEntry;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinResultControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
@@ -1751,6 +1752,40 @@
});
+ // A valid JSON-formatted response control.
+ resultList.add(
+ new Object[]
+ {
+ JSONFormattedResponseControl.createWithControls(
+ new GetServerIDResponseControl("serverID")),
+ Arrays.asList(
+ "# JSON-Formatted Response Control:",
+ "# OID: " + JSONFormattedResponseControl.
+ JSON_FORMATTED_RESPONSE_OID,
+ "# Embedded Control JSON:",
+ "# { \"oid\":\"1.3.6.1.4.1.30221.2.5.15\",",
+ "# \"control-name\":" +
+ "\"Get Server ID Response Control\",",
+ "# \"criticality\":false,",
+ "# \"value-json\":{ \"server-id\":" +
+ "\"serverID\" } }")
+ });
+
+
+ // An invalid JSON-formatted control.
+ resultList.add(
+ new Object[]
+ {
+ new Control(
+ JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID),
+ Arrays.asList(
+ "# Response Control:",
+ "# OID: " + JSONFormattedResponseControl.
+ JSON_FORMATTED_RESPONSE_OID,
+ "# Is Critical: false")
+ });
+
+
// A valid matching entry count response control for an examined count.
resultList.add(
new Object[]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|