From b68d5cc1a6352dddd67adf06b18c3690c683debe Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Mon, 07 Nov 2016 15:05:30 +0000
Subject: [PATCH] OPENDJ-3417 Move responsability of backends management to BackendConfigManager

---
 opendj-server-legacy/src/messages/org/opends/messages/backend.properties                                              |    3 
 opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java                                     |  266 +----
 opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java                                            |    4 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java       |    8 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java                                   |    2 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java      |    8 
 opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java                                   |    8 
 opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java                                        |    4 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java                         |    4 
 opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java                           |   12 
 opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java                           |    4 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java        |    2 
 opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java                                            |   51 +
 opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java                                 |    6 
 opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java                                         |    2 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java    |    8 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java    |    8 
 opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java                               |   27 
 opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java                               |    7 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java  |   10 
 opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java                          |    2 
 opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java                           |    2 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java    |    8 
 opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java                                     |    2 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java          |    6 
 opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java                    |    4 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java                     |    4 
 opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java                                        |  193 ----
 opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java                                   |    2 
 opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java                                           |    2 
 opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java                               |    4 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java                  |    4 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java                          |    2 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java          |    6 
 opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java                                         |    4 
 opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java                                |    8 
 opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java                                                |    3 
 opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java                                   |  907 ++++++++++++++++++--
 opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java                                          |    7 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java   |    9 
 opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java                         |   28 
 opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java                           |    2 
 opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java    |  396 --------
 opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java                                                 |   47 -
 opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java                                |    8 
 /dev/null                                                                                                             |  456 ----------
 opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java                        |    2 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java |    4 
 opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java                                    |    2 
 49 files changed, 1,108 insertions(+), 1,460 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java b/opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java
index 477e901..72f860d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java
@@ -41,8 +41,8 @@
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 import org.forgerock.opendj.server.config.client.LDIFBackendCfgClient;
 import org.forgerock.opendj.server.config.client.RootCfgClient;
-import org.forgerock.opendj.server.config.meta.BackendCfgDefn;
 import org.forgerock.opendj.server.config.meta.LDIFBackendCfgDefn;
+import org.forgerock.opendj.server.config.meta.LocalBackendCfgDefn.WritabilityMode;
 import org.opends.admin.ads.ADSContext.ServerProperty;
 import org.opends.admin.ads.ADSContextException.ErrorType;
 import org.opends.admin.ads.util.ConnectionWrapper;
@@ -100,7 +100,7 @@
         backend.setEnabled(true);
         backend.setLDIFFile(ADSContext.getAdminLDIFFile());
         backend.setBackendId(backendName);
-        backend.setWritabilityMode(BackendCfgDefn.WritabilityMode.ENABLED);
+        backend.setWritabilityMode(WritabilityMode.ENABLED);
         backend.setIsPrivateBackend(true);
       }
       SortedSet<DN> suffixes = backend.getBaseDN();
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
index 908893b..88a3bc0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
@@ -54,11 +54,12 @@
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.server.config.client.BackendCfgClient;
 import org.forgerock.opendj.server.config.client.CryptoManagerCfgClient;
+import org.forgerock.opendj.server.config.client.LocalBackendCfgClient;
 import org.forgerock.opendj.server.config.client.ReplicationDomainCfgClient;
 import org.forgerock.opendj.server.config.client.ReplicationServerCfgClient;
 import org.forgerock.opendj.server.config.client.ReplicationSynchronizationProviderCfgClient;
 import org.forgerock.opendj.server.config.client.RootCfgClient;
-import org.forgerock.opendj.server.config.meta.BackendCfgDefn;
+import org.forgerock.opendj.server.config.meta.LocalBackendCfgDefn.WritabilityMode;
 import org.forgerock.opendj.server.config.meta.ReplicationDomainCfgDefn;
 import org.forgerock.opendj.server.config.meta.ReplicationServerCfgDefn;
 import org.forgerock.opendj.server.config.meta.ReplicationSynchronizationProviderCfgDefn;
@@ -341,11 +342,11 @@
     try
     {
       RootCfgClient root = conn.getRootConfiguration();
-      BackendCfgClient backend = root.createBackend(backendType, backendName, null);
+      LocalBackendCfgClient backend = (LocalBackendCfgClient) root.createBackend(backendType, backendName, null);
       backend.setEnabled(true);
       backend.setBaseDN(baseDNs);
       backend.setBackendId(backendName);
-      backend.setWritabilityMode(BackendCfgDefn.WritabilityMode.ENABLED);
+      backend.setWritabilityMode(WritabilityMode.ENABLED);
       backend.commit();
     }
     catch (Throwable t)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java b/opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java
index d3b63f1..11a145c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java
@@ -121,25 +121,11 @@
   public abstract Set<DN> getBaseDNs();
 
   /**
-   * Retrieves the parent backend for this backend.
+   * Retrieves the password storage schemes defined for this backend.
    *
-   * @return  The parent backend for this backend, or {@code null} if
-   *          there is none.
+   * @return the set of supported password storage schemes
    */
-  public abstract LocalBackend<?> getParentBackend();
-
-  /**
-   * Retrieve the password storage schemes defined for this backend.
-   */
-  public abstract Set<PasswordStorageScheme<?>> getPasswordStorageSchemes();
-
-  /**
-   * Retrieves the set of subordinate backends for this backend.
-   *
-   * @return  The set of subordinate backends for this backend, or an
-   *          empty array if none exist.
-   */
-  public abstract Backend<?>[] getSubordinateBackends();
+  public abstract Set<PasswordStorageScheme<?>> getSupportedPasswordStorageSchemes();
 
   /**
    * Retrieves the OIDs of the controls that may be supported by this
@@ -219,26 +205,6 @@
   }
 
   /**
-   * Adds the provided backend to the set of subordinate backends for
-   * this backend.
-   *
-   * @param  subordinateBackend  The backend to add to the set of
-   *                             subordinate backends for this
-   *                             backend.
-   */
-  public abstract void addSubordinateBackend(Backend<?> subordinateBackend);
-
-  /**
-   * Removes the provided backend from the set of subordinate backends
-   * for this backend.
-   *
-   * @param  subordinateBackend  The backend to remove from the set of
-   *                             subordinate backends for this
-   *                             backend.
-   */
-  public abstract void removeSubordinateBackend(Backend<?> subordinateBackend);
-
-  /**
    * Specifies the unique identifier for this backend.
    *
    * @param  backendID  The unique identifier for this backend.
@@ -258,11 +224,4 @@
     this.backendMonitor = backendMonitor;
   }
 
-  /**
-   * Specifies the parent backend for this backend.
-   *
-   * @param  parentBackend  The parent backend for this backend.
-   */
-  public abstract void setParentBackend(Backend<?> parentBackend);
-
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java b/opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java
index cc8e190..26be45b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java
@@ -12,7 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2008 Sun Microsystems, Inc.
- * Portions Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2015-2016 ForgeRock AS.
  */
 package org.opends.server.api;
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
index 8ac6bd3..9fc34f0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
@@ -95,6 +95,15 @@
   /** The set of persistent searches registered with this backend. */
   private final ConcurrentLinkedQueue<PersistentSearch> persistentSearches = new ConcurrentLinkedQueue<>();
 
+  /**
+   * Returns the provided backend instance as a LocalBackend.
+   *
+   * @param backend
+   *            A backend
+   * @return a local backend
+   * @throws IllegalArgumentException
+   *            If the provided backend is not a LocalBackend
+   */
   public static LocalBackend<?> asLocalBackend(Backend<?> backend)
   {
     if (backend instanceof LocalBackend)
@@ -712,7 +721,8 @@
     return persistentSearches;
   }
 
-  public Set<PasswordStorageScheme<?>> getPasswordStorageSchemes() {
+  @Override
+  public Set<PasswordStorageScheme<?>> getSupportedPasswordStorageSchemes() {
     return new HashSet<PasswordStorageScheme<?>>(DirectoryServer.getPasswordStorageSchemes());
   }
 
@@ -725,25 +735,47 @@
    */
   public abstract long getEntryCount();
 
-  @Override
+  /**
+   * Retrieves the parent backend for this backend.
+   *
+   * @return  The parent backend for this backend, or {@code null} if
+   *          there is none.
+   */
   public final LocalBackend<?> getParentBackend()
   {
     return parentBackend;
   }
 
-  @Override
+  /**
+   * Specifies the parent backend for this backend.
+   *
+   * @param  parentBackend  The parent backend for this backend.
+   */
   public final synchronized void setParentBackend(Backend<?> parentBackend)
   {
     this.parentBackend = (LocalBackend<?>) parentBackend;
   }
 
-  @Override
+  /**
+   * Retrieves the set of subordinate backends for this backend.
+   *
+   * @return  The set of subordinate backends for this backend, or an
+   *          empty array if none exist.
+   */
   public final LocalBackend<?>[] getSubordinateBackends()
   {
     return subordinateBackends;
   }
 
-  @Override
+
+  /**
+   * Adds the provided backend to the set of subordinate backends for
+   * this backend.
+   *
+   * @param  subordinateBackend  The backend to add to the set of
+   *                             subordinate backends for this
+   *                             backend.
+   */
   public final synchronized void addSubordinateBackend(Backend<?> subordinateBackend)
   {
     LinkedHashSet<LocalBackend<?>> backendSet = new LinkedHashSet<>();
@@ -755,7 +787,14 @@
     }
   }
 
-  @Override
+  /**
+   * Removes the provided backend from the set of subordinate backends
+   * for this backend.
+   *
+   * @param  subordinateBackend  The backend to remove from the set of
+   *                             subordinate backends for this
+   *                             backend.
+   */
   public final synchronized void removeSubordinateBackend(Backend<?> subordinateBackend)
   {
     ArrayList<LocalBackend<?>> backendList = new ArrayList<>(subordinateBackends.length);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java
index 8738f84..8d7aa45 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java
@@ -241,7 +241,7 @@
   @Deprecated
   public static ChangelogBackend getInstance()
   {
-    return (ChangelogBackend) DirectoryServer.getBackend(CHANGELOG_BASE_DN);
+    return (ChangelogBackend) DirectoryServer.getLocalBackend(CHANGELOG_BASE_DN);
   }
 
   @Override
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java
index 8f4a2ba..62866be 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java
@@ -40,8 +40,9 @@
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.schema.AttributeType;
-import org.forgerock.opendj.server.config.meta.BackendCfgDefn.WritabilityMode;
+import org.forgerock.opendj.server.config.meta.LocalBackendCfgDefn.WritabilityMode;
 import org.forgerock.opendj.server.config.server.BackendCfg;
+import org.forgerock.opendj.server.config.server.LocalBackendCfg;
 import org.opends.server.api.LocalBackend;
 import org.opends.server.api.Backupable;
 import org.opends.server.api.ClientConnection;
@@ -77,7 +78,7 @@
    * needed for this specific backend, but this class is required to behave like other backends
    * during initialization.
    */
-  public final class ConfigurationBackendCfg implements BackendCfg
+  public final class ConfigurationBackendCfg implements LocalBackendCfg
   {
     private ConfigurationBackendCfg()
     {
@@ -91,7 +92,7 @@
     }
 
     @Override
-    public Class<? extends BackendCfg> configurationClass()
+    public Class<? extends LocalBackendCfg> configurationClass()
     {
       return this.getClass();
     }
@@ -127,15 +128,31 @@
     }
 
     @Override
-    public void addChangeListener(ConfigurationChangeListener<BackendCfg> listener)
+    public void addChangeListener(ConfigurationChangeListener<BackendCfg> arg0)
     {
       // no-op
+
     }
 
     @Override
-    public void removeChangeListener(ConfigurationChangeListener<BackendCfg> listener)
+    public void removeChangeListener(ConfigurationChangeListener<BackendCfg> arg0)
     {
       // no-op
+
+    }
+
+    @Override
+    public void addLocalChangeListener(ConfigurationChangeListener<LocalBackendCfg> arg0)
+    {
+      // no-op
+
+    }
+
+    @Override
+    public void removeLocalChangeListener(ConfigurationChangeListener<LocalBackendCfg> arg0)
+    {
+      // no-op
+
     }
   }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
index d66ec65..fff1f37 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
@@ -30,6 +30,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -51,8 +52,8 @@
 import org.forgerock.opendj.ldap.schema.ObjectClass;
 import org.forgerock.opendj.server.config.server.RootDSEBackendCfg;
 import org.forgerock.util.Reject;
-import org.forgerock.util.Utils;
 import org.opends.server.api.LocalBackend;
+import org.opends.server.api.Backend;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DeleteOperation;
@@ -126,11 +127,8 @@
   private DN rootDSEDN;
   /** The set of base DNs for this backend. */
   private Set<DN> baseDNs;
-  /**
-   * The set of subordinate base DNs and their associated backends that will be
-   * used for non-base searches.
-   */
-  private ConcurrentHashMap<DN, LocalBackend<?>> subordinateBaseDNs;
+
+  private ServerContext serverContext;
 
   /**
    * Creates a new backend with the provided information.  All backend
@@ -148,6 +146,7 @@
   public void configureBackend(RootDSEBackendCfg config, ServerContext serverContext) throws ConfigException
   {
     Reject.ifNull(config);
+    this.serverContext = serverContext;
     currentConfig = config;
     configEntryDN = config.dn();
   }
@@ -173,43 +172,6 @@
     rootDSEDN    = DN.rootDN();
     baseDNs = Collections.singleton(rootDSEDN);
 
-    // Create the set of subordinate base DNs.  If this is specified in the
-    // configuration, then use that set.  Otherwise, use the set of non-private
-    // backends defined in the server.
-    try
-    {
-      Set<DN> subDNs = currentConfig.getSubordinateBaseDN();
-      if (subDNs.isEmpty())
-      {
-        // This is fine -- we'll just use the set of user-defined suffixes.
-        subordinateBaseDNs = null;
-      }
-      else
-      {
-        subordinateBaseDNs = new ConcurrentHashMap<>();
-        for (DN baseDN : subDNs)
-        {
-          LocalBackend<?> backend = DirectoryServer.getBackend(baseDN);
-          if (backend != null)
-          {
-            subordinateBaseDNs.put(baseDN, backend);
-          }
-          else
-          {
-            logger.warn(WARN_ROOTDSE_NO_BACKEND_FOR_SUBORDINATE_BASE, baseDN);
-          }
-        }
-      }
-    }
-    catch (Exception e)
-    {
-      logger.traceException(e);
-
-      LocalizableMessage message = WARN_ROOTDSE_SUBORDINATE_BASE_EXCEPTION.get(
-          stackTraceToSingleLineString(e));
-      throw new InitializationException(message, e);
-    }
-
     // Determine whether all root DSE attributes should be treated as user
     // attributes.
     showAllAttributes = currentConfig.isShowAllAttributes();
@@ -314,21 +276,7 @@
     {
       return -1;
     }
-
-    long count = 1;
-    for (Map.Entry<DN, LocalBackend<?>> entry : getSubordinateBaseDNs().entrySet())
-    {
-      DN subBase = entry.getKey();
-      LocalBackend<?> b = entry.getValue();
-      Entry subBaseEntry = b.getEntry(subBase);
-      if (subBaseEntry != null)
-      {
-        count++;
-        count += b.getNumberOfEntriesInBaseDN(subBase);
-      }
-    }
-
-    return count;
+    return 1;
   }
 
   @Override
@@ -339,20 +287,7 @@
     {
       return -1;
     }
-
-    long count = 0;
-
-    for (Map.Entry<DN, LocalBackend<?>> entry : getSubordinateBaseDNs().entrySet())
-    {
-      DN subBase = entry.getKey();
-      Entry subBaseEntry = entry.getValue().getEntry(subBase);
-      if (subBaseEntry != null)
-      {
-        count ++;
-      }
-    }
-
-    return count;
+    return 0;
   }
 
   @Override
@@ -363,27 +298,6 @@
     {
       return getRootDSE();
     }
-
-    // This method should never be used to get anything other than the root DSE.
-    // If we got here, then that appears to be the case, so log a message.
-    logger.warn(WARN_ROOTDSE_GET_ENTRY_NONROOT, entryDN);
-
-    // Go ahead and check the subordinate backends to see if we can find the
-    // entry there.  Note that in order to avoid potential loop conditions, this
-    // will only work if the set of subordinate bases has been explicitly
-    // specified.
-    if (subordinateBaseDNs != null)
-    {
-      for (LocalBackend<?> b : subordinateBaseDNs.values())
-      {
-        if (b.handlesEntry(entryDN))
-        {
-          return b.getEntry(entryDN);
-        }
-      }
-    }
-
-    // If we've gotten here, then we couldn't find the entry so return null.
     return null;
   }
 
@@ -410,30 +324,27 @@
     Map<AttributeType, List<Attribute>> dseUserAttrs = new HashMap<>();
     Map<AttributeType, List<Attribute>> dseOperationalAttrs = new HashMap<>();
 
-    Map<DN, LocalBackend<?>> publicNamingContexts = showSubordinatesNamingContexts ?
-        DirectoryServer.getAllPublicNamingContexts() :
-        DirectoryServer.getPublicNamingContexts();
-    Attribute publicNamingContextAttr = createAttribute(ATTR_NAMING_CONTEXTS, publicNamingContexts.keySet());
+    Set<DN> publicNamingContexts = showSubordinatesNamingContexts ?
+        getAllPublicNamingContexts() : getTopLevelPublicNamingContexts();
+    Attribute publicNamingContextAttr = createAttribute(ATTR_NAMING_CONTEXTS, publicNamingContexts);
     addAttribute(publicNamingContextAttr, dseUserAttrs, dseOperationalAttrs);
 
     // Add the "ds-private-naming-contexts" attribute.
     Attribute privateNamingContextAttr = createAttribute(
-        ATTR_PRIVATE_NAMING_CONTEXTS, DirectoryServer.getPrivateNamingContexts().keySet());
+        ATTR_PRIVATE_NAMING_CONTEXTS, serverContext.getBackendManager().getPrivateNamingContexts().keySet());
     addAttribute(privateNamingContextAttr, dseUserAttrs, dseOperationalAttrs);
 
     // Add the "supportedControl" attribute.
-    Attribute supportedControlAttr = createAttribute(ATTR_SUPPORTED_CONTROL,
-        DirectoryServer.getSupportedControls());
+    Attribute supportedControlAttr = createAttribute(ATTR_SUPPORTED_CONTROL, getAllControls());
     addAttribute(supportedControlAttr, dseUserAttrs, dseOperationalAttrs);
 
     // Add the "supportedExtension" attribute.
-    Attribute supportedExtensionAttr = createAttribute(
-        ATTR_SUPPORTED_EXTENSION, DirectoryServer.getSupportedExtensions());
+    Attribute supportedExtensionAttr = createAttribute(ATTR_SUPPORTED_EXTENSION,
+        DirectoryServer.getSupportedExtensions());
     addAttribute(supportedExtensionAttr, dseUserAttrs, dseOperationalAttrs);
 
     // Add the "supportedFeature" attribute.
-    Attribute supportedFeatureAttr = createAttribute(ATTR_SUPPORTED_FEATURE,
-        DirectoryServer.getSupportedFeatures());
+    Attribute supportedFeatureAttr = createAttribute(ATTR_SUPPORTED_FEATURE, DirectoryServer.getSupportedFeatures());
     addAttribute(supportedFeatureAttr, dseUserAttrs, dseOperationalAttrs);
 
     // Add the "supportedSASLMechanisms" attribute.
@@ -503,6 +414,35 @@
     return e;
   }
 
+  private Set<String> getAllControls()
+  {
+    // TODO: this duplicates what is done in DirectoryServer (see DirectoryServer.getSupportedControls())
+    // How should this be handled ?
+    final Set<String> controls = new HashSet<>();
+    for (Backend<?> backend : serverContext.getBackendManager().getAllBackends())
+    {
+      controls.addAll(backend.getSupportedControls());
+    }
+    return controls;
+  }
+
+  private Set<DN> getAllPublicNamingContexts()
+  {
+    Set<DN> namingContexts = new HashSet<>();
+    for (Backend<?> backend : serverContext.getBackendManager().getAllBackends())
+    {
+      namingContexts.addAll(backend.getBaseDNs());
+    }
+    return namingContexts;
+  }
+
+  private Set<DN> getTopLevelPublicNamingContexts()
+  {
+    // TODO: this implementation is insufficient because it handles only the local backends
+    // The non-local backends must be added for completeness
+    return new HashSet<DN>(serverContext.getBackendManager().getPublicNamingContexts().keySet());
+  }
+
   private void addAll(Collection<Attribute> attributes,
       Map<AttributeType, List<Attribute>> userAttrs, Map<AttributeType, List<Attribute>> operationalAttrs)
   {
@@ -567,22 +507,6 @@
     {
       return true;
     }
-
-    // If it was not the null DN, then iterate through the associated
-    // subordinate backends to make the determination.
-    for (Map.Entry<DN, LocalBackend<?>> entry : getSubordinateBaseDNs().entrySet())
-    {
-      DN baseDN = entry.getKey();
-      if (entryDN.isSubordinateOrEqualTo(baseDN))
-      {
-        LocalBackend<?> b = entry.getValue();
-        if (b.entryExists(entryDN))
-        {
-          return true;
-        }
-      }
-    }
-
     return false;
   }
 
@@ -639,72 +563,13 @@
         break;
 
       case SINGLE_LEVEL:
-        for (Map.Entry<DN, LocalBackend<?>> entry : getSubordinateBaseDNs().entrySet())
-        {
-          searchOperation.checkIfCanceled(false);
-
-          DN subBase = entry.getKey();
-          LocalBackend<?> b = entry.getValue();
-          Entry subBaseEntry = b.getEntry(subBase);
-          if (subBaseEntry != null && filter.matchesEntry(subBaseEntry))
-          {
-            searchOperation.returnEntry(subBaseEntry, null);
-          }
-        }
-        break;
-
       case WHOLE_SUBTREE:
       case SUBORDINATES:
-        try
-        {
-          for (Map.Entry<DN, LocalBackend<?>> entry : getSubordinateBaseDNs().entrySet())
-          {
-            searchOperation.checkIfCanceled(false);
-
-            DN subBase = entry.getKey();
-            LocalBackend<?> b = entry.getValue();
-
-            searchOperation.setBaseDN(subBase);
-            try
-            {
-              b.search(searchOperation);
-            }
-            catch (DirectoryException de)
-            {
-              // If it's a "no such object" exception, then the base entry for
-              // the backend doesn't exist.  This isn't an error, so ignore it.
-              // We'll propogate all other errors, though.
-              if (de.getResultCode() != ResultCode.NO_SUCH_OBJECT)
-              {
-                throw de;
-              }
-            }
-          }
-        }
-        catch (DirectoryException de)
-        {
-          logger.traceException(de);
-
-          throw de;
-        }
-        catch (Exception e)
-        {
-          logger.traceException(e);
-
-          LocalizableMessage message = ERR_ROOTDSE_UNEXPECTED_SEARCH_FAILURE.
-              get(searchOperation.getConnectionID(),
-                  searchOperation.getOperationID(),
-                  stackTraceToSingleLineString(e));
-          throw new DirectoryException(
-                         DirectoryServer.getServerErrorResultCode(), message,
-                         e);
-        }
-        finally
-        {
-          searchOperation.setBaseDN(rootDSEDN);
-        }
-        break;
-
+        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+            ERR_ROOTDSE_NOT_SUPPORTED_SCOPE.get(
+                searchOperation.getConnectionID(),
+                searchOperation.getOperationID(),
+                searchOperation.getScope()));
       default:
         LocalizableMessage message = ERR_ROOTDSE_INVALID_SEARCH_SCOPE.
             get(searchOperation.getConnectionID(),
@@ -714,21 +579,6 @@
     }
   }
 
-  /**
-   * Returns the subordinate base DNs of the root DSE.
-   *
-   * @return the subordinate base DNs of the root DSE
-   */
-  @SuppressWarnings({ "unchecked", "rawtypes" })
-  public Map<DN, LocalBackend<?>> getSubordinateBaseDNs()
-  {
-    if (subordinateBaseDNs != null)
-    {
-      return subordinateBaseDNs;
-    }
-    return DirectoryServer.getPublicNamingContexts();
-  }
-
   @Override
   public Set<String> getSupportedControls()
   {
@@ -842,7 +692,7 @@
       {
         for (DN baseDN : subDNs)
         {
-          LocalBackend<?> backend = DirectoryServer.getBackend(baseDN);
+          LocalBackend<?> backend = DirectoryServer.getLocalBackend(baseDN);
           if (backend == null)
           {
             unacceptableReasons.add(WARN_ROOTDSE_NO_BACKEND_FOR_SUBORDINATE_BASE.get(baseDN));
@@ -869,7 +719,7 @@
     final ConfigChangeResult ccr = new ConfigChangeResult();
 
     // Check to see if we should apply a new set of base DNs.
-    ConcurrentHashMap<DN, LocalBackend<?>> subBases;
+    ConcurrentHashMap<DN, Backend<?>> subBases;
     try
     {
       Set<DN> subDNs = cfg.getSubordinateBaseDN();
@@ -883,7 +733,7 @@
         subBases = new ConcurrentHashMap<>();
         for (DN baseDN : subDNs)
         {
-          LocalBackend<?> backend = DirectoryServer.getBackend(baseDN);
+          LocalBackend<?> backend = DirectoryServer.getLocalBackend(baseDN);
           if (backend == null)
           {
             // This is not fine.  We can't use a suffix that doesn't exist.
@@ -928,18 +778,6 @@
 
     if (ccr.getResultCode() == ResultCode.SUCCESS)
     {
-      subordinateBaseDNs = subBases;
-
-      if (subordinateBaseDNs == null)
-      {
-        ccr.addMessage(INFO_ROOTDSE_USING_SUFFIXES_AS_BASE_DNS.get());
-      }
-      else
-      {
-        String basesStr = "{ " + Utils.joinAsString(", ", subordinateBaseDNs.keySet()) + " }";
-        ccr.addMessage(INFO_ROOTDSE_USING_NEW_SUBORDINATE_BASE_DNS.get(basesStr));
-      }
-
       if (showAllAttributes != newShowAll)
       {
         showAllAttributes = newShowAll;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java
index be1ea47..ff77bc5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java
@@ -17,15 +17,23 @@
 package org.opends.server.core;
 
 import static org.forgerock.opendj.ldap.ResultCode.*;
+import static org.forgerock.util.Reject.ifNull;
 import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.api.LocalBackend.asLocalBackend;
 import static org.opends.server.core.DirectoryServer.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.forgerock.i18n.LocalizableMessage;
@@ -37,10 +45,12 @@
 import org.forgerock.opendj.config.server.ConfigurationDeleteListener;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.server.config.meta.BackendCfgDefn;
+import org.forgerock.opendj.server.config.meta.LocalBackendCfgDefn;
 import org.forgerock.opendj.server.config.server.BackendCfg;
+import org.forgerock.opendj.server.config.server.LocalBackendCfg;
 import org.forgerock.opendj.server.config.server.RootCfg;
 import org.opends.server.api.LocalBackend;
+import org.opends.server.api.Backend;
 import org.opends.server.api.BackendInitializationListener;
 import org.opends.server.backends.ConfigurationBackend;
 import org.opends.server.config.ConfigConstants;
@@ -50,11 +60,10 @@
 import org.opends.server.types.WritabilityMode;
 
 /**
- * This class defines a utility that will be used to manage the configuration
- * for the set of backends defined in the Directory Server.  It will perform
- * the necessary initialization of those backends when the server is first
- * started, and then will manage any changes to them while the server is
- * running.
+ * Responsible for managing the configuration of backends defined in the Directory Server.
+ * <p>
+ * It will perform the necessary initialization of those backends when the server is first
+ * started, and then will manage any changes to them while the server is running.
  */
 public class BackendConfigManager implements
      ConfigurationChangeListener<BackendCfg>,
@@ -64,8 +73,9 @@
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   /** The mapping between configuration entry DNs and their corresponding backend implementations. */
-  private final ConcurrentHashMap<DN, LocalBackend<? extends BackendCfg>> registeredBackends = new ConcurrentHashMap<>();
+  private final ConcurrentHashMap<DN, Backend<? extends BackendCfg>> registeredBackends = new ConcurrentHashMap<>();
   private final ServerContext serverContext;
+  private final BaseDnRegistry localBackendsRegistry;
 
   /**
    * Creates a new instance of this backend config manager.
@@ -76,6 +86,7 @@
   public BackendConfigManager(ServerContext serverContext)
   {
     this.serverContext = serverContext;
+    this.localBackendsRegistry = new BaseDnRegistry();
   }
 
   /**
@@ -201,7 +212,7 @@
     initializeBackend(configBackend, configBackend.getBackendCfg());
   }
 
-  private void initializeBackend(LocalBackend<? extends BackendCfg> backend, BackendCfg backendCfg)
+  private void initializeBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg)
   {
     ConfigChangeResult ccr = new ConfigChangeResult();
     initializeBackend(backend, backendCfg, ccr);
@@ -211,10 +222,11 @@
     }
   }
 
-  private void initializeBackend(LocalBackend<? extends BackendCfg> backend, BackendCfg backendCfg, ConfigChangeResult ccr)
+  private void initializeBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg,
+      ConfigChangeResult ccr)
   {
     backend.setBackendID(backendCfg.getBackendId());
-    backend.setWritabilityMode(toWritabilityMode(backendCfg.getWritabilityMode()));
+    setLocalBackendWritabilityMode(backend, backendCfg);
 
     if (acquireSharedLock(backend, backendCfg.getBackendId(), ccr) && configureAndOpenBackend(backend, backendCfg, ccr))
     {
@@ -222,11 +234,18 @@
     }
   }
 
+  private void setLocalBackendWritabilityMode(Backend<?> backend, BackendCfg backendCfg)
+  {
+    LocalBackend<?> localBackend = asLocalBackend(backend);
+    LocalBackendCfg localCfg = (LocalBackendCfg) backendCfg;
+    localBackend.setWritabilityMode(toWritabilityMode(localCfg.getWritabilityMode()));
+  }
+
   /**
    * Acquire a shared lock on this backend. This will prevent operations like LDIF import or restore
    * from occurring while the backend is active.
    */
-  private boolean acquireSharedLock(LocalBackend<?> backend, String backendID, final ConfigChangeResult ccr)
+  private boolean acquireSharedLock(Backend<?> backend, String backendID, final ConfigChangeResult ccr)
   {
     try
     {
@@ -259,7 +278,7 @@
     ccr.addMessage(message);
   }
 
-  private void releaseSharedLock(LocalBackend<?> backend, String backendID)
+  private void releaseSharedLock(Backend<?> backend, String backendID)
   {
     try
     {
@@ -280,6 +299,158 @@
     }
   }
 
+  /**
+   * Returns the collection of all backends.
+   *
+   * @return all backends
+   */
+  public Collection<Backend<?>> getAllBackends()
+  {
+    return new ArrayList<Backend<?>>(registeredBackends.values());
+  }
+
+  /**
+   * Retrieves the local backend with the specified base DN.
+   *
+   * @param  baseDN  The DN that is registered as one of the base DNs for the
+   *                 backend to retrieve.
+   *
+   * @return  The local backend with the specified base DN, or {@code null} if there
+   *          is no local backend registered with the specified base DN.
+   */
+  public LocalBackend<?> getLocalBackendWithBaseDN(DN baseDN)
+  {
+    return localBackendsRegistry.getBackendWithBaseDN(baseDN);
+  }
+
+  /**
+   * Retrieves the local backend and the corresponding baseDN that should be used to handle operations
+   * on the specified entry.
+   *
+   * @param entryDN
+   *          The DN of the entry for which to retrieve the corresponding backend.
+   * @return The local backend with its matching base DN or {@code null} if no appropriate backend
+   *         is registered with the server.
+   */
+  public BackendAndName getLocalBackend(DN entryDN)
+  {
+    return localBackendsRegistry.getBackendAndName(entryDN);
+  }
+
+  /**
+   * Retrieves the set of subordinate backends that of the backend that corresponds to provided base DN.
+   *
+   * @param baseDN
+   *          The base DN for which to retrieve the subordinates backends.
+   * @return The set of subordinates backends (and associated base DN), which is never {@code null}
+   */
+  public Set<BackendAndName> getSubordinateBackends(DN baseDN)
+  {
+    final Set<BackendAndName> subs = new HashSet<>();
+    LocalBackend<?> backend = getLocalBackendWithBaseDN(baseDN);
+    if (backend == null)
+    {
+      return subs;
+    }
+    for (LocalBackend<?> subordinate : backend.getSubordinateBackends())
+    {
+      for (DN subordinateDN : subordinate.getBaseDNs())
+      {
+        if (subordinateDN.isSubordinateOrEqualTo(baseDN))
+        {
+          subs.add(new BackendAndName(subordinate, subordinateDN));
+        }
+      }
+    }
+    return subs;
+  }
+
+  /**
+   * Gets the mapping of registered public naming contexts, not including
+   * sub-suffixes, to their associated backend.
+   *
+   * @return mapping from naming context to backend
+   */
+  public Map<DN, LocalBackend<?>> getPublicNamingContexts()
+  {
+    return localBackendsRegistry.getPublicNamingContextsMap();
+  }
+
+  /**
+   * Gets the mapping of registered public naming contexts, including sub-suffixes,
+   * to their associated backend.
+   *
+   * @return mapping from naming context to backend
+   */
+  public Map<DN, LocalBackend<?>> getAllPublicNamingContexts()
+  {
+    return localBackendsRegistry.getAllPublicNamingContextsMap();
+  }
+
+  /**
+   * Gets the mapping of registered private naming contexts to their
+   * associated backend.
+   *
+   * @return mapping from naming context to backend
+   */
+  public Map<DN, LocalBackend<?>> getPrivateNamingContexts()
+  {
+    return localBackendsRegistry.getPrivateNamingContextsMap();
+  }
+
+  /**
+   * Indicates whether the specified DN is contained in the backends as
+   * a naming contexts.
+   *
+   * @param  dn  The DN for which to make the determination.
+   *
+   * @return  {@code true} if the specified DN is a naming context in one
+   *          backend, or {@code false} if it is not.
+   */
+  public boolean containsNamingContext(DN dn)
+  {
+    return localBackendsRegistry.containsNamingContext(dn);
+  }
+
+  /**
+   * Registers the provided base DN.
+   *
+   * @param baseDN
+   *          The base DN to register. It must not be {@code null}.
+   * @param backend
+   *          The backend responsible for the provided base DN. It must not be {@code null}.
+   * @param isPrivate
+   *          Indicates whether the base DN should be considered a private base DN. If the provided
+   *          base DN is a naming context, then this controls whether it is public or private.
+   * @throws DirectoryException
+   *           If a problem occurs while attempting to register the provided base DN.
+   */
+  public void registerBaseDN(DN baseDN, LocalBackend<?> backend, boolean isPrivate) throws DirectoryException
+  {
+    List<LocalizableMessage> warnings = localBackendsRegistry.registerBaseDN(baseDN, backend, isPrivate);
+    for (LocalizableMessage warning : warnings)
+    {
+      logger.error(warning);
+    }
+  }
+
+  /**
+   * Deregisters the provided base DN.
+   *
+   * @param baseDN
+   *          The base DN to deregister. It must not be {@code null}.
+   * @throws DirectoryException
+   *           If a problem occurs while attempting to deregister the provided base DN.
+   */
+  public void deregisterBaseDN(DN baseDN) throws DirectoryException
+  {
+    List<LocalizableMessage> warnings = localBackendsRegistry.deregisterBaseDN(baseDN);
+    for (LocalizableMessage error : warnings)
+    {
+      logger.error(error);
+    }
+  }
+
   @Override
   public boolean isConfigurationChangeAcceptable(
        BackendCfg configEntry,
@@ -287,12 +458,11 @@
   {
     DN backendDN = configEntry.dn();
 
-
     Set<DN> baseDNs = configEntry.getBaseDN();
 
     // See if the backend is registered with the server.  If it is, then
     // see what's changed and whether those changes are acceptable.
-    LocalBackend<?> backend = registeredBackends.get(backendDN);
+    Backend<?> backend = registeredBackends.get(backendDN);
     if (backend != null)
     {
       LinkedHashSet<DN> removedDNs = new LinkedHashSet<>(backend.getBaseDNs());
@@ -307,36 +477,39 @@
         }
       }
 
-      // Copy the directory server's base DN registry and make the
-      // requested changes to see if it complains.
-      BaseDnRegistry reg = DirectoryServer.copyBaseDnRegistry();
-      for (DN dn : removedDNs)
+      if (backend instanceof LocalBackend<?>)
       {
-        try
+        // Copy the registry and make the requested changes to see if it complains.
+        LocalBackend<?> localBackend = (LocalBackend<?>) backend;
+        BaseDnRegistry registry = localBackendsRegistry.copy();
+        for (DN dn : removedDNs)
         {
-          reg.deregisterBaseDN(dn);
-        }
-        catch (DirectoryException de)
-        {
-          logger.traceException(de);
+          try
+          {
+            registry.deregisterBaseDN(dn);
+          }
+          catch (DirectoryException de)
+          {
+            logger.traceException(de);
 
-          unacceptableReason.add(de.getMessageObject());
-          return false;
+            unacceptableReason.add(de.getMessageObject());
+            return false;
+          }
         }
-      }
 
-      for (DN dn : addedDNs)
-      {
-        try
+        for (DN dn : addedDNs)
         {
-          reg.registerBaseDN(dn, backend, false);
-        }
-        catch (DirectoryException de)
-        {
-          logger.traceException(de);
+          try
+          {
+            registry.registerBaseDN(dn, localBackend, false);
+          }
+          catch (DirectoryException de)
+          {
+            logger.traceException(de);
 
-          unacceptableReason.add(de.getMessageObject());
-          return false;
+            unacceptableReason.add(de.getMessageObject());
+            return false;
+          }
         }
       }
     }
@@ -356,7 +529,7 @@
           return false;
         }
 
-        LocalBackend<BackendCfg> b = backendClass.newInstance();
+        Backend<BackendCfg> b = backendClass.newInstance();
         if (! b.isConfigurationAcceptable(configEntry, unacceptableReason, serverContext))
         {
           return false;
@@ -381,7 +554,7 @@
   public ConfigChangeResult applyConfigurationChange(BackendCfg cfg)
   {
     DN backendDN = cfg.dn();
-    LocalBackend<? extends BackendCfg> backend = registeredBackends.get(backendDN);
+    Backend<? extends BackendCfg> backend = registeredBackends.get(backendDN);
     final ConfigChangeResult ccr = new ConfigChangeResult();
 
     // See if the entry contains an attribute that indicates whether the
@@ -488,43 +661,49 @@
     }
     else if (ccr.getResultCode() == ResultCode.SUCCESS && backend != null)
     {
-      backend.setWritabilityMode(toWritabilityMode(cfg.getWritabilityMode()));
+      setLocalBackendWritabilityMode(backend, cfg);
     }
 
     return ccr;
   }
 
-  private boolean registerBackend(LocalBackend<? extends BackendCfg> backend, BackendCfg backendCfg, ConfigChangeResult ccr)
+  private boolean registerBackend(Backend<? extends BackendCfg> backend, BackendCfg backendCfg, ConfigChangeResult ccr)
   {
-    for (BackendInitializationListener listener : getBackendInitializationListeners())
+    if (backend instanceof LocalBackend<?>)
     {
-      listener.performBackendPreInitializationProcessing(backend);
+      LocalBackend<?> localBackend = (LocalBackend<?>) backend;
+      for (BackendInitializationListener listener : getBackendInitializationListeners())
+      {
+        listener.performBackendPreInitializationProcessing(localBackend);
+      }
+
+      try
+      {
+        DirectoryServer.registerBackend(localBackend);
+      }
+      catch (Exception e)
+      {
+        logger.traceException(e);
+
+        LocalizableMessage message =
+            WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(), getExceptionMessage(e));
+        logger.error(message);
+
+        // FIXME -- Do we need to send an admin alert?
+        ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+        ccr.addMessage(message);
+        return false;
+      }
+
+      for (BackendInitializationListener listener : getBackendInitializationListeners())
+      {
+        listener.performBackendPostInitializationProcessing(localBackend);
+      }
+
+      registeredBackends.put(backendCfg.dn(), backend);
+      return true;
     }
-
-    try
-    {
-      DirectoryServer.registerBackend(backend);
-    }
-    catch (Exception e)
-    {
-      logger.traceException(e);
-
-      LocalizableMessage message =
-          WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(), getExceptionMessage(e));
-      logger.error(message);
-
-      // FIXME -- Do we need to send an admin alert?
-      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
-      ccr.addMessage(message);
-      return false;
-    }
-
-    for (BackendInitializationListener listener : getBackendInitializationListeners())
-    {
-      listener.performBackendPostInitializationProcessing(backend);
-    }
-
-    registeredBackends.put(backendCfg.dn(), backend);
+    // TODO: manage proxy registration here
     return true;
   }
 
@@ -576,7 +755,7 @@
 
 
     // Make sure that all of the base DNs are acceptable for use in the server.
-    BaseDnRegistry reg = DirectoryServer.copyBaseDnRegistry();
+    BaseDnRegistry registry = localBackendsRegistry.copy();
     for (DN baseDN : baseDNs)
     {
       if (baseDN.isRootDN())
@@ -586,7 +765,7 @@
       }
       try
       {
-        reg.registerBaseDN(baseDN, backend, false);
+        registry.registerBaseDN(baseDN, backend, false);
       }
       catch (DirectoryException de)
       {
@@ -665,7 +844,7 @@
     return ccr;
   }
 
-  private boolean configureAndOpenBackend(LocalBackend<?> backend, BackendCfg cfg, ConfigChangeResult ccr)
+  private boolean configureAndOpenBackend(Backend<?> backend, BackendCfg cfg, ConfigChangeResult ccr)
   {
     try
     {
@@ -686,7 +865,7 @@
   }
 
   @SuppressWarnings({ "unchecked", "rawtypes" })
-  private void configureAndOpenBackend(LocalBackend backend, BackendCfg cfg) throws ConfigException, InitializationException
+  private void configureAndOpenBackend(Backend backend, BackendCfg cfg) throws ConfigException, InitializationException
   {
     backend.configureBackend(cfg, serverContext);
     backend.openBackend();
@@ -698,7 +877,7 @@
     return (Class<LocalBackend<BackendCfg>>) DirectoryServer.loadClass(className);
   }
 
-  private WritabilityMode toWritabilityMode(BackendCfgDefn.WritabilityMode writabilityMode)
+  private WritabilityMode toWritabilityMode(LocalBackendCfgDefn.WritabilityMode writabilityMode)
   {
     switch (writabilityMode)
     {
@@ -725,20 +904,23 @@
     // provided DN.  If not, then we don't care if the entry is deleted.  If we
     // do know about it, then that means that it is enabled and we will not
     // allow removing a backend that is enabled.
-    LocalBackend<?> backend = registeredBackends.get(backendDN);
+    Backend<?> backend = registeredBackends.get(backendDN);
     if (backend == null)
     {
       return true;
     }
 
-
-    // See if the backend has any subordinate backends.  If so, then it is not
-    // acceptable to remove it.  Otherwise, it should be fine.
-    LocalBackend<?>[] subBackends = backend.getSubordinateBackends();
-    if (subBackends != null && subBackends.length != 0)
+    // TODO: what about non local backend ?
+    if (backend instanceof LocalBackend)
     {
-      unacceptableReason.add(NOTE_CONFIG_BACKEND_CANNOT_REMOVE_BACKEND_WITH_SUBORDINATES.get(backendDN));
-      return false;
+      // See if the backend has any subordinate backends.  If so, then it is not
+      // acceptable to remove it.  Otherwise, it should be fine.
+      LocalBackend<?>[] subBackends = ((LocalBackend<?>) backend).getSubordinateBackends();
+      if (subBackends != null && subBackends.length != 0)
+      {
+        unacceptableReason.add(NOTE_CONFIG_BACKEND_CANNOT_REMOVE_BACKEND_WITH_SUBORDINATES.get(backendDN));
+        return false;
+      }
     }
     return true;
   }
@@ -751,20 +933,24 @@
 
     // See if this backend config manager has a backend registered with the
     // provided DN.  If not, then we don't care if the entry is deleted.
-    LocalBackend<?> backend = registeredBackends.get(backendDN);
+    Backend<?> backend = registeredBackends.get(backendDN);
     if (backend == null)
     {
       return ccr;
     }
 
-    // See if the backend has any subordinate backends.  If so, then it is not
-    // acceptable to remove it.  Otherwise, it should be fine.
-    LocalBackend<?>[] subBackends = backend.getSubordinateBackends();
-    if (subBackends != null && subBackends.length > 0)
+    // TODO: what about non local backend ?
+    if (backend instanceof LocalBackend)
     {
-      ccr.setResultCode(UNWILLING_TO_PERFORM);
-      ccr.addMessage(NOTE_CONFIG_BACKEND_CANNOT_REMOVE_BACKEND_WITH_SUBORDINATES.get(backendDN));
-      return ccr;
+      // See if the backend has any subordinate backends.  If so, then it is not
+      // acceptable to remove it.  Otherwise, it should be fine.
+      LocalBackend<?>[] subBackends = ((LocalBackend<?>) backend).getSubordinateBackends();
+      if (subBackends != null && subBackends.length > 0)
+      {
+        ccr.setResultCode(UNWILLING_TO_PERFORM);
+        ccr.addMessage(NOTE_CONFIG_BACKEND_CANNOT_REMOVE_BACKEND_WITH_SUBORDINATES.get(backendDN));
+        return ccr;
+      }
     }
 
     deregisterBackend(backendDN, backend);
@@ -785,19 +971,546 @@
     return ccr;
   }
 
-  private void deregisterBackend(DN backendDN, LocalBackend<?> backend)
+  private void deregisterBackend(DN backendDN, Backend<?> backend)
   {
-    for (BackendInitializationListener listener : getBackendInitializationListeners())
+    if (backend instanceof LocalBackend<?>)
     {
-      listener.performBackendPreFinalizationProcessing(backend);
+      LocalBackend<?> localBackend = (LocalBackend<?>) backend;
+      for (BackendInitializationListener listener : getBackendInitializationListeners())
+      {
+        listener.performBackendPreFinalizationProcessing(localBackend);
+      }
+
+      registeredBackends.remove(backendDN);
+      DirectoryServer.deregisterBackend(localBackend);
+
+      for (BackendInitializationListener listener : getBackendInitializationListeners())
+      {
+        listener.performBackendPostFinalizationProcessing(localBackend);
+      }
+    }
+    else {
+      // TODO: manage proxy deregistering here
+    }
+  }
+
+  /**
+   * Registry for maintaining the set of registered base DN's, associated local backends
+   * and naming context information.
+   */
+  static private class BaseDnRegistry {
+
+    /** The set of base DNs registered with the server. */
+    private final TreeMap<DN, LocalBackend<?>> baseDNs = new TreeMap<>();
+    /** The set of private naming contexts registered with the server. */
+    private final TreeMap<DN, LocalBackend<?>> privateNamingContexts = new TreeMap<>();
+    /** The set of public naming contexts registered with the server. */
+    private final TreeMap<DN, LocalBackend<?>> publicNamingContexts = new TreeMap<>();
+    /** The set of public naming contexts, including sub-suffixes, registered with the server. */
+    private final TreeMap<DN, LocalBackend<?>> allPublicNamingContexts = new TreeMap<>();
+
+    /**
+     * Indicates whether this base DN registry is in test mode.
+     * A registry instance that is in test mode will not modify backend
+     * objects referred to in the above maps.
+     */
+    private boolean testOnly;
+
+    /**
+     * Registers a base DN with this registry.
+     *
+     * @param  baseDN to register
+     * @param  backend with which the base DN is associated
+     * @param  isPrivate indicates whether this base DN is private
+     * @return list of error messages generated by registering the base DN
+     *         that should be logged if the changes to this registry are
+     *         committed to the server
+     * @throws DirectoryException if the base DN cannot be registered
+     */
+    List<LocalizableMessage> registerBaseDN(DN baseDN, LocalBackend<?> backend, boolean isPrivate)
+        throws DirectoryException
+    {
+      // Check to see if the base DN is already registered with the server.
+      LocalBackend<?> existingBackend = baseDNs.get(baseDN);
+      if (existingBackend != null)
+      {
+        LocalizableMessage message = ERR_REGISTER_BASEDN_ALREADY_EXISTS.
+            get(baseDN, backend.getBackendID(), existingBackend.getBackendID());
+        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+      }
+
+      // Check to see if the backend is already registered with the server for
+      // any other base DN(s).  The new base DN must not have any hierarchical
+      // relationship with any other base Dns for the same backend.
+      LinkedList<DN> otherBaseDNs = new LinkedList<>();
+      for (DN dn : baseDNs.keySet())
+      {
+        LocalBackend<?> b = baseDNs.get(dn);
+        if (b.equals(backend))
+        {
+          otherBaseDNs.add(dn);
+
+          if (baseDN.isSuperiorOrEqualTo(dn) || baseDN.isSubordinateOrEqualTo(dn))
+          {
+            LocalizableMessage message = ERR_REGISTER_BASEDN_HIERARCHY_CONFLICT.
+                get(baseDN, backend.getBackendID(), dn);
+            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+          }
+        }
+      }
+
+      // Check to see if the new base DN is subordinate to any other base DN
+      // already defined.  If it is, then any other base DN(s) for the same
+      // backend must also be subordinate to the same base DN.
+      final LocalBackend<?> superiorBackend = getSuperiorBackend(baseDN, otherBaseDNs, backend.getBackendID());
+      if (superiorBackend == null && backend.getParentBackend() != null)
+      {
+        LocalizableMessage message = ERR_REGISTER_BASEDN_NEW_BASE_NOT_SUBORDINATE.
+            get(baseDN, backend.getBackendID(), backend.getParentBackend().getBackendID());
+        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+      }
+
+      // Check to see if the new base DN should be the superior base DN for any
+      // other base DN(s) already defined.
+      LinkedList<LocalBackend<?>> subordinateBackends = new LinkedList<>();
+      LinkedList<DN>      subordinateBaseDNs  = new LinkedList<>();
+      for (DN dn : baseDNs.keySet())
+      {
+        LocalBackend<?> b = baseDNs.get(dn);
+        DN parentDN = dn.parent();
+        while (parentDN != null)
+        {
+          if (parentDN.equals(baseDN))
+          {
+            subordinateBaseDNs.add(dn);
+            subordinateBackends.add(b);
+            break;
+          }
+          else if (baseDNs.containsKey(parentDN))
+          {
+            break;
+          }
+
+          parentDN = parentDN.parent();
+        }
+      }
+
+      // If we've gotten here, then the new base DN is acceptable.  If we should
+      // actually apply the changes then do so now.
+      final List<LocalizableMessage> errors = new LinkedList<>();
+
+      // Check to see if any of the registered backends already contain an
+      // entry with the DN specified as the base DN.  This could happen if
+      // we're creating a new subordinate backend in an existing directory
+      // (e.g., moving the "ou=People,dc=example,dc=com" branch to its own
+      // backend when that data already exists under the "dc=example,dc=com"
+      // backend).  This condition shouldn't prevent the new base DN from
+      // being registered, but it's definitely important enough that we let
+      // the administrator know about it and remind them that the existing
+      // backend will need to be reinitialized.
+      if (superiorBackend != null)
+      {
+        if (superiorBackend.entryExists(baseDN))
+        {
+          errors.add(WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS.
+              get(superiorBackend.getBackendID(), baseDN, backend.getBackendID()));
+        }
+      }
+
+      baseDNs.put(baseDN, backend);
+
+      if (superiorBackend == null)
+      {
+        if (!testOnly)
+        {
+          backend.setPrivateBackend(isPrivate);
+        }
+
+        if (isPrivate)
+        {
+          privateNamingContexts.put(baseDN, backend);
+        }
+        else
+        {
+          publicNamingContexts.put(baseDN, backend);
+        }
+      }
+      else if (otherBaseDNs.isEmpty() && !testOnly)
+      {
+        backend.setParentBackend(superiorBackend);
+        superiorBackend.addSubordinateBackend(backend);
+      }
+
+      if (!testOnly)
+      {
+        for (LocalBackend<?> b : subordinateBackends)
+        {
+          LocalBackend<?> oldParentBackend = b.getParentBackend();
+          if (oldParentBackend != null)
+          {
+            oldParentBackend.removeSubordinateBackend(b);
+          }
+
+          b.setParentBackend(backend);
+          backend.addSubordinateBackend(b);
+        }
+      }
+
+      if (!isPrivate)
+      {
+        allPublicNamingContexts.put(baseDN, backend);
+      }
+      for (DN dn : subordinateBaseDNs)
+      {
+        publicNamingContexts.remove(dn);
+        privateNamingContexts.remove(dn);
+      }
+
+      return errors;
     }
 
-    registeredBackends.remove(backendDN);
-    DirectoryServer.deregisterBackend(backend);
-
-    for (BackendInitializationListener listener : getBackendInitializationListeners())
+    LocalBackend<?> getBackendWithBaseDN(DN entryDN)
     {
-      listener.performBackendPostFinalizationProcessing(backend);
+      return baseDNs.get(entryDN);
+    }
+
+
+    BackendAndName getBackendAndName(final DN entryDN)
+    {
+      /*
+       * Try to minimize the number of lookups in the map to find the backend containing the entry.
+       * 1) If the DN contains many RDNs it is faster to iterate through the list of registered backends,
+       * 2) Otherwise iterating through the parents requires less lookups. It also avoids some attacks
+       * where we would spend time going through the list of all parents to finally decide the
+       * baseDN is absent.
+       */
+      if (entryDN.size() <= baseDNs.size())
+      {
+        DN matchedDN = entryDN;
+        while (!matchedDN.isRootDN())
+        {
+          final LocalBackend<?> backend = baseDNs.get(matchedDN);
+          if (backend != null)
+          {
+            return new BackendAndName(backend, matchedDN);
+          }
+          matchedDN = matchedDN.parent();
+        }
+        return null;
+      }
+      else
+      {
+        LocalBackend<?> backend = null;
+        DN matchedDN = null;
+        int currentSize = 0;
+        for (DN backendDN : baseDNs.keySet())
+        {
+          if (entryDN.isSubordinateOrEqualTo(backendDN) && backendDN.size() > currentSize)
+          {
+            backend = baseDNs.get(backendDN);
+            matchedDN = backendDN;
+            currentSize = backendDN.size();
+          }
+        }
+        return new BackendAndName(backend, matchedDN);
+      }
+    }
+
+    private LocalBackend<?> getSuperiorBackend(DN baseDN, LinkedList<DN> otherBaseDNs, String backendID)
+        throws DirectoryException
+    {
+      LocalBackend<?> superiorBackend = null;
+      DN parentDN = baseDN.parent();
+      while (parentDN != null)
+      {
+        if (baseDNs.containsKey(parentDN))
+        {
+          superiorBackend = baseDNs.get(parentDN);
+
+          for (DN dn : otherBaseDNs)
+          {
+            if (!dn.isSubordinateOrEqualTo(parentDN))
+            {
+              LocalizableMessage msg = ERR_REGISTER_BASEDN_DIFFERENT_PARENT_BASES.get(baseDN, backendID, dn);
+              throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
+            }
+          }
+          break;
+        }
+
+        parentDN = parentDN.parent();
+      }
+      return superiorBackend;
+    }
+
+    /**
+     * Deregisters a base DN with this registry.
+     *
+     * @param  baseDN to deregister
+     * @return list of error messages generated by deregistering the base DN
+     *         that should be logged if the changes to this registry are
+     *         committed to the server
+     * @throws DirectoryException if the base DN could not be deregistered
+     */
+     List<LocalizableMessage> deregisterBaseDN(DN baseDN)
+           throws DirectoryException
+    {
+      ifNull(baseDN);
+
+      // Make sure that the Directory Server actually contains a backend with
+      // the specified base DN.
+      LocalBackend<?> backend = baseDNs.get(baseDN);
+      if (backend == null)
+      {
+        LocalizableMessage message =
+            ERR_DEREGISTER_BASEDN_NOT_REGISTERED.get(baseDN);
+        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
+      }
+
+      // Check to see if the backend has a parent backend, and whether it has
+      // any subordinates with base DNs that are below the base DN to remove.
+      LocalBackend<?> superiorBackend = backend.getParentBackend();
+      LinkedList<LocalBackend<?>> subordinateBackends = new LinkedList<>();
+      if (backend.getSubordinateBackends() != null)
+      {
+        for (LocalBackend<?> b : backend.getSubordinateBackends())
+        {
+          for (DN dn : b.getBaseDNs())
+          {
+            if (dn.isSubordinateOrEqualTo(baseDN))
+            {
+              subordinateBackends.add(b);
+              break;
+            }
+          }
+        }
+      }
+
+      // See if there are any other base DNs registered within the same backend.
+      LinkedList<DN> otherBaseDNs = new LinkedList<>();
+      for (DN dn : baseDNs.keySet())
+      {
+        if (dn.equals(baseDN))
+        {
+          continue;
+        }
+
+        LocalBackend<?> b = baseDNs.get(dn);
+        if (backend.equals(b))
+        {
+          otherBaseDNs.add(dn);
+        }
+      }
+
+      // If we've gotten here, then it's OK to make the changes.
+
+      // Get rid of the references to this base DN in the mapping tree
+      // information.
+      baseDNs.remove(baseDN);
+      publicNamingContexts.remove(baseDN);
+      allPublicNamingContexts.remove(baseDN);
+      privateNamingContexts.remove(baseDN);
+
+      final LinkedList<LocalizableMessage> errors = new LinkedList<>();
+      if (superiorBackend == null)
+      {
+        // If there were any subordinate backends, then all of their base DNs
+        // will now be promoted to naming contexts.
+        for (LocalBackend<?> b : subordinateBackends)
+        {
+          if (!testOnly)
+          {
+            b.setParentBackend(null);
+            backend.removeSubordinateBackend(b);
+          }
+
+          for (DN dn : b.getBaseDNs())
+          {
+            if (b.isPrivateBackend())
+            {
+              privateNamingContexts.put(dn, b);
+            }
+            else
+            {
+              publicNamingContexts.put(dn, b);
+            }
+          }
+        }
+      }
+      else
+      {
+        // If there are no other base DNs for the associated backend, then
+        // remove this backend as a subordinate of the parent backend.
+        if (otherBaseDNs.isEmpty() && !testOnly)
+        {
+          superiorBackend.removeSubordinateBackend(backend);
+        }
+
+        // If there are any subordinate backends, then they need to be made
+        // subordinate to the parent backend.  Also, we should log a warning
+        // message indicating that there may be inconsistent search results
+        // because some of the structural entries will be missing.
+        if (! subordinateBackends.isEmpty())
+        {
+          // Suppress this warning message on server shutdown.
+          if (!DirectoryServer.getInstance().isShuttingDown()) {
+            errors.add(WARN_DEREGISTER_BASEDN_MISSING_HIERARCHY.get(
+                baseDN, backend.getBackendID()));
+          }
+
+          if (!testOnly)
+          {
+            for (LocalBackend<?> b : subordinateBackends)
+            {
+              backend.removeSubordinateBackend(b);
+              superiorBackend.addSubordinateBackend(b);
+              b.setParentBackend(superiorBackend);
+            }
+          }
+        }
+      }
+      return errors;
+    }
+
+    /** Creates a default instance. */
+    BaseDnRegistry()
+    {
+      this(false);
+    }
+
+    /**
+     * Returns a copy of this registry.
+     *
+     * @return copy of this registry
+     */
+    BaseDnRegistry copy()
+    {
+      final BaseDnRegistry registry = new BaseDnRegistry(true);
+      registry.baseDNs.putAll(baseDNs);
+      registry.publicNamingContexts.putAll(publicNamingContexts);
+      registry.allPublicNamingContexts.putAll(allPublicNamingContexts);
+      registry.privateNamingContexts.putAll(privateNamingContexts);
+      return registry;
+    }
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param testOnly indicates whether this registry will be used for testing;
+     *        when <code>true</code> this registry will not modify backends
+     */
+    private BaseDnRegistry(boolean testOnly)
+    {
+      this.testOnly = testOnly;
+    }
+
+    /**
+     * Gets the mapping of registered base DNs to their associated backend.
+     *
+     * @return mapping from base DN to backend
+     */
+    Map<DN, LocalBackend<?>> getBaseDnMap()
+    {
+      return this.baseDNs;
+    }
+
+    /**
+     * Gets the mapping of registered public naming contexts, not including
+     * sub-suffixes, to their associated backend.
+     *
+     * @return mapping from naming context to backend
+     */
+    Map<DN, LocalBackend<?>> getPublicNamingContextsMap()
+    {
+      return this.publicNamingContexts;
+    }
+
+    /**
+     * Gets the mapping of registered public naming contexts, including sub-suffixes,
+     * to their associated backend.
+     *
+     * @return mapping from naming context to backend
+     */
+    Map<DN, LocalBackend<?>> getAllPublicNamingContextsMap()
+    {
+      return this.allPublicNamingContexts;
+    }
+
+    /**
+     * Gets the mapping of registered private naming contexts to their
+     * associated backend.
+     *
+     * @return mapping from naming context to backend
+     */
+    Map<DN, LocalBackend<?>> getPrivateNamingContextsMap()
+    {
+      return this.privateNamingContexts;
+    }
+
+    /**
+     * Indicates whether the specified DN is contained in this registry as
+     * a naming contexts.
+     *
+     * @param  dn  The DN for which to make the determination.
+     *
+     * @return  {@code true} if the specified DN is a naming context in this
+     *          registry, or {@code false} if it is not.
+     */
+    boolean containsNamingContext(DN dn)
+    {
+      return privateNamingContexts.containsKey(dn) || publicNamingContexts.containsKey(dn);
+    }
+
+    /** Clear and nullify this registry's internal state. */
+    void clear() {
+      baseDNs.clear();
+      privateNamingContexts.clear();
+      publicNamingContexts.clear();
+      allPublicNamingContexts.clear();
+    }
+  }
+
+  /**
+   * Holder for a backend and a single base DN managed by the backend.
+   * <p>
+   * A backend can manages multiple base DNs, this class allow to keep the association for a single DN.
+   */
+  public static class BackendAndName
+  {
+    private final LocalBackend<?> backend;
+    private final DN baseDn;
+
+    /**
+     * Creates a new holder for base DN and the backend that manages it.
+     * @param backend
+     *          The backend that holds the base DN
+     * @param baseDn
+     *          A base DN of the backend
+     */
+    public BackendAndName(LocalBackend<?> backend, DN baseDn)
+    {
+      this.backend = backend;
+      this.baseDn = baseDn;
+    }
+
+    /**
+     * Returns the base DN.
+     *
+     * @return the base DN
+     */
+    public DN getBaseDn()
+    {
+      return baseDn;
+    }
+
+    /**
+     * Returns the backend.
+     *
+     * @return the backend that holds the base DN
+     */
+    public LocalBackend<?> getBackend()
+    {
+      return backend;
     }
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/BaseDnRegistry.java b/opendj-server-legacy/src/main/java/org/opends/server/core/BaseDnRegistry.java
deleted file mode 100644
index 0b6ff5d..0000000
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/BaseDnRegistry.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * The contents of this file are subject to the terms of the Common Development and
- * Distribution License (the License). You may not use this file except in compliance with the
- * License.
- *
- * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
- * specific language governing permission and limitations under the License.
- *
- * When distributing Covered Software, include this CDDL Header Notice in each file and include
- * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
- * Header, with the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyright [year] [name of copyright owner]".
- *
- * Copyright 2007-2008 Sun Microsystems, Inc.
- * Portions Copyright 2014-2016 ForgeRock AS.
- */
-package org.opends.server.core;
-
-import static org.forgerock.util.Reject.*;
-import static org.opends.messages.CoreMessages.*;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.DN;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.opends.server.api.LocalBackend;
-import org.opends.server.types.DirectoryException;
-
-/**
- * Registry for maintaining the set of registered base DN's, associated backends
- * and naming context information.
- */
-public class BaseDnRegistry {
-  /** The set of base DNs registered with the server. */
-  private final TreeMap<DN, LocalBackend<?>> baseDNs = new TreeMap<>();
-  /** The set of private naming contexts registered with the server. */
-  private final TreeMap<DN, LocalBackend<?>> privateNamingContexts = new TreeMap<>();
-  /** The set of public naming contexts registered with the server. */
-  private final TreeMap<DN, LocalBackend<?>> publicNamingContexts = new TreeMap<>();
-  /** The set of public naming contexts, including sub-suffixes, registered with the server. */
-  private final TreeMap<DN, LocalBackend<?>> allPublicNamingContexts = new TreeMap<>();
-
-  /**
-   * Indicates whether this base DN registry is in test mode.
-   * A registry instance that is in test mode will not modify backend
-   * objects referred to in the above maps.
-   */
-  private boolean testOnly;
-
-  /**
-   * Registers a base DN with this registry.
-   *
-   * @param  baseDN to register
-   * @param  backend with which the base DN is associated
-   * @param  isPrivate indicates whether this base DN is private
-   * @return list of error messages generated by registering the base DN
-   *         that should be logged if the changes to this registry are
-   *         committed to the server
-   * @throws DirectoryException if the base DN cannot be registered
-   */
-  public List<LocalizableMessage> registerBaseDN(DN baseDN, LocalBackend<?> backend, boolean isPrivate)
-      throws DirectoryException
-  {
-    // Check to see if the base DN is already registered with the server.
-    LocalBackend<?> existingBackend = baseDNs.get(baseDN);
-    if (existingBackend != null)
-    {
-      LocalizableMessage message = ERR_REGISTER_BASEDN_ALREADY_EXISTS.
-          get(baseDN, backend.getBackendID(), existingBackend.getBackendID());
-      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-    }
-
-    // Check to see if the backend is already registered with the server for
-    // any other base DN(s).  The new base DN must not have any hierarchical
-    // relationship with any other base Dns for the same backend.
-    LinkedList<DN> otherBaseDNs = new LinkedList<>();
-    for (DN dn : baseDNs.keySet())
-    {
-      LocalBackend<?> b = baseDNs.get(dn);
-      if (b.equals(backend))
-      {
-        otherBaseDNs.add(dn);
-
-        if (baseDN.isSuperiorOrEqualTo(dn) || baseDN.isSubordinateOrEqualTo(dn))
-        {
-          LocalizableMessage message = ERR_REGISTER_BASEDN_HIERARCHY_CONFLICT.
-              get(baseDN, backend.getBackendID(), dn);
-          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-        }
-      }
-    }
-
-    // Check to see if the new base DN is subordinate to any other base DN
-    // already defined.  If it is, then any other base DN(s) for the same
-    // backend must also be subordinate to the same base DN.
-    final LocalBackend<?> superiorBackend = getSuperiorBackend(baseDN, otherBaseDNs, backend.getBackendID());
-    if (superiorBackend == null && backend.getParentBackend() != null)
-    {
-      LocalizableMessage message = ERR_REGISTER_BASEDN_NEW_BASE_NOT_SUBORDINATE.
-          get(baseDN, backend.getBackendID(), backend.getParentBackend().getBackendID());
-      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-    }
-
-    // Check to see if the new base DN should be the superior base DN for any
-    // other base DN(s) already defined.
-    LinkedList<LocalBackend<?>> subordinateBackends = new LinkedList<>();
-    LinkedList<DN>      subordinateBaseDNs  = new LinkedList<>();
-    for (DN dn : baseDNs.keySet())
-    {
-      LocalBackend<?> b = baseDNs.get(dn);
-      DN parentDN = dn.parent();
-      while (parentDN != null)
-      {
-        if (parentDN.equals(baseDN))
-        {
-          subordinateBaseDNs.add(dn);
-          subordinateBackends.add(b);
-          break;
-        }
-        else if (baseDNs.containsKey(parentDN))
-        {
-          break;
-        }
-
-        parentDN = parentDN.parent();
-      }
-    }
-
-    // If we've gotten here, then the new base DN is acceptable.  If we should
-    // actually apply the changes then do so now.
-    final List<LocalizableMessage> errors = new LinkedList<>();
-
-    // Check to see if any of the registered backends already contain an
-    // entry with the DN specified as the base DN.  This could happen if
-    // we're creating a new subordinate backend in an existing directory
-    // (e.g., moving the "ou=People,dc=example,dc=com" branch to its own
-    // backend when that data already exists under the "dc=example,dc=com"
-    // backend).  This condition shouldn't prevent the new base DN from
-    // being registered, but it's definitely important enough that we let
-    // the administrator know about it and remind them that the existing
-    // backend will need to be reinitialized.
-    if (superiorBackend != null && superiorBackend.entryExists(baseDN))
-    {
-      errors.add(WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS.
-          get(superiorBackend.getBackendID(), baseDN, backend.getBackendID()));
-    }
-
-    baseDNs.put(baseDN, backend);
-
-    if (superiorBackend == null)
-    {
-      if (!testOnly)
-      {
-        backend.setPrivateBackend(isPrivate);
-      }
-
-      if (isPrivate)
-      {
-        privateNamingContexts.put(baseDN, backend);
-      }
-      else
-      {
-        publicNamingContexts.put(baseDN, backend);
-      }
-    }
-    else if (otherBaseDNs.isEmpty() && !testOnly)
-    {
-      backend.setParentBackend(superiorBackend);
-      superiorBackend.addSubordinateBackend(backend);
-    }
-
-    if (!testOnly)
-    {
-      for (LocalBackend<?> b : subordinateBackends)
-      {
-        LocalBackend<?> oldParentBackend = b.getParentBackend();
-        if (oldParentBackend != null)
-        {
-          oldParentBackend.removeSubordinateBackend(b);
-        }
-
-        b.setParentBackend(backend);
-        backend.addSubordinateBackend(b);
-      }
-    }
-
-    if (!isPrivate)
-    {
-      allPublicNamingContexts.put(baseDN, backend);
-    }
-    for (DN dn : subordinateBaseDNs)
-    {
-      publicNamingContexts.remove(dn);
-      privateNamingContexts.remove(dn);
-    }
-
-    return errors;
-  }
-
-  private LocalBackend<?> getSuperiorBackend(DN baseDN, LinkedList<DN> otherBaseDNs, String backendID)
-      throws DirectoryException
-  {
-    LocalBackend<?> superiorBackend = null;
-    DN parentDN = baseDN.parent();
-    while (parentDN != null)
-    {
-      if (baseDNs.containsKey(parentDN))
-      {
-        superiorBackend = baseDNs.get(parentDN);
-
-        for (DN dn : otherBaseDNs)
-        {
-          if (!dn.isSubordinateOrEqualTo(parentDN))
-          {
-            LocalizableMessage msg = ERR_REGISTER_BASEDN_DIFFERENT_PARENT_BASES.get(baseDN, backendID, dn);
-            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
-          }
-        }
-        break;
-      }
-
-      parentDN = parentDN.parent();
-    }
-    return superiorBackend;
-  }
-
-  /**
-   * Deregisters a base DN with this registry.
-   *
-   * @param  baseDN to deregister
-   * @return list of error messages generated by deregistering the base DN
-   *         that should be logged if the changes to this registry are
-   *         committed to the server
-   * @throws DirectoryException if the base DN could not be deregistered
-   */
-  public List<LocalizableMessage> deregisterBaseDN(DN baseDN)
-         throws DirectoryException
-  {
-    ifNull(baseDN);
-
-    // Make sure that the Directory Server actually contains a backend with
-    // the specified base DN.
-    LocalBackend<?> backend = baseDNs.get(baseDN);
-    if (backend == null)
-    {
-      LocalizableMessage message =
-          ERR_DEREGISTER_BASEDN_NOT_REGISTERED.get(baseDN);
-      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
-    }
-
-    // Check to see if the backend has a parent backend, and whether it has
-    // any subordinates with base DNs that are below the base DN to remove.
-    LocalBackend<?>             superiorBackend     = backend.getParentBackend();
-    LinkedList<LocalBackend<?>> subordinateBackends = new LinkedList<>();
-    if (backend.getSubordinateBackends() != null)
-    {
-      for (LocalBackend<?> b : backend.getSubordinateBackends())
-      {
-        for (DN dn : b.getBaseDNs())
-        {
-          if (dn.isSubordinateOrEqualTo(baseDN))
-          {
-            subordinateBackends.add(b);
-            break;
-          }
-        }
-      }
-    }
-
-    // See if there are any other base DNs registered within the same backend.
-    LinkedList<DN> otherBaseDNs = new LinkedList<>();
-    for (DN dn : baseDNs.keySet())
-    {
-      if (dn.equals(baseDN))
-      {
-        continue;
-      }
-
-      LocalBackend<?> b = baseDNs.get(dn);
-      if (backend.equals(b))
-      {
-        otherBaseDNs.add(dn);
-      }
-    }
-
-    // If we've gotten here, then it's OK to make the changes.
-
-    // Get rid of the references to this base DN in the mapping tree
-    // information.
-    baseDNs.remove(baseDN);
-    publicNamingContexts.remove(baseDN);
-    allPublicNamingContexts.remove(baseDN);
-    privateNamingContexts.remove(baseDN);
-
-    final LinkedList<LocalizableMessage> errors = new LinkedList<>();
-    if (superiorBackend == null)
-    {
-      // If there were any subordinate backends, then all of their base DNs
-      // will now be promoted to naming contexts.
-      for (LocalBackend<?> b : subordinateBackends)
-      {
-        if (!testOnly)
-        {
-          b.setParentBackend(null);
-          backend.removeSubordinateBackend(b);
-        }
-
-        for (DN dn : b.getBaseDNs())
-        {
-          if (b.isPrivateBackend())
-          {
-            privateNamingContexts.put(dn, b);
-          }
-          else
-          {
-            publicNamingContexts.put(dn, b);
-          }
-        }
-      }
-    }
-    else
-    {
-      // If there are no other base DNs for the associated backend, then
-      // remove this backend as a subordinate of the parent backend.
-      if (otherBaseDNs.isEmpty() && !testOnly)
-      {
-        superiorBackend.removeSubordinateBackend(backend);
-      }
-
-      // If there are any subordinate backends, then they need to be made
-      // subordinate to the parent backend.  Also, we should log a warning
-      // message indicating that there may be inconsistent search results
-      // because some of the structural entries will be missing.
-      if (! subordinateBackends.isEmpty())
-      {
-        // Suppress this warning message on server shutdown.
-        if (!DirectoryServer.getInstance().isShuttingDown()) {
-          errors.add(WARN_DEREGISTER_BASEDN_MISSING_HIERARCHY.get(
-              baseDN, backend.getBackendID()));
-        }
-
-        if (!testOnly)
-        {
-          for (LocalBackend<?> b : subordinateBackends)
-          {
-            backend.removeSubordinateBackend(b);
-            superiorBackend.addSubordinateBackend(b);
-            b.setParentBackend(superiorBackend);
-          }
-        }
-      }
-    }
-    return errors;
-  }
-
-  /** Creates a default instance. */
-  BaseDnRegistry()
-  {
-    this(false);
-  }
-
-  /**
-   * Returns a copy of this registry.
-   *
-   * @return copy of this registry
-   */
-  BaseDnRegistry copy()
-  {
-    final BaseDnRegistry registry = new BaseDnRegistry(true);
-    registry.baseDNs.putAll(baseDNs);
-    registry.publicNamingContexts.putAll(publicNamingContexts);
-    registry.allPublicNamingContexts.putAll(allPublicNamingContexts);
-    registry.privateNamingContexts.putAll(privateNamingContexts);
-    return registry;
-  }
-
-  /**
-   * Creates a parameterized instance.
-   *
-   * @param testOnly indicates whether this registry will be used for testing;
-   *        when <code>true</code> this registry will not modify backends
-   */
-  private BaseDnRegistry(boolean testOnly)
-  {
-    this.testOnly = testOnly;
-  }
-
-  /**
-   * Gets the mapping of registered base DNs to their associated backend.
-   *
-   * @return mapping from base DN to backend
-   */
-  Map<DN, LocalBackend<?>> getBaseDnMap()
-  {
-    return this.baseDNs;
-  }
-
-  /**
-   * Gets the mapping of registered public naming contexts, not including
-   * sub-suffixes, to their associated backend.
-   *
-   * @return mapping from naming context to backend
-   */
-  Map<DN, LocalBackend<?>> getPublicNamingContextsMap()
-  {
-    return this.publicNamingContexts;
-  }
-
-  /**
-   * Gets the mapping of registered public naming contexts, including sub-suffixes,
-   * to their associated backend.
-   *
-   * @return mapping from naming context to backend
-   */
-  Map<DN, LocalBackend<?>> getAllPublicNamingContextsMap()
-  {
-    return this.allPublicNamingContexts;
-  }
-
-  /**
-   * Gets the mapping of registered private naming contexts to their
-   * associated backend.
-   *
-   * @return mapping from naming context to backend
-   */
-  Map<DN, LocalBackend<?>> getPrivateNamingContextsMap()
-  {
-    return this.privateNamingContexts;
-  }
-
-  /**
-   * Indicates whether the specified DN is contained in this registry as
-   * a naming contexts.
-   *
-   * @param  dn  The DN for which to make the determination.
-   *
-   * @return  {@code true} if the specified DN is a naming context in this
-   *          registry, or {@code false} if it is not.
-   */
-  boolean containsNamingContext(DN dn)
-  {
-    return privateNamingContexts.containsKey(dn) || publicNamingContexts.containsKey(dn);
-  }
-
-  /** Clear and nullify this registry's internal state. */
-  void clear() {
-    baseDNs.clear();
-    privateNamingContexts.clear();
-    publicNamingContexts.clear();
-    allPublicNamingContexts.clear();
-  }
-}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
index d790ab3..517e566 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -163,8 +163,6 @@
 import org.opends.server.util.RuntimeInformation;
 import org.opends.server.util.SetupUtils;
 import org.opends.server.util.TimeThread;
-import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
-
 import com.forgerock.opendj.cli.ArgumentConstants;
 import com.forgerock.opendj.cli.ArgumentException;
 import com.forgerock.opendj.cli.ArgumentParser;
@@ -582,9 +580,6 @@
   /** The synchronization provider configuration manager for the Directory Server. */
   private SynchronizationProviderConfigManager synchronizationProviderConfigManager;
 
-  /** Registry for base DN and naming context information. */
-  private BaseDnRegistry baseDnRegistry;
-
   /** The set of backends registered with the server. */
   private TreeMap<String, LocalBackend<?>> backends;
 
@@ -1064,6 +1059,12 @@
     {
       return directoryServer.cronExecutorService;
     }
+
+    @Override
+    public BackendConfigManager getBackendManager()
+    {
+      return directoryServer.backendConfigManager;
+    }
   }
 
   /**
@@ -1216,7 +1217,6 @@
       directoryServer.monitorProviders = new ConcurrentHashMap<>();
       directoryServer.backends = new TreeMap<>();
       directoryServer.backendInitializationListeners = new CopyOnWriteArraySet<>();
-      directoryServer.baseDnRegistry = new BaseDnRegistry();
       directoryServer.initializationCompletedListeners = new CopyOnWriteArrayList<>();
       directoryServer.shutdownListeners = new CopyOnWriteArrayList<>();
       directoryServer.synchronizationProviders = new CopyOnWriteArrayList<>();
@@ -1543,8 +1543,6 @@
 
       initializeRemainingBackends();
 
-      createAndRegisterRemainingWorkflows();
-
       // Check for and initialize user configured entry cache if any.
       // If not then stick with default entry cache initialized earlier.
       entryCacheConfigManager.initializeEntryCache();
@@ -1818,67 +1816,6 @@
   }
 
   /**
-   * Creates a set of workflows for a given backend and registers the
-   * workflows with the default network group, the internal network group
-   * and he admin network group. There are as many workflows
-   * as base DNs defined in the backend.
-   *
-   * @param backend  the backend handled by the workflow
-   *
-   * @throws  DirectoryException  If the workflow ID for the provided
-   *                              workflow conflicts with the workflow
-   *                              ID of an existing workflow.
-   */
-  private static void createAndRegisterWorkflows(LocalBackend<?> backend) throws DirectoryException
-  {
-    // Create a workflow for each backend base DN and register the workflow
-    // with the default/internal/admin network group.
-    for (DN curBaseDN: backend.getBaseDNs())
-    {
-      createWorkflow(curBaseDN, backend);
-    }
-  }
-
-  /**
-   * Creates one workflow for a given base DN in a backend.
-   *
-   * @param baseDN   the base DN of the workflow to create
-   * @param backend  the backend handled by the workflow
-   * @throws  DirectoryException  If the workflow ID for the provided
-   *                              workflow conflicts with the workflow
-   *                              ID of an existing workflow.
-   */
-  private static void createWorkflow(DN baseDN, LocalBackend<?> backend) throws DirectoryException
-  {
-    LocalBackendWorkflowElement.createAndRegister(baseDN, backend);
-  }
-
-  /**
-   * Creates the missing workflows, one for the config backend and one for
-   * the rootDSE backend.
-   *
-   * This method should be invoked whatever may be the workflow
-   * configuration mode because config backend and rootDSE backend
-   * will not have any configuration section, ever.
-   *
-   * @throws  ConfigException  If there is a configuration problem with any of
-   *                           the workflows.
-   */
-  private void createAndRegisterRemainingWorkflows()
-      throws ConfigException
-  {
-    try
-    {
-      createAndRegisterWorkflows(getConfigurationBackend());
-      createAndRegisterWorkflows(rootDSEBackend);
-    }
-    catch (DirectoryException de)
-    {
-      throw new ConfigException(de.getMessageObject());
-    }
-  }
-
-  /**
    * Initializes the Directory Server group manager.
    *
    * @throws  ConfigException  If there is a configuration problem with any of
@@ -3559,12 +3496,6 @@
 
       directoryServer.backends = newBackends;
 
-      // Don't need anymore the local backend workflow element so we can remove it
-      for (DN baseDN : backend.getBaseDNs())
-      {
-        LocalBackendWorkflowElement.remove(baseDN);
-      }
-
       BackendMonitor monitor = backend.getBackendMonitor();
       if (monitor != null)
       {
@@ -3576,21 +3507,21 @@
   }
 
   /**
-   * Retrieves the backend with the specified base DN.
+   * Retrieves the local backend with the specified base DN.
    *
    * @param  baseDN  The DN that is registered as one of the base DNs for the
    *                 backend to retrieve.
    *
-   * @return  The backend with the specified base DN, or {@code null} if there
-   *          is no backend registered with the specified base DN.
+   * @return  The local backend with the specified base DN, or {@code null} if there
+   *          is no local backend registered with the specified base DN.
    */
-  public static LocalBackend<?> getBackendWithBaseDN(DN baseDN)
+  public static LocalBackend<?> getLocalBackendWithBaseDN(DN baseDN)
   {
-    return directoryServer.baseDnRegistry.getBaseDnMap().get(baseDN);
+    return directoryServer.backendConfigManager.getLocalBackendWithBaseDN(baseDN);
   }
 
   /**
-   * Retrieves the backend that should be used to handle operations on the
+   * Retrieves the local backend that should be used to handle operations on the
    * specified entry.
    *
    * @param  entryDN  The DN of the entry for which to retrieve the
@@ -3600,41 +3531,13 @@
    *          specified entry, or {@code null} if no appropriate backend is
    *          registered with the server.
    */
-  public static LocalBackend<?> getBackend(DN entryDN)
+  public static LocalBackend<?> getLocalBackend(DN entryDN)
   {
     if (entryDN.isRootDN())
     {
       return directoryServer.rootDSEBackend;
     }
-
-    Map<DN, LocalBackend<?>> baseDNs = directoryServer.baseDnRegistry.getBaseDnMap();
-    LocalBackend<?> b = baseDNs.get(entryDN);
-    while (b == null)
-    {
-      entryDN = entryDN.parent();
-      if (entryDN == null)
-      {
-        return null;
-      }
-
-      b = baseDNs.get(entryDN);
-    }
-
-    return b;
-  }
-
-  /**
-   * Obtains a copy of the server's base DN registry.  The copy can be used
-   * to test registration/deregistration of base DNs but cannot be used to
-   * modify the backends.  To modify the server's live base DN to backend
-   * mappings use {@link #registerBaseDN(DN, LocalBackend, boolean)} and
-   * {@link #deregisterBaseDN(DN)}.
-   *
-   * @return copy of the base DN registry
-   */
-  public static BaseDnRegistry copyBaseDnRegistry()
-  {
-    return directoryServer.baseDnRegistry.copy();
+    return directoryServer.backendConfigManager.getLocalBackend(entryDN).getBackend();
   }
 
   /**
@@ -3656,29 +3559,9 @@
          throws DirectoryException
   {
     ifNull(baseDN, backend);
-
     synchronized (directoryServer)
     {
-      List<LocalizableMessage> warnings =
-              directoryServer.baseDnRegistry.registerBaseDN(
-                      baseDN, backend, isPrivate);
-
-      // Since we've committed the changes we need to log any issues
-      // that this registration has caused
-      for (LocalizableMessage warning : warnings) {
-        logger.error(warning);
-      }
-
-      // When a new baseDN is registered with the server we have to create
-      // a new workflow to handle the base DN.
-      if (!baseDN.equals(DN.valueOf("cn=config")))
-      {
-        // Now create a workflow for the registered baseDN and register
-        // the workflow with the default network group, but don't register
-        // the workflow if the backend happens to be the configuration
-        // backend because it's too soon for the config backend.
-        createWorkflow(baseDN, backend);
-      }
+      directoryServer.backendConfigManager.registerBaseDN(baseDN, backend, isPrivate);
     }
   }
 
@@ -3695,22 +3578,8 @@
          throws DirectoryException
   {
     ifNull(baseDN);
-
     synchronized(directoryServer) {
-      List<LocalizableMessage> warnings =
-              directoryServer.baseDnRegistry.deregisterBaseDN(baseDN);
-
-      // Since we've committed the changes we need to log any issues
-      // that this registration has caused
-      for (LocalizableMessage error : warnings) {
-        logger.error(error);
-      }
-
-      // Now we need to deregister the workflow that was associated with the base DN
-      if (!baseDN.equals(DN.valueOf("cn=config")))
-      {
-        LocalBackendWorkflowElement.remove(baseDN);
-      }
+      directoryServer.backendConfigManager.deregisterBaseDN(baseDN);
     }
   }
 
@@ -3722,7 +3591,7 @@
    */
   public static Map<DN, LocalBackend<?>> getPublicNamingContexts()
   {
-    return directoryServer.baseDnRegistry.getPublicNamingContextsMap();
+    return directoryServer.backendConfigManager.getPublicNamingContexts();
   }
 
   /**
@@ -3734,19 +3603,7 @@
    */
   public static Map<DN, LocalBackend<?>> getAllPublicNamingContexts()
   {
-    return directoryServer.baseDnRegistry.getAllPublicNamingContextsMap();
-  }
-
-  /**
-   * Retrieves the set of private naming contexts defined in the Directory
-   * Server, mapped from the naming context DN to the corresponding backend.
-   *
-   * @return  The set of private naming contexts defined in the Directory
-   *          Server.
-   */
-  public static Map<DN, LocalBackend<?>> getPrivateNamingContexts()
-  {
-    return directoryServer.baseDnRegistry.getPrivateNamingContextsMap();
+    return directoryServer.backendConfigManager.getAllPublicNamingContexts();
   }
 
   /**
@@ -3760,7 +3617,7 @@
    */
   public static boolean isNamingContext(DN dn)
   {
-    return directoryServer.baseDnRegistry.containsNamingContext(dn);
+    return directoryServer.backendConfigManager.containsNamingContext(dn);
   }
 
   /**
@@ -3843,7 +3700,7 @@
     {
       return directoryServer.rootDSEBackend.getRootDSE();
     }
-    final LocalBackend<?> backend = getBackend(entryDN);
+    final LocalBackend<?> backend = getLocalBackend(entryDN);
     return backend != null ? backend.getEntry(entryDN) : null;
   }
 
@@ -3870,7 +3727,7 @@
 
     // Ask the appropriate backend if the entry exists.
     // If it is not appropriate for any backend, then return false.
-    LocalBackend<?> backend = getBackend(entryDN);
+    LocalBackend<?> backend = getLocalBackend(entryDN);
     return backend != null && backend.entryExists(entryDN);
   }
 
@@ -5259,8 +5116,6 @@
         logger.traceException(e);
       }
     }
-    // Deregister all the local backend workflow elements that have been registered with the server.
-    LocalBackendWorkflowElement.removeAll();
   }
 
   /**
@@ -5288,12 +5143,6 @@
     shutdownHook             = null;
     workQueue                = null;
 
-    if (baseDnRegistry != null)
-    {
-      baseDnRegistry.clear();
-      baseDnRegistry = null;
-    }
-
     if (backends != null)
     {
       backends.clear();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java
index 4bf717e..72fdca0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java
@@ -23,7 +23,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.opends.server.api.LocalBackend;
+import org.opends.server.api.Backend;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 
 import static org.opends.messages.CoreMessages.*;
@@ -436,7 +436,7 @@
    * @return  The filename that should be used for the lock file for the
    *          specified backend.
    */
-  public static String getBackendLockFileName(LocalBackend backend)
+  public static String getBackendLockFileName(Backend backend)
   {
     StringBuilder buffer = new StringBuilder();
     buffer.append(getLockDirectoryPath());
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
index 22e06ab..71f55d7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
@@ -135,4 +135,11 @@
    * @return the UNIX's cron-like executor service
    */
   ScheduledExecutorService getCronExecutorService();
+
+  /**
+   * Returns the manager of backends.
+   *
+   * @return backend manager
+   */
+  BackendConfigManager getBackendManager();
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java
index 064ac34..10b53b8 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java
@@ -163,7 +163,7 @@
     attrAlias = getSchema().getAttributeType(ATTR_CRYPTO_KEY_ID);
     attrCompromisedTime = getSchema().getAttributeType(ATTR_CRYPTO_KEY_COMPROMISED_TIME);
 
-    if (DirectoryServer.getBackendWithBaseDN(adminSuffixDN) != null)
+    if (DirectoryServer.getLocalBackendWithBaseDN(adminSuffixDN) != null)
     {
       searchAdminSuffix();
     }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java
index b58269d..c0fee94 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java
@@ -111,7 +111,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend b = DirectoryServer.getBackend(baseDN);
+        LocalBackend b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           throw new ConfigException(ERR_EXACTMAP_ATTR_UNINDEXED.get(
@@ -274,7 +274,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend b = DirectoryServer.getBackend(baseDN);
+        LocalBackend b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           unacceptableReasons.add(ERR_EXACTMAP_ATTR_UNINDEXED.get(
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java
index 0e9ff6d..5f24ce5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java
@@ -600,7 +600,7 @@
   {
     // Determine which backend should be used for the provided base DN.  If
     // there is none, then we don't need to do anything.
-    LocalBackend<?> backend = DirectoryServer.getBackend(baseDN);
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(baseDN);
     if (backend == null)
     {
       return;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java
index 9077cd3..06bb0a4 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java
@@ -118,7 +118,7 @@
     AttributeType t = configuration.getFingerprintAttribute();
     for (DN baseDN : cfgBaseDNs)
     {
-      LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+      LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
       if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
       {
         logger.warn(WARN_SATUACM_ATTR_UNINDEXED, configuration.dn(),
@@ -317,7 +317,7 @@
     AttributeType t = configuration.getFingerprintAttribute();
     for (DN baseDN : cfgBaseDNs)
     {
-      LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+      LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
       if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
       {
         LocalizableMessage message = WARN_SATUACM_ATTR_UNINDEXED.get(
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
index 250a108..e20dec4 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
@@ -60,7 +60,7 @@
   @Override
   public Attribute getValues(Entry entry, VirtualAttributeRule rule)
   {
-    LocalBackend backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend backend = DirectoryServer.getLocalBackend(entry.getName());
 
     try
     {
@@ -81,7 +81,7 @@
   @Override
   public boolean hasValue(Entry entry, VirtualAttributeRule rule)
   {
-    LocalBackend backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend backend = DirectoryServer.getLocalBackend(entry.getName());
 
     try
     {
@@ -99,7 +99,7 @@
   @Override
   public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
   {
-    LocalBackend backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend backend = DirectoryServer.getLocalBackend(entry.getName());
     MatchingRule matchingRule =
         rule.getAttributeType().getEqualityMatchingRule();
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
index 9c021e5..1acb14f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
@@ -60,7 +60,7 @@
   @Override
   public Attribute getValues(Entry entry, VirtualAttributeRule rule)
   {
-    LocalBackend backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend backend = DirectoryServer.getLocalBackend(entry.getName());
 
     try
     {
@@ -81,7 +81,7 @@
   @Override
   public boolean hasValue(Entry entry, VirtualAttributeRule rule)
   {
-    LocalBackend<?> backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(entry.getName());
 
     try
     {
@@ -97,7 +97,7 @@
   @Override
   public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
   {
-    LocalBackend<?> backend = DirectoryServer.getBackend(entry.getName());
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(entry.getName());
     try
     {
       long count = backend.getNumberOfChildren(entry.getName());
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java
index 3acf50f..cb02007 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java
@@ -138,7 +138,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend b = DirectoryServer.getBackend(baseDN);
+        LocalBackend b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           throw new ConfigException(ERR_REGEXMAP_ATTR_UNINDEXED.get(
@@ -291,7 +291,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend b = DirectoryServer.getBackend(baseDN);
+        LocalBackend b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           unacceptableReasons.add(ERR_REGEXMAP_ATTR_UNINDEXED.get(
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java
index 321d745..30b8c87 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java
@@ -327,7 +327,7 @@
   public void clearSubtree(DN baseDN)
   {
     // Determine the backend used to hold the specified base DN and clear it.
-    LocalBackend<?> backend = DirectoryServer.getBackend(baseDN);
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(baseDN);
     if (backend == null)
     {
       // FIXME -- Should we clear everything just to be safe?
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
index 105935b..3fb0635 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
@@ -119,7 +119,7 @@
     {
       for (AttributeType t : attributeMap.values())
       {
-        LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+        LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           logger.warn(WARN_SATUACM_ATTR_UNINDEXED, configuration.dn(),
@@ -296,7 +296,7 @@
     {
       for (AttributeType t : newAttributeMap.values())
       {
-        LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+        LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && !b.isIndexed(t, IndexType.EQUALITY))
         {
           LocalizableMessage message =
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
index 140f6d1..661b0c7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
@@ -105,7 +105,7 @@
     AttributeType t = configuration.getSubjectAttribute();
     for (DN baseDN : cfgBaseDNs)
     {
-      LocalBackend b = DirectoryServer.getBackend(baseDN);
+      LocalBackend b = DirectoryServer.getLocalBackend(baseDN);
       if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
       {
         logger.warn(WARN_SATUACM_ATTR_UNINDEXED, configuration.dn(),
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java b/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
index 0cee035..bb58889 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
@@ -297,7 +297,7 @@
 
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+        LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && !b.isIndexed(type, IndexType.EQUALITY))
         {
           isAcceptable = false;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java b/opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java
index b34b017..52e2b5d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java
@@ -158,7 +158,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+        LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           throw new ConfigException(ERR_PLUGIN_UNIQUEATTR_ATTR_UNINDEXED.get(
@@ -690,7 +690,7 @@
     {
       for (DN baseDN : cfgBaseDNs)
       {
-        LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+        LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
         if (b != null && ! b.isIndexed(t, IndexType.EQUALITY))
         {
           unacceptableReasons.add(ERR_PLUGIN_UNIQUEATTR_ATTR_UNINDEXED.get(
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index c1b3da2..5906016 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -3694,7 +3694,7 @@
    */
   private LocalBackend<?> getBackend()
   {
-    return DirectoryServer.getBackend(getBaseDN());
+    return DirectoryServer.getLocalBackend(getBaseDN());
   }
 
   /*
@@ -3761,7 +3761,7 @@
     }
 
     // Check that the base DN is configured as a base-dn of the directory server
-    if (DirectoryServer.getBackend(dn) == null)
+    if (DirectoryServer.getLocalBackend(dn) == null)
     {
       unacceptableReasons.add(ERR_UNKNOWN_DN.get(dn));
       return false;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java b/opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
index 7bd2c36..4c20cd2 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
@@ -299,7 +299,7 @@
       // Find the backend that includes all the branches.
       for(DN includeBranch : includeBranches)
       {
-        LocalBackend<?> locatedBackend = DirectoryServer.getBackend(includeBranch);
+        LocalBackend<?> locatedBackend = DirectoryServer.getLocalBackend(includeBranch);
         if(locatedBackend != null)
         {
           if(backend == null)
@@ -457,7 +457,7 @@
       // Find the backend that includes all the branches.
       for(DN includeBranch : includeBranches)
       {
-        LocalBackend<?> locatedBackend = DirectoryServer.getBackend(includeBranch);
+        LocalBackend<?> locatedBackend = DirectoryServer.getLocalBackend(includeBranch);
         if(locatedBackend != null)
         {
           if(backend == null)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java b/opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java
index a15bf8e..f541842 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java
@@ -166,7 +166,7 @@
     rebuildConfig.setTmpDirectory(tmpDirectory);
     rebuildConfig.setRebuildMode(rebuildMode);
 
-    final LocalBackend<?> backend = DirectoryServer.getBackendWithBaseDN(rebuildConfig.getBaseDN());
+    final LocalBackend<?> backend = DirectoryServer.getLocalBackendWithBaseDN(rebuildConfig.getBaseDN());
     if (backend == null)
     {
       logger.error(ERR_NO_BACKENDS_FOR_BASE, baseDN);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java
index 2e18413..7696218 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java
@@ -26,11 +26,12 @@
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.server.config.client.BackendCfgClient;
 import org.forgerock.opendj.server.config.client.BackendIndexCfgClient;
+import org.forgerock.opendj.server.config.client.LocalBackendCfgClient;
 import org.forgerock.opendj.server.config.client.PluggableBackendCfgClient;
 import org.forgerock.opendj.server.config.client.RootCfgClient;
-import org.forgerock.opendj.server.config.meta.BackendCfgDefn.WritabilityMode;
 import org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn;
 import org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn.IndexType;
+import org.forgerock.opendj.server.config.meta.LocalBackendCfgDefn.WritabilityMode;
 import org.forgerock.opendj.server.config.server.BackendCfg;
 import org.opends.admin.ads.util.ConnectionWrapper;
 import org.opends.guitools.controlpanel.util.Utilities;
@@ -169,7 +170,8 @@
   private static void createBackend(RootCfgClient rootConfiguration, String backendName, Collection<DN> baseDNs,
       ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType) throws Exception
   {
-    final BackendCfgClient backendCfgClient = rootConfiguration.createBackend(backendType, backendName, null);
+    final LocalBackendCfgClient backendCfgClient =
+        (LocalBackendCfgClient) rootConfiguration.createBackend(backendType, backendName, null);
     backendCfgClient.setEnabled(true);
     backendCfgClient.setBaseDN(baseDNs);
     backendCfgClient.setWritabilityMode(WritabilityMode.ENABLED);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 49d6af9..9bc806b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -141,15 +141,15 @@
   /**
    * Process this add operation against a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  public void processLocalAdd(final LocalBackendWorkflowElement wfe)
+  public void processLocalAdd(final LocalBackend<?> backend)
       throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
     ClientConnection clientConnection = getClientConnection();
 
     // Check for a request to cancel this operation.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
index fe93ac5..9d59620 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
@@ -128,12 +128,12 @@
   /**
    * Process this bind operation in a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    */
-  public void processLocalBind(LocalBackendWorkflowElement wfe)
+  public void processLocalBind(LocalBackend<?> backend)
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
 
     // Initialize a number of variables for use during the bind processing.
     clientConnection         = getClientConnection();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
index df0edcb..5f3723d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -104,16 +104,15 @@
   /**
    * Process this compare operation in a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  public void processLocalCompare(LocalBackendWorkflowElement wfe)
+  public void processLocalCompare(LocalBackend<?> backend)
       throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
-
+    this.backend = backend;
     clientConnection  = getClientConnection();
 
     // Check for a request to cancel this operation.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
index 793d031..185f053 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -115,15 +115,15 @@
   /**
    * Process this delete operation in a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  public void processLocalDelete(final LocalBackendWorkflowElement wfe)
+  public void processLocalDelete(final LocalBackend<?> backend)
       throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
 
     clientConnection = getClientConnection();
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
index d8dbe89..9951236 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -155,15 +155,15 @@
   /**
    * Process this modify DN operation in a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  public void processLocalModifyDN(final LocalBackendWorkflowElement wfe)
+  public void processLocalModifyDN(final LocalBackend<?> backend)
       throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
 
     clientConnection = getClientConnection();
 
@@ -270,7 +270,7 @@
       return;
     }
 
-    LocalBackend<?> newBackend = DirectoryServer.getBackend(newDN);
+    LocalBackend<?> newBackend = DirectoryServer.getLocalBackend(newDN);
     if (newBackend == null)
     {
       setResultCode(ResultCode.NO_SUCH_OBJECT);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 909f941..0f6d58a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -263,14 +263,14 @@
   /**
    * Process this modify operation against a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  void processLocalModify(final LocalBackendWorkflowElement wfe) throws CanceledOperationException
+  void processLocalModify(final LocalBackend<?> backend) throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
     this.clientConnection = getClientConnection();
 
     checkIfCanceled(false);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
index 42eb483..81db9b3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -81,15 +81,15 @@
   /**
    * Process this search operation against a local backend.
    *
-   * @param wfe
-   *          The local backend work-flow element.
+   * @param backend
+   *          The backend on which operation is performed.
    * @throws CanceledOperationException
    *           if this operation should be cancelled
    */
-  public void processLocalSearch(LocalBackendWorkflowElement wfe)
+  public void processLocalSearch(LocalBackend<?> backend)
       throws CanceledOperationException
   {
-    this.backend = wfe.getBackend();
+    this.backend = backend;
     this.clientConnection = getClientConnection();
 
     // Check for a request to cancel this operation.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index 046413a..eafd036 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -17,11 +17,8 @@
 package org.opends.server.workflowelement.localbackend;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.TreeMap;
-
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizableMessageBuilder;
 import org.forgerock.i18n.LocalizableMessageDescriptor;
@@ -31,7 +28,6 @@
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.api.AccessControlHandler;
 import org.opends.server.api.LocalBackend;
-import org.opends.server.backends.RootDSEBackend;
 import org.opends.server.controls.LDAPPostReadRequestControl;
 import org.opends.server.controls.LDAPPostReadResponseControl;
 import org.opends.server.controls.LDAPPreReadRequestControl;
@@ -40,6 +36,8 @@
 import org.opends.server.controls.ProxiedAuthV2Control;
 import org.opends.server.core.AccessControlConfigManager;
 import org.opends.server.core.AddOperation;
+import org.opends.server.core.BackendConfigManager;
+import org.opends.server.core.BackendConfigManager.BackendAndName;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.CompareOperation;
 import org.opends.server.core.DeleteOperation;
@@ -61,6 +59,7 @@
 
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.messages.ProtocolMessages.ERR_PROXYAUTH_AUTHZ_NOT_PERMITTED;
+import static org.opends.server.core.DirectoryServer.getRootDSEBackend;
 import static org.opends.server.util.ServerConstants.*;
 
 /**
@@ -209,91 +208,10 @@
 
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
-  /** The backend's baseDN mapped by this object. */
-  private final DN baseDN;
-
-  /** The backend associated with the local workflow element. */
-  private final LocalBackend<?> backend;
-
-  /** The set of local backend workflow elements registered with the server. */
-  private static TreeMap<DN, LocalBackendWorkflowElement> registeredLocalBackends = new TreeMap<>();
-
   /** A lock to guarantee safe concurrent access to the registeredLocalBackends variable. */
   private static final Object registeredLocalBackendsLock = new Object();
 
   /**
-   * Creates a new instance of the local backend workflow element.
-   *
-   * @param baseDN
-   *          the backend's baseDN mapped by this object
-   * @param backend
-   *          the backend associated to that workflow element
-   */
-  private LocalBackendWorkflowElement(DN baseDN, LocalBackend<?> backend)
-  {
-    this.baseDN = baseDN;
-    this.backend  = backend;
-  }
-
-  /**
-   * Indicates whether the workflow element encapsulates a private local backend.
-   *
-   * @return <code>true</code> if the workflow element encapsulates a private
-   *         local backend, <code>false</code> otherwise
-   */
-  public boolean isPrivate()
-  {
-    return this.backend != null && this.backend.isPrivateBackend();
-  }
-
-  /**
-   * Creates and registers a local backend with the server.
-   *
-   * @param baseDN
-   *          the backend's baseDN mapped by this object
-   * @param backend
-   *          the backend to associate with the local backend workflow element
-   * @return the existing local backend workflow element if it was already
-   *         created or a newly created local backend workflow element.
-   */
-  public static LocalBackendWorkflowElement createAndRegister(DN baseDN, LocalBackend<?> backend)
-  {
-    LocalBackendWorkflowElement localBackend = registeredLocalBackends.get(baseDN);
-    if (localBackend == null)
-    {
-      localBackend = new LocalBackendWorkflowElement(baseDN, backend);
-      registerLocalBackend(localBackend);
-    }
-    return localBackend;
-  }
-
-  /**
-   * Removes a local backend that was registered with the server.
-   *
-   * @param baseDN
-   *          the identifier of the workflow to remove
-   */
-  public static void remove(DN baseDN)
-  {
-    deregisterLocalBackend(baseDN);
-  }
-
-  /**
-   * Removes all the local backends that were registered with the server.
-   * This function is intended to be called when the server is shutting down.
-   */
-  public static void removeAll()
-  {
-    synchronized (registeredLocalBackendsLock)
-    {
-      for (LocalBackendWorkflowElement localBackend : registeredLocalBackends.values())
-      {
-        deregisterLocalBackend(localBackend.getBaseDN());
-      }
-    }
-  }
-
-  /**
    * Check if an OID is for a proxy authorization control.
    *
    * @param oid The OID to check
@@ -674,82 +592,45 @@
   }
 
   /**
-   * Registers a local backend with the server.
-   *
-   * @param localBackend  the local backend to register with the server
-   */
-  private static void registerLocalBackend(LocalBackendWorkflowElement localBackend)
-  {
-    synchronized (registeredLocalBackendsLock)
-    {
-      DN baseDN = localBackend.getBaseDN();
-      LocalBackendWorkflowElement existingLocalBackend = registeredLocalBackends.get(baseDN);
-      if (existingLocalBackend == null)
-      {
-        TreeMap<DN, LocalBackendWorkflowElement> newLocalBackends = new TreeMap<>(registeredLocalBackends);
-        newLocalBackends.put(baseDN, localBackend);
-        registeredLocalBackends = newLocalBackends;
-      }
-    }
-  }
-
-  /**
-   * Deregisters a local backend with the server.
-   *
-   * @param baseDN
-   *          the identifier of the local backend to remove
-   */
-  private static void deregisterLocalBackend(DN baseDN)
-  {
-    synchronized (registeredLocalBackendsLock)
-    {
-      LocalBackendWorkflowElement existingLocalBackend = registeredLocalBackends.get(baseDN);
-      if (existingLocalBackend != null)
-      {
-        TreeMap<DN, LocalBackendWorkflowElement> newLocalBackends = new TreeMap<>(registeredLocalBackends);
-        newLocalBackends.remove(baseDN);
-        registeredLocalBackends = newLocalBackends;
-      }
-    }
-  }
-
-  /**
-   * Executes the workflow for an operation.
+   * Executes an operation on the provided backend.
    *
    * @param operation
    *          the operation to execute
+   * @param backend
+   *          the backend on which operation must be executed
    * @throws CanceledOperationException
    *           if this operation should be canceled
    */
-  private void execute(Operation operation) throws CanceledOperationException {
+  private static void executeOperation(Operation operation, LocalBackend<?> backend)
+      throws CanceledOperationException {
     switch (operation.getOperationType())
     {
       case BIND:
-        new LocalBackendBindOperation((BindOperation) operation).processLocalBind(this);
+        new LocalBackendBindOperation((BindOperation) operation).processLocalBind(backend);
         break;
 
       case SEARCH:
-        new LocalBackendSearchOperation((SearchOperation) operation).processLocalSearch(this);
+        new LocalBackendSearchOperation((SearchOperation) operation).processLocalSearch(backend);
         break;
 
       case ADD:
-        new LocalBackendAddOperation((AddOperation) operation).processLocalAdd(this);
+        new LocalBackendAddOperation((AddOperation) operation).processLocalAdd(backend);
         break;
 
       case DELETE:
-        new LocalBackendDeleteOperation((DeleteOperation) operation).processLocalDelete(this);
+        new LocalBackendDeleteOperation((DeleteOperation) operation).processLocalDelete(backend);
         break;
 
       case MODIFY:
-        new LocalBackendModifyOperation((ModifyOperation) operation).processLocalModify(this);
+        new LocalBackendModifyOperation((ModifyOperation) operation).processLocalModify(backend);
         break;
 
       case MODIFY_DN:
-        new LocalBackendModifyDNOperation((ModifyDNOperation) operation).processLocalModifyDN(this);
+        new LocalBackendModifyDNOperation((ModifyDNOperation) operation).processLocalModifyDN(backend);
         break;
 
       case COMPARE:
-        new LocalBackendCompareOperation((CompareOperation) operation).processLocalCompare(this);
+        new LocalBackendCompareOperation((CompareOperation) operation).processLocalCompare(backend);
         break;
 
       case ABANDON:
@@ -791,28 +672,6 @@
   }
 
   /**
-   * Provides the workflow element identifier.
-   *
-   * @return the workflow element identifier
-   */
-  public DN getBaseDN()
-  {
-    return baseDN;
-  }
-
-  /**
-   * Gets the backend associated with this local backend workflow
-   * element.
-   *
-   * @return The backend associated with this local backend workflow
-   *         element.
-   */
-  public LocalBackend<?> getBackend()
-  {
-    return backend;
-  }
-
-  /**
    * Checks if an update operation can be performed against a backend. The
    * operation will be rejected based on the server and backend writability
    * modes.
@@ -873,8 +732,10 @@
    */
   public static boolean execute(Operation operation, DN entryDN) throws CanceledOperationException
   {
-    LocalBackendWorkflowElement workflow = getLocalBackendWorkflowElement(entryDN);
-    if (workflow == null)
+    BackendAndName backendAndName = entryDN.isRootDN()
+        ? new BackendAndName(getRootDSEBackend(), entryDN) : getBackendManager().getLocalBackend(entryDN);
+
+    if (backendAndName == null)
     {
       // We have found no backend for the requested base DN,
       // just return a no such entry result code and stop the processing.
@@ -885,213 +746,55 @@
       return false;
     }
 
-    if (workflow.getBaseDN().isRootDN())
+    executeOperation(operation, backendAndName.getBackend());
+
+    if (!entryDN.isRootDN())
     {
-      executeOnRootDSE(operation, workflow);
+      // For subtree search operation we need to go through the subordinate nodes.
+      if (operation.getOperationType() == OperationType.SEARCH)
+      {
+        executeSearchOnSubordinates((SearchOperation) operation, backendAndName.getBaseDn());
+      }
     }
-    else
-    {
-      executeOnNonRootDSE(operation, workflow);
-    }
+
     return true;
   }
 
-  private static LocalBackendWorkflowElement getLocalBackendWorkflowElement(DN entryDN)
+  private static BackendConfigManager getBackendManager()
   {
-    if (entryDN.isRootDN())
-    {
-      return registeredLocalBackends.get(entryDN);
-    }
-    /*
-     * Try to minimize the number of lookups in the Map to find the backend containing the entry.
-     * If the DN contains many RDNs it is faster to iterate through the list of registered backends,
-     * otherwise iterating through the parents requires less lookups. It also avoids some attacks
-     * where we would spend time going through the list of all parents to finally decide the
-     * baseDN is absent.
-     */
-    if (entryDN.size() <= registeredLocalBackends.size())
-    {
-      while (!entryDN.isRootDN())
-      {
-        final LocalBackendWorkflowElement workflow = registeredLocalBackends.get(entryDN);
-        if (workflow != null)
-        {
-          return workflow;
-        }
-        entryDN = entryDN.parent();
-      }
-      return null;
-    }
-    else
-    {
-      LocalBackendWorkflowElement workflow = null;
-      int currentSize = 0;
-      for (DN backendDN : registeredLocalBackends.keySet())
-      {
-        if (entryDN.isSubordinateOrEqualTo(backendDN) && backendDN.size() > currentSize)
-        {
-          workflow = registeredLocalBackends.get(backendDN);
-          currentSize = backendDN.size();
-        }
-      }
-      return workflow;
-    }
+    return DirectoryServer.getInstance().getServerContext().getBackendManager();
   }
 
   /**
-   * Executes an operation on the root DSE entry.
-   *
-   * @param operation
-   *          the operation to execute
-   * @param workflow
-   *          the workflow where to execute the operation
-   * @throws CanceledOperationException
-   *           if this operation should be cancelled.
-   */
-  private static void executeOnRootDSE(Operation operation, LocalBackendWorkflowElement workflow)
-      throws CanceledOperationException
-  {
-    OperationType operationType = operation.getOperationType();
-    if (operationType == OperationType.SEARCH)
-    {
-      executeSearch((SearchOperation) operation, workflow);
-    }
-    else
-    {
-      workflow.execute(operation);
-    }
-  }
-
-  /**
-   * Executes a search operation on the the root DSE entry.
-   *
-   * @param searchOp
-   *          the operation to execute
-   * @param workflow
-   *          the workflow where to execute the operation
-   * @throws CanceledOperationException
-   *           if this operation should be cancelled.
-   */
-  private static void executeSearch(SearchOperation searchOp, LocalBackendWorkflowElement workflow)
-      throws CanceledOperationException
-  {
-    // Keep a the original search scope because we will alter it in the operation
-    SearchScope originalScope = searchOp.getScope();
-
-    // Search base?
-    // The root DSE entry itself is never returned unless the operation
-    // is a search base on the null suffix.
-    if (originalScope == SearchScope.BASE_OBJECT)
-    {
-      workflow.execute(searchOp);
-      return;
-    }
-
-    // Create a workflow result code in case we need to perform search in
-    // subordinate workflows.
-    SearchResultCode searchResultCode =
-        new SearchResultCode(searchOp.getResultCode(), searchOp.getErrorMessage());
-
-    // The search scope is not 'base', so let's do a search on all the public
-    // naming contexts with appropriate new search scope and new base DN.
-    SearchScope newScope = elaborateScopeForSearchInSubordinates(originalScope);
-    searchOp.setScope(newScope);
-    DN originalBaseDN = searchOp.getBaseDN();
-
-    for (LocalBackendWorkflowElement subordinate : getRootDSESubordinates())
-    {
-      // We have to change the operation request base DN to match the
-      // subordinate workflow base DN. Otherwise the workflow will
-      // return a no such entry result code as the operation request
-      // base DN is a superior of the workflow base DN!
-      DN ncDN = subordinate.getBaseDN();
-
-      // Set the new request base DN then do execute the operation
-      // in the naming context workflow.
-      searchOp.setBaseDN(ncDN);
-      execute(searchOp, ncDN);
-      boolean sendReferenceEntry = searchResultCode.elaborateGlobalResultCode(
-          searchOp.getResultCode(), searchOp.getErrorMessage());
-      if (sendReferenceEntry)
-      {
-        // TODO jdemendi - turn a referral result code into a reference entry
-        // and send the reference entry to the client application
-      }
-    }
-
-    // Now restore the original request base DN and original search scope
-    searchOp.setBaseDN(originalBaseDN);
-    searchOp.setScope(originalScope);
-
-    // If the result code is still uninitialized (ie no naming context),
-    // we should return NO_SUCH_OBJECT
-    searchResultCode.elaborateGlobalResultCode(
-        ResultCode.NO_SUCH_OBJECT, new LocalizableMessageBuilder(LocalizableMessage.EMPTY));
-
-    // Set the operation result code and error message
-    searchOp.setResultCode(searchResultCode.resultCode);
-    searchOp.setErrorMessage(searchResultCode.errorMessage);
-  }
-
-  private static Collection<LocalBackendWorkflowElement> getRootDSESubordinates()
-  {
-    final RootDSEBackend rootDSEBackend = DirectoryServer.getRootDSEBackend();
-
-    final List<LocalBackendWorkflowElement> results = new ArrayList<>();
-    for (DN subordinateBaseDN : rootDSEBackend.getSubordinateBaseDNs().keySet())
-    {
-      results.add(registeredLocalBackends.get(subordinateBaseDN));
-    }
-    return results;
-  }
-
-  private static void executeOnNonRootDSE(Operation operation, LocalBackendWorkflowElement workflow)
-      throws CanceledOperationException
-  {
-    workflow.execute(operation);
-
-    // For subtree search operation we need to go through the subordinate nodes.
-    if (operation.getOperationType() == OperationType.SEARCH)
-    {
-      executeSearchOnSubordinates((SearchOperation) operation, workflow);
-    }
-  }
-
-  /**
-   * Executes a search operation on the subordinate workflows.
+   * Executes a search operation on the subordinates of backend corresponding to provided base DN.
    *
    * @param searchOp
    *          the search operation to execute
-   * @param workflow
-   *          the workflow element
+   * @param baseDN
+   *          base DN to search
    * @throws CanceledOperationException
    *           if this operation should be canceled.
    */
-  private static void executeSearchOnSubordinates(SearchOperation searchOp, LocalBackendWorkflowElement workflow)
+  private static void executeSearchOnSubordinates(SearchOperation searchOp, DN baseDN)
       throws CanceledOperationException {
-    // If the scope of the search is 'base' then it's useless to search
-    // in the subordinate workflows.
     SearchScope originalScope = searchOp.getScope();
     if (originalScope == SearchScope.BASE_OBJECT)
     {
       return;
     }
 
-    // Elaborate the new search scope before executing the search operation
-    // in the subordinate workflows.
     SearchScope newScope = elaborateScopeForSearchInSubordinates(originalScope);
     searchOp.setScope(newScope);
 
-    // Let's search in the subordinate workflows.
     SearchResultCode searchResultCode = new SearchResultCode(searchOp.getResultCode(), searchOp.getErrorMessage());
     DN originalBaseDN = searchOp.getBaseDN();
-    for (LocalBackendWorkflowElement subordinate : getSubordinates(workflow))
+    for (BackendAndName subordinate : getBackendManager().getSubordinateBackends(baseDN))
     {
       // We have to change the operation request base DN to match the
       // subordinate workflow base DN. Otherwise the workflow will
       // return a no such entry result code as the operation request
       // base DN is a superior of the subordinate workflow base DN.
-      DN subordinateDN = subordinate.getBaseDN();
+      DN subordinateDN = subordinate.getBaseDn();
 
       // If the new search scope is 'base' and the search base DN does not
       // map the subordinate workflow then skip the subordinate workflow.
@@ -1130,25 +833,6 @@
     searchOp.setErrorMessage(searchResultCode.errorMessage);
   }
 
-  private static Collection<LocalBackendWorkflowElement> getSubordinates(LocalBackendWorkflowElement workflow)
-  {
-    final DN baseDN = workflow.getBaseDN();
-    final LocalBackend<?> backend = workflow.getBackend();
-
-    final ArrayList<LocalBackendWorkflowElement> results = new ArrayList<>();
-    for (LocalBackend<?> subordinate : backend.getSubordinateBackends())
-    {
-      for (DN subordinateDN : subordinate.getBaseDNs())
-      {
-        if (subordinateDN.isSubordinateOrEqualTo(baseDN))
-        {
-          results.add(registeredLocalBackends.get(subordinateDN));
-        }
-      }
-    }
-    return results;
-  }
-
   /**
    * Elaborates a new search scope according to the current search scope. The
    * new scope is intended to be used for searches on subordinate workflows.
@@ -1195,12 +879,4 @@
     }
     return null;
   }
-
-  @Override
-  public String toString()
-  {
-    return getClass().getSimpleName()
-        + " backend=" + this.backend
-        + " baseDN=" + this.baseDN;
-  }
 }
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/backend.properties b/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
index 0e14088..ac5db33 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
@@ -1097,3 +1097,6 @@
 ERR_BACKEND_FAULTY_CRYPTO_TRANSFORMATION_608=Error while enabling confidentiality with cipher %s, %d bits: %s
 ERR_IMPORT_DUPLICATE_ENTRY_609=The import has been aborted because the data to be imported contains duplicate \
  copies of entry '%s'
+ERR_ROOTDSE_NOT_SUPPORTED_SCOPE_610=Unwilling to perform a search \
+ (connection ID %d, operation ID %d) with a scope of "%s" in the root DSE \
+ backend. Only the BASE scope is supported for the root DSE backend. 
\ No newline at end of file
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java
index 0a8cfcb..8c08a50 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java
@@ -472,7 +472,7 @@
     String taskSchedule = "00 * * " + scheduledMonth + " *";
 
     TaskBackend taskBackend =
-      (TaskBackend) DirectoryServer.getBackend(DN.valueOf("cn=tasks"));
+      (TaskBackend) DirectoryServer.getLocalBackend(DN.valueOf("cn=tasks"));
     long tasksCountBefore = taskBackend.getNumberOfEntriesInBaseDN(DN.valueOf("cn=Scheduled Tasks,cn=tasks"));
 
     assertTrue(addRecurringTask(taskID, taskSchedule));
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java
index 58191f4..7a8f72d 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java
@@ -72,7 +72,7 @@
   /** Some of the tests disable the backends, so we reenable them here. */
   @AfterMethod(alwaysRun=true)
   public void reenableBackend() throws DirectoryException {
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     b.setWritabilityMode(WritabilityMode.ENABLED);
   }
 
@@ -1209,7 +1209,7 @@
          "cn: Test User",
          "userPassword: password");
 
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     b.setWritabilityMode(WritabilityMode.DISABLED);
 
     AddOperation addOperation = getRootConnection().processAdd(entry);
@@ -1241,7 +1241,7 @@
          "cn: Test User",
          "userPassword: password");
 
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     AddOperation addOperation = getRootConnection().processAdd(entry);
@@ -1266,7 +1266,7 @@
     {
       conn.bind("cn=Directory Manager", "password");
 
-      LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
+      LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
       b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
       long addRequests  = ldapStatistics.getAddRequests();
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java
index b448607..0dae2c1 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java
@@ -129,7 +129,7 @@
 
     processAdd(backendEntry);
     assertNull(DirectoryServer.getBackend(backendID));
-    assertNull(DirectoryServer.getBackendWithBaseDN(baseDN));
+    assertNull(DirectoryServer.getLocalBackendWithBaseDN(baseDN));
 
     DeleteOperation deleteOperation = getRootConnection().processDelete(backendEntry.getName());
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
@@ -234,7 +234,7 @@
     LocalBackend<?> childBackend = DirectoryServer.getBackend(childBackendID);
     assertNotNull(childBackend);
     assertEquals(childBackend,
-                 DirectoryServer.getBackendWithBaseDN(childBaseDN));
+                 DirectoryServer.getLocalBackendWithBaseDN(childBaseDN));
     assertNotNull(childBackend.getParentBackend());
     assertEquals(parentBackend, childBackend.getParentBackend());
     assertEquals(parentBackend.getSubordinateBackends().length, 1);
@@ -305,7 +305,7 @@
     LocalBackend<?> parentBackend = DirectoryServer.getBackend(parentBackendID);
     assertNotNull(parentBackend);
     assertEquals(parentBackend,
-                 DirectoryServer.getBackendWithBaseDN(parentBaseDN));
+                 DirectoryServer.getLocalBackendWithBaseDN(parentBaseDN));
     assertNotNull(childBackend.getParentBackend());
     assertEquals(parentBackend, childBackend.getParentBackend());
     assertEquals(parentBackend.getSubordinateBackends().length, 1);
@@ -336,7 +336,7 @@
   private void assertBackend(DN baseDN, LocalBackend<?> backend) throws DirectoryException
   {
     assertNotNull(backend);
-    assertEquals(backend, DirectoryServer.getBackendWithBaseDN(baseDN));
+    assertEquals(backend, DirectoryServer.getLocalBackendWithBaseDN(baseDN));
     assertFalse(backend.entryExists(baseDN));
     assertNull(backend.getParentBackend());
     assertEquals(backend.getSubordinateBackends().length, 0);
@@ -377,7 +377,7 @@
     LocalBackend<?> grandchildBackend = DirectoryServer.getBackend(grandchildBackendID);
     assertNotNull(grandchildBackend);
     assertEquals(grandchildBackend,
-                 DirectoryServer.getBackendWithBaseDN(grandchildBaseDN));
+                 DirectoryServer.getLocalBackendWithBaseDN(grandchildBaseDN));
     assertNotNull(grandchildBackend.getParentBackend());
     assertEquals(grandchildBackend.getParentBackend(), parentBackend);
     assertEquals(parentBackend.getSubordinateBackends().length, 1);
@@ -480,7 +480,7 @@
       LocalBackend<?> grandchildBackend) throws DirectoryException
   {
     assertNotNull(childBackend);
-    assertEquals(childBackend, DirectoryServer.getBackendWithBaseDN(childBaseDN));
+    assertEquals(childBackend, DirectoryServer.getLocalBackendWithBaseDN(childBaseDN));
     assertNotNull(childBackend.getParentBackend());
     assertEquals(parentBackend, childBackend.getParentBackend());
     assertEquals(parentBackend.getSubordinateBackends().length, 1);
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java
index c2e5432..1df2b10 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java
@@ -58,7 +58,7 @@
   /** Some of the tests disable the backends, so we reenable them here. */
   @AfterMethod(alwaysRun=true)
   public void reenableBackend() throws DirectoryException {
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     b.setWritabilityMode(WritabilityMode.ENABLED);
   }
 
@@ -569,7 +569,7 @@
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LocalBackend<?> backend = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     backend.setWritabilityMode(WritabilityMode.DISABLED);
 
     DeleteOperation deleteOperation = processDeleteRaw("o=test");
@@ -591,7 +591,7 @@
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LocalBackend<?> backend = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     DeleteOperation deleteOperation = processDeleteRaw("o=test");
@@ -613,7 +613,7 @@
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LocalBackend<?> backend = DirectoryServer.getBackend(DN.valueOf("o=test"));
+    LocalBackend<?> backend = DirectoryServer.getLocalBackend(DN.valueOf("o=test"));
     backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     String[] args = getArgs("o=test");
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java
index 104c7e6..4e8ae51 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java
@@ -96,7 +96,7 @@
     for (Object[] backendBaseDN2 : getBaseDNs())
     {
       final DN baseDN = DN.valueOf(backendBaseDN2[0].toString());
-      LocalBackend<?> b = DirectoryServer.getBackend(baseDN);
+      LocalBackend<?> b = DirectoryServer.getLocalBackend(baseDN);
       b.setWritabilityMode(WritabilityMode.ENABLED);
     }
   }
@@ -2429,7 +2429,7 @@
          "mail: foo",
          "employeeNumber: 1");
 
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf(baseDN));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf(baseDN));
     b.setWritabilityMode(WritabilityMode.DISABLED);
 
     RawModification mod = newRawModification(ADD, "objectClass", "extensibleObject");
@@ -2467,7 +2467,7 @@
          "mail: foo",
          "employeeNumber: 1");
 
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf(baseDN));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf(baseDN));
     b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     RawModification mod = newRawModification(ADD, "objectClass", "extensibleObject");
@@ -2505,7 +2505,7 @@
          "mail: foo",
          "employeeNumber: 1");
 
-    LocalBackend<?> b = DirectoryServer.getBackend(DN.valueOf(baseDN));
+    LocalBackend<?> b = DirectoryServer.getLocalBackend(DN.valueOf(baseDN));
     b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     try (RemoteConnection conn = new RemoteConnection("localhost", TestCaseUtils.getServerLdapPort()))
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java
index c532eb7..a3a1de4 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java
@@ -95,7 +95,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertFalse(cache.containsEntry(testEntriesList.get(0).getName()),
       "Not expected to find " + testEntriesList.get(0).getName() +
@@ -129,7 +129,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertNull(cache.getEntry(testEntriesList.get(0).getName()),
       "Not expected to find " + testEntriesList.get(0).getName() +
@@ -163,7 +163,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertNull(cache.getEntry(testEntriesList.get(0).getName()),
       "Not expected to find " + testEntriesList.get(0).getName() +
@@ -197,7 +197,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertNull(cache.getEntry(b, -1),
       "Not expected to find entry id " + -1 +
@@ -230,7 +230,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertEquals(cache.getEntryID(testEntriesList.get(0).getName()), -1,
       "Not expected to find " + testEntriesList.get(0).getName() +
@@ -263,7 +263,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     cache.putEntry(testEntriesList.get(0), b, 1);
 
@@ -296,7 +296,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     assertTrue(cache.putEntryIfAbsent(testEntriesList.get(0), b, 1),
       "Not expected to find " + testEntriesList.get(0).getName() +
@@ -337,7 +337,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     cache.removeEntry(testEntriesList.get(0).getName());
     cache.putEntry(testEntriesList.get(0), b, 1);
@@ -372,7 +372,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     cache.clear();
     cache.putEntry(testEntriesList.get(0), b, 1);
@@ -407,8 +407,8 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
-    String c = DirectoryServer.getBackend(DN.valueOf("cn=config")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
+    String c = DirectoryServer.getLocalBackend(DN.valueOf("cn=config")).getBackendID();
 
     cache.clearBackend(b);
     cache.putEntry(testEntriesList.get(0), b, 1);
@@ -449,8 +449,8 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
-    String c = DirectoryServer.getBackend(DN.valueOf("cn=config")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
+    String c = DirectoryServer.getLocalBackend(DN.valueOf("cn=config")).getBackendID();
 
     cache.putEntry(testEntriesList.get(0), b, 1);
     Entry testEntry = testEntriesList.get(1);
@@ -510,7 +510,7 @@
   public void testCacheConcurrency()
          throws Exception
   {
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     for(int loops = 0; loops < CONCURRENCYLOOPS; loops++) {
       for(int i = 0; i < NUMTESTENTRIES; i++) {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java
index 1a6f96a..01fc19d 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java
@@ -361,7 +361,7 @@
       cache.toVerboseString());
 
     TestCaseUtils.initializeTestBackend(false);
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     // Spread test entries among all cache levels via default cache.
     for (int i = 0; i < NUMTESTENTRIES; i++) {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java
index 1ab6785..41a0853 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java
@@ -252,7 +252,7 @@
       "Expected empty cache.  " + "Cache contents:" + ServerConstants.EOL +
       cache.toVerboseString());
 
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     for(int i = 0; i < super.NUMTESTENTRIES; i++ ) {
       super.cache.putEntry(super.testEntriesList.get(i), b, i);
@@ -322,7 +322,7 @@
       "Expected empty cache.  " + "Cache contents:" + ServerConstants.EOL +
       cache.toVerboseString());
 
-    String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID();
+    String b = DirectoryServer.getLocalBackend(DN.valueOf("o=test")).getBackendID();
 
     for(int i = 0; i < super.NUMTESTENTRIES; i++ ) {
       super.cache.putEntry(super.testEntriesList.get(i), b, i);
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java
index 2f7e525..78b8cb5 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java
@@ -108,7 +108,7 @@
   @Test(enabled=false) // This isn't a test method, but TestNG thinks it is.
   public static Task getTask(final DN taskEntryDN) throws Exception
   {
-    final TaskBackend taskBackend = (TaskBackend) DirectoryServer.getBackend(DN.valueOf("cn=tasks"));
+    final TaskBackend taskBackend = (TaskBackend) DirectoryServer.getLocalBackend(DN.valueOf("cn=tasks"));
 
     TestTimer timer = new TestTimer.Builder()
       .maxSleep(10, SECONDS)
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java
index 10e5f5d..7749801 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java
@@ -2378,7 +2378,7 @@
   private Task getCompletedTask(DN taskEntryDN) throws Exception
   {
     TaskBackend taskBackend =
-         (TaskBackend) DirectoryServer.getBackend(DN.valueOf("cn=tasks"));
+         (TaskBackend) DirectoryServer.getLocalBackend(DN.valueOf("cn=tasks"));
     Task task = taskBackend.getScheduledTask(taskEntryDN);
     if (task == null)
     {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java b/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
index 197af4c..8153115 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
@@ -40,7 +40,8 @@
   public Object[][] getNamingContexts() {
     ArrayList<DN> contextList = new ArrayList<>();
     contextList.addAll(DirectoryServer.getPublicNamingContexts().keySet());
-    contextList.addAll(DirectoryServer.getPrivateNamingContexts().keySet());
+    contextList.addAll(DirectoryServer.getInstance().getServerContext().getBackendManager().
+        getPrivateNamingContexts().keySet());
 
     Object[][] contextArray = new Object[contextList.size()][1];
     for (int i = 0;i < contextArray.length;i++) {

--
Gitblit v1.10.0