From 7369ecc8296a0329e424596ff71c60629add3ce2 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Wed, 21 Feb 2007 19:44:18 +0000
Subject: [PATCH] Redesign the server to support multiple key manager providers, trust manager providers, and certificate mappers, and update the components which need access to those elements so that they can specify which one they want to use.  Among other things, this will provide the ability to use different certificates for different listeners, and provide template configuration entries that make it easier for users to enable SSL and/or StartTLS.

---
 opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java | 1225 +++++++++++++++++++++++++--------------------------------
 1 files changed, 534 insertions(+), 691 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java b/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
index 04a12fb..ec0dcfc 100644
--- a/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
+++ b/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
@@ -22,24 +22,29 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006 Sun Microsystems, Inc.
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 
 
 
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.opends.server.api.ConfigAddListener;
 import org.opends.server.api.ConfigChangeListener;
 import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.api.ConfigHandler;
+import org.opends.server.api.ConfigurableComponent;
 import org.opends.server.api.TrustManagerProvider;
 import org.opends.server.config.BooleanConfigAttribute;
 import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
 import org.opends.server.config.StringConfigAttribute;
-import org.opends.server.extensions.NullTrustManagerProvider;
 import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
 import org.opends.server.types.ErrorLogCategory;
 import org.opends.server.types.ErrorLogSeverity;
@@ -51,15 +56,17 @@
 import static org.opends.server.loggers.Error.*;
 import static org.opends.server.messages.ConfigMessages.*;
 import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
 
 
 /**
- * This class defines a utility that will be used to manage the configuration
- * for the Directory Server trust manager provider.  Only a single trust manager
- * provider may be defined, but if it is absent or disabled, then a null
- * provider will be used which will not allow any trust manager interaction.
+ * This class defines a utility that will be used to manage the set of
+ * trust manager providers defined in the Directory Server.  It will initialize
+ * the providers when the server starts, and then will manage any additions,
+ * removals, or modifications of any trust manager providers while the server is
+ * running.
  */
 public class TrustManagerProviderConfigManager
        implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
@@ -72,6 +79,15 @@
 
 
 
+  // A mapping between the DNs of the config entries and the associated
+  // trust manager providers.
+  private ConcurrentHashMap<DN,TrustManagerProvider> providers;
+
+  // The configuration handler for the Directory Server.
+  private ConfigHandler configHandler;
+
+
+
   /**
    * Creates a new instance of this trust manager provider config manager.
    */
@@ -79,243 +95,123 @@
   {
     assert debugConstructor(CLASS_NAME);
 
-    // No implementation is required.
+    configHandler = DirectoryServer.getConfigHandler();
+    providers     = new ConcurrentHashMap<DN,TrustManagerProvider>();
   }
 
 
 
   /**
-   * Initializes the configuration associated with the Directory Server trust
-   * manager provider.  This should only be called at Directory Server startup.
-   * If an error occurs, then a message will be logged and the null trust
-   * manager provider will be installed.
+   * Initializes all trust manager providers currently defined in the Directory
+   * Server configuration.  This should only be called at Directory Server
+   * startup.
    *
-   * @throws  InitializationException  If a problem occurs while trying to
-   *                                   install the null trust manager provider.
+   * @throws  ConfigException  If a configuration problem causes the trust
+   *                           manager provider initialization process to fail.
+   *
+   * @throws  InitializationException  If a problem occurs while initializing
+   *                                   the trust manager providers that is not
+   *                                   related to the server configuration.
    */
-  public void initializeTrustManagerProvider()
-         throws InitializationException
+  public void initializeTrustManagerProviders()
+         throws ConfigException, InitializationException
   {
-    assert debugEnter(CLASS_NAME, "initializeTrustManagerProvider");
+    assert debugEnter(CLASS_NAME, "initializeTrustManagerProviders");
 
 
-    // First, install a null trust manager provider so that there will be one
-    // even if we encounter a problem later.
+    // First, get the configuration base entry.
+    ConfigEntry baseEntry;
     try
     {
-      NullTrustManagerProvider nullProvider = new NullTrustManagerProvider();
-      nullProvider.initializeTrustManagerProvider(null);
-      DirectoryServer.setTrustManagerProvider(nullProvider);
+      DN providerBase = DN.decode(DN_TRUSTMANAGER_PROVIDER_CONFIG_BASE);
+      baseEntry = configHandler.getConfigEntry(providerBase);
     }
     catch (Exception e)
     {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
+      assert debugException(CLASS_NAME, "initializeTrustManagerProviders",
+                            e);
 
-      int msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTALL_NULL_PROVIDER;
-      String message = getMessage(msgID, stackTraceToSingleLineString(e));
-      throw new InitializationException(msgID, message, e);
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_CANNOT_GET_BASE;
+      String message = getMessage(msgID, String.valueOf(e));
+      throw new ConfigException(msgID, message, e);
+    }
+
+    if (baseEntry == null)
+    {
+      // The trust manager provider base entry does not exist.  This is not
+      // acceptable, so throw an exception.
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_BASE_DOES_NOT_EXIST;
+      String message = getMessage(msgID);
+      throw new ConfigException(msgID, message);
     }
 
 
-    // Get the trust manager provider configuration entry.  If it is not
-    // present, then register an add listener and just go with the null
-    // provider.
-    DN configEntryDN;
-    ConfigEntry configEntry;
-    try
-    {
-      configEntryDN = DN.decode(DN_TRUSTMANAGER_PROVIDER_CONFIG);
-      configEntry   = DirectoryServer.getConfigEntry(configEntryDN);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
+    // Register add and delete listeners with the trust manager provider base
+    // entry.  We don't care about modifications to it.
+    baseEntry.registerAddListener(this);
+    baseEntry.registerDeleteListener(this);
 
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_GET_CONFIG_ENTRY,
-               stackTraceToSingleLineString(e));
+
+    // See if the base entry has any children.  If not, then we don't need to do
+    // anything else.
+    if (! baseEntry.hasChildren())
+    {
       return;
     }
 
-    if (configEntry == null)
+
+    // Iterate through the child entries and process them as trust manager
+    // provider configuration entries.
+    for (ConfigEntry childEntry : baseEntry.getChildren().values())
     {
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_WARNING,
-               MSGID_CONFIG_TRUSTMANAGER_NO_CONFIG_ENTRY);
+      childEntry.registerChangeListener(this);
+
+      StringBuilder unacceptableReason = new StringBuilder();
+      if (! configAddIsAcceptable(childEntry, unacceptableReason))
+      {
+        logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
+                 MSGID_CONFIG_TRUSTMANAGER_ENTRY_UNACCEPTABLE,
+                 childEntry.getDN().toString(), unacceptableReason.toString());
+        continue;
+      }
 
       try
       {
-        ConfigEntry parentEntry = DirectoryServer
-            .getConfigEntry(configEntryDN.getParentDNInSuffix());
-        if (parentEntry != null)
+        ConfigChangeResult result = applyConfigurationAdd(childEntry);
+        if (result.getResultCode() != ResultCode.SUCCESS)
         {
-          parentEntry.registerAddListener(this);
+          StringBuilder buffer = new StringBuilder();
+
+          List<String> resultMessages = result.getMessages();
+          if ((resultMessages == null) || (resultMessages.isEmpty()))
+          {
+            buffer.append(getMessage(MSGID_CONFIG_UNKNOWN_UNACCEPTABLE_REASON));
+          }
+          else
+          {
+            Iterator<String> iterator = resultMessages.iterator();
+
+            buffer.append(iterator.next());
+            while (iterator.hasNext())
+            {
+              buffer.append(EOL);
+              buffer.append(iterator.next());
+            }
+          }
+
+          logError(ErrorLogCategory.CONFIGURATION,
+                   ErrorLogSeverity.SEVERE_ERROR,
+                   MSGID_CONFIG_TRUSTMANAGER_CANNOT_CREATE_PROVIDER,
+                   childEntry.getDN().toString(), buffer.toString());
         }
       }
       catch (Exception e)
       {
-        assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
         logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-                 MSGID_CONFIG_TRUSTMANAGER_CANNOT_REGISTER_ADD_LISTENER,
-                 stackTraceToSingleLineString(e));
-      }
-
-      return;
-    }
-
-
-    // At this point, we have a configuration entry.  Register a change listener
-    // with it so we can be notified of changes to it over time.  We will also
-    // want to register a delete listener with its parent to allow us to
-    // determine if the entry is deleted.
-    configEntry.registerChangeListener(this);
-    try
-    {
-      DN parentDN = configEntryDN.getParentDNInSuffix();
-      ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
-      if (parentEntry != null)
-      {
-        parentEntry.registerDeleteListener(this);
+                 MSGID_CONFIG_TRUSTMANAGER_CANNOT_CREATE_PROVIDER,
+                 childEntry.getDN().toString(), String.valueOf(e));
       }
     }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_WARNING,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_REGISTER_DELETE_LISTENER,
-               stackTraceToSingleLineString(e));
-    }
-
-
-    // See if the entry indicates whether the trust manager provider should be
-    // enabled.
-    int msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED;
-    BooleanConfigAttribute enabledStub =
-         new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
-                                    getMessage(msgID), false);
-    try
-    {
-      BooleanConfigAttribute enabledAttr =
-           (BooleanConfigAttribute)
-           configEntry.getConfigAttribute(enabledStub);
-      if (enabledAttr == null)
-      {
-        // The attribute is not present, so the trust manager provider will be
-        // disabled.  Log a warning message and return.
-        logError(ErrorLogCategory.CONFIGURATION,
-                 ErrorLogSeverity.SEVERE_WARNING,
-                 MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR);
-        return;
-      }
-      else if (! enabledAttr.activeValue())
-      {
-        // The trust manager provider is explicitly disabled.  Log a mild
-        // warning and return.
-        logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.MILD_WARNING,
-                 MSGID_CONFIG_TRUSTMANAGER_DISABLED);
-        return;
-      }
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE,
-               stackTraceToSingleLineString(e));
-      return;
-    }
-
-
-    // See if it specifies the class name for the trust manager provider
-    // implementation.
-    String className;
-    msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS;
-    StringConfigAttribute classStub =
-         new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS, getMessage(msgID),
-                                   true, false, false);
-    try
-    {
-      StringConfigAttribute classAttr =
-           (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-      if (classAttr == null)
-      {
-        logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-                 MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_ATTR);
-        return;
-      }
-      else
-      {
-        className = classAttr.activeValue();
-      }
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_DETERMINE_CLASS,
-               stackTraceToSingleLineString(e));
-      return;
-    }
-
-
-    // Try to load the class and instantiate it as a trust manager provider.
-    Class trustManagerProviderClass;
-    try
-    {
-      // FIXME -- Should we use a custom class loader for this?
-      trustManagerProviderClass = Class.forName(className);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_LOAD_CLASS,
-               String.valueOf(className), stackTraceToSingleLineString(e));
-      return;
-    }
-
-    TrustManagerProvider trustManagerProvider;
-    try
-    {
-      trustManagerProvider =
-           (TrustManagerProvider) trustManagerProviderClass.newInstance();
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTANTIATE_CLASS,
-               String.valueOf(className), stackTraceToSingleLineString(e));
-      return;
-    }
-
-
-    // Try to initialize the trust manager provider with the contents of the
-    // configuration entry.
-    try
-    {
-      trustManagerProvider.initializeTrustManagerProvider(configEntry);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "initializeTrustManagerProvider", e);
-
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_INITIALIZE,
-               String.valueOf(className), stackTraceToSingleLineString(e));
-      return;
-    }
-
-
-    // Install the new trust manager provider in the server.  We don't need to
-    // do anything to get rid of the previous null provider since it doesn't
-    // consume any resources.
-    DirectoryServer.setTrustManagerProvider(trustManagerProvider);
   }
 
 
@@ -340,21 +236,98 @@
                       String.valueOf(configEntry), "java.lang.StringBuilder");
 
 
-    // See if the entry indicates whether the trust manager provider should be
-    // enabled.
-    int msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED;
-    BooleanConfigAttribute enabledStub =
-         new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
-                                    getMessage(msgID), false);
+    // Make sure that the entry has an appropriate objectclass for a trust
+    // manager provider.
+    if (! configEntry.hasObjectClass(OC_TRUST_MANAGER_PROVIDER))
+    {
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_OBJECTCLASS;
+      String message = getMessage(msgID, configEntry.getDN().toString());
+      unacceptableReason.append(message);
+      return false;
+    }
+
+
+    // Make sure that the entry specifies the provider class name.
+    StringConfigAttribute classNameAttr;
     try
     {
-      BooleanConfigAttribute enabledAttr =
-           (BooleanConfigAttribute)
-           configEntry.getConfigAttribute(enabledStub);
+      StringConfigAttribute classStub =
+           new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS),
+                    true, false, true);
+      classNameAttr = (StringConfigAttribute)
+                      configEntry.getConfigAttribute(classStub);
+
+      if (classNameAttr == null)
+      {
+        int    msgID   = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_NAME;
+        String message = getMessage(msgID, configEntry.getDN().toString());
+        unacceptableReason.append(message);
+        return false;
+      }
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
+
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+    Class providerClass;
+    try
+    {
+      // FIXME -- Should this be done with a custom class loader?
+      providerClass = Class.forName(classNameAttr.pendingValue());
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
+
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+    try
+    {
+      TrustManagerProvider provider =
+           (TrustManagerProvider) providerClass.newInstance();
+    }
+    catch(Exception e)
+    {
+      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
+
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS;
+      String message = getMessage(msgID, providerClass.getName(),
+                                  String.valueOf(configEntry.getDN()),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+
+    // See if this trust manager provider should be enabled.
+    BooleanConfigAttribute enabledAttr;
+    try
+    {
+      BooleanConfigAttribute enabledStub =
+           new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED),
+                               false);
+      enabledAttr = (BooleanConfigAttribute)
+                    configEntry.getConfigAttribute(enabledStub);
+
       if (enabledAttr == null)
       {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
-        unacceptableReason.append(getMessage(msgID));
+        int    msgID   = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
+        String message = getMessage(msgID, configEntry.getDN().toString());
+        unacceptableReason.append(message);
         return false;
       }
     }
@@ -362,83 +335,16 @@
     {
       assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE;
-      unacceptableReason.append(getMessage(msgID,
-                                           stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_ENABLED_VALUE;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
       return false;
     }
 
 
-    // See if it specifies the class name for the trust manager provider
-    // implementation.
-    String className;
-    msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS;
-    StringConfigAttribute classStub =
-         new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS, getMessage(msgID),
-                                   true, false, false);
-    try
-    {
-      StringConfigAttribute classAttr =
-           (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-      if (classAttr == null)
-      {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_ATTR;
-        unacceptableReason.append(getMessage(msgID));
-        return false;
-      }
-      else
-      {
-        className = classAttr.activeValue();
-      }
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_DETERMINE_CLASS;
-      unacceptableReason.append(getMessage(msgID,
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-
-    // Try to load the class and instantiate it as a trust manager provider.
-    Class trustManagerProviderClass;
-    try
-    {
-      // FIXME -- Should we use a custom class loader for this?
-      trustManagerProviderClass = Class.forName(className);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_LOAD_CLASS;
-      unacceptableReason.append(getMessage(msgID, String.valueOf(className),
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-    try
-    {
-      TrustManagerProvider trustManagerProvider =
-           (TrustManagerProvider) trustManagerProviderClass.newInstance();
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configChangeIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTANTIATE_CLASS;
-      unacceptableReason.append(getMessage(msgID, String.valueOf(className),
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-
-
-    // If we've gotten to this point, then it is acceptable as far as we are
-    // concerned.  If it is unacceptable according to the configuration, then
-    // the trust manager provider itself will make that determination.
+    // If we've gotten here then the trust manager provider entry appears to be
+    // acceptable.
     return true;
   }
 
@@ -459,73 +365,78 @@
     assert debugEnter(CLASS_NAME, "applyConfigurationChange",
                       String.valueOf(configEntry));
 
+
+    DN                configEntryDN       = configEntry.getDN();
     ResultCode        resultCode          = ResultCode.SUCCESS;
     boolean           adminActionRequired = false;
     ArrayList<String> messages            = new ArrayList<String>();
 
 
-    // See if the entry indicates whether the trust manager provider should be
-    // enabled.  If not, then make sure that the trust manager is disabled and
-    // return since we don't need to do anything else.
-    boolean needsEnabled          = false;
-    String  existingProviderClass = null;
-    int msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED;
-    BooleanConfigAttribute enabledStub =
-         new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
-                                    getMessage(msgID), false);
+    // Make sure that the entry has an appropriate objectclass for a trust
+    // manager provider.
+    if (! configEntry.hasObjectClass(OC_TRUST_MANAGER_PROVIDER))
+    {
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+      resultCode = ResultCode.UNWILLING_TO_PERFORM;
+      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+    }
+
+
+    // Get the corresponding trust manager provider if it is active.
+    TrustManagerProvider provider = providers.get(configEntryDN);
+
+
+    // See if this provider should be enabled or disabled.
+    boolean needsEnabled = false;
+    BooleanConfigAttribute enabledAttr;
     try
     {
-      BooleanConfigAttribute enabledAttr =
-           (BooleanConfigAttribute)
-           configEntry.getConfigAttribute(enabledStub);
+      BooleanConfigAttribute enabledStub =
+           new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED),
+                    false);
+      enabledAttr = (BooleanConfigAttribute)
+                    configEntry.getConfigAttribute(enabledStub);
+
       if (enabledAttr == null)
       {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
-        messages.add(getMessage(msgID));
-        resultCode = ResultCode.OBJECTCLASS_VIOLATION;
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
+        messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+        resultCode = ResultCode.UNWILLING_TO_PERFORM;
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
-      else if (! enabledAttr.pendingValue())
-      {
-        DirectoryServer.getTrustManagerProvider().
-             finalizeTrustManagerProvider();
 
-        // The provider should be disabled, so install the null trust manager
-        // and return.
-        try
-        {
-          NullTrustManagerProvider nullProvider =
-               new NullTrustManagerProvider();
-          nullProvider.initializeTrustManagerProvider(null);
-          DirectoryServer.setTrustManagerProvider(nullProvider);
-          return new ConfigChangeResult(resultCode, adminActionRequired,
-                                        messages);
-        }
-        catch (Exception e)
-        {
-          assert debugException(CLASS_NAME, "applyConfigurationChange", e);
-
-          msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTALL_NULL_PROVIDER;
-          messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
-          resultCode = DirectoryServer.getServerErrorResultCode();
-          return new ConfigChangeResult(resultCode, adminActionRequired,
-                                        messages);
-        }
-      }
-      else
+      if (enabledAttr.activeValue())
       {
-        // The provider should be enabled.  If it isn't, then set a flag to
-        // indicate that we need to create it when we have more information.
-        if (DirectoryServer.getTrustManagerProvider() instanceof
-            NullTrustManagerProvider)
+        if (provider == null)
         {
           needsEnabled = true;
         }
         else
         {
-          existingProviderClass =
-               DirectoryServer.getTrustManagerProvider().getClass().getName();
+          // The provider is already active, so no action is required.
+        }
+      }
+      else
+      {
+        if (provider == null)
+        {
+          // The provider is already disabled, so no action is required and we
+          // can short-circuit out of this processing.
+          return new ConfigChangeResult(resultCode, adminActionRequired,
+                                        messages);
+        }
+        else
+        {
+          // The provider is active, so it needs to be disabled.  Do this and
+          // return that we were successful.
+          providers.remove(configEntryDN);
+          DirectoryServer.deregisterTrustManagerProvider(configEntryDN);
+          provider.finalizeTrustManagerProvider();
+          return new ConfigChangeResult(resultCode, adminActionRequired,
+                                        messages);
         }
       }
     }
@@ -533,133 +444,118 @@
     {
       assert debugException(CLASS_NAME, "applyConfigurationChange", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE;
-      messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_ENABLED_VALUE;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // Get the class name from the configuration entry.
+    // Make sure that the entry specifies the provider class name.  If it has
+    // changed, then we will not try to dynamically apply it.
     String className;
-    msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS;
-    StringConfigAttribute classStub =
-         new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS, getMessage(msgID),
-                                   true, false, false);
     try
     {
-      StringConfigAttribute classAttr =
+      StringConfigAttribute classStub =
+           new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS),
+                    true, false, true);
+      StringConfigAttribute classNameAttr =
            (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-      if (classAttr == null)
+
+      if (classNameAttr == null)
       {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_ATTR;
-        messages.add(getMessage(msgID));
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_NAME;
+        messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
         resultCode = ResultCode.OBJECTCLASS_VIOLATION;
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
-      else
-      {
-        className = classAttr.activeValue();
-      }
+
+      className = classNameAttr.pendingValue();
     }
     catch (Exception e)
     {
       assert debugException(CLASS_NAME, "applyConfigurationChange", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_DETERMINE_CLASS;
-      messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // If the trust manager provider is already enabled and the specified class
-    // is different from the class that is currently in use, then we won't try
-    // to do anything.  The trust manager provider must be disabled and
-    // re-enabled before the configuration change will be accepted.
-    if (! needsEnabled)
+    boolean classChanged = false;
+    String  oldClassName = null;
+    if (provider != null)
     {
-      if (! className.equals(existingProviderClass))
+      oldClassName = provider.getClass().getName();
+      classChanged = (! className.equals(oldClassName));
+    }
+
+
+    if (classChanged)
+    {
+      // This will not be applied dynamically.  Add a message to the response
+      // and indicate that admin action is required.
+      adminActionRequired = true;
+      messages.add(getMessage(MSGID_CONFIG_TRUSTMANAGER_CLASS_ACTION_REQUIRED,
+                              String.valueOf(oldClassName),
+                              String.valueOf(className),
+                              String.valueOf(configEntryDN)));
+      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+    }
+
+
+    if (needsEnabled)
+    {
+      try
       {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NOT_SWITCHING_CLASSES;
-        messages.add(getMessage(msgID, String.valueOf(existingProviderClass),
-                                String.valueOf(className)));
-        resultCode = ResultCode.UNWILLING_TO_PERFORM;
-        adminActionRequired = true;
+        // FIXME -- Should this be done with a dynamic class loader?
+        Class providerClass = Class.forName(className);
+        provider = (TrustManagerProvider) providerClass.newInstance();
+      }
+      catch (Exception e)
+      {
+        assert debugException(CLASS_NAME, "applyConfigurationChange", e);
+
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS;
+        messages.add(getMessage(msgID, className,
+                                String.valueOf(configEntryDN),
+                                String.valueOf(e)));
+        resultCode = DirectoryServer.getServerErrorResultCode();
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
-      else
+
+      try
       {
-        // We don't need to do anything because it's already enabled and has the
-        // right class.
+        provider.initializeTrustManagerProvider(configEntry);
+      }
+      catch (Exception e)
+      {
+        assert debugException(CLASS_NAME, "applyConfigurationChange", e);
+
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_INITIALIZATION_FAILED;
+        messages.add(getMessage(msgID, className,
+                                String.valueOf(configEntryDN),
+                                String.valueOf(e)));
+        resultCode = DirectoryServer.getServerErrorResultCode();
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
-    }
 
 
-    // Try to load the class and instantiate it as a trust manager provider.
-    Class trustManagerProviderClass;
-    try
-    {
-      // FIXME -- Should we use a custom class loader for this?
-      trustManagerProviderClass = Class.forName(className);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationChange", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_LOAD_CLASS;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
-      resultCode = DirectoryServer.getServerErrorResultCode();
-      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-    }
-
-    TrustManagerProvider trustManagerProvider;
-    try
-    {
-      trustManagerProvider =
-           (TrustManagerProvider) trustManagerProviderClass.newInstance();
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationChange", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTANTIATE_CLASS;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
-      resultCode = DirectoryServer.getServerErrorResultCode();
+      providers.put(configEntryDN, provider);
+      DirectoryServer.registerTrustManagerProvider(configEntryDN, provider);
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // Try to initialize the trust manager provider with the contents of the
-    // configuration entry.
-    try
-    {
-      trustManagerProvider.initializeTrustManagerProvider(configEntry);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationChange", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INITIALIZE;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
-      resultCode = DirectoryServer.getServerErrorResultCode();
-      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-    }
-
-
-    // Install the new trust manager provider in the server.  We don't need to
-    // do anything to get rid of the previous null provider since it doesn't
-    // consume any resources.
-    DirectoryServer.setTrustManagerProvider(trustManagerProvider);
-
-
+    // If we've gotten here, then there haven't been any changes to anything
+    // that we care about.
     return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 
@@ -685,127 +581,161 @@
                       String.valueOf(configEntry), "java.lang.StringBuilder");
 
 
-    // Get the DN of the provided entry and see if it is the DN that we expect
-    // for the trust manager configuration.  If it is not, then it's not an
-    // entry that we care about so return true.
-    DN providedEntryDN = configEntry.getDN();
-    DN expectedEntryDN;
-    try
+    // Make sure that no entry already exists with the specified DN.
+    DN configEntryDN = configEntry.getDN();
+    if (providers.containsKey(configEntryDN))
     {
-      expectedEntryDN = DN.decode(DN_TRUSTMANAGER_PROVIDER_CONFIG);
-    }
-    catch (DirectoryException de)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", de);
-
-      unacceptableReason.append(de.getErrorMessage());
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_EXISTS;
+      String message = getMessage(msgID, String.valueOf(configEntryDN));
+      unacceptableReason.append(message);
       return false;
     }
 
-    if (! providedEntryDN.equals(expectedEntryDN))
+
+    // Make sure that the entry has an appropriate objectclass for a trust
+    // manager provider.
+    if (! configEntry.hasObjectClass(OC_TRUST_MANAGER_PROVIDER))
     {
-      return true;
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_OBJECTCLASS;
+      String message = getMessage(msgID, configEntry.getDN().toString());
+      unacceptableReason.append(message);
+      return false;
     }
 
 
-    // See if the entry indicates whether the trust manager provider should be
-    // enabled.
-    int msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED;
-    BooleanConfigAttribute enabledStub =
-         new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
-                                    getMessage(msgID), false);
+    // Make sure that the entry specifies the trust manager provider class.
+    StringConfigAttribute classNameAttr;
     try
     {
-      BooleanConfigAttribute enabledAttr =
-           (BooleanConfigAttribute)
-           configEntry.getConfigAttribute(enabledStub);
+      StringConfigAttribute classStub =
+           new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS),
+                    true, false, true);
+      classNameAttr = (StringConfigAttribute)
+                      configEntry.getConfigAttribute(classStub);
+
+      if (classNameAttr == null)
+      {
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_NAME;
+        String message = getMessage(msgID, configEntry.getDN().toString());
+        unacceptableReason.append(message);
+        return false;
+      }
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
+
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+    Class providerClass;
+    try
+    {
+      // FIXME -- Should this be done with a custom class loader?
+      providerClass = Class.forName(classNameAttr.pendingValue());
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
+
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+    TrustManagerProvider provider;
+    try
+    {
+      provider = (TrustManagerProvider) providerClass.newInstance();
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
+
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS;
+      String message = getMessage(msgID, providerClass.getName(),
+                                  String.valueOf(configEntryDN),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+
+    // See if this provider should be enabled.
+    BooleanConfigAttribute enabledAttr;
+    try
+    {
+      BooleanConfigAttribute enabledStub =
+           new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED),
+                               false);
+      enabledAttr = (BooleanConfigAttribute)
+                    configEntry.getConfigAttribute(enabledStub);
+
       if (enabledAttr == null)
       {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
-        unacceptableReason.append(getMessage(msgID));
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
+        String message = getMessage(msgID, configEntry.getDN().toString());
+        unacceptableReason.append(message);
+        return false;
+      }
+      else if (! enabledAttr.pendingValue())
+      {
+        // The trust manager provider is not enabled, so we don't need to do any
+        // further validation.
+        return true;
+      }
+    }
+    catch (Exception e)
+    {
+      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
+
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_ENABLED_VALUE;
+      String message = getMessage(msgID, configEntry.getDN().toString(),
+                                  String.valueOf(e));
+      unacceptableReason.append(message);
+      return false;
+    }
+
+
+    // If the provider is a configurable component, then make sure that its
+    // configuration is valid.
+    if (provider instanceof ConfigurableComponent)
+    {
+      ConfigurableComponent cc = (ConfigurableComponent) provider;
+      LinkedList<String> errorMessages = new LinkedList<String>();
+      if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
+      {
+        if (errorMessages.isEmpty())
+        {
+          int msgID = MSGID_CONFIG_TRUSTMANAGER_UNACCEPTABLE_CONFIG;
+          unacceptableReason.append(getMessage(msgID,
+                                               String.valueOf(configEntryDN)));
+        }
+        else
+        {
+          Iterator<String> iterator = errorMessages.iterator();
+          unacceptableReason.append(iterator.next());
+          while (iterator.hasNext())
+          {
+            unacceptableReason.append("  ");
+            unacceptableReason.append(iterator.next());
+          }
+        }
+
         return false;
       }
     }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE;
-      unacceptableReason.append(getMessage(msgID,
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
 
 
-    // See if it specifies the class name for the trust manager provider
-    // implementation.
-    String className;
-    msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS;
-    StringConfigAttribute classStub =
-         new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS, getMessage(msgID),
-                                   true, false, false);
-    try
-    {
-      StringConfigAttribute classAttr =
-           (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-      if (classAttr == null)
-      {
-        msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_ATTR;
-        unacceptableReason.append(getMessage(msgID));
-        return false;
-      }
-      else
-      {
-        className = classAttr.activeValue();
-      }
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_DETERMINE_CLASS;
-      unacceptableReason.append(getMessage(msgID,
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-
-    // Try to load the class and instantiate it as a trust manager provider.
-    Class trustManagerProviderClass;
-    try
-    {
-      // FIXME -- Should we use a custom class loader for this?
-      trustManagerProviderClass = Class.forName(className);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_LOAD_CLASS;
-      unacceptableReason.append(getMessage(msgID, String.valueOf(className),
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-    try
-    {
-      TrustManagerProvider trustManagerProvider =
-           (TrustManagerProvider) trustManagerProviderClass.newInstance();
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTANTIATE_CLASS;
-      unacceptableReason.append(getMessage(msgID, String.valueOf(className),
-                                           stackTraceToSingleLineString(e)));
-      return false;
-    }
-
-
-    // If we've gotten to this point, then it is acceptable as far as we are
-    // concerned.  If it is unacceptable according to the configuration, then
-    // the trust manager provider itself will make that determination.
+    // If we've gotten here then the provider entry appears to be acceptable.
     return true;
   }
 
@@ -825,84 +755,48 @@
     assert debugEnter(CLASS_NAME, "applyConfigurationAdd",
                       String.valueOf(configEntry));
 
+
+    DN                configEntryDN       = configEntry.getDN();
     ResultCode        resultCode          = ResultCode.SUCCESS;
     boolean           adminActionRequired = false;
     ArrayList<String> messages            = new ArrayList<String>();
 
 
-    // Get the DN of the provided entry and see if it is the DN that we expect
-    // for the trust manager configuration.  If it is not, then it's not an
-    // entry that we care about so return without doing anything.
-    DN providedEntryDN = configEntry.getDN();
-    DN expectedEntryDN;
-    try
+    // Make sure that the entry has an appropriate objectclass for a trust
+    // manager provider.
+    if (! configEntry.hasObjectClass(OC_TRUST_MANAGER_PROVIDER))
     {
-      expectedEntryDN = DN.decode(DN_TRUSTMANAGER_PROVIDER_CONFIG);
-    }
-    catch (DirectoryException de)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationAdd", de);
-
-      messages.add(de.getErrorMessage());
-      resultCode = de.getResultCode();
-      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-    }
-
-    if (! providedEntryDN.equals(expectedEntryDN))
-    {
+      int    msgID   = MSGID_CONFIG_TRUSTMANAGER_INVALID_OBJECTCLASS;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+      resultCode = ResultCode.UNWILLING_TO_PERFORM;
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // Register as a change listener of the provided entry so that we will be
-    // notified of changes to it.  We will also want to register a delete
-    // listener with its parent to allow us to determine if the entry is
-    // deleted.
-    configEntry.registerChangeListener(this);
+    // See if this provider should be enabled or disabled.
+    BooleanConfigAttribute enabledAttr;
     try
     {
-      DN parentDN = configEntry.getDN().getParentDNInSuffix();
-      ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
-      if (parentEntry != null)
-      {
-        parentEntry.registerDeleteListener(this);
-      }
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
+      BooleanConfigAttribute enabledStub =
+           new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED),
+                               false);
+      enabledAttr = (BooleanConfigAttribute)
+                    configEntry.getConfigAttribute(enabledStub);
 
-      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_WARNING,
-               MSGID_CONFIG_TRUSTMANAGER_CANNOT_REGISTER_DELETE_LISTENER,
-               stackTraceToSingleLineString(e));
-    }
-
-
-    // See if the entry indicates whether the trust manager provider should be
-    // enabled.
-    int msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED;
-    BooleanConfigAttribute enabledStub =
-         new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
-                                    getMessage(msgID), false);
-    try
-    {
-      BooleanConfigAttribute enabledAttr =
-           (BooleanConfigAttribute)
-           configEntry.getConfigAttribute(enabledStub);
       if (enabledAttr == null)
       {
-        // The attribute is not present, so the trust manager provider will be
-        // disabled.  Log a warning message and return.
-        messages.add(getMessage(MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR));
-        resultCode = ResultCode.OBJECTCLASS_VIOLATION;
+        // The attribute doesn't exist, so it will be disabled by default.
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_ENABLED_ATTR;
+        messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+        resultCode = ResultCode.SUCCESS;
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
       else if (! enabledAttr.activeValue())
       {
-        // The trust manager provider is explicitly disabled.  Log a mild
-        // warning and return.
-        messages.add(getMessage(MSGID_CONFIG_TRUSTMANAGER_DISABLED));
+        // It is explicitly configured as disabled, so we don't need to do
+        // anything.
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
@@ -911,107 +805,86 @@
     {
       assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE;
-      messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_ENABLED_VALUE;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // See if it specifies the class name for the trust manager provider
-    // implementation.
+    // Make sure that the entry specifies the provider class name.
     String className;
-    msgID = MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS;
-    StringConfigAttribute classStub =
-         new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS, getMessage(msgID),
-                                   true, false, false);
     try
     {
-      StringConfigAttribute classAttr =
+      StringConfigAttribute classStub =
+           new StringConfigAttribute(ATTR_TRUSTMANAGER_CLASS,
+                    getMessage(MSGID_CONFIG_TRUSTMANAGER_DESCRIPTION_CLASS),
+                    true, false, true);
+      StringConfigAttribute classNameAttr =
            (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-      if (classAttr == null)
+
+      if (classNameAttr == null)
       {
-        messages.add(getMessage(MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_ATTR));
+        int msgID = MSGID_CONFIG_TRUSTMANAGER_NO_CLASS_NAME;
+        messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
         resultCode = ResultCode.OBJECTCLASS_VIOLATION;
         return new ConfigChangeResult(resultCode, adminActionRequired,
                                       messages);
       }
-      else
-      {
-        className = classAttr.activeValue();
-      }
+
+      className = classNameAttr.pendingValue();
     }
     catch (Exception e)
     {
       assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_DETERMINE_CLASS;
-      messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS_NAME;
+      messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // Try to load the class and instantiate it as a trust manager provider.
-    Class trustManagerProviderClass;
+    // Load and initialize the provider class, and register it with the
+    // Directory Server.
+    TrustManagerProvider provider;
     try
     {
-      // FIXME -- Should we use a custom class loader for this?
-      trustManagerProviderClass = Class.forName(className);
+      // FIXME -- Should this be done with a dynamic class loader?
+      Class providerClass = Class.forName(className);
+      provider = (TrustManagerProvider) providerClass.newInstance();
     }
     catch (Exception e)
     {
       assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_LOAD_CLASS;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INVALID_CLASS;
+      messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
-    TrustManagerProvider trustManagerProvider;
     try
     {
-      trustManagerProvider =
-           (TrustManagerProvider) trustManagerProviderClass.newInstance();
+      provider.initializeTrustManagerProvider(configEntry);
     }
     catch (Exception e)
     {
       assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
 
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INSTANTIATE_CLASS;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
+      int msgID = MSGID_CONFIG_TRUSTMANAGER_INITIALIZATION_FAILED;
+      messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
+                              String.valueOf(e)));
       resultCode = DirectoryServer.getServerErrorResultCode();
       return new ConfigChangeResult(resultCode, adminActionRequired, messages);
     }
 
 
-    // Try to initialize the trust manager provider with the contents of the
-    // configuration entry.
-    try
-    {
-      trustManagerProvider.initializeTrustManagerProvider(configEntry);
-    }
-    catch (Exception e)
-    {
-      assert debugException(CLASS_NAME, "applyConfigurationAdd", e);
-
-      msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_INITIALIZE;
-      messages.add(getMessage(msgID, String.valueOf(className),
-                              stackTraceToSingleLineString(e)));
-      resultCode = DirectoryServer.getServerErrorResultCode();
-      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-    }
-
-
-    // Install the new trust manager provider in the server.  We don't need to
-    // do anything to get rid of the previous null provider since it doesn't
-    // consume any resources.
-    DirectoryServer.setTrustManagerProvider(trustManagerProvider);
-
-
+    providers.put(configEntryDN, provider);
+    DirectoryServer.registerTrustManagerProvider(configEntryDN, provider);
     return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 
@@ -1037,46 +910,7 @@
                       String.valueOf(configEntry), "java.lang.StringBuilder");
 
 
-    // Get the DN of the provided entry and see if it is the DN that we expect
-    // for the trust manager configuration.  If it is not, then it's not an
-    // entry that we care about so return true.
-    DN providedEntryDN = configEntry.getDN();
-    DN expectedEntryDN;
-    try
-    {
-      expectedEntryDN = DN.decode(DN_TRUSTMANAGER_PROVIDER_CONFIG);
-    }
-    catch (DirectoryException de)
-    {
-      assert debugException(CLASS_NAME, "configAddIsAcceptable", de);
-
-      unacceptableReason.append(de.getErrorMessage());
-      return false;
-    }
-
-    if (! providedEntryDN.equals(expectedEntryDN))
-    {
-      return true;
-    }
-
-
-    // Determine whether there is a valid trust manager provider installed
-    // (i.e., not the null provider).  If a valid provider is installed, then we
-    // will not allow the entry to be removed.
-    TrustManagerProvider installedProvider =
-         DirectoryServer.getTrustManagerProvider();
-    if (! (installedProvider instanceof NullTrustManagerProvider))
-    {
-      int msgID = MSGID_CONFIG_TRUSTMANAGER_CANNOT_REMOVE_ACTIVE_PROVIDER;
-      unacceptableReason.append(getMessage(msgID,
-                                     installedProvider.getClass().getName()));
-      return false;
-    }
-
-
-    // If we've gotten to this point, then it is acceptable as far as we are
-    // concerned.  If it is unacceptable according to the configuration, then
-    // the trust manager provider itself will make that determination.
+    // A delete should always be acceptable, so just return true.
     return true;
   }
 
@@ -1095,14 +929,23 @@
     assert debugEnter(CLASS_NAME, "applyConfigurationDelete",
                       String.valueOf(configEntry));
 
-    ResultCode        resultCode          = ResultCode.SUCCESS;
-    boolean           adminActionRequired = false;
-    ArrayList<String> messages            = new ArrayList<String>();
+
+    DN         configEntryDN       = configEntry.getDN();
+    ResultCode resultCode          = ResultCode.SUCCESS;
+    boolean    adminActionRequired = false;
 
 
-    // Since we can never delete an active configuration, there is nothing that
-    // we need to do if a delete does go through.
-    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+    // See if the entry is registered as a trust manager provider.  If so,
+    // deregister it and stop the provider.
+    TrustManagerProvider provider = providers.remove(configEntryDN);
+    if (provider != null)
+    {
+      DirectoryServer.deregisterTrustManagerProvider(configEntryDN);
+      provider.finalizeTrustManagerProvider();
+    }
+
+
+    return new ConfigChangeResult(resultCode, adminActionRequired);
   }
 }
 

--
Gitblit v1.10.0