From 4bc3503977c547da4c1ec0292e473293d9528fdd Mon Sep 17 00:00:00 2001
From: floblanc <floblanc@localhost>
Date: Thu, 06 Nov 2008 09:26:29 +0000
Subject: [PATCH] Implement statistics for the network group. The stats are available under cn=monitor.

---
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicyStat.java |  127 ++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicy.java     |   18 +
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimits.java             |   30 ++
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsStat.java         |   87 ++++++++
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java     |  239 +++++++++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java               |   39 +++
 opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java           |    1 
 7 files changed, 536 insertions(+), 5 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
index 30ad1c6..9e1ab1a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
@@ -36,6 +36,7 @@
 
 import org.opends.server.api.ClientConnection;
 import org.opends.server.core.*;
+import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
@@ -133,6 +134,9 @@
   // The network group request filtering policy
   private RequestFilteringPolicy requestFilteringPolicy = null;
 
+  // The statistics
+  private NetworkGroupStatistics stats;
+
   /**
    * Creates a new instance of the network group.
    *
@@ -147,6 +151,9 @@
     isInternalNetworkGroup = INTERNAL_NETWORK_GROUP_NAME.equals(networkGroupID);
     isAdminNetworkGroup    = ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
     isDefaultNetworkGroup  = DEFAULT_NETWORK_GROUP_NAME.equals(networkGroupID);
+
+    stats = new NetworkGroupStatistics(this,
+        networkGroupID + " Network Group Statistics");
   }
 
 
@@ -1108,4 +1115,36 @@
       namingContexts = new NetworkGroupNamingContexts();
     }
   }
+
+  /**
+   * Retrieves the statistics associated to the request filtering policy.
+   *
+   * @return the statistics associated to the request filtering policy
+   */
+  public RequestFilteringPolicyStat getRequestFilteringPolicyStat() {
+    if (requestFilteringPolicy != null) {
+      return requestFilteringPolicy.getStat();
+    }
+    return null;
+  }
+
+  /**
+   * Retrieves the statistics associated to the resource limits.
+   *
+   * @return the statistics associated to the resource limits
+   */
+  public ResourceLimitsStat getResourceLimitStat() {
+    if (resourceLimits != null) {
+      return resourceLimits.getStat();
+    }
+    return null;
+  }
+
+  /**
+   * Updates the operations statistics.
+   * @param message The LDAP message being processed
+   */
+  public void updateMessageRead(LDAPMessage message) {
+    stats.updateMessageRead(message);
+  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java
new file mode 100644
index 0000000..b688cf3
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java
@@ -0,0 +1,239 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.core.networkgroups;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opends.messages.Message;
+import org.opends.server.admin.std.server.MonitorProviderCfg;
+import org.opends.server.api.MonitorProvider;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.ldap.LDAPMessage;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.InitializationException;
+
+import org.opends.server.types.SearchScope;
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+
+/**
+ * This class implements the statistics associated to a network group.
+ */
+public class NetworkGroupStatistics
+       extends MonitorProvider<MonitorProviderCfg> {
+
+  // The instance name for this monitor provider instance.
+  private String instanceName;
+  private NetworkGroup networkGroup;
+
+  private Object lock = new Object();
+  private long abandonRequests = 0;
+  private long addRequests = 0;
+  private long bindRequests = 0;
+  private long compareRequests = 0;
+  private long deleteRequests = 0;
+  private long extendedRequests = 0;
+  private long modifyRequests = 0;
+  private long modifyDNRequests = 0;
+  private long searchOneRequests = 0;
+  private long searchSubRequests = 0;
+  private long unbindRequests = 0;
+
+  /**
+   * Constructor.
+   * @param networkGroup The network group owning these stats
+   * @param instanceName The name of the stat object
+   */
+  public NetworkGroupStatistics(
+          NetworkGroup networkGroup, String instanceName) {
+    super("LDAP Statistics Monitor Provider");
+    this.instanceName = instanceName;
+    this.networkGroup = networkGroup;
+    DirectoryServer.registerMonitorProvider(this);
+  }
+
+
+  /**
+   * Increments the number of operations managed by this network group.
+   * @param message The LDAP Message containing the operation to be
+   * managed by the network group.
+   */
+  public void updateMessageRead(LDAPMessage message) {
+    synchronized (lock)
+    {
+      switch (message.getProtocolOp().getType())
+      {
+        case OP_TYPE_ABANDON_REQUEST:
+          abandonRequests++;
+          break;
+        case OP_TYPE_ADD_REQUEST:
+          addRequests++;
+          break;
+        case OP_TYPE_BIND_REQUEST:
+          bindRequests++;
+          break;
+        case OP_TYPE_COMPARE_REQUEST:
+          compareRequests++;
+          break;
+        case OP_TYPE_DELETE_REQUEST:
+          deleteRequests++;
+          break;
+        case OP_TYPE_EXTENDED_REQUEST:
+          extendedRequests++;
+          break;
+        case OP_TYPE_MODIFY_REQUEST:
+          modifyRequests++;
+          break;
+        case OP_TYPE_MODIFY_DN_REQUEST:
+          modifyDNRequests++;
+          break;
+        case OP_TYPE_SEARCH_REQUEST:
+          SearchScope scope = message.getSearchRequestProtocolOp().getScope();
+          if (scope == SearchScope.BASE_OBJECT
+              || scope == SearchScope.SINGLE_LEVEL) {
+            searchOneRequests++;
+          } else {
+            searchSubRequests++;
+          }
+          break;
+        case OP_TYPE_UNBIND_REQUEST:
+          unbindRequests++;
+          break;
+      }
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void initializeMonitorProvider(MonitorProviderCfg configuration)
+         throws ConfigException, InitializationException {
+    // Throw an exception, because this monitor is not intended to be
+    // dynamically loaded from the configuration.  Rather, it should be
+    // explicitly created and registered by the LDAP connection handler or an
+    // LDAP client connection.
+    Message message = ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION.get(
+        String.valueOf(configuration.dn()));
+    throw new ConfigException(message);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getMonitorInstanceName() {
+    return instanceName;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public long getUpdateInterval() {
+    // This monitor should not run periodically.
+    return -1;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void updateMonitorData() {
+    // No implementation is required since this does not do periodic updates.
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public List<Attribute> getMonitorData() {
+    ArrayList<Attribute> attrs = new ArrayList<Attribute>();
+
+    RequestFilteringPolicyStat requestFilteringPolicyStat =
+            networkGroup.getRequestFilteringPolicyStat();
+    if (requestFilteringPolicyStat != null) {
+      attrs.add(Attributes.create("ds-mon-rejected-attributes-total-count",
+          String.valueOf(requestFilteringPolicyStat.getRejectedAttributes())));
+      attrs.add(Attributes.create("ds-mon-rejected-operations-total-count",
+          String.valueOf(requestFilteringPolicyStat.getRejectedOperations())));
+      attrs.add(Attributes.create("ds-mon-rejected-search-scopes-total-count",
+          String.valueOf(requestFilteringPolicyStat.getRejectedScopes())));
+      attrs.add(Attributes.create("ds-mon-rejected-subtrees-total-count",
+          String.valueOf(requestFilteringPolicyStat.getRejectedSubtrees())));
+    }
+
+    ResourceLimitsStat resLimitStat = networkGroup.getResourceLimitStat();
+    if (resLimitStat != null) {
+      attrs.add(Attributes.create("ds-mon-client-connection-count",
+          String.valueOf(resLimitStat.getClientConnections())));
+      attrs.add(Attributes.create("ds-mon-client-connection-max-count",
+          String.valueOf(resLimitStat.getMaxClientConnections())));
+      attrs.add(Attributes.create("ds-mon-client-connection-total-count",
+          String.valueOf(resLimitStat.getTotalClientConnections())));
+    }
+
+    synchronized(lock) {
+      attrs.add(Attributes.create("ds-mon-abandon-operations-total-count",
+          String.valueOf(abandonRequests)));
+      attrs.add(Attributes.create("ds-mon-add-operations-total-count",
+          String.valueOf(addRequests)));
+      attrs.add(Attributes.create("ds-mon-bind-operations-total-count",
+          String.valueOf(bindRequests)));
+      attrs.add(Attributes.create("ds-mon-compare-operations-total-count",
+          String.valueOf(compareRequests)));
+      attrs.add(Attributes.create("ds-mon-delete-operations-total-count",
+          String.valueOf(deleteRequests)));
+      attrs.add(Attributes.create("ds-mon-extended-operations-total-count",
+          String.valueOf(extendedRequests)));
+      attrs.add(Attributes.create("ds-mon-mod-operations-total-count",
+          String.valueOf(modifyRequests)));
+      attrs.add(Attributes.create("ds-mon-moddn-operations-total-count",
+          String.valueOf(modifyDNRequests)));
+      attrs.add(Attributes.create(
+          "ds-mon-searchonelevel-operations-total-count",
+          String.valueOf(searchOneRequests)));
+      attrs.add(Attributes.create("ds-mon-searchsubtree-operations-total-count",
+          String.valueOf(searchSubRequests)));
+      attrs.add(Attributes.create("ds-mon-unbind-operations-total-count",
+          String.valueOf(unbindRequests)));
+    }
+    attrs.add(Attributes.create("ds-mon-discarded-referrals-total-count",
+        "Not implemented"));
+    attrs.add(Attributes.create("ds-mon-forwarded-referrals-total-count",
+        "Not implemented"));
+    attrs.add(Attributes.create("ds-mon-followed-referrals-total-count",
+        "Not implemented"));
+    attrs.add(Attributes.create("ds-mon-failed-referrals-total-count",
+        "Not implemented"));
+    attrs.add(Attributes.create("ds-mon-violations-schema-total-count",
+        "Not implemented"));
+    attrs.add(Attributes.create("ds-mon-persistent-searchs-count",
+        "Not implemented"));
+
+    return attrs;
+  }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicy.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicy.java
index cd890a4..8d1f938 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicy.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicy.java
@@ -90,6 +90,9 @@
   // The list of prohibited subtrees
   Set<DN> prohibitedSubtrees = null;
 
+  // The stats for the request filtering policy
+  private RequestFilteringPolicyStat stat = new RequestFilteringPolicyStat();
+
   // The current configuration
   NetworkGroupRequestFilteringPolicyCfg config = null;
 
@@ -149,6 +152,14 @@
   }
 
   /**
+   * Returns the statistics associated to this policy.
+   * @return The statistics associated to this policy
+   */
+  public RequestFilteringPolicyStat getStat() {
+    return stat;
+  }
+
+  /**
    * Configures the set of allowed operations.
    * @param allowedOps The set of allowed operations
    */
@@ -281,6 +292,7 @@
       }
 
       if (!result) {
+        stat.updateRejectedOperations();
         messages.add(INFO_ERROR_OPERATION_NOT_ALLOWED.get());
         return result;
       }
@@ -296,6 +308,7 @@
         result = (!containsProhibitedAttribute(searchOp.getRawFilter()));
       }
       if (!result) {
+        stat.updateRejectedAttributes();
         messages.add(INFO_ERROR_ATTRIBUTE_NOT_ALLOWED.get());
         return result;
       }
@@ -305,6 +318,7 @@
         result = (containsOnlyAllowedAttributes(searchOp.getRawFilter()));
       }
       if (!result) {
+        stat.updateRejectedAttributes();
         messages.add(INFO_ERROR_ATTRIBUTE_NOT_ALLOWED.get());
         return result;
       }
@@ -327,6 +341,7 @@
         }
 
         if (!result) {
+          stat.updateRejectedScopes();
           messages.add(INFO_ERROR_SEARCH_SCOPE_NOT_ALLOWED.get());
           return result;
         }
@@ -343,6 +358,7 @@
                 compareOp.getRawAttributeType()));
       }
       if (!result) {
+        stat.updateRejectedAttributes();
         messages.add(INFO_ERROR_ATTRIBUTE_NOT_ALLOWED.get());
         return result;
       }
@@ -350,6 +366,7 @@
         result = (allowedAttributes.contains(compareOp.getRawAttributeType()));
       }
       if (!result) {
+        stat.updateRejectedAttributes();
         messages.add(INFO_ERROR_ATTRIBUTE_NOT_ALLOWED.get());
         return result;
       }
@@ -404,6 +421,7 @@
                   .log(Level.SEVERE, null, ex);
     }
     if (!result) {
+      stat.updateRejectedSubtrees();
       messages.add(INFO_ERROR_SUBTREE_NOT_ALLOWED.get());
       return result;
     }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicyStat.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicyStat.java
new file mode 100644
index 0000000..3985208
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/RequestFilteringPolicyStat.java
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.core.networkgroups;
+
+/**
+ * This class implements the statistics associated to a
+ * network group request filtering policy.
+ */
+public class RequestFilteringPolicyStat {
+  private long rejectedAttributes;
+  private long rejectedOperations;
+  private long rejectedSubtrees;
+  private long rejectedScopes;
+  private Object statLock;
+
+  /**
+   * Constructor.
+   */
+  public RequestFilteringPolicyStat() {
+    rejectedAttributes = 0;
+    rejectedOperations = 0;
+    rejectedSubtrees = 0;
+    rejectedScopes = 0;
+    statLock = new Object();
+  }
+
+  /**
+   * Increments the number of rejected operations due to an
+   * attribute not allowed by the request filtering policy.
+   */
+  public void updateRejectedAttributes() {
+    synchronized(statLock) {
+      rejectedAttributes++;
+    }
+  }
+
+  /**
+   * Increments the number of rejected operations due to an
+   * operation type not allowed by the request filtering policy.
+   */
+  public void updateRejectedOperations() {
+    synchronized(statLock) {
+      rejectedOperations++;
+    }
+  }
+
+  /**
+   * Increments the number of rejected operations due to a subtree
+   * not allowed by the request filtering policy.
+   */
+  public void updateRejectedSubtrees() {
+    synchronized(statLock) {
+      rejectedSubtrees++;
+    }
+  }
+
+  /**
+   * Increments the number of rejected operations due to a search scope
+   * not allowed by the request filtering policy.
+   */
+  public void updateRejectedScopes() {
+    synchronized(statLock) {
+      rejectedScopes++;
+    }
+  }
+
+  /**
+   * Retrieves the number of rejected operations due to an
+   * attribute not allowed by the request filtering policy.
+   * @return number of rejected operations due to an invalid attribute
+   */
+  public long getRejectedAttributes() {
+    return rejectedAttributes;
+  }
+
+  /**
+   * Retrieves the number of rejected operations due to an
+   * operation type not allowed by the request filtering policy.
+   * @return number of rejected operations due to an invalid op type
+   */
+  public long getRejectedOperations() {
+    return rejectedOperations;
+  }
+
+  /**
+   * Retrieves the number of rejected operations due to a
+   * subtree not allowed by the request filtering policy.
+   * @return number of rejected operations due to an invalid subtree
+   */
+  public long getRejectedSubtrees() {
+    return rejectedSubtrees;
+  }
+
+  /**
+   * Retrieves the number of rejected operations due to a
+   * scope not allowed by the request filtering policy.
+   * @return number of rejected operations due to an invalid scope
+   */
+  public long getRejectedScopes() {
+    return rejectedScopes;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimits.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimits.java
index e34dfd5..9904e93 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimits.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimits.java
@@ -79,10 +79,17 @@
   private int minSearchSubstringLength;
 
   // The number of connections in the group
-  private int numConnections;
+  private int numConnections = 0;
+
+  // The maximum number of simultaneous connections in the group
+  // since group creation
+  private int maxNumConnections = 0;
+
+  // The total number of connections managed by the group
+  private int totalNumConnections = 0;
 
   // Map containing the connections sorted by incoming IP address
-  HashMap<String, Integer> connectionsPerIpMap;
+  HashMap<String, Integer> connectionsPerIpMap = new HashMap<String, Integer>();
 
   // The lock for the counter numConnections and the map connectionsPerIpMap
   Object connMutex = new Object();
@@ -111,8 +118,6 @@
     searchSizeLimit = -1;
     searchTimeLimit = -1;
     minSearchSubstringLength = 0;
-    numConnections = 0;
-    connectionsPerIpMap = new HashMap<String, Integer>();
     isConfigured = false;
     if (config != null) {
       config.removeChangeListener(this);
@@ -136,7 +141,6 @@
       searchSizeLimit = resourcesCfg.getSearchSizeLimit();
       searchTimeLimit = (int) resourcesCfg.getSearchTimeLimit();
       minSearchSubstringLength = resourcesCfg.getMinSubstringLength();
-      connectionsPerIpMap = new HashMap<String, Integer>();
 
       if (config == null) {
         resourcesCfg.addChangeListener(this);
@@ -248,6 +252,10 @@
     synchronized(connMutex) {
       // increment the number of connections managed by the network group
       numConnections++;
+      totalNumConnections++;
+      if (numConnections > maxNumConnections) {
+        maxNumConnections = numConnections;
+      }
 
       // increment the number of connections from the given IP address
       String ip = connection.getClientAddress();
@@ -418,6 +426,18 @@
     }
   }
 
+  /**
+   * Retrieves the statistics associated to the resource limits.
+   * @return the statistics
+   */
+  public ResourceLimitsStat getStat() {
+    ResourceLimitsStat stat;
+    synchronized(connMutex) {
+      stat = new ResourceLimitsStat(
+          numConnections, maxNumConnections, totalNumConnections);
+    }
+    return stat;
+  }
 
   /**
    * {@inheritDoc}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsStat.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsStat.java
new file mode 100644
index 0000000..2aad532
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsStat.java
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.core.networkgroups;
+
+
+/**
+ * This class implements the statistics associated to a network group
+ * resource limit.
+ */
+public class ResourceLimitsStat {
+    private long clientConnections;
+    private long maxClientConnections;
+    private long totalClientConnections;
+
+    /**
+     * Constructor.
+     * @param clientConnections number of client connections currently
+     *        in the network group
+     * @param maxClientConnections maximum number of simultaneous
+     *        connections in the network group
+     * @param totalClientConnections total number of client connections
+     *        managed by the network group since its creation
+     */
+    public ResourceLimitsStat(
+        long clientConnections,
+        long maxClientConnections,
+        long totalClientConnections) {
+      this.clientConnections = clientConnections;
+      this.maxClientConnections = maxClientConnections;
+      this.totalClientConnections = totalClientConnections;
+    }
+
+    /**
+     * Returns the number of client connections currently in the network
+     * group.
+     * @return number of client connections currently in the network
+     * group
+     */
+    public long getClientConnections() {
+      return clientConnections;
+    }
+
+    /**
+     * Returns the maximum number of simultaneous client connections in
+     * the network group.
+     * @return the maximum number of simultaneous client connections in
+     * the network group
+     */
+    public long getMaxClientConnections() {
+      return maxClientConnections;
+    }
+
+    /**
+     * Returns the total number of client connections managed by the
+     * network group since its creation.
+     * @return the cumulated number of client connections managed by
+     * the network group since its creation
+     */
+    public long getTotalClientConnections() {
+      return totalClientConnections;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
index 1ce967a..1586159 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -1814,6 +1814,7 @@
     if (keepStats)
     {
       statTracker.updateMessageRead(message);
+      this.getNetworkGroup().updateMessageRead(message);
     }
     synchronized (operationsPerformedLock) {
       operationsPerformed++;

--
Gitblit v1.10.0