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