001/* 002 * Copyright 2017-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2017-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.Iterator; 028import java.util.LinkedHashSet; 029import java.util.Set; 030import java.util.UUID; 031 032import com.unboundid.asn1.ASN1Boolean; 033import com.unboundid.asn1.ASN1Element; 034import com.unboundid.asn1.ASN1Enumerated; 035import com.unboundid.asn1.ASN1OctetString; 036import com.unboundid.asn1.ASN1Sequence; 037import com.unboundid.asn1.ASN1Set; 038import com.unboundid.ldap.sdk.Control; 039import com.unboundid.ldap.sdk.Filter; 040import com.unboundid.ldap.sdk.LDAPException; 041import com.unboundid.ldap.sdk.ResultCode; 042import com.unboundid.util.Debug; 043import com.unboundid.util.NotMutable; 044import com.unboundid.util.StaticUtils; 045import com.unboundid.util.ThreadSafety; 046import com.unboundid.util.ThreadSafetyLevel; 047import com.unboundid.util.Validator; 048 049import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 050 051 052 053/** 054 * This class provides a request control that may be included in an add, modify, 055 * or modify DN request to ensure that the contents of that request will not 056 * result in a uniqueness conflict with any other entry in the server. Each 057 * instance of this control should define exactly one uniqueness constraint for 058 * the associated operation. Multiple instances of this control can be included 059 * in the same request to define multiple independent uniqueness constraints 060 * that must all be satisfied. If any of the uniqueness constraints is not 061 * satisfied, then the corresponding LDAP result should have a result code of 062 * {@link ResultCode#ASSERTION_FAILED} and a {@link UniquenessResponseControl} 063 * for each uniqueness constraint that was not satisfied. 064 * <BR> 065 * <BLOCKQUOTE> 066 * <B>NOTE:</B> This class, and other classes within the 067 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 068 * supported for use against Ping Identity, UnboundID, and 069 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 070 * for proprietary functionality or for external specifications that are not 071 * considered stable or mature enough to be guaranteed to work in an 072 * interoperable way with other types of LDAP servers. 073 * </BLOCKQUOTE> 074 * <BR> 075 * The request properties must contain either one or more attribute types, a 076 * filter, or both. If only a filter is specified, then the server will use 077 * that filter to identify conflicts (for an add request, any matches at all 078 * will be considered a conflict; for a modify or modify DN request, any matches 079 * with any entry other than the one being updated will be considered a 080 * conflict). If a single attribute type is specified with no filter, then any 081 * change that would result in multiple entries having the same value for that 082 * attribute will be considered a conflict. If multiple attribute types are 083 * specified, then the multiple attribute behavior will be used to determine how 084 * to identify conflicts, as documented in the 085 * {@link UniquenessMultipleAttributeBehavior} enum. If both a set of attribute 086 * types and a filter are provided, then only entries matching both sets of 087 * criteria will be considered a conflict. 088 * <BR><BR> 089 * The server can perform two different searches in an attempt to identify 090 * conflicts. In the pre-commit phase, it will attempt to identify any 091 * conflicts that already exist, and will reject the associated change if there 092 * are any. In the post-commit phase, it can see if there were any conflicts 093 * introduced by the change itself or by another change happening at the same 094 * time. If a conflict is detected in the post-commit phase, then the server 095 * won't have prevented it, but at least the control can be used to provide 096 * notification about it. 097 * <BR><BR> 098 * This request control may be sent either directly to a Directory Server 099 * instance, or it may be sent to a Directory Proxy Server with or without entry 100 * balancing. If the request is sent directly to a Directory Server, then only 101 * that one server will be checked for uniqueness conflicts, and it is possible 102 * that concurrent conflicts may be introduced on other servers that have not 103 * yet been replicated by the time control processing has completed. If the 104 * request is sent to a Directory Proxy Server instance, then search may be 105 * processed in one or more backend servers based on the pre-commit and 106 * post-commit validation levels, and at the most paranoid levels, it is highly 107 * unlikely that any conflicts will go unnoticed. 108 * <BR><BR> 109 * The request control has an OID of 1.3.6.1.4.1.30221.2.5.52, a criticality of 110 * either {@code true} or {@code false}, and a value with the following 111 * encoding: 112 * <PRE> 113 * UniquenessRequestValue ::= SEQUENCE { 114 * uniquenessID [0] OCTET STRING, 115 * attributeTypes [1] SET OF OCTET STRING OPTIONAL, 116 * multipleAttributeBehavior [2] ENUMERATED { 117 * uniqueWithinEachAttribute (0), 118 * uniqueAcrossAllAttributesIncludingInSameEntry (1), 119 * uniqueAcrossAllAttributesExceptInSameEntry (2), 120 * uniqueInCombination (3), 121 * ... } DEFAULT uniqueWithinEachAttribute, 122 * baseDN [3] LDAPDN OPTIONAL, 123 * filter [4] Filter OPTIONAL, 124 * preventConflictsWithSoftDeletedEntries [5] BOOLEAN DEFAULT FALSE, 125 * preCommitValidationLevel [6] ENUMERATED { 126 * none (0), 127 * allSubtreeViews (1), 128 * allBackendSets (2), 129 * allAvailableBackendServers (3), 130 * ... } DEFAULT allSubtreeViews, 131 * postCommitValidationLevel [7] ENUMERATED { 132 * none (0), 133 * allSubtreeViews (1), 134 * allBackendSets (2), 135 * allAvailableBackendServers (3), 136 * ... } DEFAULT allSubtreeViews, 137 * ... } 138 * </PRE> 139 */ 140@NotMutable() 141@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 142public final class UniquenessRequestControl 143 extends Control 144{ 145 /** 146 * The OID (1.3.6.1.4.1.30221.2.5.52) for the uniqueness request control. 147 */ 148 public static final String UNIQUENESS_REQUEST_OID = 149 "1.3.6.1.4.1.30221.2.5.52"; 150 151 152 153 /** 154 * The BER type for the uniqueness ID element in the value sequence. 155 */ 156 private static final byte TYPE_UNIQUENESS_ID = (byte) 0x80; 157 158 159 160 /** 161 * The BER type for the attribute types element in the value sequence. 162 */ 163 private static final byte TYPE_ATTRIBUTE_TYPES = (byte) 0xA1; 164 165 166 167 /** 168 * The BER type for the multiple attribute behavior element in the value 169 * sequence. 170 */ 171 private static final byte TYPE_MULTIPLE_ATTRIBUTE_BEHAVIOR = (byte) 0x82; 172 173 174 175 /** 176 * The BER type for the base DN element in the value sequence. 177 */ 178 private static final byte TYPE_BASE_DN = (byte) 0x83; 179 180 181 182 /** 183 * The BER type for the filter element in the value sequence. 184 */ 185 private static final byte TYPE_FILTER = (byte) 0xA4; 186 187 188 189 /** 190 * The BER type for the prevent conflicts with soft-deleted entries element in 191 * the value sequence. 192 */ 193 private static final byte TYPE_PREVENT_CONFLICTS_WITH_SOFT_DELETED_ENTRIES = 194 (byte) 0x85; 195 196 197 198 /** 199 * The BER type for the pre-commit validation element in the value sequence. 200 */ 201 private static final byte TYPE_PRE_COMMIT_VALIDATION_LEVEL = (byte) 0x86; 202 203 204 205 /** 206 * The BER type for the post-commit validation element in the value sequence. 207 */ 208 private static final byte TYPE_POST_COMMIT_VALIDATION_LEVEL = (byte) 0x87; 209 210 211 212 /** 213 * The serial version UID for this serializable class. 214 */ 215 private static final long serialVersionUID = 7976218379635922852L; 216 217 218 219 // Indicates whether to prevent conflicts with soft-deleted entries. 220 private final boolean preventConflictsWithSoftDeletedEntries; 221 222 // An optional filter that should be used in the course of identifying 223 // uniqueness conflicts. 224 private final Filter filter; 225 226 // A potentially-empty set of attribute types that should be checked for 227 // uniqueness conflicts. 228 private final Set<String> attributeTypes; 229 230 // An optional base DN to use when checking for conflicts. 231 private final String baseDN; 232 233 // A value that will be used to correlate this request control with its 234 // corresponding response control. 235 private final String uniquenessID; 236 237 // The behavior that the server should exhibit if multiple attribute types 238 // are configured. 239 private final UniquenessMultipleAttributeBehavior multipleAttributeBehavior; 240 241 // The level of validation that the server should perform before processing 242 // the associated change. 243 private final UniquenessValidationLevel postCommitValidationLevel; 244 245 // The level of validation that the server should perform after processing the 246 // associated change. 247 private final UniquenessValidationLevel preCommitValidationLevel; 248 249 250 251 /** 252 * Creates a new uniqueness request control with the provided information. 253 * 254 * @param isCritical Indicates whether the control should be considered 255 * critical. 256 * @param uniquenessID A value that will be used to correlate this request 257 * control with its corresponding response control. If 258 * this is {@code null}, then a unique identifier will 259 * be automatically generated. 260 * @param properties The set of properties for this control. It must not 261 * be {@code null}. 262 * 263 * @throws LDAPException If the provided properties cannot be used to create 264 * a valid uniqueness request control. 265 */ 266 public UniquenessRequestControl(final boolean isCritical, 267 final String uniquenessID, 268 final UniquenessRequestControlProperties properties) 269 throws LDAPException 270 { 271 this((uniquenessID == null 272 ? UUID.randomUUID().toString() 273 : uniquenessID), 274 properties, isCritical); 275 } 276 277 278 279 /** 280 * Creates a new uniqueness request control with the provided information. 281 * Note that this version of the constructor takes the same set of arguments 282 * as the above constructor, but in a different order (to distinguish between 283 * the two versions), and with the additional constraint that the uniqueness 284 * ID must not be {@code null}. 285 * 286 * @param isCritical Indicates whether the control should be considered 287 * critical. 288 * @param uniquenessID A value that will be used to correlate this request 289 * control with its corresponding response control. It 290 * must not be {@code null}. 291 * @param properties The set of properties for this control. It must not 292 * be {@code null}. 293 * 294 * @throws LDAPException If the provided properties cannot be used to create 295 * a valid uniqueness request control. 296 */ 297 private UniquenessRequestControl(final String uniquenessID, 298 final UniquenessRequestControlProperties properties, 299 final boolean isCritical) 300 throws LDAPException 301 { 302 super(UNIQUENESS_REQUEST_OID, isCritical, 303 encodeValue(uniquenessID, properties)); 304 305 Validator.ensureNotNull(uniquenessID); 306 this.uniquenessID = uniquenessID; 307 308 attributeTypes = properties.getAttributeTypes(); 309 multipleAttributeBehavior = properties.getMultipleAttributeBehavior(); 310 baseDN = properties.getBaseDN(); 311 filter = properties.getFilter(); 312 preventConflictsWithSoftDeletedEntries = 313 properties.preventConflictsWithSoftDeletedEntries(); 314 preCommitValidationLevel = properties.getPreCommitValidationLevel(); 315 postCommitValidationLevel = properties.getPostCommitValidationLevel(); 316 317 if (attributeTypes.isEmpty() && (filter == null)) 318 { 319 throw new LDAPException(ResultCode.PARAM_ERROR, 320 ERR_UNIQUENESS_REQ_NO_ATTRS_OR_FILTER.get()); 321 } 322 } 323 324 325 326 /** 327 * Encodes the provided information into an octet string that is suitable for 328 * use as the value of this control. 329 * 330 * @param uniquenessID A value that will be used to correlate this request 331 * control with its corresponding response control. It 332 * must not be {@code null}. 333 * @param properties The set of properties for this control. It must not 334 * be {@code null}. 335 * 336 * @return The encoded value that was created. 337 */ 338 private static ASN1OctetString encodeValue(final String uniquenessID, 339 final UniquenessRequestControlProperties properties) 340 { 341 final ArrayList<ASN1Element> elements = new ArrayList<>(8); 342 343 elements.add(new ASN1OctetString(TYPE_UNIQUENESS_ID, uniquenessID)); 344 345 final Set<String> attributeTypes = properties.getAttributeTypes(); 346 if (!attributeTypes.isEmpty()) 347 { 348 final ArrayList<ASN1Element> attributeTypeElements = 349 new ArrayList<>(attributeTypes.size()); 350 for (final String attributeType : attributeTypes) 351 { 352 attributeTypeElements.add(new ASN1OctetString(attributeType)); 353 } 354 elements.add(new ASN1Set(TYPE_ATTRIBUTE_TYPES, attributeTypeElements)); 355 } 356 357 final UniquenessMultipleAttributeBehavior multipleAttributeBehavior = 358 properties.getMultipleAttributeBehavior(); 359 if (multipleAttributeBehavior != 360 UniquenessMultipleAttributeBehavior.UNIQUE_WITHIN_EACH_ATTRIBUTE) 361 { 362 elements.add(new ASN1Enumerated(TYPE_MULTIPLE_ATTRIBUTE_BEHAVIOR, 363 multipleAttributeBehavior.intValue())); 364 } 365 366 final String baseDN = properties.getBaseDN(); 367 if (baseDN != null) 368 { 369 elements.add(new ASN1OctetString(TYPE_BASE_DN, baseDN)); 370 } 371 372 final Filter filter = properties.getFilter(); 373 if (filter != null) 374 { 375 elements.add(new ASN1Element(TYPE_FILTER, filter.encode().encode())); 376 } 377 378 if (properties.preventConflictsWithSoftDeletedEntries()) 379 { 380 elements.add(new ASN1Boolean( 381 TYPE_PREVENT_CONFLICTS_WITH_SOFT_DELETED_ENTRIES, true)); 382 } 383 384 final UniquenessValidationLevel preCommitValidationLevel = 385 properties.getPreCommitValidationLevel(); 386 if (preCommitValidationLevel != UniquenessValidationLevel.ALL_SUBTREE_VIEWS) 387 { 388 elements.add(new ASN1Enumerated(TYPE_PRE_COMMIT_VALIDATION_LEVEL, 389 preCommitValidationLevel.intValue())); 390 } 391 392 final UniquenessValidationLevel postCommitValidationLevel = 393 properties.getPostCommitValidationLevel(); 394 if (postCommitValidationLevel != 395 UniquenessValidationLevel.ALL_SUBTREE_VIEWS) 396 { 397 elements.add(new ASN1Enumerated(TYPE_POST_COMMIT_VALIDATION_LEVEL, 398 postCommitValidationLevel.intValue())); 399 } 400 401 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 402 } 403 404 405 406 /** 407 * Creates a new uniqueness request control that is decoded from the provided 408 * generic control. 409 * 410 * @param control The control to be decoded as a uniqueness request control. 411 * It must not be {@code null}. 412 * 413 * @throws LDAPException If the provided control cannot be decoded as a 414 * valid uniqueness request control. 415 */ 416 public UniquenessRequestControl(final Control control) 417 throws LDAPException 418 { 419 super(control); 420 421 final ASN1OctetString value = control.getValue(); 422 if (value == null) 423 { 424 throw new LDAPException(ResultCode.DECODING_ERROR, 425 ERR_UNIQUENESS_REQ_DECODE_NO_VALUE.get()); 426 } 427 428 try 429 { 430 boolean decodedPreventSoftDeletedConflicts = false; 431 Filter decodedFilter = null; 432 Set<String> decodedAttributeTypes = Collections.emptySet(); 433 String decodedBaseDN = null; 434 String decodedUniquenessID = null; 435 UniquenessMultipleAttributeBehavior decodedMultipleAttributeBehavior = 436 UniquenessMultipleAttributeBehavior.UNIQUE_WITHIN_EACH_ATTRIBUTE; 437 UniquenessValidationLevel decodedPreCommitLevel = 438 UniquenessValidationLevel.ALL_SUBTREE_VIEWS; 439 UniquenessValidationLevel decodedPostCommitLevel = 440 UniquenessValidationLevel.ALL_SUBTREE_VIEWS; 441 442 final ASN1Element[] elements = 443 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 444 for (final ASN1Element e : elements) 445 { 446 switch (e.getType()) 447 { 448 case TYPE_UNIQUENESS_ID: 449 decodedUniquenessID = 450 ASN1OctetString.decodeAsOctetString(e).stringValue(); 451 break; 452 case TYPE_ATTRIBUTE_TYPES: 453 final ASN1Element[] atElements = ASN1Set.decodeAsSet(e).elements(); 454 final LinkedHashSet<String> atNames = 455 new LinkedHashSet<>(atElements.length); 456 for (final ASN1Element atElement : atElements) 457 { 458 atNames.add(ASN1OctetString.decodeAsOctetString( 459 atElement).stringValue()); 460 } 461 decodedAttributeTypes = Collections.unmodifiableSet(atNames); 462 break; 463 case TYPE_MULTIPLE_ATTRIBUTE_BEHAVIOR: 464 final int mabIntValue = 465 ASN1Enumerated.decodeAsEnumerated(e).intValue(); 466 decodedMultipleAttributeBehavior = 467 UniquenessMultipleAttributeBehavior.valueOf(mabIntValue); 468 if (decodedMultipleAttributeBehavior == null) 469 { 470 throw new LDAPException(ResultCode.DECODING_ERROR, 471 ERR_UNIQUENESS_REQ_DECODE_UNKNOWN_MULTIPLE_ATTR_BEHAVIOR.get( 472 mabIntValue)); 473 } 474 break; 475 case TYPE_BASE_DN: 476 decodedBaseDN = 477 ASN1OctetString.decodeAsOctetString(e).stringValue(); 478 break; 479 case TYPE_FILTER: 480 decodedFilter = Filter.decode(ASN1Element.decode(e.getValue())); 481 break; 482 case TYPE_PREVENT_CONFLICTS_WITH_SOFT_DELETED_ENTRIES: 483 decodedPreventSoftDeletedConflicts = 484 ASN1Boolean.decodeAsBoolean(e).booleanValue(); 485 break; 486 case TYPE_PRE_COMMIT_VALIDATION_LEVEL: 487 final int preCommitIntValue = 488 ASN1Enumerated.decodeAsEnumerated(e).intValue(); 489 decodedPreCommitLevel = 490 UniquenessValidationLevel.valueOf(preCommitIntValue); 491 if (decodedPreCommitLevel == null) 492 { 493 throw new LDAPException(ResultCode.DECODING_ERROR, 494 ERR_UNIQUENESS_REQ_DECODE_UNKNOWN_PRE_COMMIT_LEVEL.get( 495 preCommitIntValue)); 496 } 497 break; 498 case TYPE_POST_COMMIT_VALIDATION_LEVEL: 499 final int postCommitIntValue = 500 ASN1Enumerated.decodeAsEnumerated(e).intValue(); 501 decodedPostCommitLevel = 502 UniquenessValidationLevel.valueOf(postCommitIntValue); 503 if (decodedPostCommitLevel == null) 504 { 505 throw new LDAPException(ResultCode.DECODING_ERROR, 506 ERR_UNIQUENESS_REQ_DECODE_UNKNOWN_POST_COMMIT_LEVEL.get( 507 postCommitIntValue)); 508 } 509 break; 510 default: 511 throw new LDAPException(ResultCode.DECODING_ERROR, 512 ERR_UNIQUENESS_REQ_DECODE_UNKNOWN_ELEMENT_TYPE.get( 513 StaticUtils.toHex(e.getType()))); 514 } 515 } 516 517 if (decodedUniquenessID == null) 518 { 519 throw new LDAPException(ResultCode.DECODING_ERROR, 520 ERR_UNIQUENESS_REQ_MISSING_UNIQUENESS_ID.get()); 521 } 522 523 if (decodedAttributeTypes.isEmpty() && (decodedFilter == null)) 524 { 525 throw new LDAPException(ResultCode.DECODING_ERROR, 526 ERR_UNIQUENESS_REQ_NO_ATTRS_OR_FILTER.get()); 527 } 528 529 uniquenessID = decodedUniquenessID; 530 attributeTypes = decodedAttributeTypes; 531 multipleAttributeBehavior = decodedMultipleAttributeBehavior; 532 baseDN = decodedBaseDN; 533 filter = decodedFilter; 534 preventConflictsWithSoftDeletedEntries = 535 decodedPreventSoftDeletedConflicts; 536 preCommitValidationLevel = decodedPreCommitLevel; 537 postCommitValidationLevel = decodedPostCommitLevel; 538 } 539 catch (final LDAPException le) 540 { 541 Debug.debugException(le); 542 throw le; 543 } 544 catch (final Exception e) 545 { 546 Debug.debugException(e); 547 throw new LDAPException(ResultCode.DECODING_ERROR, 548 ERR_UNIQUENESS_REQ_DECODE_ERROR_DECODING_VALUE.get( 549 StaticUtils.getExceptionMessage(e)), 550 e); 551 } 552 } 553 554 555 556 /** 557 * Retrieves the uniqueness identifier for this control, which may be used to 558 * identify the response control that corresponds to this request control. 559 * This is primarily useful for requests that contain multiple uniqueness 560 * controls, as there may be a separate response control for each. 561 * 562 * @return The uniqueness identifier for this control. 563 */ 564 public String getUniquenessID() 565 { 566 return uniquenessID; 567 } 568 569 570 571 /** 572 * Retrieves the set of attribute types that the server will check for 573 * uniqueness conflicts. 574 * 575 * @return The set of attribute types that the server will check for 576 * uniqueness conflicts, or an empty set if only a filter should be 577 * used to identify conflicts. 578 */ 579 public Set<String> getAttributeTypes() 580 { 581 return attributeTypes; 582 } 583 584 585 586 /** 587 * Retrieves the behavior that the server should exhibit if multiple attribute 588 * types are configured. 589 * 590 * @return The behavior that the server should exhibit if multiple attribute 591 * types are configured. 592 */ 593 public UniquenessMultipleAttributeBehavior getMultipleAttributeBehavior() 594 { 595 return multipleAttributeBehavior; 596 } 597 598 599 600 /** 601 * Retrieves the base DN that will be used for searches used to identify 602 * uniqueness conflicts, if defined. 603 * 604 * @return The base DN that will be used for searches used to identify 605 * uniqueness conflicts, or {@code null} if the server should search 606 * below all public naming contexts. 607 */ 608 public String getBaseDN() 609 { 610 return baseDN; 611 } 612 613 614 615 /** 616 * Retrieves a filter that will be used to identify uniqueness conflicts, if 617 * defined. 618 * 619 * @return A filter that will be used to identify uniqueness conflicts, or 620 * {@code null} if no filter has been defined. 621 */ 622 public Filter getFilter() 623 { 624 return filter; 625 } 626 627 628 629 /** 630 * Indicates whether the server should attempt to identify conflicts with 631 * soft-deleted entries. 632 * 633 * @return {@code true} if the server should identify conflicts with both 634 * regular entries and soft-deleted entries, or {@code false} if the 635 * server should only identify conflicts with regular entries. 636 */ 637 public boolean preventConflictsWithSoftDeletedEntries() 638 { 639 return preventConflictsWithSoftDeletedEntries; 640 } 641 642 643 644 /** 645 * Retrieves the pre-commit validation level, which will be used to identify 646 * any conflicts before the associated request is processed. 647 * 648 * @return The pre-commit validation level. 649 */ 650 public UniquenessValidationLevel getPreCommitValidationLevel() 651 { 652 return preCommitValidationLevel; 653 } 654 655 656 657 /** 658 * Retrieves the post-commit validation level, which will be used to identify 659 * any conflicts that were introduced by the request with which the control is 660 * associated, or by some other concurrent changed processed in the server. 661 * 662 * @return The post-commit validation level. 663 */ 664 public UniquenessValidationLevel getPostCommitValidationLevel() 665 { 666 return postCommitValidationLevel; 667 } 668 669 670 671 /** 672 * {@inheritDoc} 673 */ 674 @Override() 675 public String getControlName() 676 { 677 return INFO_UNIQUENESS_REQ_CONTROL_NAME.get(); 678 } 679 680 681 682 /** 683 * {@inheritDoc} 684 */ 685 @Override() 686 public void toString(final StringBuilder buffer) 687 { 688 buffer.append("UniquenessRequestControl(isCritical="); 689 buffer.append(isCritical()); 690 buffer.append(", uniquenessID='"); 691 buffer.append(uniquenessID); 692 buffer.append("', attributeTypes={"); 693 694 final Iterator<String> attributeTypesIterator = attributeTypes.iterator(); 695 while (attributeTypesIterator.hasNext()) 696 { 697 buffer.append('\''); 698 buffer.append(attributeTypesIterator.next()); 699 buffer.append('\''); 700 701 if (attributeTypesIterator.hasNext()) 702 { 703 buffer.append(", "); 704 } 705 } 706 707 buffer.append("}, multipleAttributeBehavior="); 708 buffer.append(multipleAttributeBehavior); 709 710 if (baseDN != null) 711 { 712 buffer.append(", baseDN='"); 713 buffer.append(baseDN); 714 buffer.append('\''); 715 } 716 717 if (filter != null) 718 { 719 buffer.append(", filter='"); 720 buffer.append(filter); 721 buffer.append('\''); 722 } 723 724 buffer.append(", preventConflictsWithSoftDeletedEntries="); 725 buffer.append(preventConflictsWithSoftDeletedEntries); 726 buffer.append(", preCommitValidationLevel="); 727 buffer.append(preCommitValidationLevel); 728 buffer.append(", postCommitValidationLevel="); 729 buffer.append(postCommitValidationLevel); 730 buffer.append(')'); 731 } 732}