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