mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
21.44.2007 7369ecc8296a0329e424596ff71c60629add3ce2
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);
  }
}