From 3a209faa6fafaa9ee7ba9640a850449062b4b78d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 13 Jan 2012 23:13:48 +0000
Subject: [PATCH] Fix OPENDJ-98: Searches on cn=monitor take a long time

---
 opends/src/server/org/opends/server/backends/MonitorBackend.java | 1785 ++++++++++++++++++++++++++++-------------------------------
 1 files changed, 841 insertions(+), 944 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/MonitorBackend.java b/opends/src/server/org/opends/server/backends/MonitorBackend.java
index 9fd6d86..be0a594 100644
--- a/opends/src/server/org/opends/server/backends/MonitorBackend.java
+++ b/opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -23,62 +23,34 @@
  *
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2012 ForgeRock AS.
  */
 package org.opends.server.backends;
 
+
+
 import static org.opends.messages.BackendMessages.*;
 import static org.opends.messages.ConfigMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.StaticUtils.getExceptionMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
+import java.util.*;
 
-import java.util.Set;
 import org.opends.messages.Message;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.MonitorBackendCfg;
-import org.opends.server.admin.std.server.MonitorProviderCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.core.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.BackupConfig;
-import org.opends.server.types.BackupDirectory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.LDIFImportResult;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RestoreConfig;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.util.DynamicConstants;
 import org.opends.server.util.LDIFWriter;
 import org.opends.server.util.TimeThread;
@@ -87,14 +59,13 @@
 
 
 /**
- * This class defines a backend to hold Directory Server monitor entries.  It
+ * This class defines a backend to hold Directory Server monitor entries. It
  * will not actually store anything, but upon request will retrieve the
- * requested monitor and dynamically generate the associated entry.  It will
- * also construct a base monitor entry with some useful server-wide data.
+ * requested monitor and dynamically generate the associated entry. It will also
+ * construct a base monitor entry with some useful server-wide data.
  */
-public class MonitorBackend
-       extends Backend
-       implements ConfigurationChangeListener<MonitorBackendCfg>
+public class MonitorBackend extends Backend implements
+    ConfigurationChangeListener<MonitorBackendCfg>
 {
   /**
    * The tracer object for the debug logger.
@@ -106,7 +77,7 @@
   private ArrayList<Attribute> userDefinedAttributes;
 
   // The set of objectclasses that will be used in monitor entries.
-  private HashMap<ObjectClass,String> monitorObjectClasses;
+  private HashMap<ObjectClass, String> monitorObjectClasses;
 
   // The DN of the configuration entry for this backend.
   private DN configEntryDN;
@@ -126,13 +97,10 @@
   // The set of supported features for this backend.
   private HashSet<String> supportedFeatures;
 
-  // The mapping between entry DNs and the corresponding entries.
-  private LinkedHashMap<DN,Entry> entryMap;
-  // The mapping between parent DNs and their immediate children.
-  private HashMap<DN,HashSet<DN>> childDNs;
+
 
   /**
-   * Creates a new backend with the provided information.  All backend
+   * Creates a new backend with the provided information. All backend
    * implementations must implement a default constructor that use
    * <CODE>super()</CODE> to invoke this constructor.
    */
@@ -142,95 +110,167 @@
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   @Override()
-  public void configureBackend(Configuration config)
-         throws ConfigException
+  public void addEntry(final Entry entry, final AddOperation addOperation)
+      throws DirectoryException
   {
-    Validator.ensureNotNull(config);
-    Validator.ensureTrue(config instanceof MonitorBackendCfg);
-
-    MonitorBackendCfg cfg = (MonitorBackendCfg)config;
-    ConfigEntry configEntry = DirectoryServer.getConfigEntry(cfg.dn());
+    final Message message = ERR_MONITOR_ADD_NOT_SUPPORTED.get(String
+        .valueOf(entry.getDN()));
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
 
 
-    // Make sure that a configuration entry was provided.  If not, then we will
-    // not be able to complete initialization.
-    if (configEntry == null)
-    {
-      Message message = ERR_MONITOR_CONFIG_ENTRY_NULL.get();
-      throw new ConfigException(message);
-    }
 
-    configEntryDN = configEntry.getDN();
+  /**
+   * {@inheritDoc}
+   */
+  public ConfigChangeResult applyConfigurationChange(
+      final MonitorBackendCfg backendCfg)
+  {
+    ResultCode resultCode = ResultCode.SUCCESS;
+    final boolean adminActionRequired = false;
+    final ArrayList<Message> messages = new ArrayList<Message>();
 
-
-    // Get the set of user-defined attributes for the configuration entry.  Any
-    // attributes that we don't recognize will be included directly in the base
-    // monitor entry.
-    userDefinedAttributes = new ArrayList<Attribute>();
-    for (List<Attribute> attrs :
-         configEntry.getEntry().getUserAttributes().values())
-    {
-      for (Attribute a : attrs)
-      {
-        if (! isMonitorConfigAttribute(a))
-        {
-          userDefinedAttributes.add(a);
-        }
-      }
-    }
-    for (List<Attribute> attrs :
-         configEntry.getEntry().getOperationalAttributes().values())
-    {
-      for (Attribute a : attrs)
-      {
-        if (! isMonitorConfigAttribute(a))
-        {
-          userDefinedAttributes.add(a);
-        }
-      }
-    }
-
-
-    // Construct the set of objectclasses to include in the base monitor entry.
-    monitorObjectClasses = new LinkedHashMap<ObjectClass,String>(2);
-    ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
-    monitorObjectClasses.put(topOC, OC_TOP);
-
-    ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_ENTRY,
-                                                           true);
-    monitorObjectClasses.put(monitorOC, OC_MONITOR_ENTRY);
-
-
-    // Define an empty sets for the supported controls and features.
-    supportedControls = new HashSet<String>(0);
-    supportedFeatures = new HashSet<String>(0);
-
-    // Create the set of base DNs that we will handle.  In this case, it's just
-    // the DN of the base monitor entry.
+    // Check to see if there is a new set of user-defined attributes.
+    final ArrayList<Attribute> userAttrs = new ArrayList<Attribute>();
     try
     {
-      baseMonitorDN = DN.decode(DN_MONITOR_ROOT);
+      final ConfigEntry configEntry = DirectoryServer
+          .getConfigEntry(configEntryDN);
+      for (final List<Attribute> attrs : configEntry.getEntry()
+          .getUserAttributes().values())
+      {
+        for (final Attribute a : attrs)
+        {
+          if (!isMonitorConfigAttribute(a))
+          {
+            userAttrs.add(a);
+          }
+        }
+      }
+      for (final List<Attribute> attrs : configEntry.getEntry()
+          .getOperationalAttributes().values())
+      {
+        for (final Attribute a : attrs)
+        {
+          if (!isMonitorConfigAttribute(a))
+          {
+            userAttrs.add(a);
+          }
+        }
+      }
     }
-    catch (Exception e)
+    catch (final Exception e)
     {
       if (debugEnabled())
       {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
 
-      Message message =
-          ERR_MONITOR_CANNOT_DECODE_MONITOR_ROOT_DN.get(getExceptionMessage(e));
+      messages.add(ERR_CONFIG_BACKEND_ERROR_INTERACTING_WITH_BACKEND_ENTRY.get(
+          String.valueOf(configEntryDN), stackTraceToSingleLineString(e)));
+      resultCode = DirectoryServer.getServerErrorResultCode();
+    }
+
+    userDefinedAttributes = userAttrs;
+
+    final Message message = INFO_MONITOR_USING_NEW_USER_ATTRS.get();
+    messages.add(message);
+
+    currentConfig = backendCfg;
+    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void configureBackend(final Configuration config)
+      throws ConfigException
+  {
+    Validator.ensureNotNull(config);
+    Validator.ensureTrue(config instanceof MonitorBackendCfg);
+
+    final MonitorBackendCfg cfg = (MonitorBackendCfg) config;
+    final ConfigEntry configEntry = DirectoryServer.getConfigEntry(cfg.dn());
+
+    // Make sure that a configuration entry was provided. If not, then we will
+    // not be able to complete initialization.
+    if (configEntry == null)
+    {
+      final Message message = ERR_MONITOR_CONFIG_ENTRY_NULL.get();
+      throw new ConfigException(message);
+    }
+
+    configEntryDN = configEntry.getDN();
+
+    // Get the set of user-defined attributes for the configuration entry. Any
+    // attributes that we don't recognize will be included directly in the base
+    // monitor entry.
+    userDefinedAttributes = new ArrayList<Attribute>();
+    for (final List<Attribute> attrs : configEntry.getEntry()
+        .getUserAttributes().values())
+    {
+      for (final Attribute a : attrs)
+      {
+        if (!isMonitorConfigAttribute(a))
+        {
+          userDefinedAttributes.add(a);
+        }
+      }
+    }
+    for (final List<Attribute> attrs : configEntry.getEntry()
+        .getOperationalAttributes().values())
+    {
+      for (final Attribute a : attrs)
+      {
+        if (!isMonitorConfigAttribute(a))
+        {
+          userDefinedAttributes.add(a);
+        }
+      }
+    }
+
+    // Construct the set of objectclasses to include in the base monitor entry.
+    monitorObjectClasses = new LinkedHashMap<ObjectClass, String>(2);
+    final ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
+    monitorObjectClasses.put(topOC, OC_TOP);
+
+    final ObjectClass monitorOC = DirectoryServer.getObjectClass(
+        OC_MONITOR_ENTRY, true);
+    monitorObjectClasses.put(monitorOC, OC_MONITOR_ENTRY);
+
+    // Define an empty sets for the supported controls and features.
+    supportedControls = new HashSet<String>(0);
+    supportedFeatures = new HashSet<String>(0);
+
+    // Create the set of base DNs that we will handle. In this case, it's just
+    // the DN of the base monitor entry.
+    try
+    {
+      baseMonitorDN = DN.decode(DN_MONITOR_ROOT);
+    }
+    catch (final Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      final Message message = ERR_MONITOR_CANNOT_DECODE_MONITOR_ROOT_DN
+          .get(getExceptionMessage(e));
       throw new ConfigException(message, e);
     }
 
     // FIXME -- Deal with this more correctly.
     this.baseDNs = new DN[] { baseMonitorDN };
 
-
     currentConfig = cfg;
   }
 
@@ -240,32 +280,146 @@
    * {@inheritDoc}
    */
   @Override()
-  public void initializeBackend()
-         throws ConfigException, InitializationException
+  public void createBackup(final BackupConfig backupConfig)
+      throws DirectoryException
   {
-    // Register with the Directory Server as a configurable component.
-    currentConfig.addMonitorChangeListener(this);
+    // This backend does not provide a backup/restore mechanism.
+    final Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
 
-    entryMap = new LinkedHashMap<DN,Entry>();
-    childDNs = new HashMap<DN,HashSet<DN>>();
 
-    this.initEntryMaps();
 
-    // Register the monitor base as a private suffix.
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void deleteEntry(final DN entryDN,
+      final DeleteOperation deleteOperation) throws DirectoryException
+  {
+    final Message message = ERR_MONITOR_DELETE_NOT_SUPPORTED.get(String
+        .valueOf(entryDN));
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean entryExists(final DN entryDN) throws DirectoryException
+  {
+    return getDIT().containsKey(entryDN);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void exportLDIF(final LDIFExportConfig exportConfig)
+      throws DirectoryException
+  {
+    // TODO export-ldif reports nonsense for upTime etc.
+
+    // Create the LDIF writer.
+    LDIFWriter ldifWriter;
     try
     {
-      DirectoryServer.registerBaseDN(baseMonitorDN, this, true);
+      ldifWriter = new LDIFWriter(exportConfig);
     }
-    catch (Exception e)
+    catch (final Exception e)
     {
       if (debugEnabled())
       {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
 
-      Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get(
-          baseMonitorDN.toString(), getExceptionMessage(e));
-      throw new InitializationException(message, e);
+      final Message message = ERR_ROOTDSE_UNABLE_TO_CREATE_LDIF_WRITER
+          .get(stackTraceToSingleLineString(e));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+          message);
+    }
+
+    // Write the base monitor entry to the LDIF.
+    try
+    {
+      ldifWriter.writeEntry(getBaseMonitorEntry());
+    }
+    catch (final Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      try
+      {
+        ldifWriter.close();
+      }
+      catch (final Exception e2)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e2);
+        }
+      }
+
+      final Message message = ERR_MONITOR_UNABLE_TO_EXPORT_BASE
+          .get(stackTraceToSingleLineString(e));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+          message);
+    }
+
+    // Get all the monitor providers, convert them to entries, and write them to
+    // LDIF.
+    for (final MonitorProvider<?> monitorProvider : DirectoryServer
+        .getMonitorProviders().values())
+    {
+      try
+      {
+        // TODO implementation of export is incomplete
+      }
+      catch (final Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        try
+        {
+          ldifWriter.close();
+        }
+        catch (final Exception e2)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e2);
+          }
+        }
+
+        final Message message = ERR_MONITOR_UNABLE_TO_EXPORT_PROVIDER_ENTRY
+            .get(monitorProvider.getMonitorInstanceName(),
+                stackTraceToSingleLineString(e));
+        throw new DirectoryException(
+            DirectoryServer.getServerErrorResultCode(), message);
+      }
+    }
+
+    // Close the monitor provider and return.
+    try
+    {
+      ldifWriter.close();
+    }
+    catch (final Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
     }
   }
 
@@ -277,15 +431,12 @@
   @Override()
   public void finalizeBackend()
   {
-    entryMap.clear();
-    childDNs.clear();
     currentConfig.removeMonitorChangeListener(this);
-
     try
     {
       DirectoryServer.deregisterBaseDN(baseMonitorDN);
     }
-    catch (Exception e)
+    catch (final Exception e)
     {
       if (debugEnabled())
       {
@@ -297,33 +448,6 @@
 
 
   /**
-   * Indicates whether the provided attribute is one that is used in the
-   * configuration of this backend.
-   *
-   * @param  attribute  The attribute for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if the provided attribute is one that is used in
-   *          the configuration of this backend, <CODE>false</CODE> if not.
-   */
-  private boolean isMonitorConfigAttribute(Attribute attribute)
-  {
-    AttributeType attrType = attribute.getAttributeType();
-    if (attrType.hasName(ATTR_COMMON_NAME) ||
-        attrType.hasName(ATTR_BACKEND_ENABLED.toLowerCase()) ||
-        attrType.hasName(ATTR_BACKEND_CLASS.toLowerCase()) ||
-        attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase()) ||
-        attrType.hasName(ATTR_BACKEND_ID.toLowerCase()) ||
-        attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase()))
-    {
-      return true;
-    }
-
-    return false;
-  }
-
-
-
-  /**
    * {@inheritDoc}
    */
   @Override()
@@ -338,12 +462,166 @@
    * {@inheritDoc}
    */
   @Override()
+  public Entry getEntry(final DN entryDN) throws DirectoryException
+  {
+    // If the requested entry was null, then throw an exception.
+    if (entryDN == null)
+    {
+      final Message message = ERR_MONITOR_GET_ENTRY_NULL.get();
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+          message);
+    }
+
+    // If the requested entry was the monitor base entry, then retrieve it
+    // without constructing the DIT.
+    if (entryDN.equals(baseMonitorDN))
+    {
+      return getBaseMonitorEntry();
+    }
+
+    // From now on we'll need the DIT.
+    final Map<DN, MonitorProvider<?>> dit = getDIT();
+    if (!dit.containsKey(entryDN))
+    {
+      final Message message = ERR_MONITOR_INVALID_BASE.get(
+          String.valueOf(entryDN), String.valueOf(baseMonitorDN));
+      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
+    }
+
+    // The DN is associated with a valid monitor/glue entry.
+    return getEntry(entryDN, dit);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
   public long getEntryCount()
   {
-    if (entryMap != null) {
-      return entryMap.size();
+    return getDIT().size();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public HashSet<String> getSupportedControls()
+  {
+    return supportedControls;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public HashSet<String> getSupportedFeatures()
+  {
+    return supportedFeatures;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public ConditionResult hasSubordinates(final DN entryDN)
+      throws DirectoryException
+  {
+    final NavigableMap<DN, MonitorProvider<?>> dit = getDIT();
+    if (!dit.containsKey(entryDN))
+    {
+      return ConditionResult.UNDEFINED;
     }
-    return -1;
+    else
+    {
+      final DN nextDN = dit.higherKey(entryDN);
+      if (nextDN == null || !nextDN.isDescendantOf(entryDN))
+      {
+        return ConditionResult.FALSE;
+      }
+      else
+      {
+        return ConditionResult.TRUE;
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public LDIFImportResult importLDIF(final LDIFImportConfig importConfig)
+      throws DirectoryException
+  {
+    // This backend does not support LDIF imports.
+    final Message message = ERR_MONITOR_IMPORT_NOT_SUPPORTED.get();
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void initializeBackend() throws ConfigException,
+      InitializationException
+  {
+    // Register with the Directory Server as a configurable component.
+    currentConfig.addMonitorChangeListener(this);
+
+    // Register the monitor base as a private suffix.
+    try
+    {
+      DirectoryServer.registerBaseDN(baseMonitorDN, this, true);
+    }
+    catch (final Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      final Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get(
+          baseMonitorDN.toString(), getExceptionMessage(e));
+      throw new InitializationException(message, e);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isConfigurationChangeAcceptable(
+      final MonitorBackendCfg backendCfg,
+      final List<Message> unacceptableReasons)
+  {
+    // We'll pretty much accept anything here as long as it isn't one of our
+    // private attributes.
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean isIndexed(final AttributeType attributeType,
+      final IndexType indexType)
+  {
+    // All searches in this backend will always be considered indexed.
+    return true;
   }
 
 
@@ -364,120 +642,42 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean isIndexed(AttributeType attributeType, IndexType indexType)
+  public long numSubordinates(final DN entryDN, final boolean subtree)
+      throws DirectoryException
   {
-    // All searches in this backend will always be considered indexed.
-    return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public ConditionResult hasSubordinates(DN entryDN)
-         throws DirectoryException
-  {
-    long ret = numSubordinates(entryDN, false);
-    if(ret < 0)
+    final NavigableMap<DN, MonitorProvider<?>> dit = getDIT();
+    if (!dit.containsKey(entryDN))
     {
-      return ConditionResult.UNDEFINED;
-    }
-    else if(ret == 0)
-    {
-      return ConditionResult.FALSE;
-    }
-    else
-    {
-      return ConditionResult.TRUE;
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public long numSubordinates(DN entryDN, boolean subtree)
-         throws DirectoryException {
-
-    Set<DN> children = childDNs.get(entryDN);
-    if (children == null)
-    {
-      if(entryMap.get(entryDN) != null)
-      {
-        // The entry does exist but just no children.
-        return 0;
-      }
-      return -1;
-    }
-
-    if(!subtree)
-    {
-      return children.size();
+      return -1L;
     }
     else
     {
       long count = 0;
-      for(DN child : children)
+      final int childDNSize = entryDN.getNumComponents() + 1;
+      for (final DN dn : dit.tailMap(entryDN, false).navigableKeySet())
       {
-        count += numSubordinates(child, true);
-        count++;
+        if (!dn.isDescendantOf(entryDN))
+        {
+          break;
+        }
+        else if (subtree || dn.getNumComponents() == childDNSize)
+        {
+          count++;
+        }
       }
       return count;
     }
   }
 
+
+
   /**
    * {@inheritDoc}
    */
-  @Override()
-  public Entry getEntry(DN entryDN)
-         throws DirectoryException
+  @Override
+  public void preloadEntryCache() throws UnsupportedOperationException
   {
-    // If the requested entry was null, then throw an exception.
-    if (entryDN == null)
-    {
-      Message message = ERR_MONITOR_GET_ENTRY_NULL.get();
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
-    }
-
-
-    // If the requested entry was the monitor base entry, then retrieve it.
-    if (entryDN.equals(baseMonitorDN))
-    {
-      return getBaseMonitorEntry();
-    }
-
-    if (!isATreeNode(entryDN)) {
-      Message message = ERR_MONITOR_INVALID_BASE.get(
-          String.valueOf(entryDN), String.valueOf(baseMonitorDN));
-      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
-    }
-
-
-    // Get the RDN for the requested DN and make sure it is single-valued.
-    RDN entryRDN = entryDN.getRDN();
-    if (entryRDN.isMultiValued())
-    {
-      Message message =
-          ERR_MONITOR_MULTIVALUED_RDN.get(String.valueOf(entryDN));
-      throw new DirectoryException(
-              ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
-    }
-
-    String rdnValue = getRdns(entryDN);
-    MonitorProvider<? extends MonitorProviderCfg> monitorProvider =
-         DirectoryServer.getMonitorProvider(rdnValue.toLowerCase());
-
-    // 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);
+    throw new UnsupportedOperationException("Operation not supported.");
   }
 
 
@@ -486,10 +686,193 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean entryExists(DN entryDN)
-         throws DirectoryException
+  public void removeBackup(final BackupDirectory backupDirectory,
+      final String backupID) throws DirectoryException
   {
-    return this.isATreeNode(entryDN);
+    // This backend does not provide a backup/restore mechanism.
+    final Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void renameEntry(final DN currentDN, final Entry entry,
+      final ModifyDNOperation modifyDNOperation) throws DirectoryException
+  {
+    final Message message = ERR_MONITOR_MODIFY_DN_NOT_SUPPORTED.get(String
+        .valueOf(currentDN));
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void replaceEntry(final Entry oldEntry, final Entry newEntry,
+      final ModifyOperation modifyOperation) throws DirectoryException
+  {
+    final Message message = ERR_MONITOR_MODIFY_NOT_SUPPORTED.get(
+        String.valueOf(newEntry.getDN()), String.valueOf(configEntryDN));
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void restoreBackup(final RestoreConfig restoreConfig)
+      throws DirectoryException
+  {
+    // This backend does not provide a backup/restore mechanism.
+    final Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
+    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void search(final SearchOperation searchOperation)
+      throws DirectoryException
+  {
+    // Get the base DN, scope, and filter for the search.
+    final DN baseDN = searchOperation.getBaseDN();
+    final SearchScope scope = searchOperation.getScope();
+    final SearchFilter filter = searchOperation.getFilter();
+
+    // Compute the current monitor DIT.
+    final NavigableMap<DN, MonitorProvider<?>> dit = getDIT();
+
+    // Resolve the base entry and return no such object if it does not exist.
+    if (!dit.containsKey(baseDN))
+    {
+      // Not found, so find the nearest match.
+      DN matchedDN = baseDN.getParent();
+      while (matchedDN != null)
+      {
+        if (dit.containsKey(matchedDN))
+        {
+          break;
+        }
+        matchedDN = matchedDN.getParent();
+      }
+      final Message message = ERR_MEMORYBACKEND_ENTRY_DOESNT_EXIST.get(String
+          .valueOf(baseDN));
+      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message,
+          matchedDN, null);
+    }
+
+    // Walk through all entries and send the ones that match.
+    for (final Map.Entry<DN, MonitorProvider<?>> e : dit.tailMap(baseDN)
+        .entrySet())
+    {
+      final DN dn = e.getKey();
+      if (dn.matchesBaseAndScope(baseDN, scope))
+      {
+        final Entry entry = getEntry(dn, dit);
+        if (filter.matchesEntry(entry))
+        {
+          searchOperation.returnEntry(entry, null);
+        }
+      }
+      else if (scope == SearchScope.BASE_OBJECT || !dn.isDescendantOf(baseDN))
+      {
+        // No more entries will be in scope.
+        break;
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean supportsBackup()
+  {
+    // This backend does not provide a backup/restore mechanism.
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean supportsBackup(final BackupConfig backupConfig,
+      final StringBuilder unsupportedReason)
+  {
+    // This backend does not provide a backup/restore mechanism.
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean supportsLDIFExport()
+  {
+    // We can export all the monitor entries as a point-in-time snapshot.
+    // TODO implementation of export is incomplete
+    // TODO export-ldif reports nonsense for upTime etc.
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean supportsLDIFImport()
+  {
+    // This backend does not support LDIF imports.
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean supportsRestore()
+  {
+    // This backend does not provide a backup/restore mechanism.
+    return false;
+  }
+
+
+
+  /**
+   * Creates an attribute for a monitor entry with the following criteria.
+   *
+   * @param name
+   *          The name for the attribute.
+   * @param lowerName
+   *          The name for the attribute formatted in all lowercase characters.
+   * @param value
+   *          The value to use for the attribute.
+   * @return The constructed attribute.
+   */
+  private Attribute createAttribute(final String name, final String lowerName,
+      final String value)
+  {
+    return Attributes.create(name, value);
   }
 
 
@@ -497,130 +880,110 @@
   /**
    * Retrieves the base monitor entry for the Directory Server.
    *
-   * @return  The base monitor entry for the Directory Server.
+   * @return The base monitor entry for the Directory Server.
    */
-  public Entry getBaseMonitorEntry()
+  private Entry getBaseMonitorEntry()
   {
-    HashMap<ObjectClass,String> monitorClasses =
-         new LinkedHashMap<ObjectClass,String>(3);
+    final HashMap<ObjectClass, String> monitorClasses =
+        new LinkedHashMap<ObjectClass, String>(3);
     monitorClasses.putAll(monitorObjectClasses);
 
-    ObjectClass extensibleObjectOC =
-         DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true);
+    final ObjectClass extensibleObjectOC = DirectoryServer.getObjectClass(
+        OC_EXTENSIBLE_OBJECT_LC, true);
     monitorClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT);
 
-    HashMap<AttributeType,List<Attribute>> monitorUserAttrs =
-         new LinkedHashMap<AttributeType,List<Attribute>>();
-
-    HashMap<AttributeType,List<Attribute>> monitorOperationalAttrs =
-         new LinkedHashMap<AttributeType,List<Attribute>>();
-
+    final HashMap<AttributeType, List<Attribute>> monitorUserAttrs =
+        new LinkedHashMap<AttributeType, List<Attribute>>();
+    final HashMap<AttributeType, List<Attribute>> monitorOperationalAttrs =
+        new LinkedHashMap<AttributeType, List<Attribute>>();
 
     // Add the "cn" attribute.
-    Attribute cnAttr = createAttribute(ATTR_COMMON_NAME, ATTR_COMMON_NAME,
-                                       "monitor");
-    ArrayList<Attribute> cnList = new ArrayList<Attribute>(1);
+    final Attribute cnAttr = createAttribute(ATTR_COMMON_NAME,
+        ATTR_COMMON_NAME, "monitor");
+    final ArrayList<Attribute> cnList = new ArrayList<Attribute>(1);
     cnList.add(cnAttr);
     monitorUserAttrs.put(cnAttr.getAttributeType(), cnList);
 
-
     // Add the server product name.
-    Attribute productNameAttr = createAttribute(ATTR_PRODUCT_NAME,
-                                                ATTR_PRODUCT_NAME_LC,
-                                                DynamicConstants.PRODUCT_NAME);
-    ArrayList<Attribute> productNameList = new ArrayList<Attribute>(1);
+    final Attribute productNameAttr = createAttribute(ATTR_PRODUCT_NAME,
+        ATTR_PRODUCT_NAME_LC, DynamicConstants.PRODUCT_NAME);
+    final ArrayList<Attribute> productNameList = new ArrayList<Attribute>(1);
     productNameList.add(productNameAttr);
     monitorUserAttrs.put(productNameAttr.getAttributeType(), productNameList);
 
-
     // Add the vendor name.
-    Attribute vendorNameAttr = createAttribute(ATTR_VENDOR_NAME,
-                                               ATTR_VENDOR_NAME_LC,
-                                               SERVER_VENDOR_NAME);
-    ArrayList<Attribute> vendorNameList = new ArrayList<Attribute>(1);
+    final Attribute vendorNameAttr = createAttribute(ATTR_VENDOR_NAME,
+        ATTR_VENDOR_NAME_LC, SERVER_VENDOR_NAME);
+    final ArrayList<Attribute> vendorNameList = new ArrayList<Attribute>(1);
     vendorNameList.add(vendorNameAttr);
     monitorUserAttrs.put(vendorNameAttr.getAttributeType(), vendorNameList);
 
-
     // Add the vendor version.
-    Attribute versionAttr = createAttribute(ATTR_VENDOR_VERSION,
-                                            ATTR_VENDOR_VERSION_LC,
-                                            DirectoryServer.getVersionString());
-    ArrayList<Attribute> versionList = new ArrayList<Attribute>(1);
+    final Attribute versionAttr = createAttribute(ATTR_VENDOR_VERSION,
+        ATTR_VENDOR_VERSION_LC, DirectoryServer.getVersionString());
+    final ArrayList<Attribute> versionList = new ArrayList<Attribute>(1);
     versionList.add(versionAttr);
     monitorUserAttrs.put(versionAttr.getAttributeType(), versionList);
 
-
     // Add the server startup time.
-    Attribute startTimeAttr =
-         createAttribute(ATTR_START_TIME, ATTR_START_TIME_LC,
-                         DirectoryServer.getStartTimeUTC());
-    ArrayList<Attribute> startTimeList = new ArrayList<Attribute>(1);
+    final Attribute startTimeAttr = createAttribute(ATTR_START_TIME,
+        ATTR_START_TIME_LC, DirectoryServer.getStartTimeUTC());
+    final ArrayList<Attribute> startTimeList = new ArrayList<Attribute>(1);
     startTimeList.add(startTimeAttr);
     monitorUserAttrs.put(startTimeAttr.getAttributeType(), startTimeList);
 
-
     // Add the current time.
-    Attribute currentTimeAttr =
-         createAttribute(ATTR_CURRENT_TIME, ATTR_CURRENT_TIME_LC,
-                         TimeThread.getGMTTime());
-    ArrayList<Attribute> currentTimeList = new ArrayList<Attribute>(1);
+    final Attribute currentTimeAttr = createAttribute(ATTR_CURRENT_TIME,
+        ATTR_CURRENT_TIME_LC, TimeThread.getGMTTime());
+    final ArrayList<Attribute> currentTimeList = new ArrayList<Attribute>(1);
     currentTimeList.add(currentTimeAttr);
     monitorUserAttrs.put(currentTimeAttr.getAttributeType(), currentTimeList);
 
-
     // Add the uptime as a human-readable string.
-    long upSeconds =
-         ((System.currentTimeMillis() - DirectoryServer.getStartTime()) / 1000);
-    long upDays = (upSeconds / 86400);
+    long upSeconds = ((System.currentTimeMillis() - DirectoryServer
+        .getStartTime()) / 1000);
+    final long upDays = (upSeconds / 86400);
     upSeconds %= 86400;
-    long upHours = (upSeconds / 3600);
+    final long upHours = (upSeconds / 3600);
     upSeconds %= 3600;
-    long upMinutes = (upSeconds / 60);
+    final long upMinutes = (upSeconds / 60);
     upSeconds %= 60;
-    Message upTimeStr =
-        INFO_MONITOR_UPTIME.get(upDays, upHours, upMinutes, upSeconds);
-    Attribute upTimeAttr = createAttribute(ATTR_UP_TIME, ATTR_UP_TIME_LC,
-                                           upTimeStr.toString());
-    ArrayList<Attribute> upTimeList = new ArrayList<Attribute>(1);
+    final Message upTimeStr = INFO_MONITOR_UPTIME.get(upDays, upHours,
+        upMinutes, upSeconds);
+    final Attribute upTimeAttr = createAttribute(ATTR_UP_TIME, ATTR_UP_TIME_LC,
+        upTimeStr.toString());
+    final ArrayList<Attribute> upTimeList = new ArrayList<Attribute>(1);
     upTimeList.add(upTimeAttr);
     monitorUserAttrs.put(upTimeAttr.getAttributeType(), upTimeList);
 
-
     // Add the number of connections currently established.
-    long currentConns = DirectoryServer.getCurrentConnections();
-    Attribute currentConnsAttr = createAttribute(ATTR_CURRENT_CONNS,
-                                                 ATTR_CURRENT_CONNS_LC,
-                                                 String.valueOf(currentConns));
-    ArrayList<Attribute> currentConnsList = new ArrayList<Attribute>(1);
+    final long currentConns = DirectoryServer.getCurrentConnections();
+    final Attribute currentConnsAttr = createAttribute(ATTR_CURRENT_CONNS,
+        ATTR_CURRENT_CONNS_LC, String.valueOf(currentConns));
+    final ArrayList<Attribute> currentConnsList = new ArrayList<Attribute>(1);
     currentConnsList.add(currentConnsAttr);
     monitorUserAttrs.put(currentConnsAttr.getAttributeType(), currentConnsList);
 
-
     // Add the maximum number of connections established at one time.
-    long maxConns = DirectoryServer.getMaxConnections();
-    Attribute maxConnsAttr = createAttribute(ATTR_MAX_CONNS,
-                                             ATTR_MAX_CONNS_LC,
-                                             String.valueOf(maxConns));
-    ArrayList<Attribute> maxConnsList = new ArrayList<Attribute>(1);
+    final long maxConns = DirectoryServer.getMaxConnections();
+    final Attribute maxConnsAttr = createAttribute(ATTR_MAX_CONNS,
+        ATTR_MAX_CONNS_LC, String.valueOf(maxConns));
+    final ArrayList<Attribute> maxConnsList = new ArrayList<Attribute>(1);
     maxConnsList.add(maxConnsAttr);
     monitorUserAttrs.put(maxConnsAttr.getAttributeType(), maxConnsList);
 
-
     // Add the total number of connections the server has accepted.
-    long totalConns = DirectoryServer.getTotalConnections();
-    Attribute totalConnsAttr = createAttribute(ATTR_TOTAL_CONNS,
-                                               ATTR_TOTAL_CONNS_LC,
-                                               String.valueOf(totalConns));
-    ArrayList<Attribute> totalConnsList = new ArrayList<Attribute>(1);
+    final long totalConns = DirectoryServer.getTotalConnections();
+    final Attribute totalConnsAttr = createAttribute(ATTR_TOTAL_CONNS,
+        ATTR_TOTAL_CONNS_LC, String.valueOf(totalConns));
+    final ArrayList<Attribute> totalConnsList = new ArrayList<Attribute>(1);
     totalConnsList.add(totalConnsAttr);
     monitorUserAttrs.put(totalConnsAttr.getAttributeType(), totalConnsList);
 
-
     // Add all the user-defined attributes.
-    for (Attribute a : userDefinedAttributes)
+    for (final Attribute a : userDefinedAttributes)
     {
-      AttributeType type = a.getAttributeType();
+      final AttributeType type = a.getAttributeType();
 
       if (type.isOperational())
       {
@@ -652,95 +1015,167 @@
       }
     }
 
-
     // Construct and return the entry.
-    Entry e = new Entry(baseMonitorDN, monitorClasses, monitorUserAttrs,
-                        monitorOperationalAttrs);
+    final Entry e = new Entry(baseMonitorDN, monitorClasses, monitorUserAttrs,
+        monitorOperationalAttrs);
     e.processVirtualAttributes();
     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) {
 
-    HashMap<ObjectClass,String> monitorClasses =
-         new LinkedHashMap<ObjectClass,String>(3);
+
+  /**
+   * Retrieves the branch monitor entry for the Directory Server.
+   *
+   * @param dn
+   *          to get.
+   * @return The branch monitor entry for the Directory Server.
+   */
+  private Entry getBranchMonitorEntry(final DN dn)
+  {
+
+    final HashMap<ObjectClass, String> monitorClasses =
+        new LinkedHashMap<ObjectClass, String>(3);
     monitorClasses.putAll(monitorObjectClasses);
-    ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_BRANCH,
-                                                           true);
+    final ObjectClass monitorOC = DirectoryServer.getObjectClass(
+        OC_MONITOR_BRANCH, true);
     monitorClasses.put(monitorOC, OC_MONITOR_BRANCH);
 
-    HashMap<AttributeType,List<Attribute>> monitorUserAttrs =
-      new LinkedHashMap<AttributeType,List<Attribute>>();
+    final HashMap<AttributeType, List<Attribute>> monitorUserAttrs =
+        new LinkedHashMap<AttributeType, List<Attribute>>();
 
-    RDN rdn = dn.getRDN();
+    final RDN rdn = dn.getRDN();
     if (rdn != null)
     {
       // Add the RDN values
-      for (int i=0; i<rdn.getNumValues(); i++)
+      for (int i = 0; i < rdn.getNumValues(); i++)
       {
-        AttributeType attributeType = rdn.getAttributeType(i);
-        AttributeValue value = rdn.getAttributeValue(attributeType);
-        Attribute attr = Attributes.create(attributeType, value);
-        List<Attribute> attrList = new ArrayList<Attribute>(1);
+        final AttributeType attributeType = rdn.getAttributeType(i);
+        final AttributeValue value = rdn.getAttributeValue(attributeType);
+        final Attribute attr = Attributes.create(attributeType, value);
+        final List<Attribute> attrList = new ArrayList<Attribute>(1);
         attrList.add(attr);
         monitorUserAttrs.put(attributeType, attrList);
       }
     }
 
     // Construct and return the entry.
-    Entry  e = new Entry(dn, monitorClasses, monitorUserAttrs, null);
+    final Entry e = new Entry(dn, monitorClasses, monitorUserAttrs, null);
     e.processVirtualAttributes();
     return e;
   }
 
+
+
   /**
-   * Generates and returns a monitor entry based on the contents of the
-   * provided monitor provider.
+   * Returns a map containing records for each DN in the monitor backend's DIT.
+   * Each record maps the entry DN to the associated monitor provider, or
+   * {@code null} if the entry is a glue (branch) entry.
    *
-   * @param  entryDN          The DN to use for the entry.
-   * @param  monitorProvider  The monitor provider to use to obtain the
-   *                          information for the entry.
-   *
-   * @return  The monitor entry generated from the information in the provided
-   *          monitor provider.
+   * @return A map containing records for each DN in the monitor backend's DIT.
    */
-  private Entry getMonitorEntry(DN entryDN,
-                     MonitorProvider<? extends MonitorProviderCfg>
-                          monitorProvider)
+  private NavigableMap<DN, MonitorProvider<?>> getDIT()
   {
-    HashMap<ObjectClass,String> monitorClasses =
-         new LinkedHashMap<ObjectClass,String>(3);
+    final NavigableMap<DN, MonitorProvider<?>> dit =
+        new TreeMap<DN, MonitorProvider<?>>();
+    for (final MonitorProvider<?> monitorProvider : DirectoryServer
+        .getMonitorProviders().values())
+    {
+      DN dn = DirectoryServer.getMonitorProviderDN(monitorProvider);
+      dit.put(dn, monitorProvider);
+
+      // Added glue records.
+      for (dn = dn.getParent(); dn != null; dn = dn.getParent())
+      {
+        if (dit.containsKey(dn))
+        {
+          break;
+        }
+        else
+        {
+          dit.put(dn, null);
+        }
+      }
+    }
+    return dit;
+  }
+
+
+
+  /**
+   * Creates the monitor entry having the specified DN.
+   *
+   * @param entryDN
+   *          The name of the monitor entry.
+   * @param dit
+   *          The monitor DIT.
+   * @return Returns the monitor entry having the specified DN.
+   */
+  private Entry getEntry(final DN entryDN,
+      final Map<DN, MonitorProvider<?>> dit)
+  {
+    // Get the monitor provider.
+    final MonitorProvider<?> monitorProvider = dit.get(entryDN);
+    if (monitorProvider != null)
+    {
+      return getMonitorEntry(entryDN, monitorProvider);
+    }
+    else if (entryDN.equals(baseMonitorDN))
+    {
+      // The monitor base entry needs special treatment.
+      return getBaseMonitorEntry();
+    }
+    else
+    {
+      // Create a generic glue branch entry.
+      return getBranchMonitorEntry(entryDN);
+    }
+  }
+
+
+
+  /**
+   * Generates and returns a monitor entry based on the contents of the provided
+   * monitor provider.
+   *
+   * @param entryDN
+   *          The DN to use for the entry.
+   * @param monitorProvider
+   *          The monitor provider to use to obtain the information for the
+   *          entry.
+   * @return The monitor entry generated from the information in the provided
+   *         monitor provider.
+   */
+  private Entry getMonitorEntry(final DN entryDN,
+      final MonitorProvider<?> monitorProvider)
+  {
+    final HashMap<ObjectClass, String> monitorClasses =
+        new LinkedHashMap<ObjectClass, String>(
+        3);
     monitorClasses.putAll(monitorObjectClasses);
 
-    ObjectClass monitorOC = monitorProvider.getMonitorObjectClass();
+    final ObjectClass monitorOC = monitorProvider.getMonitorObjectClass();
     monitorClasses.put(monitorOC, monitorOC.getPrimaryName());
 
-    List<Attribute> monitorAttrs = monitorProvider.getMonitorData();
-    HashMap<AttributeType,List<Attribute>> attrMap =
-         new LinkedHashMap<AttributeType,List<Attribute>>(
-                  monitorAttrs.size()+1);
-
+    final List<Attribute> monitorAttrs = monitorProvider.getMonitorData();
+    final HashMap<AttributeType, List<Attribute>> attrMap =
+        new LinkedHashMap<AttributeType, List<Attribute>>(
+          monitorAttrs.size() + 1);
 
     // Make sure to include the RDN attribute.
-    RDN            entryRDN = entryDN.getRDN();
-    AttributeType  rdnType  = entryRDN.getAttributeType(0);
-    AttributeValue rdnValue = entryRDN.getAttributeValue(0);
+    final RDN entryRDN = entryDN.getRDN();
+    final AttributeType rdnType = entryRDN.getAttributeType(0);
+    final AttributeValue rdnValue = entryRDN.getAttributeValue(0);
 
-    Attribute rdnAttr = Attributes.create(rdnType, rdnValue);
-    ArrayList<Attribute> rdnList = new ArrayList<Attribute>(1);
+    final Attribute rdnAttr = Attributes.create(rdnType, rdnValue);
+    final ArrayList<Attribute> rdnList = new ArrayList<Attribute>(1);
     rdnList.add(rdnAttr);
     attrMap.put(rdnType, rdnList);
 
-
     // Take the rest of the information from the monitor data.
-    for (Attribute a : monitorAttrs)
+    for (final Attribute a : monitorAttrs)
     {
-      AttributeType type = a.getAttributeType();
+      final AttributeType type = a.getAttributeType();
 
       List<Attribute> attrs = attrMap.get(type);
       if (attrs == null)
@@ -755,575 +1190,37 @@
       }
     }
 
-    Entry e = new Entry(entryDN, monitorClasses, attrMap,
-                        new HashMap<AttributeType,List<Attribute>>(0));
+    final Entry e = new Entry(entryDN, monitorClasses, attrMap,
+        new HashMap<AttributeType, List<Attribute>>(0));
     e.processVirtualAttributes();
     return e;
   }
 
 
 
-
-
   /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void addEntry(Entry entry, AddOperation addOperation)
-         throws DirectoryException
-  {
-    Message message =
-        ERR_MONITOR_ADD_NOT_SUPPORTED.get(String.valueOf(entry.getDN()));
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void deleteEntry(DN entryDN, DeleteOperation deleteOperation)
-         throws DirectoryException
-  {
-    Message message =
-        ERR_MONITOR_DELETE_NOT_SUPPORTED.get(String.valueOf(entryDN));
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void replaceEntry(Entry oldEntry, Entry newEntry,
-      ModifyOperation modifyOperation) throws DirectoryException
-  {
-    Message message = ERR_MONITOR_MODIFY_NOT_SUPPORTED.get(
-        String.valueOf(newEntry.getDN()), String.valueOf(configEntryDN));
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void renameEntry(DN currentDN, Entry entry,
-                                   ModifyDNOperation modifyDNOperation)
-         throws DirectoryException
-  {
-    Message message =
-        ERR_MONITOR_MODIFY_DN_NOT_SUPPORTED.get(String.valueOf(currentDN));
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public synchronized void search(SearchOperation searchOperation)
-         throws DirectoryException
-  {
-
-    // Get the base DN, scope, and filter for the search.
-    DN           baseDN = searchOperation.getBaseDN();
-    SearchScope  scope  = searchOperation.getScope();
-    SearchFilter filter = searchOperation.getFilter();
-
-
-    // Make sure the base entry exists if it's supposed to be in this backend.
-    this.initEntryMaps();
-    Entry baseEntry = entryMap.get(baseDN);
-    if ((baseEntry == null) && handlesEntry(baseDN))
-    {
-      DN matchedDN = baseDN.getParentDNInSuffix();
-      while (matchedDN != null)
-      {
-        if (entryMap.containsKey(matchedDN))
-        {
-          break;
-        }
-
-        matchedDN = matchedDN.getParentDNInSuffix();
-      }
-
-      Message message =
-          ERR_MEMORYBACKEND_ENTRY_DOESNT_EXIST.get(String.valueOf(baseDN));
-      throw new DirectoryException(
-              ResultCode.NO_SUCH_OBJECT, message, matchedDN, null);
-    }
-
-    if (baseEntry != null)
-    {
-      baseEntry = baseEntry.duplicate(true);
-    }
-
-
-    // If it's a base-level search, then just get that entry and return it if it
-    // matches the filter.
-    if (scope == SearchScope.BASE_OBJECT)
-    {
-      if (filter.matchesEntry(baseEntry))
-      {
-        searchOperation.returnEntry(baseEntry, null);
-      }
-    }
-    else
-    {
-      // Walk through all entries and send the ones that match.
-      for (Entry e : entryMap.values()) {
-        boolean matched = filter.matchesEntry(e);
-        if (matched) {
-            if (e.matchesBaseAndScope(baseDN, scope)==true) {
-                searchOperation.returnEntry(e, null);
-            }
-        }
-      }
-    }
-  }
-
-  // Build the internal monitor tree (entries, and children)
-  private synchronized void initEntryMaps() {
-      this.entryMap.clear();
-      this.childDNs.clear();
-      for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
-           DirectoryServer.getMonitorProviders().values()) {
-            try {
-                DN providerdn =
-                        DirectoryServer.getMonitorProviderDN(monitorProvider);
-                if (!entryMap.containsKey(providerdn)) {
-                  getAndAddParentInMaps(providerdn);
-                  Entry entry = getEntry(providerdn);
-                  entryMap.put(providerdn, entry);
-              }
-            } catch (Exception ex) {
-              if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-              }
-            }
-      }
-  }
-
- /**
-  * Recursively builds the entryMap and the childDN Map.
-  */
-  private void getAndAddParentInMaps(DN providerDN)
-  {
-    try
-    {
-      DN parentdn = providerDN.getParentDNInSuffix();
-      DN child = providerDN;
-
-      if ((parentdn != null) && (!entryMap.containsKey(parentdn)))
-      {
-        getAndAddParentInMaps(parentdn);
-        entryMap.put(parentdn, getEntry(parentdn));
-      }
-
-      if (childDNs.containsKey(parentdn))
-      {
-        HashSet<DN> children = childDNs.get(parentdn);
-        children.add(child);
-        childDNs.put(parentdn, children);
-      }
-      else
-      {
-        HashSet<DN> children = new HashSet<DN>();
-        children.add(child);
-        childDNs.put(parentdn, children);
-      }
-    } catch (Exception e) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public HashSet<String> getSupportedControls()
-  {
-    return supportedControls;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public HashSet<String> getSupportedFeatures()
-  {
-    return supportedFeatures;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean supportsLDIFExport()
-  {
-    // We can export all the monitor entries as a point-in-time snapshot.
-    // TODO implementation of export is incomplete
-    // TODO export-ldif reports nonsense for upTime etc.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void exportLDIF(LDIFExportConfig exportConfig)
-         throws DirectoryException
-  {
-    // TODO export-ldif reports nonsense for upTime etc.
-
-    // Create the LDIF writer.
-    LDIFWriter ldifWriter;
-    try
-    {
-      ldifWriter = new LDIFWriter(exportConfig);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_ROOTDSE_UNABLE_TO_CREATE_LDIF_WRITER.get(
-          stackTraceToSingleLineString(e));
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
-    }
-
-
-    // Write the base monitor entry to the LDIF.
-    try
-    {
-      ldifWriter.writeEntry(getBaseMonitorEntry());
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      try
-      {
-        ldifWriter.close();
-      }
-      catch (Exception e2)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-        }
-      }
-
-      Message message = ERR_MONITOR_UNABLE_TO_EXPORT_BASE.get(
-          stackTraceToSingleLineString(e));
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
-    }
-
-
-    // Get all the monitor providers, convert them to entries, and write them to
-    // LDIF.
-    for (MonitorProvider<?> monitorProvider :
-         DirectoryServer.getMonitorProviders().values())
-    {
-      try
-      {
-        // TODO implementation of export is incomplete
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        try
-        {
-          ldifWriter.close();
-        }
-        catch (Exception e2)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-          }
-        }
-
-        Message message = ERR_MONITOR_UNABLE_TO_EXPORT_PROVIDER_ENTRY.
-            get(monitorProvider.getMonitorInstanceName(),
-                stackTraceToSingleLineString(e));
-        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                     message);
-      }
-    }
-
-
-    // Close the monitor provider and return.
-    try
-    {
-      ldifWriter.close();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean supportsLDIFImport()
-  {
-    // This backend does not support LDIF imports.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public LDIFImportResult importLDIF(LDIFImportConfig importConfig)
-         throws DirectoryException
-  {
-    // This backend does not support LDIF imports.
-    Message message = ERR_MONITOR_IMPORT_NOT_SUPPORTED.get();
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean supportsBackup()
-  {
-    // This backend does not provide a backup/restore mechanism.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean supportsBackup(BackupConfig backupConfig,
-                                StringBuilder unsupportedReason)
-  {
-    // This backend does not provide a backup/restore mechanism.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void createBackup(BackupConfig backupConfig)
-         throws DirectoryException
-  {
-    // This backend does not provide a backup/restore mechanism.
-    Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void removeBackup(BackupDirectory backupDirectory,
-                           String backupID)
-         throws DirectoryException
-  {
-    // This backend does not provide a backup/restore mechanism.
-    Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean supportsRestore()
-  {
-    // This backend does not provide a backup/restore mechanism.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void restoreBackup(RestoreConfig restoreConfig)
-         throws DirectoryException
-  {
-    // This backend does not provide a backup/restore mechanism.
-    Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
-    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean isConfigurationChangeAcceptable(
-       MonitorBackendCfg backendCfg,
-       List<Message> unacceptableReasons)
-  {
-    // We'll pretty much accept anything here as long as it isn't one of our
-    // private attributes.
-    return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationChange(
-                                 MonitorBackendCfg backendCfg)
-  {
-    ResultCode        resultCode          = ResultCode.SUCCESS;
-    boolean           adminActionRequired = false;
-    ArrayList<Message> messages            = new ArrayList<Message>();
-
-
-    // Check to see if there is a new set of user-defined attributes.
-    ArrayList<Attribute> userAttrs = new ArrayList<Attribute>();
-    try
-    {
-      ConfigEntry configEntry = DirectoryServer.getConfigEntry(configEntryDN);
-      for (List<Attribute> attrs :
-           configEntry.getEntry().getUserAttributes().values())
-      {
-        for (Attribute a : attrs)
-        {
-          if (! isMonitorConfigAttribute(a))
-          {
-            userAttrs.add(a);
-          }
-        }
-      }
-      for (List<Attribute> attrs :
-           configEntry.getEntry().getOperationalAttributes().values())
-      {
-        for (Attribute a : attrs)
-        {
-          if (! isMonitorConfigAttribute(a))
-          {
-            userAttrs.add(a);
-          }
-        }
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-
-      messages.add(ERR_CONFIG_BACKEND_ERROR_INTERACTING_WITH_BACKEND_ENTRY.get(
-              String.valueOf(configEntryDN),
-              stackTraceToSingleLineString(e)));
-      resultCode = DirectoryServer.getServerErrorResultCode();
-    }
-
-
-    userDefinedAttributes = userAttrs;
-
-    Message message = INFO_MONITOR_USING_NEW_USER_ATTRS.get();
-    messages.add(message);
-
-
-    currentConfig = backendCfg;
-    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void preloadEntryCache() throws UnsupportedOperationException {
-    throw new UnsupportedOperationException("Operation not supported.");
-  }
-
-  // Private Methods
-  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);
-  }
-
-   /**
-   * Creates an attribute for a monitor entry with the following criteria.
+   * Indicates whether the provided attribute is one that is used in the
+   * configuration of this backend.
    *
-   * @param  name       The name for the attribute.
-   * @param  lowerName  The name for the attribute formatted in all lowercase
-   *                    characters.
-   * @param  value      The value to use for the attribute.
-   *
-   * @return  The constructed attribute.
+   * @param attribute
+   *          The attribute for which to make the determination.
+   * @return <CODE>true</CODE> if the provided attribute is one that is used in
+   *         the configuration of this backend, <CODE>false</CODE> if not.
    */
-  private Attribute createAttribute(String name, String lowerName,
-                                    String value) {
-    return Attributes.create(name, value);
+  private boolean isMonitorConfigAttribute(final Attribute attribute)
+  {
+    final AttributeType attrType = attribute.getAttributeType();
+    if (attrType.hasName(ATTR_COMMON_NAME)
+        || attrType.hasName(ATTR_BACKEND_ENABLED.toLowerCase())
+        || attrType.hasName(ATTR_BACKEND_CLASS.toLowerCase())
+        || attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase())
+        || attrType.hasName(ATTR_BACKEND_ID.toLowerCase())
+        || attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase()))
+    {
+      return true;
+    }
+
+    return false;
   }
 
 }

--
Gitblit v1.10.0