001/* 002 * Copyright 2017-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2017-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2017-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.controls; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.LinkedHashMap; 043import java.util.List; 044import java.util.Map; 045 046import com.unboundid.asn1.ASN1Boolean; 047import com.unboundid.asn1.ASN1Element; 048import com.unboundid.asn1.ASN1OctetString; 049import com.unboundid.asn1.ASN1Sequence; 050import com.unboundid.ldap.sdk.Control; 051import com.unboundid.ldap.sdk.DecodeableControl; 052import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 053import com.unboundid.ldap.sdk.LDAPException; 054import com.unboundid.ldap.sdk.LDAPResult; 055import com.unboundid.ldap.sdk.ResultCode; 056import com.unboundid.util.Debug; 057import com.unboundid.util.NotMutable; 058import com.unboundid.util.NotNull; 059import com.unboundid.util.Nullable; 060import com.unboundid.util.StaticUtils; 061import com.unboundid.util.ThreadSafety; 062import com.unboundid.util.ThreadSafetyLevel; 063import com.unboundid.util.Validator; 064import com.unboundid.util.json.JSONBoolean; 065import com.unboundid.util.json.JSONField; 066import com.unboundid.util.json.JSONObject; 067import com.unboundid.util.json.JSONString; 068import com.unboundid.util.json.JSONValue; 069 070import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 071 072 073 074/** 075 * This class provides a response control that may be included in the response 076 * to add, modify, and modify DN requests that included the 077 * {@link UniquenessRequestControl}. It provides information about the 078 * uniqueness processing that was performed. 079 * <BR> 080 * <BLOCKQUOTE> 081 * <B>NOTE:</B> This class, and other classes within the 082 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 083 * supported for use against Ping Identity, UnboundID, and 084 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 085 * for proprietary functionality or for external specifications that are not 086 * considered stable or mature enough to be guaranteed to work in an 087 * interoperable way with other types of LDAP servers. 088 * </BLOCKQUOTE> 089 * <BR> 090 * The control has an OID of 1.3.6.1.4.1.30221.2.5.53 and a criticality of 091 * false. It must have a value with the following encoding: 092 * <PRE> 093 * UniquenessResponseValue ::= SEQUENCE { 094 * uniquenessID [0] OCTET STRING, 095 * preCommitValidationPassed [1] BOOLEAN OPTIONAL, 096 * postCommitValidationPassed [2] BOOLEAN OPTIONAL, 097 * validationMessage [3] OCTET STRING OPTIONAL, 098 * ... } 099 * </PRE> 100 */ 101@NotMutable() 102@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 103public final class UniquenessResponseControl 104 extends Control 105 implements DecodeableControl 106{ 107 /** 108 * The OID (1.3.6.1.4.1.30221.2.5.53) for the uniqueness response control. 109 */ 110 @NotNull public static final String UNIQUENESS_RESPONSE_OID = 111 "1.3.6.1.4.1.30221.2.5.53"; 112 113 114 115 /** 116 * The BER type for the uniqueness ID element in the value sequence. 117 */ 118 private static final byte TYPE_UNIQUENESS_ID = (byte) 0x80; 119 120 121 122 /** 123 * The BER type for the pre-commit validation passed element in the value 124 * sequence. 125 */ 126 private static final byte TYPE_PRE_COMMIT_VALIDATION_PASSED = (byte) 0x81; 127 128 129 130 /** 131 * The BER type for the post-commit validation passed element in the value 132 * sequence. 133 */ 134 private static final byte TYPE_POST_COMMIT_VALIDATION_PASSED = (byte) 0x82; 135 136 137 138 /** 139 * The BER type for the validation message element in the value sequence. 140 */ 141 private static final byte TYPE_VALIDATION_MESSAGE = (byte) 0x83; 142 143 144 145 /** 146 * The name of the field used to hold the post-commit-validation-passed flag 147 * in the JSON representation of this control. 148 */ 149 @NotNull private static final String 150 JSON_FIELD_POST_COMMIT_VALIDATION_PASSED = 151 "post-commit-validation-passed"; 152 153 154 155 /** 156 * The name of the field used to hold the pre-commit-validation-passed flag in 157 * the JSON representation of this control. 158 */ 159 @NotNull private static final String JSON_FIELD_PRE_COMMIT_VALIDATION_PASSED = 160 "pre-commit-validation-passed"; 161 162 163 164 /** 165 * The name of the field used to hold the uniqueness ID in the JSON 166 * representation of this control. 167 */ 168 @NotNull private static final String JSON_FIELD_UNIQUENESS_ID = 169 "uniqueness-id"; 170 171 172 173 /** 174 * The name of the field used to hold the validation message in the JSON 175 * representation of this control. 176 */ 177 @NotNull private static final String JSON_FIELD_VALIDATION_MESSAGE = 178 "validation-message"; 179 180 181 182 /** 183 * The serial version UID for this serializable class. 184 */ 185 private static final long serialVersionUID = 5090348902351420617L; 186 187 188 189 // Indicates whether post-commit validation passed. 190 @Nullable private final Boolean postCommitValidationPassed; 191 192 // Indicates whether pre-commit validation passed. 193 @Nullable private final Boolean preCommitValidationPassed; 194 195 // A value that will be used to correlate this response control with its 196 // corresponding request control. 197 @NotNull private final String uniquenessID; 198 199 // The validation message, if any. 200 @Nullable private final String validationMessage; 201 202 203 204 /** 205 * Creates a new empty control instance that is intended to be used only for 206 * decoding controls via the {@code DecodeableControl} interface. 207 */ 208 UniquenessResponseControl() 209 { 210 uniquenessID = null; 211 preCommitValidationPassed = null; 212 postCommitValidationPassed = null; 213 validationMessage = null; 214 } 215 216 217 218 /** 219 * Creates a new uniqueness response control with the provided information. 220 * 221 * @param uniquenessID The uniqueness ID that may be used to 222 * correlate this uniqueness response 223 * control with the corresponding request 224 * control. This must not be 225 * {@code null}. 226 * @param preCommitValidationPassed Indicates whether the pre-commit 227 * validation was successful. This may be 228 * {@code null} if no pre-commit 229 * validation was attempted. 230 * @param postCommitValidationPassed Indicates whether the post-commit 231 * validation was successful. This may be 232 * {@code null} if no post-commit 233 * validation was attempted. 234 * @param validationMessage A message with additional information 235 * about the validation processing. This 236 * may be {@code null} if no validation 237 * message is needed. 238 */ 239 public UniquenessResponseControl(@NotNull final String uniquenessID, 240 @Nullable final Boolean preCommitValidationPassed, 241 @Nullable final Boolean postCommitValidationPassed, 242 @Nullable final String validationMessage) 243 { 244 super(UNIQUENESS_RESPONSE_OID, false, 245 encodeValue(uniquenessID, preCommitValidationPassed, 246 postCommitValidationPassed, validationMessage)); 247 248 Validator.ensureNotNull(uniquenessID); 249 250 this.uniquenessID = uniquenessID; 251 this.preCommitValidationPassed = preCommitValidationPassed; 252 this.postCommitValidationPassed = postCommitValidationPassed; 253 this.validationMessage = validationMessage; 254 } 255 256 257 258 /** 259 * Encodes the provided information into an ASN.1 octet string suitable for 260 * use as the value of this control. 261 * 262 * @param uniquenessID The uniqueness ID that may be used to 263 * correlate this uniqueness response 264 * control with the corresponding request 265 * control. This must not be 266 * {@code null}. 267 * @param preCommitValidationPassed Indicates whether the pre-commit 268 * validation was successful. This may be 269 * {@code null} if no pre-commit 270 * validation was attempted. 271 * @param postCommitValidationPassed Indicates whether the post-commit 272 * validation was successful. This may be 273 * {@code null} if no post-commit 274 * validation was attempted. 275 * @param validationMessage A message with additional information 276 * about the validation processing. This 277 * may be {@code null} if no validation 278 * message is needed. 279 * 280 * @return The encoded control value. 281 */ 282 @NotNull() 283 private static ASN1OctetString encodeValue( 284 @NotNull final String uniquenessID, 285 @Nullable final Boolean preCommitValidationPassed, 286 @Nullable final Boolean postCommitValidationPassed, 287 @Nullable final String validationMessage) 288 { 289 final ArrayList<ASN1Element> elements = new ArrayList<>(4); 290 elements.add(new ASN1OctetString(TYPE_UNIQUENESS_ID, uniquenessID)); 291 292 if (preCommitValidationPassed != null) 293 { 294 elements.add(new ASN1Boolean(TYPE_PRE_COMMIT_VALIDATION_PASSED, 295 preCommitValidationPassed)); 296 } 297 298 if (postCommitValidationPassed != null) 299 { 300 elements.add(new ASN1Boolean(TYPE_POST_COMMIT_VALIDATION_PASSED, 301 postCommitValidationPassed)); 302 } 303 304 if (validationMessage != null) 305 { 306 elements.add(new ASN1OctetString(TYPE_VALIDATION_MESSAGE, 307 validationMessage)); 308 } 309 310 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 311 } 312 313 314 315 /** 316 * Creates a new uniqueness response control with the provided information. 317 * 318 * @param oid The OID for the control. 319 * @param isCritical Indicates whether the control should be marked 320 * critical. 321 * @param value The encoded value for the control. This may be 322 * {@code null} if no value was provided. 323 * 324 * @throws LDAPException If the provided control cannot be decoded as a 325 * uniqueness response control. 326 */ 327 public UniquenessResponseControl(@NotNull final String oid, 328 final boolean isCritical, 329 @Nullable final ASN1OctetString value) 330 throws LDAPException 331 { 332 super(oid, isCritical, value); 333 334 if (value == null) 335 { 336 throw new LDAPException(ResultCode.DECODING_ERROR, 337 ERR_UNIQUENESS_RES_DECODE_NO_VALUE.get()); 338 } 339 340 try 341 { 342 String id = null; 343 Boolean prePassed = null; 344 Boolean postPassed = null; 345 String message = null; 346 for (final ASN1Element e : 347 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 348 { 349 switch (e.getType()) 350 { 351 case TYPE_UNIQUENESS_ID: 352 id = ASN1OctetString.decodeAsOctetString(e).stringValue(); 353 break; 354 case TYPE_PRE_COMMIT_VALIDATION_PASSED: 355 prePassed = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 356 break; 357 case TYPE_POST_COMMIT_VALIDATION_PASSED: 358 postPassed = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 359 break; 360 case TYPE_VALIDATION_MESSAGE: 361 message = ASN1OctetString.decodeAsOctetString(e).stringValue(); 362 break; 363 default: 364 throw new LDAPException(ResultCode.DECODING_ERROR, 365 ERR_UNIQUENESS_RES_DECODE_UNKNOWN_ELEMENT_TYPE.get( 366 StaticUtils.toHex(e.getType()))); 367 } 368 } 369 370 if (id == null) 371 { 372 throw new LDAPException(ResultCode.DECODING_ERROR, 373 ERR_UNIQUENESS_RES_DECODE_NO_UNIQUENESS_ID.get()); 374 } 375 376 uniquenessID = id; 377 preCommitValidationPassed = prePassed; 378 postCommitValidationPassed = postPassed; 379 validationMessage = message; 380 } 381 catch (final LDAPException le) 382 { 383 Debug.debugException(le); 384 throw le; 385 } 386 catch (final Exception e) 387 { 388 Debug.debugException(e); 389 throw new LDAPException(ResultCode.DECODING_ERROR, 390 ERR_UNIQUENESS_RES_DECODE_ERROR.get( 391 StaticUtils.getExceptionMessage(e)), 392 e); 393 } 394 } 395 396 397 398 /** 399 * {@inheritDoc} 400 */ 401 @Override() 402 @NotNull() 403 public UniquenessResponseControl decodeControl(@NotNull final String oid, 404 final boolean isCritical, 405 @Nullable final ASN1OctetString value) 406 throws LDAPException 407 { 408 return new UniquenessResponseControl(oid, isCritical, value); 409 } 410 411 412 413 /** 414 * Retrieves the set of uniqueness response controls included in the provided 415 * result. 416 * 417 * @param result The result to process. 418 * 419 * @return The set of uniqueness response controls included in the provided 420 * result, indexed by uniqueness ID. It may be empty if the result 421 * does not include any uniqueness response controls. 422 * 423 * @throws LDAPException If a problem is encountered while getting the set 424 * of uniqueness response controls contained in the 425 * provided result. 426 */ 427 @NotNull() 428 public static Map<String,UniquenessResponseControl> get( 429 @NotNull final LDAPResult result) 430 throws LDAPException 431 { 432 final Control[] responseControls = result.getResponseControls(); 433 if (responseControls.length == 0) 434 { 435 return Collections.emptyMap(); 436 } 437 438 final LinkedHashMap<String,UniquenessResponseControl> controlMap = 439 new LinkedHashMap<>(StaticUtils.computeMapCapacity( 440 responseControls.length)); 441 for (final Control c : responseControls) 442 { 443 if (! c.getOID().equals(UNIQUENESS_RESPONSE_OID)) 444 { 445 continue; 446 } 447 448 final UniquenessResponseControl urc; 449 if (c instanceof UniquenessResponseControl) 450 { 451 urc = (UniquenessResponseControl) c; 452 } 453 else 454 { 455 urc = new UniquenessResponseControl().decodeControl(c.getOID(), 456 c.isCritical(), c.getValue()); 457 } 458 459 final String uniquenessID = urc.getUniquenessID(); 460 if (controlMap.containsKey(uniquenessID)) 461 { 462 throw new LDAPException(ResultCode.DECODING_ERROR, 463 ERR_UNIQUENESS_RES_GET_ID_CONFLICT.get(uniquenessID)); 464 } 465 else 466 { 467 controlMap.put(uniquenessID, urc); 468 } 469 } 470 471 return Collections.unmodifiableMap(controlMap); 472 } 473 474 475 476 /** 477 * Indicates whether a uniqueness conflict was found during processing. 478 * 479 * @return {@code true} if a uniqueness conflict was found during processing, 480 * or {@code false} if no conflict was found or if no validation was 481 * attempted. 482 */ 483 public boolean uniquenessConflictFound() 484 { 485 return ((preCommitValidationPassed == Boolean.FALSE) || 486 (postCommitValidationPassed == Boolean.FALSE)); 487 } 488 489 490 491 /** 492 * Retrieves the identifier that may be used to correlate this uniqueness 493 * response control with the corresponding request control. This is primarily 494 * useful for requests that contain multiple uniqueness controls, as there may 495 * be a separate response control for each. 496 * 497 * @return The identifier that may be used to correlate this uniqueness 498 * response control with the corresponding request control. 499 */ 500 @NotNull() 501 public String getUniquenessID() 502 { 503 return uniquenessID; 504 } 505 506 507 508 /** 509 * Retrieves the result of the server's pre-commit validation processing. 510 * The same information can be inferred from the 511 * {@link #getPreCommitValidationPassed()} method, but this method may provide 512 * a more intuitive result and does not have the possibility of a {@code null} 513 * return value. 514 * 515 * @return {@link UniquenessValidationResult#VALIDATION_PASSED} if the 516 * server did not find any conflicting entries during the pre-commit 517 * check, {@link UniquenessValidationResult#VALIDATION_FAILED} if 518 * the server found at least one conflicting entry during the 519 * pre-commit check, or 520 * {@link UniquenessValidationResult#VALIDATION_NOT_ATTEMPTED} if 521 * the server did not attempt any pre-commit validation. 522 */ 523 @NotNull() 524 public UniquenessValidationResult getPreCommitValidationResult() 525 { 526 if (preCommitValidationPassed == null) 527 { 528 return UniquenessValidationResult.VALIDATION_NOT_ATTEMPTED; 529 } 530 else if (preCommitValidationPassed) 531 { 532 return UniquenessValidationResult.VALIDATION_PASSED; 533 } 534 else 535 { 536 return UniquenessValidationResult.VALIDATION_FAILED; 537 } 538 } 539 540 541 542 /** 543 * Retrieves a value that indicates whether pre-commit validation was 544 * attempted, and whether that validation passed. Note that this method is 545 * still supported and is not deprecated at this time, but the 546 * {@link #getPreCommitValidationResult()} is now the recommended way to get 547 * this information. 548 * 549 * @return {@code Boolean.TRUE} if pre-commit validation was attempted and 550 * passed, {@code Boolean.FALSE} if pre-commit validation was 551 * attempted and did not pass, or {@code null} if pre-commit 552 * validation was not attempted. 553 */ 554 @Nullable() 555 public Boolean getPreCommitValidationPassed() 556 { 557 return preCommitValidationPassed; 558 } 559 560 561 562 /** 563 * Retrieves the result of the server's post-commit validation processing. 564 * The same information can be inferred from the 565 * {@link #getPostCommitValidationPassed()} method, but this method may 566 * provide a more intuitive result and does not have the possibility of a 567 * {@code null} return value. 568 * 569 * @return {@link UniquenessValidationResult#VALIDATION_PASSED} if the 570 * server did not find any conflicting entries during the post-commit 571 * check, {@link UniquenessValidationResult#VALIDATION_FAILED} if 572 * the server found at least one conflicting entry during the 573 * post-commit check, or 574 * {@link UniquenessValidationResult#VALIDATION_NOT_ATTEMPTED} if 575 * the server did not attempt any post-commit validation. 576 */ 577 @NotNull() 578 public UniquenessValidationResult getPostCommitValidationResult() 579 { 580 if (postCommitValidationPassed == null) 581 { 582 return UniquenessValidationResult.VALIDATION_NOT_ATTEMPTED; 583 } 584 else if (postCommitValidationPassed) 585 { 586 return UniquenessValidationResult.VALIDATION_PASSED; 587 } 588 else 589 { 590 return UniquenessValidationResult.VALIDATION_FAILED; 591 } 592 } 593 594 595 596 /** 597 * Retrieves a value that indicates whether post-commit validation was 598 * attempted, and whether that validation passed. 599 * 600 * @return {@code Boolean.TRUE} if post-commit validation was attempted and 601 * passed, {@code Boolean.FALSE} if post-commit validation was 602 * attempted and did not pass, or {@code null} if post-commit 603 * validation was not attempted. 604 */ 605 @Nullable() 606 public Boolean getPostCommitValidationPassed() 607 { 608 return postCommitValidationPassed; 609 } 610 611 612 613 /** 614 * Retrieves a message with additional information about the validation 615 * processing that was performed. 616 * 617 * @return A message with additional information about the validation 618 * processing that was performed, or {@code null} if no validation 619 * message is available. 620 */ 621 @Nullable() 622 public String getValidationMessage() 623 { 624 return validationMessage; 625 } 626 627 628 629 /** 630 * {@inheritDoc} 631 */ 632 @Override() 633 @NotNull() 634 public String getControlName() 635 { 636 return INFO_UNIQUENESS_RES_CONTROL_NAME.get(); 637 } 638 639 640 641 /** 642 * Retrieves a representation of this uniqueness response control as a JSON 643 * object. The JSON object uses the following fields: 644 * <UL> 645 * <LI> 646 * {@code oid} -- A mandatory string field whose value is the object 647 * identifier for this control. For the uniqueness response control, the 648 * OID is "1.3.6.1.4.1.30221.2.5.53". 649 * </LI> 650 * <LI> 651 * {@code control-name} -- An optional string field whose value is a 652 * human-readable name for this control. This field is only intended for 653 * descriptive purposes, and when decoding a control, the {@code oid} 654 * field should be used to identify the type of control. 655 * </LI> 656 * <LI> 657 * {@code criticality} -- A mandatory Boolean field used to indicate 658 * whether this control is considered critical. 659 * </LI> 660 * <LI> 661 * {@code value-base64} -- An optional string field whose value is a 662 * base64-encoded representation of the raw value for this uniqueness 663 * response control. Exactly one of the {@code value-base64} and 664 * {@code value-json} fields must be present. 665 * </LI> 666 * <LI> 667 * {@code value-json} -- An optional JSON object field whose value is a 668 * user-friendly representation of the value for this uniqueness response 669 * control. Exactly one of the {@code value-base64} and 670 * {@code value-json} fields must be present, and if the 671 * {@code value-json} field is used, then it will use the following 672 * fields: 673 * <UL> 674 * <LI> 675 * {@code uniqueness-id} -- A string field whose value is the 676 * uniqueness ID from the uniqueness request control with which this 677 * response control is associated. 678 * </LI> 679 * <LI> 680 * {@code pre-commit-validation-passed} -- An optional Boolean field 681 * that indicates whether pre-commit validation passed without 682 * identifying any conflicts. 683 * </LI> 684 * <LI> 685 * {@code post-commit-validation-passed} -- An optional Boolean field 686 * that indicates whether post-commit validation passed without 687 * identifying any conflicts. 688 * </LI> 689 * <LI> 690 * {@code validation-message} -- An optional String field whose value 691 * is a message with additional information about the uniqueness 692 * processing. 693 * </LI> 694 * </UL> 695 * </LI> 696 * </UL> 697 * 698 * @return A JSON object that contains a representation of this control. 699 */ 700 @Override() 701 @NotNull() 702 public JSONObject toJSONControl() 703 { 704 final Map<String,JSONValue> valueFields = new LinkedHashMap<>(); 705 valueFields.put(JSON_FIELD_UNIQUENESS_ID, new JSONString(uniquenessID)); 706 707 if (preCommitValidationPassed != null) 708 { 709 valueFields.put(JSON_FIELD_PRE_COMMIT_VALIDATION_PASSED, 710 new JSONBoolean(preCommitValidationPassed)); 711 } 712 713 if (postCommitValidationPassed != null) 714 { 715 valueFields.put(JSON_FIELD_POST_COMMIT_VALIDATION_PASSED, 716 new JSONBoolean(postCommitValidationPassed)); 717 } 718 719 if (validationMessage != null) 720 { 721 valueFields.put(JSON_FIELD_VALIDATION_MESSAGE, 722 new JSONString(validationMessage)); 723 } 724 725 return new JSONObject( 726 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 727 UNIQUENESS_RESPONSE_OID), 728 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 729 INFO_UNIQUENESS_RES_CONTROL_NAME.get()), 730 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 731 isCritical()), 732 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 733 new JSONObject(valueFields))); 734 } 735 736 737 738 /** 739 * Attempts to decode the provided object as a JSON representation of a 740 * uniqueness response control. 741 * 742 * @param controlObject The JSON object to be decoded. It must not be 743 * {@code null}. 744 * @param strict Indicates whether to use strict mode when decoding 745 * the provided JSON object. If this is {@code true}, 746 * then this method will throw an exception if the 747 * provided JSON object contains any unrecognized 748 * fields. If this is {@code false}, then unrecognized 749 * fields will be ignored. 750 * 751 * @return The uniqueness response control that was decoded from 752 * the provided JSON object. 753 * 754 * @throws LDAPException If the provided JSON object cannot be parsed as a 755 * valid uniqueness response control. 756 */ 757 @NotNull() 758 public static UniquenessResponseControl decodeJSONControl( 759 @NotNull final JSONObject controlObject, 760 final boolean strict) 761 throws LDAPException 762 { 763 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 764 controlObject, strict, true, true); 765 766 final ASN1OctetString rawValue = jsonControl.getRawValue(); 767 if (rawValue != null) 768 { 769 return new UniquenessResponseControl(jsonControl.getOID(), 770 jsonControl.getCriticality(), rawValue); 771 } 772 773 774 final JSONObject valueObject = jsonControl.getValueObject(); 775 776 final String uniquenessID = 777 valueObject.getFieldAsString(JSON_FIELD_UNIQUENESS_ID); 778 if (uniquenessID == null) 779 { 780 throw new LDAPException(ResultCode.DECODING_ERROR, 781 ERR_UNIQUENESS_RES_JSON_MISSING_UNIQUENESS_ID.get( 782 controlObject.toSingleLineString(), JSON_FIELD_UNIQUENESS_ID)); 783 } 784 785 final Boolean preCommitValidationPassed = 786 valueObject.getFieldAsBoolean(JSON_FIELD_PRE_COMMIT_VALIDATION_PASSED); 787 788 final Boolean postCommitValidationPassed = 789 valueObject.getFieldAsBoolean( 790 JSON_FIELD_POST_COMMIT_VALIDATION_PASSED); 791 792 final String validationMessage = 793 valueObject.getFieldAsString(JSON_FIELD_VALIDATION_MESSAGE); 794 795 796 if (strict) 797 { 798 final List<String> unrecognizedFields = 799 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 800 valueObject, JSON_FIELD_UNIQUENESS_ID, 801 JSON_FIELD_PRE_COMMIT_VALIDATION_PASSED, 802 JSON_FIELD_POST_COMMIT_VALIDATION_PASSED, 803 JSON_FIELD_VALIDATION_MESSAGE); 804 if (! unrecognizedFields.isEmpty()) 805 { 806 throw new LDAPException(ResultCode.DECODING_ERROR, 807 ERR_UNIQUENESS_RES_JSON_UNRECOGNIZED_FIELD.get( 808 controlObject.toSingleLineString(), 809 unrecognizedFields.get(0))); 810 } 811 } 812 813 814 return new UniquenessResponseControl(uniquenessID, 815 preCommitValidationPassed, postCommitValidationPassed, 816 validationMessage); 817 } 818 819 820 821 /** 822 * {@inheritDoc} 823 */ 824 @Override() 825 public void toString(@NotNull final StringBuilder buffer) 826 { 827 buffer.append("UniquenessResponseControl(uniquenessID='"); 828 buffer.append(uniquenessID); 829 buffer.append("', preCommitValidationResult='"); 830 buffer.append(getPreCommitValidationResult().getName()); 831 buffer.append("', preCommitValidationResult='"); 832 buffer.append(getPostCommitValidationResult().getName()); 833 buffer.append('\''); 834 835 if (validationMessage != null) 836 { 837 buffer.append(", validationMessage='"); 838 buffer.append(validationMessage); 839 buffer.append('\''); 840 } 841 buffer.append(')'); 842 } 843}