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 }