001/* 002 * Copyright 2013-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-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.Collection; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.List; 030 031import com.unboundid.asn1.ASN1Boolean; 032import com.unboundid.asn1.ASN1Element; 033import com.unboundid.asn1.ASN1Enumerated; 034import com.unboundid.asn1.ASN1OctetString; 035import com.unboundid.asn1.ASN1Sequence; 036import com.unboundid.ldap.sdk.Control; 037import com.unboundid.ldap.sdk.DecodeableControl; 038import com.unboundid.ldap.sdk.LDAPException; 039import com.unboundid.ldap.sdk.LDAPResult; 040import com.unboundid.ldap.sdk.ResultCode; 041import com.unboundid.util.Debug; 042import com.unboundid.util.NotMutable; 043import com.unboundid.util.StaticUtils; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046 047import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 048 049 050 051/** 052 * This class provides an implementation of an LDAP control that can be included 053 * in add, bind, modify, modify DN, and certain extended responses to provide 054 * information about the result of replication assurance processing for that 055 * operation. 056 * <BR> 057 * <BLOCKQUOTE> 058 * <B>NOTE:</B> This class, and other classes within the 059 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 060 * supported for use against Ping Identity, UnboundID, and 061 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 062 * for proprietary functionality or for external specifications that are not 063 * considered stable or mature enough to be guaranteed to work in an 064 * interoperable way with other types of LDAP servers. 065 * </BLOCKQUOTE> 066 * <BR> 067 * The OID for this control is 1.3.6.1.4.1.30221.2.5.29. It will have a 068 * criticality of FALSE, and will have a value with the following encoding: 069 * <PRE> 070 * AssuredReplicationResponse ::= SEQUENCE { 071 * localLevel [0] LocalLevel OPTIONAL, 072 * localAssuranceSatisfied [1] BOOLEAN, 073 * localAssuranceMessage [2] OCTET STRING OPTIONAL, 074 * remoteLevel [3] RemoteLevel OPTIONAL, 075 * remoteAssuranceSatisfied [4] BOOLEAN, 076 * remoteAssuranceMessage [5] OCTET STRING OPTIONAL, 077 * csn [6] OCTET STRING OPTIONAL, 078 * serverResults [7] SEQUENCE OF ServerResult OPTIONAL, 079 * ... } 080 * 081 * ServerResult ::= SEQUENCE { 082 * resultCode [0] ENUMERATED { 083 * complete (0), 084 * timeout (1), 085 * conflict (2), 086 * serverShutdown (3), 087 * unavailable (4), 088 * duplicate (5), 089 * ... }, 090 * replicationServerID [1] INTEGER OPTIONAL, 091 * replicaID [2] INTEGER OPTIONAL, 092 * ... } 093 * </PRE> 094 * 095 * @see AssuredReplicationRequestControl 096 */ 097@NotMutable() 098@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 099public final class AssuredReplicationResponseControl 100 extends Control 101 implements DecodeableControl 102{ 103 /** 104 * The OID (1.3.6.1.4.1.30221.2.5.29) for the assured replication response 105 * control. 106 */ 107 public static final String ASSURED_REPLICATION_RESPONSE_OID = 108 "1.3.6.1.4.1.30221.2.5.29"; 109 110 111 /** 112 * The BER type for the local level element. 113 */ 114 private static final byte TYPE_LOCAL_LEVEL = (byte) 0x80; 115 116 117 /** 118 * The BER type for the local assurance satisfied element. 119 */ 120 private static final byte TYPE_LOCAL_SATISFIED = (byte) 0x81; 121 122 123 /** 124 * The BER type for the local message element. 125 */ 126 private static final byte TYPE_LOCAL_MESSAGE = (byte) 0x82; 127 128 129 /** 130 * The BER type for the remote level element. 131 */ 132 private static final byte TYPE_REMOTE_LEVEL = (byte) 0x83; 133 134 135 /** 136 * The BER type for the remote assurance satisfied element. 137 */ 138 private static final byte TYPE_REMOTE_SATISFIED = (byte) 0x84; 139 140 141 /** 142 * The BER type for the remote message element. 143 */ 144 private static final byte TYPE_REMOTE_MESSAGE = (byte) 0x85; 145 146 147 /** 148 * The BER type for the CSN element. 149 */ 150 private static final byte TYPE_CSN = (byte) 0x86; 151 152 153 /** 154 * The BER type for the server results element. 155 */ 156 private static final byte TYPE_SERVER_RESULTS = (byte) 0xA7; 157 158 159 160 /** 161 * The serial version UID for this serializable class. 162 */ 163 private static final long serialVersionUID = -4521456074629871607L; 164 165 166 167 // The assurance level for local processing. 168 private final AssuredReplicationLocalLevel localLevel; 169 170 // The assurance level for remote processing. 171 private final AssuredReplicationRemoteLevel remoteLevel; 172 173 // Indicates whether the desired local assurance has been satisfied. 174 private final boolean localAssuranceSatisfied; 175 176 // Indicates whether the desired remote assurance has been satisfied. 177 private final boolean remoteAssuranceSatisfied; 178 179 // The results from individual replication and/or directory servers. 180 private final List<AssuredReplicationServerResult> serverResults; 181 182 // The replication change sequence number for the associated operation. 183 private final String csn; 184 185 // An optional message with additional information about local assurance 186 // processing. 187 private final String localAssuranceMessage; 188 189 // An optional message with additional information about local assurance 190 // processing. 191 private final String remoteAssuranceMessage; 192 193 194 195 /** 196 * Creates a new empty control instance that is intended to be used only for 197 * decoding controls via the {@code DecodeableControl} interface. 198 */ 199 AssuredReplicationResponseControl() 200 { 201 localLevel = null; 202 localAssuranceSatisfied = false; 203 localAssuranceMessage = null; 204 remoteLevel = null; 205 remoteAssuranceSatisfied = false; 206 remoteAssuranceMessage = null; 207 csn = null; 208 serverResults = null; 209 } 210 211 212 213 /** 214 * Creates a new assured replication response control with the provided 215 * information. 216 * 217 * @param localLevel The local assurance level selected by the 218 * server for the associated operation. It 219 * may be {@code null} if this is not 220 * available. 221 * @param localAssuranceSatisfied Indicates whether the desired local level 222 * of assurance is known to have been 223 * satisfied. 224 * @param localAssuranceMessage An optional message providing additional 225 * information about local assurance 226 * processing. This may be {@code null} if 227 * no additional message is needed. 228 * @param remoteLevel The remote assurance level selected by 229 * the server for the associated operation. 230 * It may be {@code null} if this is not 231 * available. 232 * @param remoteAssuranceSatisfied Indicates whether the desired remote 233 * level of assurance is known to have been 234 * satisfied. 235 * @param remoteAssuranceMessage An optional message providing additional 236 * information about remote assurance 237 * processing. This may be {@code null} if 238 * no additional message is needed. 239 * @param csn The change sequence number (CSN) that has 240 * been assigned to the associated 241 * operation. It may be {@code null} if no 242 * CSN is available. 243 * @param serverResults The set of individual results from the 244 * local and/or remote replication servers 245 * and/or directory servers used in 246 * assurance processing. This may be 247 * {@code null} or empty if no server 248 * results are available. 249 */ 250 public AssuredReplicationResponseControl( 251 final AssuredReplicationLocalLevel localLevel, 252 final boolean localAssuranceSatisfied, 253 final String localAssuranceMessage, 254 final AssuredReplicationRemoteLevel remoteLevel, 255 final boolean remoteAssuranceSatisfied, 256 final String remoteAssuranceMessage, final String csn, 257 final Collection<AssuredReplicationServerResult> serverResults) 258 { 259 super(ASSURED_REPLICATION_RESPONSE_OID, false, 260 encodeValue(localLevel, localAssuranceSatisfied, 261 localAssuranceMessage, remoteLevel, remoteAssuranceSatisfied, 262 remoteAssuranceMessage, csn, serverResults)); 263 264 this.localLevel = localLevel; 265 this.localAssuranceSatisfied = localAssuranceSatisfied; 266 this.localAssuranceMessage = localAssuranceMessage; 267 this.remoteLevel = remoteLevel; 268 this.remoteAssuranceSatisfied = remoteAssuranceSatisfied; 269 this.remoteAssuranceMessage = remoteAssuranceMessage; 270 this.csn = csn; 271 272 if (serverResults == null) 273 { 274 this.serverResults = Collections.emptyList(); 275 } 276 else 277 { 278 this.serverResults = Collections.unmodifiableList( 279 new ArrayList<>(serverResults)); 280 } 281 } 282 283 284 285 /** 286 * Creates a new assured replication response control with the provided 287 * information. 288 * 289 * @param oid The OID for the control. 290 * @param isCritical Indicates whether the control should be marked 291 * critical. 292 * @param value The encoded value for the control. This may be 293 * {@code null} if no value was provided. 294 * 295 * @throws LDAPException If the provided control cannot be decoded as an 296 * assured replication response control. 297 */ 298 public AssuredReplicationResponseControl(final String oid, 299 final boolean isCritical, 300 final ASN1OctetString value) 301 throws LDAPException 302 { 303 super(oid, isCritical, value); 304 305 if (value == null) 306 { 307 throw new LDAPException(ResultCode.DECODING_ERROR, 308 ERR_ASSURED_REPLICATION_RESPONSE_NO_VALUE.get()); 309 } 310 311 AssuredReplicationLocalLevel lLevel = null; 312 Boolean lSatisfied = null; 313 String lMessage = null; 314 AssuredReplicationRemoteLevel rLevel = null; 315 Boolean rSatisfied = null; 316 String rMessage = null; 317 String seqNum = null; 318 List<AssuredReplicationServerResult> sResults = Collections.emptyList(); 319 320 try 321 { 322 for (final ASN1Element e : 323 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 324 { 325 switch (e.getType()) 326 { 327 case TYPE_LOCAL_LEVEL: 328 int intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 329 lLevel = AssuredReplicationLocalLevel.valueOf(intValue); 330 if (lLevel == null) 331 { 332 throw new LDAPException(ResultCode.DECODING_ERROR, 333 ERR_ASSURED_REPLICATION_RESPONSE_INVALID_LOCAL_LEVEL.get( 334 intValue)); 335 } 336 break; 337 338 case TYPE_LOCAL_SATISFIED: 339 lSatisfied = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 340 break; 341 342 case TYPE_LOCAL_MESSAGE: 343 lMessage = ASN1OctetString.decodeAsOctetString(e).stringValue(); 344 break; 345 346 case TYPE_REMOTE_LEVEL: 347 intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 348 rLevel = AssuredReplicationRemoteLevel.valueOf(intValue); 349 if (lLevel == null) 350 { 351 throw new LDAPException(ResultCode.DECODING_ERROR, 352 ERR_ASSURED_REPLICATION_RESPONSE_INVALID_REMOTE_LEVEL.get( 353 intValue)); 354 } 355 break; 356 357 case TYPE_REMOTE_SATISFIED: 358 rSatisfied = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 359 break; 360 361 case TYPE_REMOTE_MESSAGE: 362 rMessage = ASN1OctetString.decodeAsOctetString(e).stringValue(); 363 break; 364 365 case TYPE_CSN: 366 seqNum = ASN1OctetString.decodeAsOctetString(e).stringValue(); 367 break; 368 369 case TYPE_SERVER_RESULTS: 370 final ASN1Element[] srElements = 371 ASN1Sequence.decodeAsSequence(e).elements(); 372 final ArrayList<AssuredReplicationServerResult> srList = 373 new ArrayList<>(srElements.length); 374 for (final ASN1Element srElement : srElements) 375 { 376 try 377 { 378 srList.add(AssuredReplicationServerResult.decode(srElement)); 379 } 380 catch (final Exception ex) 381 { 382 Debug.debugException(ex); 383 throw new LDAPException(ResultCode.DECODING_ERROR, 384 ERR_ASSURED_REPLICATION_RESPONSE_ERROR_DECODING_SR.get( 385 StaticUtils.getExceptionMessage(ex)), 386 ex); 387 } 388 } 389 sResults = Collections.unmodifiableList(srList); 390 break; 391 392 default: 393 throw new LDAPException(ResultCode.DECODING_ERROR, 394 ERR_ASSURED_REPLICATION_RESPONSE_UNEXPECTED_ELEMENT_TYPE.get( 395 StaticUtils.toHex(e.getType()))); 396 } 397 } 398 } 399 catch (final LDAPException le) 400 { 401 Debug.debugException(le); 402 throw le; 403 } 404 catch (final Exception e) 405 { 406 Debug.debugException(e); 407 throw new LDAPException(ResultCode.DECODING_ERROR, 408 ERR_ASSURED_REPLICATION_RESPONSE_ERROR_DECODING_VALUE.get( 409 StaticUtils.getExceptionMessage(e)), 410 e); 411 } 412 413 if (lSatisfied == null) 414 { 415 throw new LDAPException(ResultCode.DECODING_ERROR, 416 ERR_ASSURED_REPLICATION_RESPONSE_NO_LOCAL_SATISFIED.get()); 417 } 418 419 if (rSatisfied == null) 420 { 421 throw new LDAPException(ResultCode.DECODING_ERROR, 422 ERR_ASSURED_REPLICATION_RESPONSE_NO_REMOTE_SATISFIED.get()); 423 } 424 425 localLevel = lLevel; 426 localAssuranceSatisfied = lSatisfied; 427 localAssuranceMessage = lMessage; 428 remoteLevel = rLevel; 429 remoteAssuranceSatisfied = rSatisfied; 430 remoteAssuranceMessage = rMessage; 431 csn = seqNum; 432 serverResults = sResults; 433 } 434 435 436 437 /** 438 * Encodes the provided information to an ASN.1 octet string suitable for 439 * use as an assured replication response control value. 440 * 441 * @param localLevel The local assurance level selected by the 442 * server for the associated operation. It 443 * may be {@code null} if this is not 444 * available. 445 * @param localAssuranceSatisfied Indicates whether the desired local level 446 * of assurance is known to have been 447 * satisfied. 448 * @param localAssuranceMessage An optional message providing additional 449 * information about local assurance 450 * processing. This may be {@code null} if 451 * no additional message is needed. 452 * @param remoteLevel The remote assurance level selected by 453 * the server for the associated operation. 454 * It may be {@code null} if this is not 455 * available. 456 * @param remoteAssuranceSatisfied Indicates whether the desired remote 457 * level of assurance is known to have been 458 * satisfied. 459 * @param remoteAssuranceMessage An optional message providing additional 460 * information about remote assurance 461 * processing. This may be {@code null} if 462 * no additional message is needed. 463 * @param csn The change sequence number (CSN) that has 464 * been assigned to the associated 465 * operation. It may be {@code null} if no 466 * CSN is available. 467 * @param serverResults The set of individual results from the 468 * local and/or remote replication servers 469 * and/or directory servers used in 470 * assurance processing. This may be 471 * {@code null} or empty if no server 472 * results are available. 473 * 474 * @return The ASN.1 octet string containing the encoded value. 475 */ 476 private static ASN1OctetString encodeValue( 477 final AssuredReplicationLocalLevel localLevel, 478 final boolean localAssuranceSatisfied, 479 final String localAssuranceMessage, 480 final AssuredReplicationRemoteLevel remoteLevel, 481 final boolean remoteAssuranceSatisfied, 482 final String remoteAssuranceMessage, final String csn, 483 final Collection<AssuredReplicationServerResult> serverResults) 484 { 485 final ArrayList<ASN1Element> elements = new ArrayList<>(8); 486 487 if (localLevel != null) 488 { 489 elements.add(new ASN1Enumerated(TYPE_LOCAL_LEVEL, localLevel.intValue())); 490 } 491 492 elements.add(new ASN1Boolean(TYPE_LOCAL_SATISFIED, 493 localAssuranceSatisfied)); 494 495 if (localAssuranceMessage != null) 496 { 497 elements.add(new ASN1OctetString(TYPE_LOCAL_MESSAGE, 498 localAssuranceMessage)); 499 } 500 501 if (remoteLevel != null) 502 { 503 elements.add(new ASN1Enumerated(TYPE_REMOTE_LEVEL, 504 remoteLevel.intValue())); 505 } 506 507 elements.add(new ASN1Boolean(TYPE_REMOTE_SATISFIED, 508 remoteAssuranceSatisfied)); 509 510 if (remoteAssuranceMessage != null) 511 { 512 elements.add(new ASN1OctetString(TYPE_REMOTE_MESSAGE, 513 remoteAssuranceMessage)); 514 } 515 516 if (csn != null) 517 { 518 elements.add(new ASN1OctetString(TYPE_CSN, csn)); 519 } 520 521 if ((serverResults != null) && (! serverResults.isEmpty())) 522 { 523 final ArrayList<ASN1Element> srElements = 524 new ArrayList<>(serverResults.size()); 525 for (final AssuredReplicationServerResult r : serverResults) 526 { 527 srElements.add(r.encode()); 528 } 529 elements.add(new ASN1Sequence(TYPE_SERVER_RESULTS, srElements)); 530 } 531 532 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 533 } 534 535 536 537 /** 538 * {@inheritDoc} 539 */ 540 @Override() 541 public AssuredReplicationResponseControl decodeControl(final String oid, 542 final boolean isCritical, 543 final ASN1OctetString value) 544 throws LDAPException 545 { 546 return new AssuredReplicationResponseControl(oid, isCritical, value); 547 } 548 549 550 551 /** 552 * Extracts an assured replication response control from the provided LDAP 553 * result. If there are multiple assured replication response controls 554 * included in the result, then only the first will be returned. 555 * 556 * @param result The LDAP result from which to retrieve the assured 557 * replication response control. 558 * 559 * @return The assured replication response control contained in the provided 560 * LDAP result, or {@code null} if the result did not contain an 561 * assured replication response control. 562 * 563 * @throws LDAPException If a problem is encountered while attempting to 564 * decode the assured replication response control 565 * contained in the provided result. 566 */ 567 public static AssuredReplicationResponseControl get(final LDAPResult result) 568 throws LDAPException 569 { 570 final Control c = 571 result.getResponseControl(ASSURED_REPLICATION_RESPONSE_OID); 572 if (c == null) 573 { 574 return null; 575 } 576 577 if (c instanceof AssuredReplicationResponseControl) 578 { 579 return (AssuredReplicationResponseControl) c; 580 } 581 else 582 { 583 return new AssuredReplicationResponseControl(c.getOID(), c.isCritical(), 584 c.getValue()); 585 } 586 } 587 588 589 590 /** 591 * Extracts all assured replication response controls from the provided LDAP 592 * result. 593 * 594 * @param result The LDAP result from which to retrieve the assured 595 * replication response controls. 596 * 597 * @return A list containing the assured replication response controls 598 * contained in the provided LDAP result, or an empty list if the 599 * result did not contain any assured replication response control. 600 * 601 * @throws LDAPException If a problem is encountered while attempting to 602 * decode any assured replication response control 603 * contained in the provided result. 604 */ 605 public static List<AssuredReplicationResponseControl> getAll( 606 final LDAPResult result) 607 throws LDAPException 608 { 609 final Control[] controls = result.getResponseControls(); 610 final ArrayList<AssuredReplicationResponseControl> decodedControls = 611 new ArrayList<>(controls.length); 612 for (final Control c : controls) 613 { 614 if (c.getOID().equals(ASSURED_REPLICATION_RESPONSE_OID)) 615 { 616 if (c instanceof AssuredReplicationResponseControl) 617 { 618 decodedControls.add((AssuredReplicationResponseControl) c); 619 } 620 else 621 { 622 decodedControls.add(new AssuredReplicationResponseControl(c.getOID(), 623 c.isCritical(), c.getValue())); 624 } 625 } 626 } 627 628 return Collections.unmodifiableList(decodedControls); 629 } 630 631 632 633 /** 634 * Retrieves the local assurance level selected by the server for the 635 * associated operation, if available. 636 * 637 * @return The local assurance level selected by the server for the 638 * associated operation, or {@code null} if this is not available. 639 */ 640 public AssuredReplicationLocalLevel getLocalLevel() 641 { 642 return localLevel; 643 } 644 645 646 647 /** 648 * Indicates whether the desired local level of assurance is known to have 649 * been satisfied. 650 * 651 * @return {@code true} if the desired local level of assurance is known to 652 * have been satisfied, or {@code false} if not. 653 */ 654 public boolean localAssuranceSatisfied() 655 { 656 return localAssuranceSatisfied; 657 } 658 659 660 661 /** 662 * Retrieves a message with additional information about local assurance 663 * processing, if available. 664 * 665 * @return A message with additional information about local assurance 666 * processing, or {@code null} if none is available. 667 */ 668 public String getLocalAssuranceMessage() 669 { 670 return localAssuranceMessage; 671 } 672 673 674 675 /** 676 * Retrieves the remote assurance level selected by the server for the 677 * associated operation, if available. 678 * 679 * @return The remote assurance level selected by the server for the 680 * associated operation, or {@code null} if the remote assurance 681 * level is not available. 682 */ 683 public AssuredReplicationRemoteLevel getRemoteLevel() 684 { 685 return remoteLevel; 686 } 687 688 689 690 /** 691 * Indicates whether the desired remote level of assurance is known to have 692 * been satisfied. 693 * 694 * @return {@code true} if the desired remote level of assurance is known to 695 * have been satisfied, or {@code false} if not. 696 */ 697 public boolean remoteAssuranceSatisfied() 698 { 699 return remoteAssuranceSatisfied; 700 } 701 702 703 704 /** 705 * Retrieves a message with additional information about remote assurance 706 * processing, if available. 707 * 708 * @return A message with additional information about remote assurance 709 * processing, or {@code null} if none is available. 710 */ 711 public String getRemoteAssuranceMessage() 712 { 713 return remoteAssuranceMessage; 714 } 715 716 717 718 /** 719 * Retrieves the replication change sequence number (CSN) assigned to the 720 * associated operation, if available. 721 * 722 * @return The replication CSN assigned to the associated operation, or 723 * {@code null} if the CSN is not available. 724 */ 725 public String getCSN() 726 { 727 return csn; 728 } 729 730 731 732 /** 733 * Retrieves a list of the results from individual replication servers and/or 734 * directory servers used in assurance processing. It may be empty if no 735 * server results are available. 736 * 737 * @return A list of the results from individual replication servers and/or 738 * directory servers used in assurance processing. 739 */ 740 public List<AssuredReplicationServerResult> getServerResults() 741 { 742 return serverResults; 743 } 744 745 746 747 /** 748 * {@inheritDoc} 749 */ 750 @Override() 751 public String getControlName() 752 { 753 return INFO_CONTROL_NAME_ASSURED_REPLICATION_RESPONSE.get(); 754 } 755 756 757 758 /** 759 * {@inheritDoc} 760 */ 761 @Override() 762 public void toString(final StringBuilder buffer) 763 { 764 buffer.append("AssuredReplicationResponseControl(isCritical="); 765 buffer.append(isCritical()); 766 767 if (localLevel != null) 768 { 769 buffer.append(", localLevel="); 770 buffer.append(localLevel.name()); 771 } 772 773 buffer.append(", localAssuranceSatisfied="); 774 buffer.append(localAssuranceSatisfied); 775 776 if (localAssuranceMessage != null) 777 { 778 buffer.append(", localMessage='"); 779 buffer.append(localAssuranceMessage); 780 buffer.append('\''); 781 } 782 783 if (remoteLevel != null) 784 { 785 buffer.append(", remoteLevel="); 786 buffer.append(remoteLevel.name()); 787 } 788 789 buffer.append(", remoteAssuranceSatisfied="); 790 buffer.append(remoteAssuranceSatisfied); 791 792 if (remoteAssuranceMessage != null) 793 { 794 buffer.append(", remoteMessage='"); 795 buffer.append(remoteAssuranceMessage); 796 buffer.append('\''); 797 } 798 799 if (csn != null) 800 { 801 buffer.append(", csn='"); 802 buffer.append(csn); 803 buffer.append('\''); 804 } 805 806 if ((serverResults != null) && (! serverResults.isEmpty())) 807 { 808 buffer.append(", serverResults={"); 809 810 final Iterator<AssuredReplicationServerResult> iterator = 811 serverResults.iterator(); 812 while (iterator.hasNext()) 813 { 814 if (iterator.hasNext()) 815 { 816 iterator.next().toString(buffer); 817 buffer.append(", "); 818 } 819 } 820 821 buffer.append('}'); 822 } 823 824 buffer.append(')'); 825 } 826}