From 04ceec5b8fcb3a41602d3a8db4521484f31338c0 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 28 Sep 2009 15:33:19 +0000
Subject: [PATCH] Fix issue 4043 - intermittent failures in ACI unit tests

---
 opendj-sdk/opends/src/server/org/opends/server/api/plugin/InternalDirectoryServerPlugin.java                         |   96 ++
 opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java                                             |   64 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java                      |  706 +++++++++++--------
 opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java                                         | 1118 +++++++++++++++++---------------
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java |    9 
 opendj-sdk/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java                                 |   23 
 6 files changed, 1,163 insertions(+), 853 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java b/opendj-sdk/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
index 7c92f13..940ff5d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
@@ -111,26 +111,29 @@
 
   /**
    * Performs any initialization that should be done for all types of
-   * plugins regardless of type.  This should only be called by the
+   * plugins regardless of type. This should only be called by the
    * core Directory Server code during the course of loading a plugin.
    *
-   * @param  configuration  The configuration for this plugin.
-   * @param  pluginTypes    The set of plugin types for which this
-   *                        plugin is registered.
+   * @param pluginDN
+   *          The configuration entry name of this plugin.
+   * @param pluginTypes
+   *          The set of plugin types for which this plugin is
+   *          registered.
+   * @param invokeForInternalOps
+   *          Indicates whether this plugin should be invoked for
+   *          internal operations.
    */
   @org.opends.server.types.PublicAPI(
        stability=org.opends.server.types.StabilityLevel.PRIVATE,
        mayInstantiate=false,
        mayExtend=false,
        mayInvoke=false)
-  public final void initializeInternal(PluginCfg configuration,
-                                       Set<PluginType> pluginTypes)
+  public final void initializeInternal(DN pluginDN,
+      Set<PluginType> pluginTypes, boolean invokeForInternalOps)
   {
+    this.pluginDN = pluginDN;
     this.pluginTypes = pluginTypes;
-
-    pluginDN = configuration.dn();
-    invokeForInternalOps =
-         configuration.isInvokeForInternalOperations();
+    this.invokeForInternalOps = invokeForInternalOps;
   }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/plugin/InternalDirectoryServerPlugin.java b/opendj-sdk/opends/src/server/org/opends/server/api/plugin/InternalDirectoryServerPlugin.java
new file mode 100644
index 0000000..233840b
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/plugin/InternalDirectoryServerPlugin.java
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.api.plugin;
+
+
+
+import java.util.List;
+import java.util.Set;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.DN;
+import org.opends.server.types.InitializationException;
+
+
+
+/**
+ * An internal directory server plugin which can be registered with
+ * the server without requiring any associated configuration.
+ */
+public abstract class InternalDirectoryServerPlugin extends
+    DirectoryServerPlugin<PluginCfg>
+{
+
+  /**
+   * Creates a new internal directory server plugin using the provided
+   * component name and plugin types.
+   *
+   * @param componentDN
+   *          The configuration entry name of the component associated
+   *          with this internal plugin.
+   * @param pluginTypes
+   *          The set of plugin types for which this internal plugin
+   *          is registered.
+   * @param invokeForInternalOps
+   *          Indicates whether this internal plugin should be invoked
+   *          for internal operations.
+   */
+  protected InternalDirectoryServerPlugin(DN componentDN,
+      Set<PluginType> pluginTypes, boolean invokeForInternalOps)
+  {
+    initializeInternal(componentDN, pluginTypes,
+        invokeForInternalOps);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void initializePlugin(Set<PluginType> pluginTypes,
+      PluginCfg configuration) throws ConfigException,
+      InitializationException
+  {
+    // Unused.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isConfigurationAcceptable(
+      PluginCfg configuration, List<Message> unacceptableReasons)
+  {
+    // Unused.
+    return true;
+  }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index 9954423..440f508 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -22,21 +22,27 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2008-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.server.authorization.dseecompat;
+
+
+
 import org.opends.messages.Message;
 
 import org.opends.server.workflowelement.localbackend.*;
-import org.opends.server.api.ChangeNotificationListener;
 import org.opends.server.api.BackendInitializationListener;
 import org.opends.server.api.Backend;
 import org.opends.server.api.AlertGenerator;
-import org.opends.server.types.operation.PostResponseAddOperation;
-import org.opends.server.types.operation.PostResponseDeleteOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
-import org.opends.server.types.operation.PostResponseModifyDNOperation;
+import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
+import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.api.plugin.PluginType;
+import org.opends.server.api.plugin.PluginResult.PostOperation;
+import org.opends.server.types.operation.PostOperationAddOperation;
+import org.opends.server.types.operation.PostOperationDeleteOperation;
+import org.opends.server.types.operation.PostOperationModifyDNOperation;
+import org.opends.server.types.operation.PostOperationModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPControl;
@@ -44,341 +50,437 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.*;
+
 import static org.opends.messages.AccessControlMessages.*;
 import org.opends.server.core.DirectoryServer;
 import static org.opends.server.util.ServerConstants.*;
 
 import java.util.*;
 
+
+
 /**
- * The AciListenerManager updates an ACI list after each
- * modification operation. Also, updates ACI list when backends are initialized
- * and finalized.
+ * The AciListenerManager updates an ACI list after each modification
+ * operation. Also, updates ACI list when backends are initialized and
+ * finalized.
  */
-public class AciListenerManager
-        implements ChangeNotificationListener, BackendInitializationListener,
-                   AlertGenerator {
+public class AciListenerManager implements
+    BackendInitializationListener, AlertGenerator
+{
   /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
 
-
-    /**
-     * The fully-qualified name of this class.
-     */
-    private static final String CLASS_NAME =
-         "org.opends.server.authorization.dseecompat.AciListenerManager";
-
-    /*
-     *  The configuration DN.
-     */
-    private DN configurationDN;
+  /**
+   * The fully-qualified name of this class.
+   */
+  private static final String CLASS_NAME =
+      "org.opends.server.authorization.dseecompat.AciListenerManager";
 
 
-    /*
-     *  True if the server is in lockdown mode.
-     */
-    private boolean inLockDownMode=false;
 
-    /*
-     * The AciList caches the ACIs.
-     */
-    private AciList aciList;
-
-    /*
-     * Search filter used in context search for "aci" attribute types.
-     */
-    private static SearchFilter aciFilter;
-
-    /*
-     * The aci attribute type is operational so we need to specify it to be
-     * returned.
-     */
-    private static LinkedHashSet<String> attrs = new LinkedHashSet<String>();
-
-    static {
-        /*
-         * Set up the filter used to search private and public contexts.
-         */
-        try {
-            aciFilter=SearchFilter.createFilterFromString("(aci=*)");
-        } catch (DirectoryException ex) {
-            //TODO should never happen, error message?
-        }
-        attrs.add("aci");
-    }
-
-    /**
-     * Save the list created by the AciHandler routine. Registers as an
-     * Alert Generator that can send alerts when the server is being put
-     * in lockdown  mode. Registers as backend initialization listener that is
-     * used to manage the ACI list cache when backends are
-     * initialized/finalized. Registers as a change notification listener that
-     * is used to manage the ACI list cache after ACI modifications have been
-     * performed.
-     *
-     * @param aciList The list object created and loaded by the handler.
-     * @param cfgDN The DN of the access control configuration entry.
-     */
-    public AciListenerManager(AciList aciList, DN cfgDN) {
-        this.aciList=aciList;
-        this.configurationDN=cfgDN;
-        DirectoryServer.registerChangeNotificationListener(this);
-        DirectoryServer.registerBackendInitializationListener(this);
-        DirectoryServer.registerAlertGenerator(this);
-    }
-
-   /**
-    * Deregister from the change notification listener, the backend
-    * initialization listener and the alert generator.
-    */
-    public void finalizeListenerManager() {
-        DirectoryServer.deregisterChangeNotificationListener(this);
-        DirectoryServer.deregisterBackendInitializationListener(this);
-        DirectoryServer.deregisterAlertGenerator(this);
-    }
-
-
-    /**
-     * A delete operation succeeded. Remove any ACIs associated with the
-     * entry deleted.
-     * @param deleteOperation The delete operation.
-     * @param entry The entry being deleted.
-     */
-    public void handleDeleteOperation(PostResponseDeleteOperation
-            deleteOperation, Entry entry) {
-        boolean hasAci,  hasGlobalAci=false;
-        //This entry might have both global and aci attribute types.
-        if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) ||
-                (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType)))
-            aciList.removeAci(entry, hasAci, hasGlobalAci);
-    }
-
-    /**
-     * An Add operation succeeded. Add any ACIs associated with the
-     * entry being added.
-     * @param addOperation  The add operation.
-     * @param entry   The entry being added.
-     */
-    public void handleAddOperation(PostResponseAddOperation addOperation,
-                                   Entry entry) {
-        boolean hasAci, hasGlobalAci=false;
-        //Ignore this list, the ACI syntax has already passed and it should be
-        //empty.
-        LinkedList<Message>failedACIMsgs=new LinkedList<Message>();
-        //This entry might have both global and aci attribute types.
-        if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) ||
-                (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType)))
-            aciList.addAci(entry, hasAci, hasGlobalAci, failedACIMsgs);
-    }
-
-    /**
-     * A modify operation succeeded. Adjust the ACIs by removing
-     * ACIs based on the oldEntry and then adding ACIs based on the new
-     * entry.
-     * @param modOperation  the modify operation.
-     * @param oldEntry The old entry to examine.
-     * @param newEntry  The new entry to examine.
-     */
-    public void handleModifyOperation(PostResponseModifyOperation modOperation,
-                                      Entry oldEntry, Entry newEntry)
+  /**
+   * Internal plugin used for updating the cache before a response is
+   * sent to the client.
+   */
+  private final class AciChangeListenerPlugin extends
+      InternalDirectoryServerPlugin
+  {
+    private AciChangeListenerPlugin()
     {
-        // A change to the ACI list is expensive so let's first make sure that
-        // the modification included changes to the ACI. We'll check for
-        //both "aci" attribute types and global "ds-cfg-global-aci" attribute
-        //types.
-        boolean hasAci = false, hasGlobalAci=false;
-        List<Modification> mods = modOperation.getModifications();
-        for (Modification mod : mods) {
-            AttributeType attributeType=mod.getAttribute().getAttributeType();
-            if (attributeType.equals(AciHandler.aciType))
-                hasAci = true;
-           else if(attributeType.equals(AciHandler.globalAciType))
-                hasGlobalAci=true;
-            if(hasAci && hasGlobalAci)
-               break;
-        }
-        if (hasAci || hasGlobalAci)
-            aciList.modAciOldNewEntry(oldEntry, newEntry, hasAci, hasGlobalAci);
+      super(configurationDN, EnumSet.of(PluginType.POST_OPERATION_ADD,
+          PluginType.POST_OPERATION_DELETE,
+          PluginType.POST_OPERATION_MODIFY,
+          PluginType.POST_OPERATION_MODIFY_DN), true);
     }
 
+
+
     /**
-     * A modify DN operation has succeeded. Adjust the ACIs by moving ACIs
-     * under the old entry DN to the new entry DN.
-     * @param modifyDNOperation  The LDAP modify DN operation.
-     * @param oldEntry  The old entry.
-     * @param newEntry The new entry.
+     * {@inheritDoc}
      */
-    public void handleModifyDNOperation(
-            PostResponseModifyDNOperation modifyDNOperation,
-            Entry oldEntry, Entry newEntry)
+    public PostOperation doPostOperation(
+        PostOperationAddOperation addOperation)
     {
-        aciList.renameAci(oldEntry.getDN(), newEntry.getDN());
-    }
-
-    /**
-     * {@inheritDoc}  In this case, the server will search the backend to find
-     * all aci attribute type values that it may contain and add them to the
-     * ACI list.
-     */
-    public void performBackendInitializationProcessing(Backend backend) {
-      // Check to make sure that the backend has a presence index defined for
-      // the ACI attribute.  If it does not, then log a warning message because
-      // this processing could be very expensive.
-      AttributeType aciType = DirectoryServer.getAttributeType("aci", true);
-      if (backend.getEntryCount() > 0 &&
-          ! backend.isIndexed(aciType, IndexType.PRESENCE))
+      // This entry might have both global and aci attribute types.
+      Entry entry = addOperation.getEntryToAdd();
+      boolean hasAci, hasGlobalAci = false;
+      if ((hasAci = entry.hasOperationalAttribute(AciHandler.aciType))
+          || (hasGlobalAci =
+              entry.hasAttribute(AciHandler.globalAciType)))
       {
-        logError(WARN_ACI_ATTRIBUTE_NOT_INDEXED.get(backend.getBackendID(),
-                                                    "aci"));
+        // Ignore this list, the ACI syntax has already passed and it
+        // should be empty.
+        LinkedList<Message> failedACIMsgs = new LinkedList<Message>();
+
+        aciList.addAci(entry, hasAci, hasGlobalAci, failedACIMsgs);
       }
 
+      // If we've gotten here, then everything is acceptable.
+      return PluginResult.PostOperation.continueOperationProcessing();
+    }
 
-      InternalClientConnection conn =
-           InternalClientConnection.getRootConnection();
-      LinkedList<Message>failedACIMsgs=new LinkedList<Message>();
-      //Add manageDsaIT control so any ACIs in referral entries will be
-      //picked up.
-      ArrayList<Control> controls = new ArrayList<Control>(1);
-      controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
-      //Add group membership control to let a backend look for it and
-      //decide if it would abort searches.
-      controls.add(new LDAPControl(
-          OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE ,false));
-      for (DN baseDN : backend.getBaseDNs()) {
-        try {
-          if (! backend.entryExists(baseDN))  {
-            continue;
-          }
-        } catch (Exception e) {
-            if (debugEnabled())
-            {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-            continue;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PostOperation doPostOperation(
+        PostOperationDeleteOperation deleteOperation)
+    {
+      // This entry might have both global and aci attribute types.
+      boolean hasAci, hasGlobalAci = false;
+      Entry entry = deleteOperation.getEntryToDelete();
+      if ((hasAci = entry.hasOperationalAttribute(AciHandler.aciType))
+          || (hasGlobalAci =
+              entry.hasAttribute(AciHandler.globalAciType)))
+      {
+        aciList.removeAci(entry, hasAci, hasGlobalAci);
+      }
+
+      // If we've gotten here, then everything is acceptable.
+      return PluginResult.PostOperation.continueOperationProcessing();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PostOperation doPostOperation(
+        PostOperationModifyDNOperation modifyDNOperation)
+    {
+      aciList.renameAci(modifyDNOperation.getOriginalEntry().getDN(),
+          modifyDNOperation.getUpdatedEntry().getDN());
+
+      // If we've gotten here, then everything is acceptable.
+      return PluginResult.PostOperation.continueOperationProcessing();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PostOperation doPostOperation(
+        PostOperationModifyOperation modifyOperation)
+    {
+      // A change to the ACI list is expensive so let's first make sure
+      // that the modification included changes to the ACI. We'll check
+      // for both "aci" attribute types and global "ds-cfg-global-aci"
+      // attribute types.
+      boolean hasAci = false, hasGlobalAci = false;
+      List<Modification> mods = modifyOperation.getModifications();
+      for (Modification mod : mods)
+      {
+        AttributeType attributeType =
+            mod.getAttribute().getAttributeType();
+        if (attributeType.equals(AciHandler.aciType))
+        {
+          hasAci = true;
         }
-        InternalSearchOperation internalSearch =
-             new InternalSearchOperation(
-                  conn,
-                  InternalClientConnection.nextOperationID(),
-                  InternalClientConnection.nextMessageID(),
-                  controls, baseDN, SearchScope.WHOLE_SUBTREE,
-                  DereferencePolicy.NEVER_DEREF_ALIASES,
-                  0, 0, false, aciFilter, attrs, null);
-        LocalBackendSearchOperation localInternalSearch =
+        else if (attributeType.equals(AciHandler.globalAciType))
+        {
+          hasGlobalAci = true;
+        }
+
+        if (hasAci && hasGlobalAci)
+        {
+          break;
+        }
+      }
+
+      if (hasAci || hasGlobalAci)
+      {
+        Entry oldEntry = modifyOperation.getCurrentEntry();
+        Entry newEntry = modifyOperation.getModifiedEntry();
+        aciList.modAciOldNewEntry(oldEntry, newEntry, hasAci,
+            hasGlobalAci);
+      }
+
+      // If we've gotten here, then everything is acceptable.
+      return PluginResult.PostOperation.continueOperationProcessing();
+    }
+
+  }
+
+  /*
+   * The configuration DN.
+   */
+  private DN configurationDN;
+
+  /*
+   * True if the server is in lockdown mode.
+   */
+  private boolean inLockDownMode = false;
+
+  /*
+   * The AciList caches the ACIs.
+   */
+  private AciList aciList;
+
+  /*
+   * Search filter used in context search for "aci" attribute types.
+   */
+  private static SearchFilter aciFilter;
+
+  /*
+   * Internal plugin used for updating the cache before a response is
+   * sent to the client.
+   */
+  private final AciChangeListenerPlugin plugin;
+
+  /*
+   * The aci attribute type is operational so we need to specify it to
+   * be returned.
+   */
+  private static LinkedHashSet<String> attrs =
+      new LinkedHashSet<String>();
+
+  static
+  {
+    /*
+     * Set up the filter used to search private and public contexts.
+     */
+    try
+    {
+      aciFilter = SearchFilter.createFilterFromString("(aci=*)");
+    }
+    catch (DirectoryException ex)
+    {
+      // TODO should never happen, error message?
+    }
+    attrs.add("aci");
+  }
+
+
+
+  /**
+   * Save the list created by the AciHandler routine. Registers as an
+   * Alert Generator that can send alerts when the server is being put
+   * in lockdown mode. Registers as backend initialization listener that
+   * is used to manage the ACI list cache when backends are
+   * initialized/finalized. Registers as a change notification listener
+   * that is used to manage the ACI list cache after ACI modifications
+   * have been performed.
+   *
+   * @param aciList
+   *          The list object created and loaded by the handler.
+   * @param cfgDN
+   *          The DN of the access control configuration entry.
+   */
+  public AciListenerManager(AciList aciList, DN cfgDN)
+  {
+    this.aciList = aciList;
+    this.configurationDN = cfgDN;
+    this.plugin = new AciChangeListenerPlugin();
+
+    DirectoryServer.registerInternalPlugin(plugin);
+    DirectoryServer.registerBackendInitializationListener(this);
+    DirectoryServer.registerAlertGenerator(this);
+  }
+
+
+
+  /**
+   * Deregister from the change notification listener, the backend
+   * initialization listener and the alert generator.
+   */
+  public void finalizeListenerManager()
+  {
+    DirectoryServer.deregisterInternalPlugin(plugin);
+    DirectoryServer.deregisterBackendInitializationListener(this);
+    DirectoryServer.deregisterAlertGenerator(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc} In this case, the server will search the backend to
+   * find all aci attribute type values that it may contain and add them
+   * to the ACI list.
+   */
+  public void performBackendInitializationProcessing(Backend backend)
+  {
+    // Check to make sure that the backend has a presence index defined
+    // for the ACI attribute. If it does not, then log a warning message
+    // because this processing could be very expensive.
+    AttributeType aciType =
+        DirectoryServer.getAttributeType("aci", true);
+    if (backend.getEntryCount() > 0
+        && !backend.isIndexed(aciType, IndexType.PRESENCE))
+    {
+      logError(WARN_ACI_ATTRIBUTE_NOT_INDEXED.get(backend
+          .getBackendID(), "aci"));
+    }
+
+    InternalClientConnection conn =
+        InternalClientConnection.getRootConnection();
+    LinkedList<Message> failedACIMsgs = new LinkedList<Message>();
+    // Add manageDsaIT control so any ACIs in referral entries will be
+    // picked up.
+    ArrayList<Control> controls = new ArrayList<Control>(1);
+    controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
+    // Add group membership control to let a backend look for it and
+    // decide if it would abort searches.
+    controls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+        false));
+    for (DN baseDN : backend.getBaseDNs())
+    {
+      try
+      {
+        if (!backend.entryExists(baseDN))
+        {
+          continue;
+        }
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+        continue;
+      }
+      InternalSearchOperation internalSearch =
+          new InternalSearchOperation(conn, InternalClientConnection
+              .nextOperationID(), InternalClientConnection
+              .nextMessageID(), controls, baseDN,
+              SearchScope.WHOLE_SUBTREE,
+              DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+              aciFilter, attrs, null);
+      LocalBackendSearchOperation localInternalSearch =
           new LocalBackendSearchOperation(internalSearch);
-        try  {
-          backend.search(localInternalSearch);
-        } catch (Exception e) {
-            if (debugEnabled())
-            {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-            continue;
+      try
+      {
+        backend.search(localInternalSearch);
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
-        if(!internalSearch.getSearchEntries().isEmpty()) {
-          int validAcis = aciList.addAci(
-               internalSearch.getSearchEntries(), failedACIMsgs);
-          if(!failedACIMsgs.isEmpty())
-                    logMsgsSetLockDownMode(failedACIMsgs);
-          Message message = INFO_ACI_ADD_LIST_ACIS.get(
-              Integer.toString(validAcis), String.valueOf(baseDN));
-          logError(message);
-        }
+        continue;
+      }
+      if (!internalSearch.getSearchEntries().isEmpty())
+      {
+        int validAcis =
+            aciList.addAci(internalSearch.getSearchEntries(),
+                failedACIMsgs);
+        if (!failedACIMsgs.isEmpty())
+          logMsgsSetLockDownMode(failedACIMsgs);
+        Message message =
+            INFO_ACI_ADD_LIST_ACIS.get(Integer.toString(validAcis),
+                String.valueOf(baseDN));
+        logError(message);
       }
     }
-
-    /**
-     * {@inheritDoc}  In this case, the server will remove all aci attribute
-     * type values associated with entries in the provided backend.
-     */
-    public void performBackendFinalizationProcessing(Backend backend) {
-        aciList.removeAci(backend);
-    }
+  }
 
 
 
-    /**
-     * Retrieves the fully-qualified name of the Java class for this alert
-     * generator implementation.
-     *
-     * @return  The fully-qualified name of the Java class for this alert
-     *          generator implementation.
-     */
-    public String getClassName()
+  /**
+   * {@inheritDoc} In this case, the server will remove all aci
+   * attribute type values associated with entries in the provided
+   * backend.
+   */
+  public void performBackendFinalizationProcessing(Backend backend)
+  {
+    aciList.removeAci(backend);
+  }
+
+
+
+  /**
+   * Retrieves the fully-qualified name of the Java class for this alert
+   * generator implementation.
+   *
+   * @return The fully-qualified name of the Java class for this alert
+   *         generator implementation.
+   */
+  public String getClassName()
+  {
+    return CLASS_NAME;
+  }
+
+
+
+  /**
+   * Retrieves the DN of the configuration entry used to configure the
+   * handler.
+   *
+   * @return The DN of the configuration entry containing the Access
+   *         Control configuration information.
+   */
+  public DN getComponentEntryDN()
+  {
+    return this.configurationDN;
+  }
+
+
+
+  /**
+   * Retrieves information about the set of alerts that this generator
+   * may produce. The map returned should be between the notification
+   * type for a particular notification and the human-readable
+   * description for that notification. This alert generator must not
+   * generate any alerts with types that are not contained in this list.
+   *
+   * @return Information about the set of alerts that this generator may
+   *         produce.
+   */
+  public LinkedHashMap<String, String> getAlerts()
+  {
+    LinkedHashMap<String, String> alerts =
+        new LinkedHashMap<String, String>();
+    alerts.put(ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED,
+        ALERT_DESCRIPTION_ACCESS_CONTROL_PARSE_FAILED);
+    return alerts;
+
+  }
+
+
+
+  /**
+   * Log the exception messages from the failed ACI decode and then put
+   * the server in lockdown mode -- if needed.
+   *
+   * @param failedACIMsgs
+   *          List of exception messages from failed ACI decodes.
+   */
+  public void logMsgsSetLockDownMode(LinkedList<Message> failedACIMsgs)
+  {
+
+    for (Message msg : failedACIMsgs)
     {
-        return CLASS_NAME;
+      Message message = WARN_ACI_SERVER_DECODE_FAILED.get(msg);
+      logError(message);
     }
+    if (!inLockDownMode)
+      setLockDownMode();
+  }
 
 
-    /**
-     * Retrieves the DN of the configuration entry used to configure the
-     * handler.
-     *
-     * @return  The DN of the configuration entry containing the Access Control
-     *          configuration information.
-     */
-    public DN getComponentEntryDN()
+
+  /**
+   * Send an WARN_ACI_ENTER_LOCKDOWN_MODE alert notification and put the
+   * server in lockdown mode.
+   */
+  private void setLockDownMode()
+  {
+    if (!inLockDownMode)
     {
-      return this.configurationDN;
-    }
-
-
-    /**
-     * Retrieves information about the set of alerts that this generator may
-     * produce.  The map returned should be between the notification type for a
-     * particular notification and the human-readable description for that
-     * notification.  This alert generator must not generate any alerts with
-     * types that are not contained in this list.
-     *
-     * @return  Information about the set of alerts that this generator may
-     *          produce.
-     */
-    public LinkedHashMap<String,String> getAlerts()
-    {
-        LinkedHashMap<String,String> alerts =
-                new LinkedHashMap<String,String>();
-        alerts.put(ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED,
-                ALERT_DESCRIPTION_ACCESS_CONTROL_PARSE_FAILED);
-        return alerts;
+      inLockDownMode = true;
+      // Send ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED alert that
+      // lockdown is about to be entered.
+      Message lockDownMsg = WARN_ACI_ENTER_LOCKDOWN_MODE.get();
+      DirectoryServer.sendAlertNotification(this,
+          ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED, lockDownMsg);
+      // Enter lockdown mode.
+      DirectoryServer.setLockdownMode(true);
 
     }
-
-    /**
-     * Log the exception messages from the failed ACI decode and then put the
-     * server in lockdown mode -- if needed.
-     *
-     * @param failedACIMsgs  List of exception messages from failed ACI decodes.
-     */
-    public  void logMsgsSetLockDownMode(LinkedList<Message> failedACIMsgs) {
-
-        for(Message msg : failedACIMsgs) {
-            Message message=WARN_ACI_SERVER_DECODE_FAILED.get(msg);
-            logError(message);
-        }
-        if(!inLockDownMode)
-            setLockDownMode();
-    }
-
-
-    /**
-     * Send an WARN_ACI_ENTER_LOCKDOWN_MODE alert notification and put the
-     * server in lockdown mode.
-     *
-     */
-    private void setLockDownMode() {
-        if(!inLockDownMode) {
-            inLockDownMode=true;
-            //Send ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED alert that
-            //lockdown is about to be entered.
-            Message lockDownMsg=WARN_ACI_ENTER_LOCKDOWN_MODE.get();
-            DirectoryServer.sendAlertNotification(this,
-                    ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED,
-                    lockDownMsg );
-            //Enter lockdown mode.
-            DirectoryServer.setLockdownMode(true);
-
-        }
-    }
+  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index 52f3984..62d23f2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -123,6 +123,7 @@
 import org.opends.server.api.SynchronizationProvider;
 import org.opends.server.api.TrustManagerProvider;
 import org.opends.server.api.WorkQueue;
+import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.api.plugin.PluginType;
 import org.opends.server.api.ExtensibleMatchingRule;
@@ -1341,6 +1342,11 @@
       initializeSchema();
 
 
+      // Initialize the plugin manager so that internal plugins can be
+      // registered.
+      pluginConfigManager.initializePluginConfigManager();
+
+
       // Initialize all the virtual attribute handlers.
       initializeVirtualAttributes();
 
@@ -1474,9 +1480,8 @@
       initializePasswordPolicyComponents();
 
 
-      // Load and initialize all the plugins, and then call the registered
-      // startup plugins.
-      initializePlugins();
+      // Load and initialize the user plugins.
+      pluginConfigManager.initializeUserPlugins(null);
 
       // Initialize any synchronization providers that may be defined.
       if (!environmentConfig.disableSynchronization())
@@ -1491,6 +1496,7 @@
       workQueue = new WorkQueueConfigManager().initializeWorkQueue();
 
 
+      // Invoke the startup plugins.
       PluginResult.Startup startupPluginResult =
            pluginConfigManager.invokeStartupPlugins();
       if (! startupPluginResult.continueProcessing())
@@ -2906,24 +2912,6 @@
 
 
   /**
-   * Initializes the set of plugins defined in the Directory Server.
-   *
-   * @throws  ConfigException  If there is a configuration problem with any of
-   *                           the Directory Server plugins.
-   *
-   * @throws  InitializationException  If a problem occurs while initializing
-   *                                   the plugins that is not related to the
-   *                                   server configuration.
-   */
-  public void initializePlugins()
-         throws ConfigException, InitializationException
-  {
-    pluginConfigManager.initializePluginConfig(null);
-  }
-
-
-
-  /**
    * Initializes the set of plugins defined in the Directory Server.  Only the
    * specified types of plugins will be initialized.
    *
@@ -2941,7 +2929,8 @@
          throws ConfigException, InitializationException
   {
     pluginConfigManager = new PluginConfigManager();
-    pluginConfigManager.initializePluginConfig(pluginTypes);
+    pluginConfigManager.initializePluginConfigManager();
+    pluginConfigManager.initializeUserPlugins(pluginTypes);
   }
 
 
@@ -3005,6 +2994,37 @@
 
 
   /**
+   * Registers the provided internal plugin with the Directory Server
+   * and ensures that it will be invoked in the specified ways.
+   *
+   * @param plugin
+   *          The internal plugin to register with the Directory Server.
+   *          The plugin must specify a configuration entry which is
+   *          guaranteed to be unique.
+   */
+  public static void registerInternalPlugin(
+      InternalDirectoryServerPlugin plugin)
+  {
+    directoryServer.pluginConfigManager.registerInternalPlugin(plugin);
+  }
+
+
+
+  /**
+   * Deregisters the provided internal plugin with the Directory Server.
+   *
+   * @param plugin
+   *          The internal plugin to deregister from the Directory Server.
+   */
+  public static void deregisterInternalPlugin(
+      InternalDirectoryServerPlugin plugin)
+  {
+    directoryServer.pluginConfigManager.deregisterInternalPlugin(plugin);
+  }
+
+
+
+  /**
    * Retrieves the requested entry from the Directory Server configuration.
    *
    * @param  entryDN  The DN of the configuration entry to retrieve.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 3213d0e..3f0bf15 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -234,46 +234,58 @@
 
 
   /**
-   * Initializes the configuration associated with the Directory Server plugins.
-   * This should only be called at Directory Server startup.
+   * Initializes this plugin configuration manager. This should only
+   * be called at Directory Server startup and before user plugins are
+   * loaded.
    *
-   * @param  pluginTypes  The set of plugin types for the plugins to initialize,
-   *                      or <CODE>null</CODE> to initialize all types of
-   *                      plugins defined in the server configuration.  In
-   *                      general, this should only be non-null for cases in
-   *                      which the server is running in a special mode that
-   *                      only uses a minimal set of plugins (e.g., LDIF import
-   *                      or export).
-   *
-   * @throws  ConfigException  If a critical configuration problem prevents the
-   *                           plugin initialization from succeeding.
-   *
-   * @throws  InitializationException  If a problem occurs while initializing
-   *                                   the plugins that is not related to the
-   *                                   server configuration.
+   * @throws ConfigException
+   *           If a critical configuration problem prevents the plugin
+   *           initialization from succeeding.
    */
-  public void initializePluginConfig(Set<PluginType> pluginTypes)
-         throws ConfigException, InitializationException
+  public void initializePluginConfigManager() throws ConfigException
   {
     registeredPlugins.clear();
 
-
     // Get the root configuration object.
     ServerManagementContext managementContext =
          ServerManagementContext.getInstance();
     RootCfg rootConfiguration =
          managementContext.getRootConfiguration();
 
-
     // Get the plugin root configuration and register with it as an add and
     // delete listener so we can be notified if any plugin entries are added or
     // removed.
     pluginRootConfig = rootConfiguration.getPluginRoot();
     pluginRootConfig.addPluginAddListener(this);
     pluginRootConfig.addPluginDeleteListener(this);
+  }
 
 
-    //Initialize the existing plugins.
+
+  /**
+   * Initializes any plugins defined in the directory server
+   * configuration. This should only be called at Directory Server
+   * startup and after this plugin configuration manager has been
+   * initialized.
+   *
+   * @param pluginTypes
+   *          The set of plugin types for the plugins to initialize, or
+   *          <CODE>null</CODE> to initialize all types of plugins
+   *          defined in the server configuration. In general, this
+   *          should only be non-null for cases in which the server is
+   *          running in a special mode that only uses a minimal set of
+   *          plugins (e.g., LDIF import or export).
+   * @throws ConfigException
+   *           If a critical configuration problem prevents the plugin
+   *           initialization from succeeding.
+   * @throws InitializationException
+   *           If a problem occurs while initializing the plugins that
+   *           is not related to the server configuration.
+   */
+  public void initializeUserPlugins(Set<PluginType> pluginTypes)
+         throws ConfigException, InitializationException
+  {
+    //Initialize the user plugins.
     for (String pluginName : pluginRootConfig.listPlugins())
     {
       PluginCfg pluginConfiguration = pluginRootConfig.getPlugin(pluginName);
@@ -360,12 +372,12 @@
 
       if (initialize)
       {
-        Method method = plugin.getClass().getMethod("initializeInternal",
-                                                    PluginCfg.class, Set.class);
-        method.invoke(plugin, configuration, pluginTypes);
+        plugin.initializeInternal(configuration.dn(), pluginTypes,
+            configuration.isInvokeForInternalOperations());
 
-        method = plugin.getClass().getMethod("initializePlugin", Set.class,
-            configuration.configurationClass());
+        Method method =
+            plugin.getClass().getMethod("initializePlugin", Set.class,
+                configuration.configurationClass());
         method.invoke(plugin, pluginTypes, configuration);
       }
       else
@@ -553,297 +565,338 @@
 
 
   /**
-   * Registers the provided plugin with this plugin config manager and ensures
-   * that it will be invoked in the specified ways.
+   * Registers the provided internal plugin with this plugin config
+   * manager and ensures that it will be invoked in the specified ways.
    *
-   * @param  plugin         The plugin to register with the server.
-   * @param  pluginEntryDN  The DN of the configuration entry for the provided
-   *                        plugin.
-   * @param  pluginTypes    The plugin types that will be used to control the
-   *                        points at which the provided plugin is invoked.
+   * @param plugin
+   *          The internal plugin to register with the server. The
+   *          plugin must specify a configuration entry which is
+   *          guaranteed to be unique.
    */
-  private void registerPlugin(
-                    DirectoryServerPlugin<? extends PluginCfg> plugin,
-                    DN pluginEntryDN, Set<PluginType> pluginTypes)
+  void registerInternalPlugin(InternalDirectoryServerPlugin plugin)
   {
     pluginLock.lock();
-
     try
     {
-      registeredPlugins.put(pluginEntryDN, plugin);
+      registerPlugin0(plugin, plugin.getPluginTypes());
+    }
+    finally
+    {
+      pluginLock.unlock();
+    }
+  }
 
-      for (PluginType t : pluginTypes)
+
+
+  /**
+   * Register a plugin in the appropriate tables.
+   *
+   * @param plugin
+   *          The plugin to register with the server.
+   * @param pluginTypes
+   *          The plugin types that will be used to control the points
+   *          at which the provided plugin is invoked.
+   */
+  private void registerPlugin0(
+      DirectoryServerPlugin<? extends PluginCfg> plugin,
+      Set<PluginType> pluginTypes)
+  {
+    for (PluginType t : pluginTypes)
+    {
+      switch (t)
       {
-        switch (t)
-        {
-          case STARTUP:
-            startupPlugins =
-                 addPlugin(startupPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderStartup());
-            break;
-          case SHUTDOWN:
-            shutdownPlugins =
-                 addPlugin(shutdownPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderShutdown());
-            break;
-          case POST_CONNECT:
-            postConnectPlugins =
-                 addPlugin(postConnectPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostConnect());
-            break;
-          case POST_DISCONNECT:
-            postDisconnectPlugins =
-                 addPlugin(postDisconnectPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostDisconnect());
-            break;
-          case LDIF_IMPORT:
-            ldifImportPlugins =
-                 addPlugin(ldifImportPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderLDIFImport());
-            break;
-          case LDIF_IMPORT_END:
-            ldifImportEndPlugins =
-                 addPlugin(ldifImportEndPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderLDIFImportEnd());
-            break;
-          case LDIF_IMPORT_BEGIN:
-            ldifImportBeginPlugins =
-                 addPlugin(ldifImportBeginPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderLDIFImportBegin());
-            break;
-          case LDIF_EXPORT:
-            ldifExportPlugins =
-                 addPlugin(ldifExportPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderLDIFExport());
-            break;
-          case PRE_PARSE_ABANDON:
-            preParseAbandonPlugins =
-                 addPlugin(preParseAbandonPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseAbandon());
-            break;
-          case PRE_PARSE_ADD:
-            preParseAddPlugins =
-                 addPlugin(preParseAddPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseAdd());
-            break;
-          case PRE_PARSE_BIND:
-            preParseBindPlugins =
-                 addPlugin(preParseBindPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseBind());
-            break;
-          case PRE_PARSE_COMPARE:
-            preParseComparePlugins =
-                 addPlugin(preParseComparePlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseCompare());
-            break;
-          case PRE_PARSE_DELETE:
-            preParseDeletePlugins =
-                 addPlugin(preParseDeletePlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseDelete());
-            break;
-          case PRE_PARSE_EXTENDED:
-            preParseExtendedPlugins =
-                 addPlugin(preParseExtendedPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseExtended());
-            break;
-          case PRE_PARSE_MODIFY:
-            preParseModifyPlugins =
-                 addPlugin(preParseModifyPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseModify());
-            break;
-          case PRE_PARSE_MODIFY_DN:
-            preParseModifyDNPlugins =
-                 addPlugin(preParseModifyDNPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseModifyDN());
-            break;
-          case PRE_PARSE_SEARCH:
-            preParseSearchPlugins =
-                 addPlugin(preParseSearchPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseSearch());
-            break;
-          case PRE_PARSE_UNBIND:
-            preParseUnbindPlugins =
-                 addPlugin(preParseUnbindPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreParseUnbind());
-            break;
-          case PRE_OPERATION_ADD:
-            preOperationAddPlugins =
-                 addPlugin(preOperationAddPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreOperationAdd());
-            break;
-          case PRE_OPERATION_BIND:
-            preOperationBindPlugins =
-                 addPlugin(preOperationBindPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreOperationBind());
-            break;
-          case PRE_OPERATION_COMPARE:
-            preOperationComparePlugins =
-                 addPlugin(preOperationComparePlugins,plugin, t,
-                      pluginRootConfig.getPluginOrderPreOperationCompare());
-            break;
-          case PRE_OPERATION_DELETE:
-            preOperationDeletePlugins =
-                 addPlugin(preOperationDeletePlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreOperationDelete());
-            break;
-          case PRE_OPERATION_EXTENDED:
-            preOperationExtendedPlugins =
-                 addPlugin(preOperationExtendedPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPreOperationExtended());
-            break;
-          case PRE_OPERATION_MODIFY:
-            preOperationModifyPlugins =
-                 addPlugin(preOperationModifyPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreOperationModify());
-            break;
-          case PRE_OPERATION_MODIFY_DN:
-            preOperationModifyDNPlugins =
-                 addPlugin(preOperationModifyDNPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPreOperationModifyDN());
-            break;
-          case PRE_OPERATION_SEARCH:
-            preOperationSearchPlugins =
-                 addPlugin(preOperationSearchPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPreOperationSearch());
-            break;
-          case POST_OPERATION_ABANDON:
-            postOperationAbandonPlugins =
-                 addPlugin(postOperationAbandonPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationAbandon());
-            break;
-          case POST_OPERATION_ADD:
-            postOperationAddPlugins =
-                 addPlugin(postOperationAddPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostOperationAdd());
-            break;
-          case POST_OPERATION_BIND:
-            postOperationBindPlugins =
-                 addPlugin(postOperationBindPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostOperationBind());
-            break;
-          case POST_OPERATION_COMPARE:
-            postOperationComparePlugins =
-                 addPlugin(postOperationComparePlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationCompare());
-            break;
-          case POST_OPERATION_DELETE:
-            postOperationDeletePlugins =
-                 addPlugin(postOperationDeletePlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationDelete());
-            break;
-          case POST_OPERATION_EXTENDED:
-            postOperationExtendedPlugins =
-                 addPlugin(postOperationExtendedPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationExtended());
-            break;
-          case POST_OPERATION_MODIFY:
-            postOperationModifyPlugins =
-                 addPlugin(postOperationModifyPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationModify());
-            break;
-          case POST_OPERATION_MODIFY_DN:
-            postOperationModifyDNPlugins =
-                 addPlugin(postOperationModifyDNPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationModifyDN());
-            break;
-          case POST_OPERATION_SEARCH:
-            postOperationSearchPlugins =
-                 addPlugin(postOperationSearchPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationSearch());
-            break;
-          case POST_OPERATION_UNBIND:
-            postOperationUnbindPlugins =
-                 addPlugin(postOperationUnbindPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostOperationUnbind());
-            break;
-          case POST_RESPONSE_ADD:
-            postResponseAddPlugins =
-                 addPlugin(postResponseAddPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostResponseAdd());
-            break;
-          case POST_RESPONSE_BIND:
-            postResponseBindPlugins =
-                 addPlugin(postResponseBindPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostResponseBind());
-            break;
-          case POST_RESPONSE_COMPARE:
-            postResponseComparePlugins =
-                 addPlugin(postResponseComparePlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostResponseCompare());
-            break;
-          case POST_RESPONSE_DELETE:
-            postResponseDeletePlugins =
-                 addPlugin(postResponseDeletePlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostResponseDelete());
-            break;
-          case POST_RESPONSE_EXTENDED:
-            postResponseExtendedPlugins =
-                 addPlugin(postResponseExtendedPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostResponseExtended());
-            break;
-          case POST_RESPONSE_MODIFY:
-            postResponseModifyPlugins =
-                 addPlugin(postResponseModifyPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostResponseModify());
-            break;
-          case POST_RESPONSE_MODIFY_DN:
-            postResponseModifyDNPlugins =
-                 addPlugin(postResponseModifyDNPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderPostResponseModifyDN());
-            break;
-          case POST_RESPONSE_SEARCH:
-            postResponseSearchPlugins =
-                 addPlugin(postResponseSearchPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderPostResponseSearch());
-            break;
-          case POST_SYNCHRONIZATION_ADD:
-            postSynchronizationAddPlugins =
-                 addPlugin(postSynchronizationAddPlugins, plugin, t,
-                           pluginRootConfig.
-                                getPluginOrderPostSynchronizationAdd());
-            break;
-          case POST_SYNCHRONIZATION_DELETE:
-            postSynchronizationDeletePlugins =
-                 addPlugin(postSynchronizationDeletePlugins, plugin, t,
-                           pluginRootConfig.
-                                getPluginOrderPostSynchronizationDelete());
-            break;
-          case POST_SYNCHRONIZATION_MODIFY:
-            postSynchronizationModifyPlugins =
-                 addPlugin(postSynchronizationModifyPlugins, plugin, t,
-                           pluginRootConfig.
-                                getPluginOrderPostSynchronizationModify());
-            break;
-          case POST_SYNCHRONIZATION_MODIFY_DN:
-            postSynchronizationModifyDNPlugins =
-                 addPlugin(postSynchronizationModifyDNPlugins, plugin, t,
-                           pluginRootConfig.
-                                getPluginOrderPostSynchronizationModifyDN());
-            break;
-          case SEARCH_RESULT_ENTRY:
-            searchResultEntryPlugins =
-                 addPlugin(searchResultEntryPlugins, plugin, t,
-                           pluginRootConfig.getPluginOrderSearchResultEntry());
-            break;
-          case SEARCH_RESULT_REFERENCE:
-            searchResultReferencePlugins =
-                 addPlugin(searchResultReferencePlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderSearchResultReference());
-            break;
-          case SUBORDINATE_MODIFY_DN:
-            subordinateModifyDNPlugins =
-                 addPlugin(subordinateModifyDNPlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderSubordinateModifyDN());
-            break;
-          case INTERMEDIATE_RESPONSE:
-            intermediateResponsePlugins =
-                 addPlugin(intermediateResponsePlugins, plugin, t,
-                      pluginRootConfig.getPluginOrderIntermediateResponse());
-            break;
-          default:
-        }
+      case STARTUP:
+        startupPlugins =
+            addPlugin(startupPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderStartup());
+        break;
+      case SHUTDOWN:
+        shutdownPlugins =
+            addPlugin(shutdownPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderShutdown());
+        break;
+      case POST_CONNECT:
+        postConnectPlugins =
+            addPlugin(postConnectPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderPostConnect());
+        break;
+      case POST_DISCONNECT:
+        postDisconnectPlugins =
+            addPlugin(postDisconnectPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostDisconnect());
+        break;
+      case LDIF_IMPORT:
+        ldifImportPlugins =
+            addPlugin(ldifImportPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderLDIFImport());
+        break;
+      case LDIF_IMPORT_END:
+        ldifImportEndPlugins =
+            addPlugin(ldifImportEndPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderLDIFImportEnd());
+        break;
+      case LDIF_IMPORT_BEGIN:
+        ldifImportBeginPlugins =
+            addPlugin(ldifImportBeginPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderLDIFImportBegin());
+        break;
+      case LDIF_EXPORT:
+        ldifExportPlugins =
+            addPlugin(ldifExportPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderLDIFExport());
+        break;
+      case PRE_PARSE_ABANDON:
+        preParseAbandonPlugins =
+            addPlugin(preParseAbandonPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseAbandon());
+        break;
+      case PRE_PARSE_ADD:
+        preParseAddPlugins =
+            addPlugin(preParseAddPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderPreParseAdd());
+        break;
+      case PRE_PARSE_BIND:
+        preParseBindPlugins =
+            addPlugin(preParseBindPlugins, plugin, t, pluginRootConfig
+                .getPluginOrderPreParseBind());
+        break;
+      case PRE_PARSE_COMPARE:
+        preParseComparePlugins =
+            addPlugin(preParseComparePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseCompare());
+        break;
+      case PRE_PARSE_DELETE:
+        preParseDeletePlugins =
+            addPlugin(preParseDeletePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseDelete());
+        break;
+      case PRE_PARSE_EXTENDED:
+        preParseExtendedPlugins =
+            addPlugin(preParseExtendedPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseExtended());
+        break;
+      case PRE_PARSE_MODIFY:
+        preParseModifyPlugins =
+            addPlugin(preParseModifyPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseModify());
+        break;
+      case PRE_PARSE_MODIFY_DN:
+        preParseModifyDNPlugins =
+            addPlugin(preParseModifyDNPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseModifyDN());
+        break;
+      case PRE_PARSE_SEARCH:
+        preParseSearchPlugins =
+            addPlugin(preParseSearchPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseSearch());
+        break;
+      case PRE_PARSE_UNBIND:
+        preParseUnbindPlugins =
+            addPlugin(preParseUnbindPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreParseUnbind());
+        break;
+      case PRE_OPERATION_ADD:
+        preOperationAddPlugins =
+            addPlugin(preOperationAddPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationAdd());
+        break;
+      case PRE_OPERATION_BIND:
+        preOperationBindPlugins =
+            addPlugin(preOperationBindPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationBind());
+        break;
+      case PRE_OPERATION_COMPARE:
+        preOperationComparePlugins =
+            addPlugin(preOperationComparePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationCompare());
+        break;
+      case PRE_OPERATION_DELETE:
+        preOperationDeletePlugins =
+            addPlugin(preOperationDeletePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationDelete());
+        break;
+      case PRE_OPERATION_EXTENDED:
+        preOperationExtendedPlugins =
+            addPlugin(preOperationExtendedPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationExtended());
+        break;
+      case PRE_OPERATION_MODIFY:
+        preOperationModifyPlugins =
+            addPlugin(preOperationModifyPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationModify());
+        break;
+      case PRE_OPERATION_MODIFY_DN:
+        preOperationModifyDNPlugins =
+            addPlugin(preOperationModifyDNPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationModifyDN());
+        break;
+      case PRE_OPERATION_SEARCH:
+        preOperationSearchPlugins =
+            addPlugin(preOperationSearchPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPreOperationSearch());
+        break;
+      case POST_OPERATION_ABANDON:
+        postOperationAbandonPlugins =
+            addPlugin(postOperationAbandonPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationAbandon());
+        break;
+      case POST_OPERATION_ADD:
+        postOperationAddPlugins =
+            addPlugin(postOperationAddPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationAdd());
+        break;
+      case POST_OPERATION_BIND:
+        postOperationBindPlugins =
+            addPlugin(postOperationBindPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationBind());
+        break;
+      case POST_OPERATION_COMPARE:
+        postOperationComparePlugins =
+            addPlugin(postOperationComparePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationCompare());
+        break;
+      case POST_OPERATION_DELETE:
+        postOperationDeletePlugins =
+            addPlugin(postOperationDeletePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationDelete());
+        break;
+      case POST_OPERATION_EXTENDED:
+        postOperationExtendedPlugins =
+            addPlugin(postOperationExtendedPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationExtended());
+        break;
+      case POST_OPERATION_MODIFY:
+        postOperationModifyPlugins =
+            addPlugin(postOperationModifyPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationModify());
+        break;
+      case POST_OPERATION_MODIFY_DN:
+        postOperationModifyDNPlugins =
+            addPlugin(postOperationModifyDNPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationModifyDN());
+        break;
+      case POST_OPERATION_SEARCH:
+        postOperationSearchPlugins =
+            addPlugin(postOperationSearchPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationSearch());
+        break;
+      case POST_OPERATION_UNBIND:
+        postOperationUnbindPlugins =
+            addPlugin(postOperationUnbindPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostOperationUnbind());
+        break;
+      case POST_RESPONSE_ADD:
+        postResponseAddPlugins =
+            addPlugin(postResponseAddPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseAdd());
+        break;
+      case POST_RESPONSE_BIND:
+        postResponseBindPlugins =
+            addPlugin(postResponseBindPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseBind());
+        break;
+      case POST_RESPONSE_COMPARE:
+        postResponseComparePlugins =
+            addPlugin(postResponseComparePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseCompare());
+        break;
+      case POST_RESPONSE_DELETE:
+        postResponseDeletePlugins =
+            addPlugin(postResponseDeletePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseDelete());
+        break;
+      case POST_RESPONSE_EXTENDED:
+        postResponseExtendedPlugins =
+            addPlugin(postResponseExtendedPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseExtended());
+        break;
+      case POST_RESPONSE_MODIFY:
+        postResponseModifyPlugins =
+            addPlugin(postResponseModifyPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseModify());
+        break;
+      case POST_RESPONSE_MODIFY_DN:
+        postResponseModifyDNPlugins =
+            addPlugin(postResponseModifyDNPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseModifyDN());
+        break;
+      case POST_RESPONSE_SEARCH:
+        postResponseSearchPlugins =
+            addPlugin(postResponseSearchPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostResponseSearch());
+        break;
+      case POST_SYNCHRONIZATION_ADD:
+        postSynchronizationAddPlugins =
+            addPlugin(postSynchronizationAddPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderPostSynchronizationAdd());
+        break;
+      case POST_SYNCHRONIZATION_DELETE:
+        postSynchronizationDeletePlugins =
+            addPlugin(postSynchronizationDeletePlugins, plugin, t,
+                pluginRootConfig
+                    .getPluginOrderPostSynchronizationDelete());
+        break;
+      case POST_SYNCHRONIZATION_MODIFY:
+        postSynchronizationModifyPlugins =
+            addPlugin(postSynchronizationModifyPlugins, plugin, t,
+                pluginRootConfig
+                    .getPluginOrderPostSynchronizationModify());
+        break;
+      case POST_SYNCHRONIZATION_MODIFY_DN:
+        postSynchronizationModifyDNPlugins =
+            addPlugin(postSynchronizationModifyDNPlugins, plugin, t,
+                pluginRootConfig
+                    .getPluginOrderPostSynchronizationModifyDN());
+        break;
+      case SEARCH_RESULT_ENTRY:
+        searchResultEntryPlugins =
+            addPlugin(searchResultEntryPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderSearchResultEntry());
+        break;
+      case SEARCH_RESULT_REFERENCE:
+        searchResultReferencePlugins =
+            addPlugin(searchResultReferencePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderSearchResultReference());
+        break;
+      case SUBORDINATE_MODIFY_DN:
+        subordinateModifyDNPlugins =
+            addPlugin(subordinateModifyDNPlugins, plugin, t,
+                pluginRootConfig.getPluginOrderSubordinateModifyDN());
+        break;
+      case INTERMEDIATE_RESPONSE:
+        intermediateResponsePlugins =
+            addPlugin(intermediateResponsePlugins, plugin, t,
+                pluginRootConfig.getPluginOrderIntermediateResponse());
+        break;
+      default:
       }
     }
+  }
+
+
+
+  /**
+   * Registers the provided plugin with this plugin config manager and
+   * ensures that it will be invoked in the specified ways.
+   *
+   * @param plugin
+   *          The plugin to register with the server.
+   * @param pluginEntryDN
+   *          The DN of the configuration entry for the provided plugin.
+   * @param pluginTypes
+   *          The plugin types that will be used to control the points
+   *          at which the provided plugin is invoked.
+   */
+  private void registerPlugin(
+      DirectoryServerPlugin<? extends PluginCfg> plugin,
+      DN pluginEntryDN, Set<PluginType> pluginTypes)
+  {
+    pluginLock.lock();
+    registeredPlugins.put(pluginEntryDN, plugin);
+    try
+    {
+      registerPlugin0(plugin, pluginTypes);
+    }
     finally
     {
       pluginLock.unlock();
@@ -1067,233 +1120,266 @@
 
 
   /**
+   * Deregisters the provided internal plugin.
+   *
+   * @param plugin
+   *          The internal plugin to deregister from the server.
+   */
+  void deregisterInternalPlugin(InternalDirectoryServerPlugin plugin)
+  {
+    pluginLock.lock();
+    try
+    {
+      deregisterPlugin0(plugin);
+      plugin.finalizePlugin();
+    }
+    finally
+    {
+      pluginLock.unlock();
+    }
+  }
+
+
+
+  /**
    * Deregisters the plugin with the provided configuration entry DN.
    *
-   * @param  configEntryDN  The DN of the configuration entry for the plugin to
-   *                        deregister.
+   * @param configEntryDN
+   *          The DN of the configuration entry for the plugin to
+   *          deregister.
    */
   private void deregisterPlugin(DN configEntryDN)
   {
     pluginLock.lock();
-
     DirectoryServerPlugin<? extends PluginCfg> plugin;
     try
     {
       plugin = registeredPlugins.remove(configEntryDN);
-      if (plugin == null)
+      if (plugin != null)
       {
-        return;
-      }
-
-      for (PluginType t : plugin.getPluginTypes())
-      {
-        switch (t)
-        {
-          case STARTUP:
-            startupPlugins = removePlugin(startupPlugins, plugin);
-            break;
-          case SHUTDOWN:
-            shutdownPlugins = removePlugin(shutdownPlugins, plugin);
-            break;
-          case POST_CONNECT:
-            postConnectPlugins = removePlugin(postConnectPlugins, plugin);
-            break;
-          case POST_DISCONNECT:
-            postDisconnectPlugins = removePlugin(postDisconnectPlugins, plugin);
-            break;
-          case LDIF_IMPORT:
-            ldifImportPlugins = removePlugin(ldifImportPlugins, plugin);
-            break;
-          case LDIF_IMPORT_END:
-            ldifImportEndPlugins = removePlugin(ldifImportEndPlugins, plugin);
-            break;
-          case LDIF_IMPORT_BEGIN:
-            ldifImportBeginPlugins =
-              removePlugin(ldifImportBeginPlugins, plugin);
-            break;
-          case LDIF_EXPORT:
-            ldifExportPlugins = removePlugin(ldifExportPlugins, plugin);
-            break;
-          case PRE_PARSE_ABANDON:
-            preParseAbandonPlugins = removePlugin(preParseAbandonPlugins,
-                                                  plugin);
-            break;
-          case PRE_PARSE_ADD:
-            preParseAddPlugins = removePlugin(preParseAddPlugins, plugin);
-            break;
-          case PRE_PARSE_BIND:
-            preParseBindPlugins = removePlugin(preParseBindPlugins, plugin);
-            break;
-          case PRE_PARSE_COMPARE:
-            preParseComparePlugins = removePlugin(preParseComparePlugins,
-                                                  plugin);
-            break;
-          case PRE_PARSE_DELETE:
-            preParseDeletePlugins = removePlugin(preParseDeletePlugins, plugin);
-            break;
-          case PRE_PARSE_EXTENDED:
-            preParseExtendedPlugins = removePlugin(preParseExtendedPlugins,
-                                                   plugin);
-            break;
-          case PRE_PARSE_MODIFY:
-            preParseModifyPlugins = removePlugin(preParseModifyPlugins, plugin);
-            break;
-          case PRE_PARSE_MODIFY_DN:
-            preParseModifyDNPlugins = removePlugin(preParseModifyDNPlugins,
-                                                   plugin);
-            break;
-          case PRE_PARSE_SEARCH:
-            preParseSearchPlugins = removePlugin(preParseSearchPlugins, plugin);
-            break;
-          case PRE_PARSE_UNBIND:
-            preParseUnbindPlugins = removePlugin(preParseUnbindPlugins, plugin);
-            break;
-          case PRE_OPERATION_ADD:
-            preOperationAddPlugins = removePlugin(preOperationAddPlugins,
-                                                  plugin);
-            break;
-          case PRE_OPERATION_BIND:
-            preOperationBindPlugins = removePlugin(preOperationBindPlugins,
-                                                   plugin);
-            break;
-          case PRE_OPERATION_COMPARE:
-            preOperationComparePlugins =
-                 removePlugin(preOperationComparePlugins, plugin);
-            break;
-          case PRE_OPERATION_DELETE:
-            preOperationDeletePlugins = removePlugin(preOperationDeletePlugins,
-                                                     plugin);
-            break;
-          case PRE_OPERATION_EXTENDED:
-            preOperationExtendedPlugins =
-                 removePlugin(preOperationExtendedPlugins, plugin);
-            break;
-          case PRE_OPERATION_MODIFY:
-            preOperationModifyPlugins = removePlugin(preOperationModifyPlugins,
-                                                     plugin);
-            break;
-          case PRE_OPERATION_MODIFY_DN:
-            preOperationModifyDNPlugins =
-                 removePlugin(preOperationModifyDNPlugins, plugin);
-            break;
-          case PRE_OPERATION_SEARCH:
-            preOperationSearchPlugins = removePlugin(preOperationSearchPlugins,
-                                                     plugin);
-            break;
-          case POST_OPERATION_ABANDON:
-            postOperationAbandonPlugins =
-                 removePlugin(postOperationAbandonPlugins, plugin);
-            break;
-          case POST_OPERATION_ADD:
-            postOperationAddPlugins = removePlugin(postOperationAddPlugins,
-                                                   plugin);
-            break;
-          case POST_OPERATION_BIND:
-            postOperationBindPlugins = removePlugin(postOperationBindPlugins,
-                                                    plugin);
-            break;
-          case POST_OPERATION_COMPARE:
-            postOperationComparePlugins =
-                 removePlugin(postOperationComparePlugins, plugin);
-            break;
-          case POST_OPERATION_DELETE:
-            postOperationDeletePlugins =
-                 removePlugin(postOperationDeletePlugins, plugin);
-            break;
-          case POST_OPERATION_EXTENDED:
-            postOperationExtendedPlugins =
-                 removePlugin(postOperationExtendedPlugins, plugin);
-            break;
-          case POST_OPERATION_MODIFY:
-            postOperationModifyPlugins =
-                 removePlugin(postOperationModifyPlugins, plugin);
-            break;
-          case POST_OPERATION_MODIFY_DN:
-            postOperationModifyDNPlugins =
-                 removePlugin(postOperationModifyDNPlugins, plugin);
-            break;
-          case POST_OPERATION_SEARCH:
-            postOperationSearchPlugins =
-                 removePlugin(postOperationSearchPlugins, plugin);
-            break;
-          case POST_OPERATION_UNBIND:
-            postOperationUnbindPlugins =
-                 removePlugin(postOperationUnbindPlugins, plugin);
-            break;
-          case POST_RESPONSE_ADD:
-            postResponseAddPlugins = removePlugin(postResponseAddPlugins,
-                                                  plugin);
-            break;
-          case POST_RESPONSE_BIND:
-            postResponseBindPlugins = removePlugin(postResponseBindPlugins,
-                                                   plugin);
-            break;
-          case POST_RESPONSE_COMPARE:
-            postResponseComparePlugins =
-                 removePlugin(postResponseComparePlugins, plugin);
-            break;
-          case POST_RESPONSE_DELETE:
-            postResponseDeletePlugins = removePlugin(postResponseDeletePlugins,
-                                                     plugin);
-            break;
-          case POST_RESPONSE_EXTENDED:
-            postResponseExtendedPlugins =
-                 removePlugin(postResponseExtendedPlugins, plugin);
-            break;
-          case POST_RESPONSE_MODIFY:
-            postResponseModifyPlugins = removePlugin(postResponseModifyPlugins,
-                                                     plugin);
-            break;
-          case POST_RESPONSE_MODIFY_DN:
-            postResponseModifyDNPlugins =
-                 removePlugin(postResponseModifyDNPlugins, plugin);
-            break;
-          case POST_RESPONSE_SEARCH:
-            postResponseSearchPlugins = removePlugin(postResponseSearchPlugins,
-                                                     plugin);
-            break;
-          case POST_SYNCHRONIZATION_ADD:
-            postSynchronizationAddPlugins =
-                 removePlugin(postSynchronizationAddPlugins, plugin);
-            break;
-          case POST_SYNCHRONIZATION_DELETE:
-            postSynchronizationDeletePlugins =
-                 removePlugin(postSynchronizationDeletePlugins, plugin);
-            break;
-          case POST_SYNCHRONIZATION_MODIFY:
-            postSynchronizationModifyPlugins =
-                 removePlugin(postSynchronizationModifyPlugins, plugin);
-            break;
-          case POST_SYNCHRONIZATION_MODIFY_DN:
-            postSynchronizationModifyDNPlugins =
-                 removePlugin(postSynchronizationModifyDNPlugins, plugin);
-            break;
-          case SEARCH_RESULT_ENTRY:
-            searchResultEntryPlugins = removePlugin(searchResultEntryPlugins,
-                                                    plugin);
-            break;
-          case SEARCH_RESULT_REFERENCE:
-            searchResultReferencePlugins =
-                 removePlugin(searchResultReferencePlugins, plugin);
-            break;
-          case SUBORDINATE_MODIFY_DN:
-            subordinateModifyDNPlugins =
-                 removePlugin(subordinateModifyDNPlugins, plugin);
-            break;
-          case INTERMEDIATE_RESPONSE:
-            intermediateResponsePlugins =
-                 removePlugin(intermediateResponsePlugins, plugin);
-            break;
-          default:
-        }
+        deregisterPlugin0(plugin);
+        plugin.finalizePlugin();
       }
     }
     finally
     {
       pluginLock.unlock();
     }
+  }
 
-    plugin.finalizePlugin();
+
+
+  /**
+   * Deregisters the provided plugin.
+   *
+   * @param plugin
+   *          The plugin to deregister from the server.
+   */
+  private void deregisterPlugin0(
+      DirectoryServerPlugin<? extends PluginCfg> plugin)
+  {
+    for (PluginType t : plugin.getPluginTypes())
+    {
+      switch (t)
+      {
+        case STARTUP:
+          startupPlugins = removePlugin(startupPlugins, plugin);
+          break;
+        case SHUTDOWN:
+          shutdownPlugins = removePlugin(shutdownPlugins, plugin);
+          break;
+        case POST_CONNECT:
+          postConnectPlugins = removePlugin(postConnectPlugins, plugin);
+          break;
+        case POST_DISCONNECT:
+          postDisconnectPlugins = removePlugin(postDisconnectPlugins, plugin);
+          break;
+        case LDIF_IMPORT:
+          ldifImportPlugins = removePlugin(ldifImportPlugins, plugin);
+          break;
+        case LDIF_IMPORT_END:
+          ldifImportEndPlugins = removePlugin(ldifImportEndPlugins, plugin);
+          break;
+        case LDIF_IMPORT_BEGIN:
+          ldifImportBeginPlugins =
+            removePlugin(ldifImportBeginPlugins, plugin);
+          break;
+        case LDIF_EXPORT:
+          ldifExportPlugins = removePlugin(ldifExportPlugins, plugin);
+          break;
+        case PRE_PARSE_ABANDON:
+          preParseAbandonPlugins = removePlugin(preParseAbandonPlugins,
+                                                plugin);
+          break;
+        case PRE_PARSE_ADD:
+          preParseAddPlugins = removePlugin(preParseAddPlugins, plugin);
+          break;
+        case PRE_PARSE_BIND:
+          preParseBindPlugins = removePlugin(preParseBindPlugins, plugin);
+          break;
+        case PRE_PARSE_COMPARE:
+          preParseComparePlugins = removePlugin(preParseComparePlugins,
+                                                plugin);
+          break;
+        case PRE_PARSE_DELETE:
+          preParseDeletePlugins = removePlugin(preParseDeletePlugins, plugin);
+          break;
+        case PRE_PARSE_EXTENDED:
+          preParseExtendedPlugins = removePlugin(preParseExtendedPlugins,
+                                                 plugin);
+          break;
+        case PRE_PARSE_MODIFY:
+          preParseModifyPlugins = removePlugin(preParseModifyPlugins, plugin);
+          break;
+        case PRE_PARSE_MODIFY_DN:
+          preParseModifyDNPlugins = removePlugin(preParseModifyDNPlugins,
+                                                 plugin);
+          break;
+        case PRE_PARSE_SEARCH:
+          preParseSearchPlugins = removePlugin(preParseSearchPlugins, plugin);
+          break;
+        case PRE_PARSE_UNBIND:
+          preParseUnbindPlugins = removePlugin(preParseUnbindPlugins, plugin);
+          break;
+        case PRE_OPERATION_ADD:
+          preOperationAddPlugins = removePlugin(preOperationAddPlugins,
+                                                plugin);
+          break;
+        case PRE_OPERATION_BIND:
+          preOperationBindPlugins = removePlugin(preOperationBindPlugins,
+                                                 plugin);
+          break;
+        case PRE_OPERATION_COMPARE:
+          preOperationComparePlugins =
+               removePlugin(preOperationComparePlugins, plugin);
+          break;
+        case PRE_OPERATION_DELETE:
+          preOperationDeletePlugins = removePlugin(preOperationDeletePlugins,
+                                                   plugin);
+          break;
+        case PRE_OPERATION_EXTENDED:
+          preOperationExtendedPlugins =
+               removePlugin(preOperationExtendedPlugins, plugin);
+          break;
+        case PRE_OPERATION_MODIFY:
+          preOperationModifyPlugins = removePlugin(preOperationModifyPlugins,
+                                                   plugin);
+          break;
+        case PRE_OPERATION_MODIFY_DN:
+          preOperationModifyDNPlugins =
+               removePlugin(preOperationModifyDNPlugins, plugin);
+          break;
+        case PRE_OPERATION_SEARCH:
+          preOperationSearchPlugins = removePlugin(preOperationSearchPlugins,
+                                                   plugin);
+          break;
+        case POST_OPERATION_ABANDON:
+          postOperationAbandonPlugins =
+               removePlugin(postOperationAbandonPlugins, plugin);
+          break;
+        case POST_OPERATION_ADD:
+          postOperationAddPlugins = removePlugin(postOperationAddPlugins,
+                                                 plugin);
+          break;
+        case POST_OPERATION_BIND:
+          postOperationBindPlugins = removePlugin(postOperationBindPlugins,
+                                                  plugin);
+          break;
+        case POST_OPERATION_COMPARE:
+          postOperationComparePlugins =
+               removePlugin(postOperationComparePlugins, plugin);
+          break;
+        case POST_OPERATION_DELETE:
+          postOperationDeletePlugins =
+               removePlugin(postOperationDeletePlugins, plugin);
+          break;
+        case POST_OPERATION_EXTENDED:
+          postOperationExtendedPlugins =
+               removePlugin(postOperationExtendedPlugins, plugin);
+          break;
+        case POST_OPERATION_MODIFY:
+          postOperationModifyPlugins =
+               removePlugin(postOperationModifyPlugins, plugin);
+          break;
+        case POST_OPERATION_MODIFY_DN:
+          postOperationModifyDNPlugins =
+               removePlugin(postOperationModifyDNPlugins, plugin);
+          break;
+        case POST_OPERATION_SEARCH:
+          postOperationSearchPlugins =
+               removePlugin(postOperationSearchPlugins, plugin);
+          break;
+        case POST_OPERATION_UNBIND:
+          postOperationUnbindPlugins =
+               removePlugin(postOperationUnbindPlugins, plugin);
+          break;
+        case POST_RESPONSE_ADD:
+          postResponseAddPlugins = removePlugin(postResponseAddPlugins,
+                                                plugin);
+          break;
+        case POST_RESPONSE_BIND:
+          postResponseBindPlugins = removePlugin(postResponseBindPlugins,
+                                                 plugin);
+          break;
+        case POST_RESPONSE_COMPARE:
+          postResponseComparePlugins =
+               removePlugin(postResponseComparePlugins, plugin);
+          break;
+        case POST_RESPONSE_DELETE:
+          postResponseDeletePlugins = removePlugin(postResponseDeletePlugins,
+                                                   plugin);
+          break;
+        case POST_RESPONSE_EXTENDED:
+          postResponseExtendedPlugins =
+               removePlugin(postResponseExtendedPlugins, plugin);
+          break;
+        case POST_RESPONSE_MODIFY:
+          postResponseModifyPlugins = removePlugin(postResponseModifyPlugins,
+                                                   plugin);
+          break;
+        case POST_RESPONSE_MODIFY_DN:
+          postResponseModifyDNPlugins =
+               removePlugin(postResponseModifyDNPlugins, plugin);
+          break;
+        case POST_RESPONSE_SEARCH:
+          postResponseSearchPlugins = removePlugin(postResponseSearchPlugins,
+                                                   plugin);
+          break;
+        case POST_SYNCHRONIZATION_ADD:
+          postSynchronizationAddPlugins =
+               removePlugin(postSynchronizationAddPlugins, plugin);
+          break;
+        case POST_SYNCHRONIZATION_DELETE:
+          postSynchronizationDeletePlugins =
+               removePlugin(postSynchronizationDeletePlugins, plugin);
+          break;
+        case POST_SYNCHRONIZATION_MODIFY:
+          postSynchronizationModifyPlugins =
+               removePlugin(postSynchronizationModifyPlugins, plugin);
+          break;
+        case POST_SYNCHRONIZATION_MODIFY_DN:
+          postSynchronizationModifyDNPlugins =
+               removePlugin(postSynchronizationModifyDNPlugins, plugin);
+          break;
+        case SEARCH_RESULT_ENTRY:
+          searchResultEntryPlugins = removePlugin(searchResultEntryPlugins,
+                                                  plugin);
+          break;
+        case SEARCH_RESULT_REFERENCE:
+          searchResultReferencePlugins =
+               removePlugin(searchResultReferencePlugins, plugin);
+          break;
+        case SUBORDINATE_MODIFY_DN:
+          subordinateModifyDNPlugins =
+               removePlugin(subordinateModifyDNPlugins, plugin);
+          break;
+        case INTERMEDIATE_RESPONSE:
+          intermediateResponsePlugins =
+               removePlugin(intermediateResponsePlugins, plugin);
+          break;
+        default:
+      }
+    }
   }
 
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
index c72f2c7..90d7f9a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
@@ -560,8 +560,9 @@
     sigList = new LinkedList<String>();
     sigList.add("initializeInternal");
     sigList.add("void");
-    sigList.add("org.opends.server.admin.std.server.PluginCfg");
+    sigList.add("org.opends.server.types.DN");
     sigList.add("java.util.Set");
+    sigList.add("boolean");
     expectedPublicMethods.add(sigList);
 
     sigList = new LinkedList<String>();
@@ -821,7 +822,8 @@
       pluginTypes.add(t);
     }
 
-    nullPlugin.initializeInternal(configuration, pluginTypes);
+    nullPlugin.initializeInternal(configuration.dn(), pluginTypes,
+        configuration.isInvokeForInternalOperations());
     assertEquals(nullPlugin.getPluginEntryDN(), pluginEntryDN);
   }
 
@@ -907,7 +909,8 @@
       pluginTypes.add(t);
     }
 
-    nullPlugin.initializeInternal(configuration, pluginTypes);
+    nullPlugin.initializeInternal(configuration.dn(), pluginTypes,
+        configuration.isInvokeForInternalOperations());
     assertEquals(nullPlugin.getPluginTypes(), pluginTypes);
   }
 

--
Gitblit v1.10.0