From d90a8f4889fdc359bfe5f089b937b303a4d58973 Mon Sep 17 00:00:00 2001
From: fguigues <fguigues@localhost>
Date: Fri, 12 Dec 2008 13:13:01 +0000
Subject: [PATCH] * Ability to create monitor provider with hierarchical naming * Modification of Network Monitor provider names (includes hierarchical naming) * Provide basic Monitoring objects. * Add monitoring instrumentation for the connection handlers. * Add the ability to do a subtree search in the monitor backend.

---
 opends/resource/schema/02-config.ldif                                                                   |    6 
 opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java                       |   72 ++++-
 opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java                      |   10 
 opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java                   |   14 +
 opends/src/server/org/opends/server/api/ConnectionHandler.java                                          |    9 
 opends/src/server/org/opends/server/util/ServerConstants.java                                           |   11 
 opends/src/server/org/opends/server/core/DirectoryServer.java                                           |    7 
 opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java                                |    3 
 opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java                              |   11 
 opends/src/server/org/opends/server/backends/MonitorBackend.java                                        |  205 +++++++++-------
 opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java |    8 
 opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java                           |    4 
 opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java                                  |  175 ++++++++++++++
 opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java                            |  127 +++++++++-
 14 files changed, 514 insertions(+), 148 deletions(-)

diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 79bf5ae..e2a9fc0 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -3968,3 +3968,9 @@
         ds-cfg-allowed-subtrees $
         ds-cfg-prohibited-subtrees )
   X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.950
+  NAME 'ds-mon-branch'
+  SUP top
+  STRUCTURAL
+  MUST cn
+  X-ORIGIN 'OpenDS Directory Server' )
diff --git a/opends/src/server/org/opends/server/api/ConnectionHandler.java b/opends/src/server/org/opends/server/api/ConnectionHandler.java
index 694e63d..52fdf46 100644
--- a/opends/src/server/org/opends/server/api/ConnectionHandler.java
+++ b/opends/src/server/org/opends/server/api/ConnectionHandler.java
@@ -35,6 +35,7 @@
 import org.opends.server.admin.std.server.*;
 import org.opends.server.config.ConfigException;
 import org.opends.server.monitors.ConnectionHandlerMonitor;
+import org.opends.server.types.DN;
 import org.opends.server.types.HostPort;
 import org.opends.server.types.InitializationException;
 
@@ -115,6 +116,14 @@
   public abstract String getConnectionHandlerName();
 
 
+   /**
+   * Retrieves the DN of the configuration entry with which this alert
+   * generator is associated.
+   *
+   * @return The DN of the configuration entry with which this alert
+   *         generator is associated.
+   */
+  public abstract DN getComponentEntryDN();
 
   /**
    * Retrieves the name of the protocol used to communicate with
diff --git a/opends/src/server/org/opends/server/backends/MonitorBackend.java b/opends/src/server/org/opends/server/backends/MonitorBackend.java
index a038e5f..bd774fe 100644
--- a/opends/src/server/org/opends/server/backends/MonitorBackend.java
+++ b/opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -467,25 +467,10 @@
       return getBaseMonitorEntry();
     }
 
-
-    // See if the monitor base entry is the immediate parent for the requested
-    // entry.  If not, then throw an exception.
-    DN parentDN = entryDN.getParentDNInSuffix();
-    if ((parentDN == null) || (! parentDN.equals(baseMonitorDN)))
-    {
-      if (baseMonitorDN.isAncestorOf(entryDN))
-      {
-        Message message = ERR_MONITOR_BASE_TOO_DEEP.get(
-            String.valueOf(entryDN), String.valueOf(baseMonitorDN));
-        throw new DirectoryException(
-                ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
-      }
-      else
-      {
-        Message message = ERR_MONITOR_INVALID_BASE.get(
-            String.valueOf(entryDN), String.valueOf(baseMonitorDN));
-        throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
-      }
+    if (!isATreeNode(entryDN)) {
+      Message message = ERR_MONITOR_INVALID_BASE.get(
+          String.valueOf(entryDN), String.valueOf(baseMonitorDN));
+      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
     }
 
 
@@ -499,20 +484,14 @@
               ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
     }
 
-
-    // Get the RDN value and see if it matches the instance name for one of
-    // the directory server monitor providers.
-    String rdnValue = entryRDN.getAttributeValue(0).getStringValue();
+    String rdnValue = getRdns(entryDN);
     MonitorProvider<? extends MonitorProviderCfg> monitorProvider =
          DirectoryServer.getMonitorProvider(rdnValue.toLowerCase());
-    if (monitorProvider == null)
-    {
-      Message message =
-          ERR_MONITOR_NO_SUCH_PROVIDER.get(String.valueOf(rdnValue));
-      throw new DirectoryException(
-              ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
-    }
 
+    // Could be a monitor branch
+    if (monitorProvider == null) {
+       return getBranchMonitorEntry(entryDN);
+    }
 
     // Take the data from the monitor provider and stuff it into an entry.
     return getMonitorEntry(entryDN, monitorProvider);
@@ -527,27 +506,7 @@
   public boolean entryExists(DN entryDN)
          throws DirectoryException
   {
-    if (entryDN.equals(baseMonitorDN))
-    {
-      return true;
-    }
-
-    DN parentDN = entryDN.getParentDNInSuffix();
-    if ((parentDN == null) || (! parentDN.equals(baseMonitorDN)))
-    {
-      return false;
-    }
-
-    RDN rdn = entryDN.getRDN();
-    if (rdn.isMultiValued())
-    {
-      return false;
-    }
-
-    String rdnValue = rdn.getAttributeValue(0).getStringValue();
-    MonitorProvider<?> monitorProvider =
-         DirectoryServer.getMonitorProvider(toLowerCase(rdnValue));
-    return (monitorProvider != null);
+      return this.isATreeNode(entryDN);
   }
 
 
@@ -718,7 +677,37 @@
     return e;
   }
 
+   /**
+   * Retrieves the branch monitor entry for the Directory Server.
+   * @param dn to get.
+   * @return  The branch monitor entry for the Directory Server.
+   */
+  public Entry getBranchMonitorEntry(DN dn) {
 
+    Entry e=null;
+    // Construct the set of objectclasses to include in the base monitor entry.
+    HashMap<ObjectClass,String> monitorClasses =
+         new LinkedHashMap<ObjectClass,String>(3);
+    monitorClasses.putAll(monitorObjectClasses);
+    ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_BRANCH,
+                                                           true);
+    monitorClasses.put(monitorOC, OC_MONITOR_BRANCH);
+
+    // Iterate through all of the monitor providers defined in the server.
+
+    for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
+           DirectoryServer.getMonitorProviders().values()) {
+
+      DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
+      if (providerDN.isDescendantOf(dn)) {
+         // Construct and return the entry.
+         e = new Entry(dn, monitorClasses, null, null);
+         break;
+      }
+    }
+
+    return e;
+  }
 
   /**
    * Generates and returns a monitor entry based on the contents of the
@@ -872,60 +861,100 @@
     DN    baseDN    = searchOperation.getBaseDN();
     Entry baseEntry = getEntry(baseDN);
 
+    if (baseEntry==null) {
+      Message message =
+          ERR_MONITOR_NO_SUCH_PROVIDER.get(String.valueOf(baseDN.toString()));
+      throw new DirectoryException(
+              ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
+
+    }
 
     // Figure out whether the base is the monitor base entry or one of its
     // children for a specific monitor.
     SearchScope  scope  = searchOperation.getScope();
     SearchFilter filter = searchOperation.getFilter();
-    if (baseMonitorDN.equals(baseDN))
+    if ((scope == SearchScope.BASE_OBJECT) ||
+        (scope == SearchScope.WHOLE_SUBTREE))
     {
-      // If it is a base-level or subtree search, then we need to look at the
-      // base monitor entry.
-      if ((scope == SearchScope.BASE_OBJECT) ||
-          (scope == SearchScope.WHOLE_SUBTREE))
+      if (filter.matchesEntry(baseEntry))
       {
-        if (filter.matchesEntry(baseEntry))
-        {
-          searchOperation.returnEntry(baseEntry, null);
-        }
-
-
-        // If it is a base-level search, then we're done.
-        if (scope == SearchScope.BASE_OBJECT)
-        {
-          return;
-        }
+        searchOperation.returnEntry(baseEntry, null);
       }
 
 
-      // Iterate through all of the monitor providers defined in the server.
-      // Get an entry for each and compare it against the filter.
-      for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
-           DirectoryServer.getMonitorProviders().values())
+      // If it is a base-level search, then we're done.
+      if (scope == SearchScope.BASE_OBJECT)
       {
-        DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
-        Entry monitorEntry = getMonitorEntry(providerDN, monitorProvider);
-        if (filter.matchesEntry(monitorEntry))
-        {
-          searchOperation.returnEntry(monitorEntry, null);
-        }
+        return;
       }
     }
-    else
-    {
-      // Look at the scope for the search.  We only need to return something if
-      // it is a base-level or subtree search.
-      if ((scope == SearchScope.BASE_OBJECT) ||
-          (scope == SearchScope.WHOLE_SUBTREE))
-      {
-        if (filter.matchesEntry(baseEntry))
-        {
-          searchOperation.returnEntry(baseEntry, null);
-        }
+
+    HashSet<DN> branches = new HashSet<DN>();
+    // Iterate through all of the monitor providers defined in the server.
+    // Get an entry for each and compare it against the filter.
+    for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
+           DirectoryServer.getMonitorProviders().values()) {
+
+      DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
+      if (baseDN.isAncestorOf(providerDN)) {
+         DN parentDN = providerDN.getParentDNInSuffix();
+         while ((parentDN!=null) && (!parentDN.equals(baseMonitorDN)) &&
+                 (!parentDN.equals(baseDN))) {
+            if ((!branches.contains(parentDN)) && (
+                    isABranch(parentDN))) {
+              Entry branchEntry = getBranchMonitorEntry(parentDN);
+              if (filter.matchesEntry(branchEntry)) {
+                  searchOperation.returnEntry(branchEntry, null);
+              }
+              branches.add(parentDN);
+            }
+            parentDN = parentDN.getParentDNInSuffix();
+         }
+         if (!providerDN.equals(baseDN)) {
+             Entry monitorEntry = getMonitorEntry(providerDN, monitorProvider);
+             if (filter.matchesEntry(monitorEntry)) {
+                searchOperation.returnEntry(monitorEntry, null);
+             }
+         }
+
       }
     }
   }
 
+  private boolean isABranch(DN dn) {
+      boolean found=false;
+      for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
+           DirectoryServer.getMonitorProviders().values()) {
+         DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
+         if (dn.equals(providerDN)) {
+             found=true;
+         }
+      }
+      return (!found);
+  }
+
+  private boolean isATreeNode(DN dn) {
+      boolean found=false;
+
+      if (dn.equals(baseMonitorDN)) {
+          return true;
+      }
+      for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
+           DirectoryServer.getMonitorProviders().values()) {
+         DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
+         if ((dn.isAncestorOf(providerDN)) ||
+                 (dn.equals(providerDN))) {
+             found=true;
+             return (found);
+         }
+      }
+      return (found);
+  }
+
+  private String getRdns(DN dn) {
+      int index = dn.toString().lastIndexOf(",");
+      return dn.toString().substring(3, index);
+  }
 
 
   /**
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index ebe41bf..780386e 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -163,7 +163,6 @@
 import org.opends.server.types.OperatingSystem;
 import org.opends.server.types.OperationType;
 import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
 import org.opends.server.types.RestoreConfig;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.Schema;
@@ -9827,7 +9826,8 @@
     DN monitorRootDN;
     try
     {
-      monitorRootDN = DN.decode(DN_MONITOR_ROOT);
+      // Get a complete DN which could be a tree naming schema
+      monitorRootDN = DN.decode("cn="+monitorName+","+DN_MONITOR_ROOT);
     }
     catch (DirectoryException e)
     {
@@ -9835,8 +9835,7 @@
       throw new RuntimeException();
     }
 
-    RDN rdn = RDN.create(cnType, new AttributeValue(cnType, monitorName));
-    return monitorRootDN.concat(rdn);
+    return monitorRootDN;
   }
 
 
diff --git a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
index a827ddc..ecc8e71 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
@@ -156,8 +156,7 @@
     isAdminNetworkGroup    = ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
     isDefaultNetworkGroup  = DEFAULT_NETWORK_GROUP_NAME.equals(networkGroupID);
 
-    stats = new NetworkGroupStatistics(this,
-        networkGroupID + " Network Group Statistics");
+    stats = new NetworkGroupStatistics(this);
   }
 
 
diff --git a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java
index b688cf3..c323e1d 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupStatistics.java
@@ -69,12 +69,10 @@
   /**
    * 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;
+  public NetworkGroupStatistics(NetworkGroup networkGroup) {
+    super(networkGroup.getID());
+    this.instanceName = networkGroup.getID();
     this.networkGroup = networkGroup;
     DirectoryServer.registerMonitorProvider(this);
   }
@@ -148,7 +146,7 @@
    * {@inheritDoc}
    */
   public String getMonitorInstanceName() {
-    return instanceName;
+      return this.instanceName+",cn=Network Groups";
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java b/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
index 58294d6..65feaa3 100644
--- a/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
@@ -56,13 +56,26 @@
 public class ClientConnectionMonitorProvider
        extends MonitorProvider<ClientConnectionMonitorProviderCfg>
 {
+
+  private ConnectionHandler<?> handler;
+
   /**
    * Creates an instance of this monitor provider.
    */
   public ClientConnectionMonitorProvider()
   {
     super("Client Connection Monitor Provider");
+    // No initialization should be performed here.
+  }
 
+  /**
+   * Creates an instance of this monitor provider.
+   * @param handler to which the monitor provider is associated.
+   */
+  public ClientConnectionMonitorProvider(ConnectionHandler handler)
+  {
+    super("Client Connection Monitor Provider");
+    this.handler=handler;
     // No initialization should be performed here.
   }
 
@@ -88,7 +101,14 @@
    */
   public String getMonitorInstanceName()
   {
-    return "Client Connections";
+    if (this.handler==null) {
+       return "Client Connections";
+    }
+    else {
+       // Client connections of a connection handler
+       return "Client Connections"+",cn="+
+               this.handler.getConnectionHandlerName();
+    }
   }
 
 
@@ -135,31 +155,38 @@
    */
   public ArrayList<Attribute> getMonitorData()
   {
-    // Get information about all the available connections.
-    ArrayList<Collection<ClientConnection>> connCollections =
-         new ArrayList<Collection<ClientConnection>>();
-    for (ConnectionHandler<?> handler : DirectoryServer.getConnectionHandlers())
-    {
-      ConnectionHandler<? extends ConnectionHandlerCfg> connHandler =
-           (ConnectionHandler<? extends ConnectionHandlerCfg>) handler;
-      connCollections.add(connHandler.getClientConnections());
-    }
-
-
     // Re-order the connections by connection ID.
     TreeMap<Long,ClientConnection> connMap =
-         new TreeMap<Long,ClientConnection>();
-    for (Collection<ClientConnection> collection : connCollections)
-    {
-      for (ClientConnection conn : collection)
-      {
-        connMap.put(conn.getConnectionID(), conn);
-      }
+             new TreeMap<Long,ClientConnection>();
+
+    if (this.handler==null) {
+        // Get information about all the available connections.
+        ArrayList<Collection<ClientConnection>> connCollections =
+             new ArrayList<Collection<ClientConnection>>();
+        for (ConnectionHandler<?> hdl : DirectoryServer.getConnectionHandlers())
+        {
+          ConnectionHandler<? extends ConnectionHandlerCfg> connHandler =
+               (ConnectionHandler<? extends ConnectionHandlerCfg>) hdl;
+          connCollections.add(connHandler.getClientConnections());
+        }
+        for (Collection<ClientConnection> collection : connCollections)
+        {
+          for (ClientConnection conn : collection)
+          {
+            connMap.put(conn.getConnectionID(), conn);
+          }
+        }
+
+    }
+    else {
+       Collection<ClientConnection> collection =
+               this.handler.getClientConnections();
+       for (ClientConnection conn : collection) {
+            connMap.put(conn.getConnectionID(), conn);
+       }
     }
 
 
-    // Iterate through all the client connections and create a one-line summary
-    // of each.
     AttributeType attrType = DirectoryServer
         .getDefaultAttributeType("connection");
     AttributeBuilder builder = new AttributeBuilder(attrType);
@@ -168,8 +195,7 @@
       builder.add(new AttributeValue(attrType, conn.getMonitorSummary()));
     }
 
-
-    ArrayList<Attribute> attrs = new ArrayList<Attribute>(1);
+    ArrayList<Attribute> attrs = new ArrayList<Attribute>(2);
     attrs.add(builder.toAttribute());
     return attrs;
   }
diff --git a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
index 72c8aba..252f3c6 100644
--- a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
+++ b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
@@ -70,6 +70,9 @@
   // The attribute type that will be used to report the protocol.
   private AttributeType protocolType;
 
+  // The attribute type that will be used to report the config dn .
+  private AttributeType configDnType;
+
   // The connection handler with which this monitor is associated.
   private ConnectionHandler<?> connectionHandler;
 
@@ -118,6 +121,10 @@
     protocolType =
          DirectoryConfig.getAttributeType(ATTR_MONITOR_CONNHANDLER_PROTOCOL,
                                           true);
+
+    configDnType =
+         DirectoryConfig.getAttributeType(ATTR_MONITOR_CONFIG_DN,
+                                          true);
   }
 
 
@@ -174,6 +181,10 @@
   {
     LinkedList<Attribute> attrs = new LinkedList<Attribute>();
 
+    // Configuration DN
+    attrs.add(Attributes.create(configDnType, String.valueOf(
+            connectionHandler.getComponentEntryDN().toNormalizedString())));
+
     int numConnections = 0;
     LinkedList<ClientConnection> conns = new LinkedList<ClientConnection>(
         connectionHandler.getClientConnections());
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java b/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
index 328e901..041e600 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
@@ -36,6 +36,7 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
 import org.opends.server.config.ConfigException;
+import org.opends.server.types.DN;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.HostPort;
 
@@ -67,6 +68,8 @@
   // The name of the protocol for this connection handler.
   private String protocol;
 
+  // Configuration object of the connection hanlder
+  private ConnectionHandlerCfg configuration;
 
 
   /**
@@ -124,7 +127,7 @@
                    ConnectionHandlerCfg configuration)
       throws ConfigException, InitializationException
   {
-    // No implementation required.
+    this.configuration = configuration;
   }
 
 
@@ -269,5 +272,14 @@
     InternalClientConnection.clearRootClientConnectionAtShutdown();
   }
 
+  /**
+   * Return the configuration dn of the object.
+   * @return DN of the entry.
+   */
+  @Override()
+  public DN getComponentEntryDN() {
+      return this.configuration.dn();
+  }
+
 }
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
index 6d77f00..df57bde 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -64,6 +64,7 @@
 import org.opends.server.extensions.TLSCapableConnection;
 import org.opends.server.extensions.TLSConnectionSecurityProvider;
 import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.monitors.OperationMonitor;
 import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Sequence;
@@ -90,6 +91,7 @@
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
 import static org.opends.server.util.StaticUtils.getExceptionMessage;
 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.server.types.OperationType.*;
 
 
 
@@ -192,6 +194,9 @@
   // The statistics tracker associated with this client connection.
   private LDAPStatistics statTracker;
 
+  // The connectionHandler statistic tracker.
+  private LDAPStatistics parentTracker;
+
   // The connection ID assigned to this connection.
   private long connectionID;
 
@@ -224,6 +229,18 @@
   //during a SASL bind (GSSAPI and DIGEST-MD5 only).
   private ConnectionSecurityProvider saslSecurityProvider;
 
+  // Statistics for the processed operations
+  private OperationMonitor addMonitor;
+  private OperationMonitor searchMonitor;
+  private OperationMonitor abandonMonitor;
+  private OperationMonitor bindMonitor;
+  private OperationMonitor compareMonitor;
+  private OperationMonitor delMonitor;
+  private OperationMonitor extendedMonitor;
+  private OperationMonitor modMonitor;
+  private OperationMonitor moddnMonitor;
+  private OperationMonitor unbindMonitor;
+
   /**
    * Creates a new LDAP client connection with the provided information.
    *
@@ -276,10 +293,12 @@
     serverAddress = clientChannel.socket().getLocalAddress().getHostAddress();
     serverPort    = clientChannel.socket().getLocalPort();
 
-    LDAPStatistics parentTracker = connectionHandler.getStatTracker();
+    parentTracker = connectionHandler.getStatTracker();
     String         instanceName  = parentTracker.getMonitorInstanceName() +
                                    " for " + toString();
-    statTracker = new LDAPStatistics(instanceName, parentTracker);
+    this.initializeOperationMonitors();
+    statTracker = new LDAPStatistics(connectionHandler,
+            instanceName, parentTracker);
 
     if (keepStats)
     {
@@ -1846,28 +1865,89 @@
     // the connection being terminated.
     try
     {
+      boolean result;
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_ABANDON_REQUEST:
-          return processAbandonRequest(message, opControls);
+          if (keepStats) this.abandonMonitor.start();
+          result=processAbandonRequest(message, opControls);
+          if (keepStats) {
+              this.abandonMonitor.stop();
+              this.abandonMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_ADD_REQUEST:
-          return processAddRequest(message, opControls);
+          if (keepStats) this.addMonitor.start();
+          result=processAddRequest(message, opControls);
+          if (keepStats) {
+              this.addMonitor.stop();
+              this.addMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_BIND_REQUEST:
-          return processBindRequest(message, opControls);
+          if (keepStats) this.bindMonitor.start();
+          result=processBindRequest(message, opControls);
+          if (keepStats) {
+              this.bindMonitor.stop();
+              this.bindMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_COMPARE_REQUEST:
-          return processCompareRequest(message, opControls);
+          if (keepStats) this.compareMonitor.start();
+          result=processCompareRequest(message, opControls);
+          if (keepStats) {
+              this.compareMonitor.stop();
+              this.compareMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_DELETE_REQUEST:
-          return processDeleteRequest(message, opControls);
+          if (keepStats) this.delMonitor.start();
+          result=processDeleteRequest(message, opControls);
+          if (keepStats) {
+              this.delMonitor.stop();
+              this.delMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_EXTENDED_REQUEST:
-          return processExtendedRequest(message, opControls);
+          if (keepStats) this.extendedMonitor.start();
+          result=processExtendedRequest(message, opControls);
+          if (keepStats) {
+              this.extendedMonitor.stop();
+              this.extendedMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_MODIFY_REQUEST:
-          return processModifyRequest(message, opControls);
+          if (keepStats) this.modMonitor.start();
+          result=processModifyRequest(message, opControls);
+          if (keepStats) {
+              this.modMonitor.stop();
+              this.modMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_MODIFY_DN_REQUEST:
-          return processModifyDNRequest(message, opControls);
+          if (keepStats) this.moddnMonitor.start();
+          result=processModifyDNRequest(message, opControls);
+          if (keepStats) {
+              this.moddnMonitor.stop();
+              this.moddnMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_SEARCH_REQUEST:
-          return processSearchRequest(message, opControls);
+          if (keepStats) this.searchMonitor.start();
+          result=processSearchRequest(message, opControls);
+          if (keepStats) {
+              this.searchMonitor.stop();
+              this.searchMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         case OP_TYPE_UNBIND_REQUEST:
-          return processUnbindRequest(message, opControls);
+          if (keepStats) this.unbindMonitor.start();
+          result=processUnbindRequest(message, opControls);
+          if (keepStats) {
+              this.unbindMonitor.stop();
+              this.unbindMonitor.updateMonitorProvider(statTracker);
+          }
+          return result;
         default:
           Message msg = ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE.get(
                   message.getProtocolOpName(), message.getMessageID());
@@ -2893,5 +2973,28 @@
       return 0L;
     }
   }
+
+  private void initializeOperationMonitors() {
+    this.addMonitor = OperationMonitor.getOperationMonitor(
+            ADD);
+    this.searchMonitor = OperationMonitor.getOperationMonitor(
+            SEARCH);
+    this.abandonMonitor = OperationMonitor.getOperationMonitor(
+            ABANDON);
+    this.bindMonitor = OperationMonitor.getOperationMonitor(
+            BIND);
+    this.compareMonitor = OperationMonitor.getOperationMonitor(
+            COMPARE);
+    this.delMonitor = OperationMonitor.getOperationMonitor(
+            DELETE);
+    this.extendedMonitor = OperationMonitor.getOperationMonitor(
+            EXTENDED);
+    this.modMonitor = OperationMonitor.getOperationMonitor(
+            MODIFY);
+    this.moddnMonitor = OperationMonitor.getOperationMonitor(
+            MODIFY_DN);
+    this.unbindMonitor = OperationMonitor.getOperationMonitor(
+            UNBIND);
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 080ab42..8b5da30 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -293,7 +293,7 @@
     if (currentConfig.isAllowLDAPV2() != config.isAllowLDAPV2()) {
       if (config.isAllowLDAPV2()) {
         if (statTracker == null) {
-          statTracker = new LDAPStatistics(handlerName
+          statTracker = new LDAPStatistics(this,handlerName
               + " Statistics");
         } else {
           statTracker.clearStatistics();
@@ -736,7 +736,7 @@
     }
 
     // Perform any additional initialization that might be required.
-    statTracker = new LDAPStatistics(handlerName + " Statistics");
+    statTracker = new LDAPStatistics(this, handlerName + " Statistics");
 
     // Attempt to bind to the listen port on all configured addresses to
     // verify whether the connection handler will be able to start.
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
index 5aae8a6..78627b0 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
@@ -32,10 +32,13 @@
 
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.MonitorProviderCfg;
+import org.opends.server.api.ConnectionHandler;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.config.ConfigException;
 import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.monitors.ClientConnectionMonitorProvider;
+import org.opends.server.monitors.OperationMonitor;
 import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
@@ -46,6 +49,7 @@
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.types.OperationType.*;
 
 
 
@@ -128,17 +132,43 @@
   // The instance name for this monitor provider instance.
   private String instanceName;
 
+  // Connection Handler to which the statistics belong to.
+  private ConnectionHandler handler;
 
 
+    // Monitor Objects : for Operations.
+    private OperationMonitor addRequestsMonitor =
+            OperationMonitor.getOperationMonitor(ADD);
+    private OperationMonitor searchRequestsMonitor =
+            OperationMonitor.getOperationMonitor(SEARCH);
+    private OperationMonitor delRequestsMonitor =
+            OperationMonitor.getOperationMonitor(DELETE);
+    private OperationMonitor bindRequestsMonitor =
+            OperationMonitor.getOperationMonitor(BIND);
+    private OperationMonitor unbindRequestsMonitor =
+            OperationMonitor.getOperationMonitor(UNBIND);
+    private OperationMonitor compareRequestsMonitor =
+            OperationMonitor.getOperationMonitor(COMPARE);
+    private OperationMonitor modRequestsMonitor =
+            OperationMonitor.getOperationMonitor(MODIFY);
+    private OperationMonitor moddnRequestsMonitor =
+            OperationMonitor.getOperationMonitor(MODIFY);
+    private OperationMonitor abandonRequestsMonitor =
+            OperationMonitor.getOperationMonitor(ABANDON);
+    private OperationMonitor extendedRequestsMonitor =
+            OperationMonitor.getOperationMonitor(EXTENDED);
+
 
   /**
    * Creates a new instance of this class with no parent.
    *
+   * @param handler to which the stats belong  to.
    * @param  instanceName  The name for this monitor provider instance.
    */
-  public LDAPStatistics(String instanceName)
+  public LDAPStatistics(ConnectionHandler handler,
+          String instanceName)
   {
-    this(instanceName, null);
+    this(handler, instanceName, null);
 
     DirectoryServer.registerMonitorProvider(this);
   }
@@ -148,18 +178,21 @@
   /**
    * Creates a new instance of this class with the specified parent.
    *
+   * @param  handler       the handler to which the stats belong to.
    * @param  instanceName  The name for this monitor provider instance.
    * @param  parent        The parent object that should also be updated
    *                       whenever this class is updated.  It may be null if
    *                       there should not be a parent.
    */
-  public LDAPStatistics(String instanceName, LDAPStatistics parent)
+  public LDAPStatistics(ConnectionHandler handler,
+          String instanceName, LDAPStatistics parent)
   {
     super("LDAP Statistics Monitor Provider");
 
 
     this.instanceName = instanceName;
     this.parent       = parent;
+    this.handler = handler;
 
     abandonLock    = new Object();
     connectLock    = new Object();
@@ -196,6 +229,11 @@
     searchResultReferences = 0;
     searchResultsDone      = 0;
     unbindRequests         = 0;
+
+    ClientConnectionMonitorProvider connections =
+                new ClientConnectionMonitorProvider(this.handler);
+
+    DirectoryServer.registerMonitorProvider(connections);
   }
 
 
@@ -407,7 +445,89 @@
     attrs.add(createAttribute("unbindRequests",
                               String.valueOf(tmpUnbindRequests)));
 
-    return attrs;
+     // adds
+     attrs.add(createAttribute(
+                "ds-mon-add-operations-total-count",
+                String.valueOf(addRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+                "ds-mon-resident-time-add-operations-total-time",
+                String.valueOf(addRequestsMonitor.getTotalTime())));
+
+     // search
+     attrs.add(createAttribute(
+              "ds-mon-search-operations-total-count",
+                String.valueOf(searchRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+                "ds-mon-resident-time-search-operations-total-time",
+                String.valueOf(searchRequestsMonitor.getTotalTime())));
+
+     // bind
+     attrs.add(createAttribute(
+                "ds-mon-bind-operations-total-count",
+                String.valueOf(bindRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+                "ds-mon-resident-time-bind-operations-total-time",
+                String.valueOf(bindRequestsMonitor.getTotalTime())));
+
+     // unbind
+     attrs.add(createAttribute(
+              "ds-mon-unbind-operations-total-count",
+              String.valueOf(unbindRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+                "ds-mon-resident-time-unbind-operations-total-time",
+                String.valueOf(unbindRequestsMonitor.getTotalTime())));
+
+     // compare
+     attrs.add(createAttribute(
+             "ds-mon-compare-operations-total-count",
+             String.valueOf(
+             compareRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+             "ds-mon-resident-time-compare-operations-total-time",
+             String.valueOf(compareRequestsMonitor.getTotalTime())));
+     // del
+     attrs.add(createAttribute(
+             "ds-mon-delete-operations-total-count",
+             String.valueOf(delRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+             "ds-mon-resident-time-delete-operations-total-time",
+             String.valueOf(delRequestsMonitor.getTotalTime())));
+
+     // mod
+     attrs.add(createAttribute(
+             "ds-mon-mod-operations-total-count",
+             String.valueOf(modRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+            "ds-mon-resident-time-mod-operations-total-time",
+            String.valueOf(modRequestsMonitor.getTotalTime())));
+
+     // moddn
+     attrs.add(createAttribute(
+            "ds-mon-moddn-operations-total-count",
+            String.valueOf(moddnRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+            "ds-mon-resident-time-moddn-operations-total-time",
+            String.valueOf(moddnRequestsMonitor.getTotalTime())));
+
+     // abandon
+     attrs.add(createAttribute(
+             "ds-mon-abandon-operations-total-count",
+             String.valueOf(
+             abandonRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+             "ds-mon-resident-time-abandon-operations-total-time",
+             String.valueOf(abandonRequestsMonitor.getTotalTime())));
+
+     // extended
+     attrs.add(createAttribute(
+             "ds-mon-extended-operations-total-count",
+             String.valueOf(
+             extendedRequestsMonitor.getCounter().getCount())));
+     attrs.add(createAttribute(
+             "ds-mon-resident-time-extended-operations-total-time",
+             String.valueOf(extendedRequestsMonitor.getTotalTime())));
+
+     return attrs;
   }
 
 
@@ -1163,5 +1283,52 @@
   {
     return parent;
   }
+
+   /**
+     * Updates the monitor object.
+     * @param opMonitor monitor object.
+     */
+    public void updateMonitor(OperationMonitor opMonitor) {
+        synchronized (readLock) {
+            switch (opMonitor.getType()) {
+                case ABANDON:
+                    this.abandonRequestsMonitor.add(opMonitor);
+                    break;
+                case ADD:
+                    this.addRequestsMonitor.add(opMonitor);
+                    break;
+                case BIND:
+                    this.bindRequestsMonitor.add(opMonitor);
+                    break;
+                case COMPARE:
+                    this.compareRequestsMonitor.add(opMonitor);
+                    break;
+                case DELETE:
+                    this.delRequestsMonitor.add(opMonitor);
+                    break;
+                case EXTENDED:
+                    this.extendedRequestsMonitor.add(opMonitor);
+                    break;
+                case MODIFY:
+                    this.modRequestsMonitor.add(opMonitor);
+                    break;
+                case MODIFY_DN:
+                    this.moddnRequestsMonitor.add(opMonitor);
+                    break;
+                case SEARCH:
+                    this.searchRequestsMonitor.add(opMonitor);
+                    break;
+                case UNBIND:
+                    this.unbindRequestsMonitor.add(opMonitor);
+                    break;
+                default:
+            }
+            if (parent!=null) {
+                parent.updateMonitor(opMonitor);
+            }
+            opMonitor.reset();
+        }
+    }
+
 }
 
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index fdbe328..6403536 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -287,6 +287,12 @@
   public static final String ATTR_MONITOR_CONNHANDLER_LISTENER =
        "ds-connectionhandler-listener";
 
+   /**
+   * The name of the monitor attribute that is used to hold the connection
+   * handler listeners.
+   */
+  public static final String ATTR_MONITOR_CONFIG_DN =
+       "ds-mon-config-dn";
 
 
   /**
@@ -847,6 +853,11 @@
    */
   public static final String OC_MONITOR_ENTRY = "ds-monitor-entry";
 
+   /**
+   * The name of the objectclass that will be used as the structural class for
+   * monitor branches.
+   */
+  public static final String OC_MONITOR_BRANCH = "ds-mon-branch";
 
 
   /**
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
index 72daeea..6d52725 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -140,12 +140,8 @@
   public void testWithBaseObjectMonitorSearch(String monitorName)
          throws Exception
   {
-    AttributeType cnType = DirectoryServer.getAttributeType(ATTR_COMMON_NAME);
-
-    RDN[] rdns = new RDN[2];
-    rdns[0] = RDN.create(cnType, new AttributeValue(cnType, monitorName));
-    rdns[1] = RDN.create(cnType, new AttributeValue(cnType, "monitor"));
-    DN monitorDN = new DN(rdns);
+    // could be more than one level
+    DN monitorDN = DN.decode("cn="+monitorName+",cn=monitor");
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();

--
Gitblit v1.10.0