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

Nicolas Capponi
07.48.2016 b68d5cc1a6352dddd67adf06b18c3690c683debe
OPENDJ-3417 Move responsability of backends management to BackendConfigManager
1 files deleted
48 files modified
2568 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/admin/ads/ADSContextHelper.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java 7 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/api/Backend.java 47 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/api/BackendInitializationListener.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java 51 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/ConfigurationBackend.java 27 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java 266 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/BackendConfigManager.java 907 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/BaseDnRegistry.java 456 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java 193 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/LockFileManager.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java 7 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerSync.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/ExactMatchIdentityMapper.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FIFOEntryCache.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FingerprintCertificateMapper.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java 6 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java 6 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/RegularExpressionIdentityMapper.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/SoftReferenceEntryCache.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/plugins/UniqueAttributePlugin.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/RebuildTask.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java 6 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java 9 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java 10 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java 396 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/messages/org/opends/messages/backend.properties 3 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/task/TaskBackendTestCase.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/core/AddOperationTestCase.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/core/BackendConfigManagerTestCase.java 12 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/core/DeleteOperationTestCase.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/CommonEntryCacheTestCase.java 28 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/DefaultEntryCacheTestCase.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/FIFOEntryCacheTestCase.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/tasks/TasksTestCase.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/types/PrivilegeTestCase.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java 3 ●●●● patch | view | raw | blame | history
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();
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)
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);
}
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;
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);
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
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
    }
  }
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;
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;
    }
  }
}
opendj-server-legacy/src/main/java/org/opends/server/core/BaseDnRegistry.java
File was deleted
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();
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());
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();
}
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();
    }
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(
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;
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(
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();
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());
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(
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?
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 =
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(),
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;
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(
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;
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)
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);
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);
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.
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();
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.
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();
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);
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);
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.
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;
  }
}
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.
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));
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();
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);
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");
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()))
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++) {
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++) {
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);
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)
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)
    {
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++) {