001/*
002 * Copyright 2009-2023 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2009-2023 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) 2009-2023 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.monitors;
037
038
039
040import java.util.Collections;
041import java.util.LinkedHashMap;
042import java.util.Map;
043
044import com.unboundid.ldap.sdk.Entry;
045import com.unboundid.util.Debug;
046import com.unboundid.util.NotMutable;
047import com.unboundid.util.NotNull;
048import com.unboundid.util.Nullable;
049import com.unboundid.util.StaticUtils;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052
053import static com.unboundid.ldap.sdk.unboundidds.monitors.MonitorMessages.*;
054
055
056
057/**
058 * This class defines a monitor entry that provides information about the state
059 * of a replica, including the base DN, replica ID, and generation ID, as well
060 * as information about its communication with the replication server
061 * <BR>
062 * <BLOCKQUOTE>
063 *   <B>NOTE:</B>  This class, and other classes within the
064 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
065 *   supported for use against Ping Identity, UnboundID, and
066 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
067 *   for proprietary functionality or for external specifications that are not
068 *   considered stable or mature enough to be guaranteed to work in an
069 *   interoperable way with other types of LDAP servers.
070 * </BLOCKQUOTE>
071 * <BR>
072 * The server should present a replica monitor entry for each replicated base
073 * DN.  They can be retrieved using the
074 * {@link MonitorManager#getReplicaMonitorEntries} method.  These entries
075 * provide specific methods for accessing information about the replica.
076 * Alternately, this information may be accessed using the generic API.  See the
077 * {@link MonitorManager} class documentation for an example that demonstrates
078 * the use of the generic API for accessing monitor data.
079 */
080@NotMutable()
081@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
082public final class ReplicaMonitorEntry
083       extends MonitorEntry
084{
085  /**
086   * The structural object class used in replica monitor entries.
087   */
088  @NotNull static final String REPLICA_MONITOR_OC =
089       "ds-replica-monitor-entry";
090
091
092
093  /**
094   * The name of the attribute that contains the base DNs for the replicated
095   * data.
096   */
097  @NotNull private static final String ATTR_BASE_DN = "base-dn";
098
099
100
101  /**
102   * The name of the attribute that contains the address and port of the
103   * replication server to which the replica is connected.
104   */
105  @NotNull private static final String ATTR_CONNECTED_TO =
106       "connected-to";
107
108
109
110  /**
111   * The name of the attribute that provides information about the current
112   * receive window size.
113   */
114  @NotNull private static final String ATTR_CURRENT_RECEIVE_WINDOW_SIZE =
115       "current-rcv-window";
116
117
118
119  /**
120   * The name of the attribute that provides information about the current send
121   * window size.
122   */
123  @NotNull private static final String ATTR_CURRENT_SEND_WINDOW_SIZE =
124       "current-send-window";
125
126
127
128  /**
129   * The name of the attribute that provides the generation ID for the replica.
130   */
131  @NotNull private static final String ATTR_GENERATION_ID = "generation-id";
132
133
134
135  /**
136   * The name of the attribute that provides information about the number of
137   * times the connection to the replication server has been lost.
138   */
139  @NotNull private static final String ATTR_LOST_CONNECTIONS =
140       "lost-connections";
141
142
143
144  /**
145   * The name of the attribute that provides information about the maximum
146   * receive window size.
147   */
148  @NotNull private static final String ATTR_MAX_RECEIVE_WINDOW_SIZE =
149       "max-rcv-window";
150
151
152
153  /**
154   * The name of the attribute that provides information about the maximum send
155   * window size.
156   */
157  @NotNull private static final String ATTR_MAX_SEND_WINDOW_SIZE =
158       "max-send-window";
159
160
161
162  /**
163   * The name of the attribute that provides information about the number of
164   * pending updates which are currently being processed by the Directory Server
165   * and have not yet been sent to the replication server.
166   */
167  @NotNull private static final String ATTR_PENDING_UPDATES = "pending-updates";
168
169
170
171  /**
172   * The name of the attribute that provides information about the number of
173   * updates received from the replication server for this replica.
174   */
175  @NotNull private static final String ATTR_RECEIVED_UPDATES =
176       "received-updates";
177
178
179
180  /**
181   * The name of the attribute that provides the replica ID for this replica.
182   */
183  @NotNull private static final String ATTR_REPLICA_ID = "replica-id";
184
185
186
187  /**
188   * The name of the attribute that provides information about the number of
189   * updates that were replayed after resolving a modify conflict.
190   */
191  @NotNull private static final String ATTR_RESOLVED_MODIFY_CONFLICTS =
192       "resolved-modify-conflicts";
193
194
195
196  /**
197   * The name of the attribute that provides information about the number of
198   * updates that were replayed after resolving a naming conflict.
199   */
200  @NotNull private static final String ATTR_RESOLVED_NAMING_CONFLICTS =
201       "resolved-naming-conflicts";
202
203
204
205  /**
206   * The name of the attribute that provides information about the number of
207   * updates sent to the replication server from this replica.
208   */
209  @NotNull private static final String ATTR_SENT_UPDATES = "sent-updates";
210
211
212
213  /**
214   * The name of the attribute that indicates whether SSL is used when
215   * communicating with the replication server.
216   */
217  @NotNull private static final String ATTR_SSL_ENCRYPTION = "ssl-encryption";
218
219
220
221  /**
222   * The name of the attribute that provides information about the number of
223   * updates that have been successfully replayed with no problems.
224   */
225  @NotNull private static final String ATTR_SUCCESSFUL_REPLAYED =
226       "replayed-updates-ok";
227
228
229
230  /**
231   * The name of the attribute that provides information about the total number
232   * of updates that have been replayed in some form.
233   */
234  @NotNull private static final String ATTR_TOTAL_REPLAYED = "replayed-updates";
235
236
237
238  /**
239   * The name of the attribute that provides information about the number of
240   * updates that could not be replayed because of an unresolved naming
241   * conflict.
242   */
243  @NotNull private static final String ATTR_UNRESOLVED_NAMING_CONFLICTS =
244       "unresolved-naming-conflicts";
245
246
247
248  /**
249   * The serial version UID for this serializable class.
250   */
251  private static final long serialVersionUID = -9164207693317460579L;
252
253
254
255  // Indicates whether the replica uses SSL when communicating with the
256  // replication server.
257  @Nullable private final Boolean useSSL;
258
259  // The current receive window size.
260  @Nullable private final Long currentReceiveWindowSize;
261
262  // The current send window size.
263  @Nullable private final Long currentSendWindowSize;
264
265  // The number of lost connections.
266  @Nullable private final Long lostConnections;
267
268  // The maximum receive window size.
269  @Nullable private final Long maxReceiveWindowSize;
270
271  // The maximum send window size.
272  @Nullable private final Long maxSendWindowSize;
273
274  // The number of pending updates that haven't been sent to the replication
275  // server.
276  @Nullable private final Long pendingUpdates;
277
278  // The number of updates received from the replication server.
279  @Nullable private final Long receivedUpdates;
280
281  // The number of updates replayed after resolving a modify conflict.
282  @Nullable private final Long replayedAfterModifyConflict;
283
284  // The number of updates replayed after resolving a naming conflict.
285  @Nullable private final Long replayedAfterNamingConflict;
286
287  // The port number of the replication server.
288  @Nullable private final Long replicationServerPort;
289
290  // The number of updates sent to the replication server.
291  @Nullable private final Long sentUpdates;
292
293  // The number of updates replayed successfully.
294  @Nullable private final Long successfullyReplayed;
295
296  // The total number of updates replayed.
297  @Nullable private final Long totalReplayed;
298
299  // The number of unresolved naming conflicts that could not be successfully
300  // replayed.
301  @Nullable private final Long unresolvedNamingConflicts;
302
303  // The base DN for the replicated data.
304  @Nullable private final String baseDN;
305
306  // The generation ID for the replicated data.
307  @Nullable private final String generationID;
308
309  // The replica ID for the replica.
310  @Nullable private final String replicaID;
311
312  // The address of the replication server.
313  @Nullable private final String replicationServerAddress;
314
315
316
317  /**
318   * Creates a new replica monitor entry from the provided entry.
319   *
320   * @param  entry  The entry to be parsed as a replica monitor entry.  It must
321   *                not be {@code null}.
322   */
323  public ReplicaMonitorEntry(@NotNull final Entry entry)
324  {
325    super(entry);
326
327    useSSL                      = getBoolean(ATTR_SSL_ENCRYPTION);
328    lostConnections             = getLong(ATTR_LOST_CONNECTIONS);
329    receivedUpdates             = getLong(ATTR_RECEIVED_UPDATES);
330    sentUpdates                 = getLong(ATTR_SENT_UPDATES);
331    pendingUpdates              = getLong(ATTR_PENDING_UPDATES);
332    totalReplayed               = getLong(ATTR_TOTAL_REPLAYED);
333    successfullyReplayed        = getLong(ATTR_SUCCESSFUL_REPLAYED);
334    replayedAfterModifyConflict = getLong(ATTR_RESOLVED_MODIFY_CONFLICTS);
335    replayedAfterNamingConflict = getLong(ATTR_RESOLVED_NAMING_CONFLICTS);
336    unresolvedNamingConflicts   = getLong(ATTR_UNRESOLVED_NAMING_CONFLICTS);
337    currentReceiveWindowSize    = getLong(ATTR_CURRENT_RECEIVE_WINDOW_SIZE);
338    currentSendWindowSize       = getLong(ATTR_CURRENT_SEND_WINDOW_SIZE);
339    maxReceiveWindowSize        = getLong(ATTR_MAX_RECEIVE_WINDOW_SIZE);
340    maxSendWindowSize           = getLong(ATTR_MAX_SEND_WINDOW_SIZE);
341    baseDN                      = getString(ATTR_BASE_DN);
342    generationID                = getString(ATTR_GENERATION_ID);
343    replicaID                   = getString(ATTR_REPLICA_ID);
344
345    String addr = null;
346    Long   port = null;
347    final String connectedTo = getString(ATTR_CONNECTED_TO);
348    if (connectedTo != null)
349    {
350      try
351      {
352        final int colonPos = connectedTo.indexOf(':');
353        if (colonPos > 0)
354        {
355          addr = connectedTo.substring(0, colonPos);
356          port = Long.parseLong(connectedTo.substring(colonPos+1));
357        }
358      }
359      catch (final Exception e)
360      {
361        Debug.debugException(e);
362        addr = null;
363        port = null;
364      }
365    }
366
367    replicationServerAddress = addr;
368    replicationServerPort    = port;
369  }
370
371
372
373  /**
374   * Retrieves the base DN for this replica.
375   *
376   * @return  The base DN for this replica, or {@code null} if it was not
377   *          included in the monitor entry.
378   */
379  @Nullable()
380  public String getBaseDN()
381  {
382    return baseDN;
383  }
384
385
386
387  /**
388   * Retrieves the replica ID for this replica.
389   *
390   * @return  The replica ID for this replica, or {@code null} if it was not
391   *          included in the monitor entry.
392   */
393  @Nullable()
394  public String getReplicaID()
395  {
396    return replicaID;
397  }
398
399
400
401  /**
402   * Retrieves the generation ID for this replica.
403   *
404   * @return  The generation ID for this replica, or {@code null} if it was not
405   *          included in the monitor entry.
406   */
407  @Nullable()
408  public String getGenerationID()
409  {
410    return generationID;
411  }
412
413
414
415  /**
416   * Retrieves the address of the replication server to which this replica is
417   * connected.
418   *
419   * @return  The address of the replication server to which this replica is
420   *          connected, or {@code null} if it was not included in the monitor
421   *          entry.
422   */
423  @Nullable()
424  public String getReplicationServerAddress()
425  {
426    return replicationServerAddress;
427  }
428
429
430
431  /**
432   * Retrieves the port number of the replication server to which this replica
433   * is connected.
434   *
435   * @return  The port number of the replication server to which this replica is
436   *          connected, or {@code null} if it was not included in the monitor
437   *          entry.
438   */
439  @Nullable()
440  public Long getReplicationServerPort()
441  {
442    return replicationServerPort;
443  }
444
445
446
447  /**
448   * Indicates whether this replica uses SSL when communicating with the
449   * replication server.
450   *
451   * @return  {@code Boolean.TRUE} if this replica uses SSL when communicating
452   *          with the replication server, {@code Boolean.FALSE} if it does not
453   *          use SSL, or {@code null} if it was not included in the monitor
454   *          entry.
455   */
456  @Nullable()
457  public Boolean useSSL()
458  {
459    return useSSL;
460  }
461
462
463
464  /**
465   * Retrieves the number of times this replica has lost the connection to a
466   * replication server.
467   *
468   * @return  The number of times this replica has lost the connection to a
469   *          replication server, or {@code null} if it was not included in the
470   *          monitor entry.
471   */
472  @Nullable()
473  public Long getLostConnections()
474  {
475    return lostConnections;
476  }
477
478
479
480  /**
481   * Retrieves the number of updates that this replica has received from the
482   * replication server.
483   *
484   * @return  The number of updates that this replica has received from the
485   *          replication server, or {@code null} if it was not included in the
486   *          monitor entry.
487   */
488  @Nullable()
489  public Long getReceivedUpdates()
490  {
491    return receivedUpdates;
492  }
493
494
495
496  /**
497   * Retrieves the number of updates that this replica has sent to the
498   * replication server.
499   *
500   * @return  The number of updates that this replica has sent to the
501   *          replication server, or {@code null} if it was not included in the
502   *          monitor entry.
503   */
504  @Nullable()
505  public Long getSentUpdates()
506  {
507    return sentUpdates;
508  }
509
510
511
512  /**
513   * Retrieves the number of updates that are currently in progress in the
514   * Directory Server and have not yet been sent to the replication server.
515   *
516   * @return  The number of updates that are currently in progress in the
517   *          Directory Server and have not yet been sent to the replication
518   *          server, or {@code null} if it was not included in the monitor
519   *          entry.
520   */
521  @Nullable()
522  public Long getPendingUpdates()
523  {
524    return pendingUpdates;
525  }
526
527
528
529  /**
530   * Retrieves the total number of updates that have been replayed in this
531   * replica.
532   *
533   * @return  The total number of updates that have been replayed in this
534   *          replica, or {@code null} if it was not included in the monitor
535   *          entry.
536   */
537  @Nullable()
538  public Long getTotalUpdatesReplayed()
539  {
540    return totalReplayed;
541  }
542
543
544
545  /**
546   * Retrieves the number of updates that have been successfully replayed in
547   * this replica without conflicts.
548   *
549   * @return  The number of updates that have been successfully replayed in this
550   *          replica without conflicts, or {@code null} if it was not included
551   *          in the monitor entry.
552   */
553  @Nullable()
554  public Long getUpdatesSuccessfullyReplayed()
555  {
556    return successfullyReplayed;
557  }
558
559
560
561  /**
562   * Retrieves the number of updates that have been replayed in this replica
563   * after automatically resolving a modify conflict.
564   *
565   * @return  The number of updates that have been replayed in this replica
566   *          after automatically resolving a modify conflict, or {@code null}
567   *          if it was not included in the monitor entry.
568   */
569  @Nullable()
570  public Long getUpdatesReplayedAfterModifyConflict()
571  {
572    return replayedAfterModifyConflict;
573  }
574
575
576
577  /**
578   * Retrieves the number of updates that have been replayed in this replica
579   * after automatically resolving a naming conflict.
580   *
581   * @return  The number of updates that have been replayed in this replica
582   *          after automatically resolving a naming conflict, or {@code null}
583   *          if it was not included in the monitor entry.
584   */
585  @Nullable()
586  public Long getUpdatesReplayedAfterNamingConflict()
587  {
588    return replayedAfterNamingConflict;
589  }
590
591
592
593  /**
594   * Retrieves the number of updates that could not be replayed as a result of a
595   * naming conflict that could not be automatically resolved.
596   *
597   * @return  The number of updates that could not be replayed as a result of a
598   *          naming conflict that could not be automatically resolved, or
599   *          {@code null} if it was not included in the monitor entry.
600   */
601  @Nullable()
602  public Long getUnresolvedNamingConflicts()
603  {
604    return unresolvedNamingConflicts;
605  }
606
607
608
609  /**
610   * Retrieves the current receive window size for this replica.
611   *
612   * @return  The current receive window size for this replica, or {@code null}
613   *          if it was not included in the monitor entry.
614   */
615  @Nullable()
616  public Long getCurrentReceiveWindowSize()
617  {
618    return currentReceiveWindowSize;
619  }
620
621
622
623  /**
624   * Retrieves the current send window size for this replica.
625   *
626   * @return  The current send window size for this replica, or {@code null} if
627   *          it was not included in the monitor entry.
628   */
629  @Nullable()
630  public Long getCurrentSendWindowSize()
631  {
632    return currentSendWindowSize;
633  }
634
635
636
637  /**
638   * Retrieves the maximum receive window size for this replica.
639   *
640   * @return  The maximum receive window size for this replica, or {@code null}
641   *          if it was not included in the monitor entry.
642   */
643  @Nullable()
644  public Long getMaximumReceiveWindowSize()
645  {
646    return maxReceiveWindowSize;
647  }
648
649
650
651  /**
652   * Retrieves the maximum send window size for this replica.
653   *
654   * @return  The maximum send window size for this replica, or {@code null} if
655   *          it was not included in the monitor entry.
656   */
657  @Nullable()
658  public Long getMaximumSendWindowSize()
659  {
660    return maxSendWindowSize;
661  }
662
663
664
665  /**
666   * {@inheritDoc}
667   */
668  @Override()
669  @NotNull()
670  public String getMonitorDisplayName()
671  {
672    return INFO_REPLICA_MONITOR_DISPNAME.get();
673  }
674
675
676
677  /**
678   * {@inheritDoc}
679   */
680  @Override()
681  @NotNull()
682  public String getMonitorDescription()
683  {
684    return INFO_REPLICA_MONITOR_DESC.get();
685  }
686
687
688
689  /**
690   * {@inheritDoc}
691   */
692  @Override()
693  @NotNull()
694  public Map<String,MonitorAttribute> getMonitorAttributes()
695  {
696    final LinkedHashMap<String,MonitorAttribute> attrs =
697         new LinkedHashMap<>(StaticUtils.computeMapCapacity(30));
698
699    if (baseDN != null)
700    {
701      addMonitorAttribute(attrs,
702           ATTR_BASE_DN,
703           INFO_REPLICA_DISPNAME_BASE_DN.get(),
704           INFO_REPLICA_DESC_BASE_DN.get(),
705           baseDN);
706    }
707
708    if (replicaID != null)
709    {
710      addMonitorAttribute(attrs,
711           ATTR_REPLICA_ID,
712           INFO_REPLICA_DISPNAME_REPLICA_ID.get(),
713           INFO_REPLICA_DESC_REPLICA_ID.get(),
714           replicaID);
715    }
716
717    if (generationID != null)
718    {
719      addMonitorAttribute(attrs,
720           ATTR_GENERATION_ID,
721           INFO_REPLICA_DISPNAME_GENERATION_ID.get(),
722           INFO_REPLICA_DESC_GENERATION_ID.get(),
723           generationID);
724    }
725
726    if (replicationServerAddress != null)
727    {
728      addMonitorAttribute(attrs,
729           ATTR_CONNECTED_TO,
730           INFO_REPLICA_DISPNAME_CONNECTED_TO.get(),
731           INFO_REPLICA_DESC_CONNECTED_TO.get(),
732           replicationServerAddress + ':' + replicationServerPort);
733    }
734
735    if (useSSL != null)
736    {
737      addMonitorAttribute(attrs,
738           ATTR_SSL_ENCRYPTION,
739           INFO_REPLICA_DISPNAME_USE_SSL.get(),
740           INFO_REPLICA_DESC_USE_SSL.get(),
741           useSSL);
742    }
743
744    if (lostConnections != null)
745    {
746      addMonitorAttribute(attrs,
747           ATTR_LOST_CONNECTIONS,
748           INFO_REPLICA_DISPNAME_LOST_CONNECTIONS.get(),
749           INFO_REPLICA_DESC_LOST_CONNECTIONS.get(),
750           lostConnections);
751    }
752
753    if (receivedUpdates != null)
754    {
755      addMonitorAttribute(attrs,
756           ATTR_RECEIVED_UPDATES,
757           INFO_REPLICA_DISPNAME_RECEIVED_UPDATES.get(),
758           INFO_REPLICA_DESC_RECEIVED_UPDATES.get(),
759           receivedUpdates);
760    }
761
762    if (sentUpdates != null)
763    {
764      addMonitorAttribute(attrs,
765           ATTR_SENT_UPDATES,
766           INFO_REPLICA_DISPNAME_SENT_UPDATES.get(),
767           INFO_REPLICA_DESC_SENT_UPDATES.get(),
768           sentUpdates);
769    }
770
771    if (pendingUpdates != null)
772    {
773      addMonitorAttribute(attrs,
774           ATTR_PENDING_UPDATES,
775           INFO_REPLICA_DISPNAME_PENDING_UPDATES.get(),
776           INFO_REPLICA_DESC_PENDING_UPDATES.get(),
777           pendingUpdates);
778    }
779
780    if (totalReplayed != null)
781    {
782      addMonitorAttribute(attrs,
783           ATTR_TOTAL_REPLAYED,
784           INFO_REPLICA_DISPNAME_TOTAL_REPLAYED.get(),
785           INFO_REPLICA_DESC_TOTAL_REPLAYED.get(),
786           totalReplayed);
787    }
788
789    if (successfullyReplayed != null)
790    {
791      addMonitorAttribute(attrs,
792           ATTR_SUCCESSFUL_REPLAYED,
793           INFO_REPLICA_DISPNAME_SUCCESSFUL_REPLAYED.get(),
794           INFO_REPLICA_DESC_SUCCESSFUL_REPLAYED.get(),
795           successfullyReplayed);
796    }
797
798    if (replayedAfterModifyConflict != null)
799    {
800      addMonitorAttribute(attrs,
801           ATTR_RESOLVED_MODIFY_CONFLICTS,
802           INFO_REPLICA_DISPNAME_RESOLVED_MODIFY_CONFLICTS.get(),
803           INFO_REPLICA_DESC_RESOLVED_MODIFY_CONFLICTS.get(),
804           replayedAfterModifyConflict);
805    }
806
807    if (replayedAfterNamingConflict != null)
808    {
809      addMonitorAttribute(attrs,
810           ATTR_RESOLVED_NAMING_CONFLICTS,
811           INFO_REPLICA_DISPNAME_RESOLVED_NAMING_CONFLICTS.get(),
812           INFO_REPLICA_DESC_RESOLVED_NAMING_CONFLICTS.get(),
813           replayedAfterNamingConflict);
814    }
815
816    if (unresolvedNamingConflicts != null)
817    {
818      addMonitorAttribute(attrs,
819           ATTR_UNRESOLVED_NAMING_CONFLICTS,
820           INFO_REPLICA_DISPNAME_UNRESOLVED_NAMING_CONFLICTS.get(),
821           INFO_REPLICA_DESC_UNRESOLVED_NAMING_CONFLICTS.get(),
822           unresolvedNamingConflicts);
823    }
824
825    if (currentReceiveWindowSize != null)
826    {
827      addMonitorAttribute(attrs,
828           ATTR_CURRENT_RECEIVE_WINDOW_SIZE,
829           INFO_REPLICA_DISPNAME_CURRENT_RECEIVE_WINDOW_SIZE.get(),
830           INFO_REPLICA_DESC_CURRENT_RECEIVE_WINDOW_SIZE.get(),
831           currentReceiveWindowSize);
832    }
833
834    if (currentSendWindowSize != null)
835    {
836      addMonitorAttribute(attrs,
837           ATTR_CURRENT_SEND_WINDOW_SIZE,
838           INFO_REPLICA_DISPNAME_CURRENT_SEND_WINDOW_SIZE.get(),
839           INFO_REPLICA_DESC_CURRENT_SEND_WINDOW_SIZE.get(),
840           currentSendWindowSize);
841    }
842
843    if (maxReceiveWindowSize != null)
844    {
845      addMonitorAttribute(attrs,
846           ATTR_MAX_RECEIVE_WINDOW_SIZE,
847           INFO_REPLICA_DISPNAME_MAX_RECEIVE_WINDOW_SIZE.get(),
848           INFO_REPLICA_DESC_MAX_RECEIVE_WINDOW_SIZE.get(),
849           maxReceiveWindowSize);
850    }
851
852    if (maxSendWindowSize != null)
853    {
854      addMonitorAttribute(attrs,
855           ATTR_MAX_SEND_WINDOW_SIZE,
856           INFO_REPLICA_DISPNAME_MAX_SEND_WINDOW_SIZE.get(),
857           INFO_REPLICA_DESC_MAX_SEND_WINDOW_SIZE.get(),
858           maxSendWindowSize);
859    }
860
861    return Collections.unmodifiableMap(attrs);
862  }
863}