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