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

kenneth_suter
24.15.2007 d75c93322e20bdad4cc2c57bd784a03d95fd3105
Creation of a base DN registry for managing the base DN and naming context to backend maps.  Supports a 'test' mode that can be used to test whether registration/deregistration operations will be acceptable.
1 files added
13 files modified
961 ■■■■■ changed files
opends/src/server/org/opends/server/backends/BackupBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/LDIFBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MemoryBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MonitorBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/TrustStoreBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/TaskBackend.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/BackendConfigManager.java 14 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/BaseDnRegistry.java 516 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 380 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java 5 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java 4 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/BackupBackend.java
@@ -213,7 +213,7 @@
    // Register the backup base as a private suffix.
    try
    {
      DirectoryServer.registerBaseDN(backupBaseDN, this, true, false);
      DirectoryServer.registerBaseDN(backupBaseDN, this, true);
    }
    catch (Exception e)
    {
@@ -247,7 +247,7 @@
    try
    {
      DirectoryServer.deregisterBaseDN(backupBaseDN, false);
      DirectoryServer.deregisterBaseDN(backupBaseDN);
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/backends/LDIFBackend.java
@@ -170,7 +170,7 @@
    {
      try
      {
        DirectoryServer.registerBaseDN(dn, this, false, false);
        DirectoryServer.registerBaseDN(dn, this, false);
      }
      catch (Exception e)
      {
@@ -375,7 +375,7 @@
      {
        try
        {
          DirectoryServer.deregisterBaseDN(dn, false);
          DirectoryServer.deregisterBaseDN(dn);
        }
        catch (Exception e)
        {
opends/src/server/org/opends/server/backends/MemoryBackend.java
@@ -203,7 +203,7 @@
    {
      try
      {
        DirectoryServer.registerBaseDN(dn, this, false, false);
        DirectoryServer.registerBaseDN(dn, this, false);
      }
      catch (Exception e)
      {
@@ -243,7 +243,7 @@
    {
      try
      {
        DirectoryServer.deregisterBaseDN(dn, false);
        DirectoryServer.deregisterBaseDN(dn);
      }
      catch (Exception e)
      {
opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -247,7 +247,7 @@
    // Register the monitor base as a private suffix.
    try
    {
      DirectoryServer.registerBaseDN(baseMonitorDN, this, true, false);
      DirectoryServer.registerBaseDN(baseMonitorDN, this, true);
    }
    catch (Exception e)
    {
@@ -281,7 +281,7 @@
    try
    {
      DirectoryServer.deregisterBaseDN(baseMonitorDN, false);
      DirectoryServer.deregisterBaseDN(baseMonitorDN);
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -366,7 +366,7 @@
    {
      try
      {
        DirectoryServer.registerBaseDN(baseDNs[i], this, true, false);
        DirectoryServer.registerBaseDN(baseDNs[i], this, true);
      }
      catch (Exception e)
      {
@@ -514,7 +514,7 @@
    {
      try
      {
        DirectoryServer.deregisterBaseDN(baseDN, false);
        DirectoryServer.deregisterBaseDN(baseDN);
      }
      catch (Exception e)
      {
@@ -5156,7 +5156,7 @@
      {
        try
        {
          DirectoryServer.deregisterBaseDN(dn, false);
          DirectoryServer.deregisterBaseDN(dn);
          messages.add(INFO_SCHEMA_DEREGISTERED_BASE_DN.get(
                  String.valueOf(dn)));
        }
@@ -5179,7 +5179,7 @@
      {
        try
        {
          DirectoryServer.registerBaseDN(dn, this, true, false);
          DirectoryServer.registerBaseDN(dn, this, true);
          messages.add(INFO_SCHEMA_REGISTERED_BASE_DN.get(String.valueOf(dn)));
        }
        catch (Exception e)
opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -366,7 +366,7 @@
    // Register the trust store base as a private suffix.
    try
    {
      DirectoryServer.registerBaseDN(baseDN, this, true, false);
      DirectoryServer.registerBaseDN(baseDN, this, true);
    }
    catch (Exception e)
    {
@@ -392,7 +392,7 @@
    try
    {
      DirectoryServer.deregisterBaseDN(baseDN, false);
      DirectoryServer.deregisterBaseDN(baseDN);
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -340,7 +340,7 @@
    {
      try
      {
        DirectoryServer.registerBaseDN(dn, this, false, false);
        DirectoryServer.registerBaseDN(dn, this, false);
      }
      catch (Exception e)
      {
@@ -386,7 +386,7 @@
    {
      try
      {
        DirectoryServer.deregisterBaseDN(dn, false);
        DirectoryServer.deregisterBaseDN(dn);
      }
      catch (Exception e)
      {
@@ -1571,7 +1571,7 @@
          if (!found)
          {
            // The base DN was deleted.
            DirectoryServer.deregisterBaseDN(baseDN, false);
            DirectoryServer.deregisterBaseDN(baseDN);
            EntryContainer ec =
                rootContainer.unregisterEntryContainer(baseDN);
            ec.delete();
@@ -1588,7 +1588,7 @@
              EntryContainer ec =
                  rootContainer.openEntryContainer(baseDN, null);
              rootContainer.registerEntryContainer(baseDN, ec);
              DirectoryServer.registerBaseDN(baseDN, this, false, false);
              DirectoryServer.registerBaseDN(baseDN, this, false);
            }
            catch (Exception e)
            {
opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -255,7 +255,7 @@
    // Register the task base as a private suffix.
    try
    {
      DirectoryServer.registerBaseDN(taskRootDN, this, true, false);
      DirectoryServer.registerBaseDN(taskRootDN, this, true);
    }
    catch (Exception e)
    {
@@ -318,7 +318,7 @@
    try
    {
      DirectoryServer.deregisterBaseDN(taskRootDN, false);
      DirectoryServer.deregisterBaseDN(taskRootDN);
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/core/BackendConfigManager.java
@@ -402,11 +402,14 @@
        }
      }
      for (DN dn : addedDNs)
      // 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)
      {
        try
        {
          DirectoryServer.registerBaseDN(dn, backend, false, true);
          reg.deregisterBaseDN(dn);
        }
        catch (DirectoryException de)
        {
@@ -420,11 +423,11 @@
        }
      }
      for (DN dn : removedDNs)
      for (DN dn : addedDNs)
      {
        try
        {
          DirectoryServer.deregisterBaseDN(dn, true);
          reg.registerBaseDN(dn, backend, false);
        }
        catch (DirectoryException de)
        {
@@ -928,11 +931,12 @@
    // Make sure that all of the base DNs are acceptable for use in the server.
    BaseDnRegistry reg = DirectoryServer.copyBaseDnRegistry();
    for (DN baseDN : baseDNs)
    {
      try
      {
        DirectoryServer.registerBaseDN(baseDN, backend, false, true);
        reg.registerBaseDN(baseDN, backend, false);
      }
      catch (DirectoryException de)
      {
opends/src/server/org/opends/server/core/BaseDnRegistry.java
New file
@@ -0,0 +1,516 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ResultCode;
import org.opends.server.api.Backend;
import static org.opends.server.util.Validator.ensureNotNull;
import org.opends.messages.Message;
import static org.opends.messages.CoreMessages.*;
import java.util.TreeMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
/**
 * Registry for maintaining the set of registered base DN's, assocated
 * backends and naming context information.
 */
public class BaseDnRegistry {
  // The set of base DNs registered with the server.
  private TreeMap<DN,Backend> baseDNs;
  // The set of private naming contexts registered with the server.
  private TreeMap<DN,Backend> privateNamingContexts;
  // The set of public naming contexts registered with the server.
  private TreeMap<DN,Backend> publicNamingContexts;
  // Indicates whether or not 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 assocated
   * @param  isPrivate indicates whether or not this base DN is private
   * @return list of error messages generated by registering the base DN
   *         that should be logged if the changes to this registry are
   *         committed to the server
   * @throws DirectoryException if the base DN cannot be registered
   */
  public List<Message> registerBaseDN(DN baseDN, Backend backend,
                                      boolean isPrivate)
          throws DirectoryException
  {
    List<Message> errors = new LinkedList<Message>();
    // Check to see if the base DN is already registered with the server.
    Backend existingBackend = baseDNs.get(baseDN);
    if (existingBackend != null)
    {
      Message message = ERR_REGISTER_BASEDN_ALREADY_EXISTS.
          get(String.valueOf(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<DN>();
    for (DN dn : baseDNs.keySet())
    {
      Backend b = baseDNs.get(dn);
      if (b.equals(backend))
      {
        otherBaseDNs.add(dn);
        if (baseDN.isAncestorOf(dn) || baseDN.isDescendantOf(dn))
        {
          Message message = ERR_REGISTER_BASEDN_HIERARCHY_CONFLICT.
              get(String.valueOf(baseDN), backend.getBackendID(),
                  String.valueOf(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.
    Backend superiorBackend = null;
    DN      superiorBaseDN        ;
    DN      parentDN        = baseDN.getParent();
    while (parentDN != null)
    {
      if (baseDNs.containsKey(parentDN))
      {
        superiorBaseDN  = parentDN;
        superiorBackend = baseDNs.get(parentDN);
        for (DN dn : otherBaseDNs)
        {
          if (! dn.isDescendantOf(superiorBaseDN))
          {
            Message message = ERR_REGISTER_BASEDN_DIFFERENT_PARENT_BASES.
                get(String.valueOf(baseDN), backend.getBackendID(),
                    String.valueOf(dn));
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message);
          }
        }
        break;
      }
      parentDN = parentDN.getParent();
    }
    if (superiorBackend == null)
    {
      if (backend.getParentBackend() != null)
      {
        Message message = ERR_REGISTER_BASEDN_NEW_BASE_NOT_SUBORDINATE.
            get(String.valueOf(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<Backend> subordinateBackends = new LinkedList<Backend>();
    LinkedList<DN>      subordinateBaseDNs  = new LinkedList<DN>();
    for (DN dn : baseDNs.keySet())
    {
      Backend b = baseDNs.get(dn);
      parentDN = dn.getParent();
      while (parentDN != null)
      {
        if (parentDN.equals(baseDN))
        {
          subordinateBaseDNs.add(dn);
          subordinateBackends.add(b);
          break;
        }
        else if (baseDNs.containsKey(parentDN))
        {
          break;
        }
        parentDN = parentDN.getParent();
      }
    }
    // If we've gotten here, then the new base DN is acceptable.  If we should
    // actually apply the changes then do so now.
    // 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))
      {
        Message message = WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS.
            get(superiorBackend.getBackendID(), String.valueOf(baseDN),
                backend.getBackendID());
        errors.add(message);
      }
    }
    baseDNs.put(baseDN, backend);
    if (superiorBackend == null)
    {
      if (isPrivate)
      {
        if (!testOnly)
        {
          backend.setPrivateBackend(true);
        }
        privateNamingContexts.put(baseDN, backend);
      }
      else
      {
        if (!testOnly)
        {
          backend.setPrivateBackend(false);
        }
        publicNamingContexts.put(baseDN, backend);
      }
    }
    else if (otherBaseDNs.isEmpty())
    {
      if (!testOnly)
      {
        backend.setParentBackend(superiorBackend);
        superiorBackend.addSubordinateBackend(backend);
      }
    }
    if (!testOnly)
    {
      for (Backend b : subordinateBackends)
      {
        Backend oldParentBackend = b.getParentBackend();
        if (oldParentBackend != null)
        {
          oldParentBackend.removeSubordinateBackend(b);
        }
        b.setParentBackend(backend);
        backend.addSubordinateBackend(b);
      }
    }
    for (DN dn : subordinateBaseDNs)
    {
      publicNamingContexts.remove(dn);
      privateNamingContexts.remove(dn);
    }
    return errors;
  }
  /**
   * Deregisters a base DN with this registry.
   *
   * @param  baseDN to deregister
   * @return list of error messages generated by deregistering the base DN
   *         that should be logged if the changes to this registry are
   *         committed to the server
   * @throws DirectoryException if the base DN could not be deregistered
   */
  public List<Message> deregisterBaseDN(DN baseDN)
         throws DirectoryException
  {
    LinkedList<Message> errors = new LinkedList<Message>();
    ensureNotNull(baseDN);
    // Make sure that the Directory Server actually contains a backend with
    // the specified base DN.
    Backend backend = baseDNs.get(baseDN);
    if (backend == null)
    {
      Message message =
          ERR_DEREGISTER_BASEDN_NOT_REGISTERED.get(String.valueOf(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.
    Backend             superiorBackend     = backend.getParentBackend();
    LinkedList<Backend> subordinateBackends = new LinkedList<Backend>();
    if (backend.getSubordinateBackends() != null)
    {
      for (Backend b : backend.getSubordinateBackends())
      {
        for (DN dn : b.getBaseDNs())
        {
          if (dn.isDescendantOf(baseDN))
          {
            subordinateBackends.add(b);
            break;
          }
        }
      }
    }
    // See if there are any other base DNs registered within the same backend.
    LinkedList<DN> otherBaseDNs = new LinkedList<DN>();
    for (DN dn : baseDNs.keySet())
    {
      if (dn.equals(baseDN))
      {
        continue;
      }
      Backend 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);
    privateNamingContexts.remove(baseDN);
    if (superiorBackend == null)
    {
      // If there were any subordinate backends, then all of their base DNs
      // will now be promoted to naming contexts.
      for (Backend 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())
      {
        if (!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())
      {
        Message message = WARN_DEREGISTER_BASEDN_MISSING_HIERARCHY.get(
            String.valueOf(baseDN), backend.getBackendID());
        errors.add(message);
        if (!testOnly)
        {
          for (Backend b : subordinateBackends)
          {
            backend.removeSubordinateBackend(b);
            superiorBackend.addSubordinateBackend(b);
            b.setParentBackend(superiorBackend);
          }
        }
      }
    }
    return errors;
  }
  /**
   * Creates a default instance.
   */
  BaseDnRegistry()
  {
    this(new TreeMap<DN,Backend>(), new TreeMap<DN,Backend>(),
         new TreeMap<DN,Backend>(), false);
  }
  /**
   * Returns a copy of this registry.
   *
   * @return copy of this registry
   */
  BaseDnRegistry copy()
  {
    return new BaseDnRegistry(
            new TreeMap<DN,Backend>(baseDNs),
            new TreeMap<DN,Backend>(publicNamingContexts),
            new TreeMap<DN,Backend>(privateNamingContexts),
            true);
  }
  /**
   * Creates a parameterized instance.
   *
   * @param baseDNs map
   * @param publicNamingContexts map
   * @param privateNamingContexts map
   * @param testOnly indicates whether this registry will be used for testing;
   *        when <code>true</code> this registry will not modify backends
   */
  private BaseDnRegistry(TreeMap<DN, Backend> baseDNs,
                         TreeMap<DN, Backend> publicNamingContexts,
                         TreeMap<DN, Backend> privateNamingContexts,
                         boolean testOnly)
  {
    this.baseDNs = baseDNs;
    this.publicNamingContexts = publicNamingContexts;
    this.privateNamingContexts = privateNamingContexts;
    this.testOnly = testOnly;
  }
  /**
   * Gets the mapping of registered base DNs to their associated backend.
   *
   * @return mapping from base DN to backend
   */
  Map<DN,Backend> getBaseDnMap() {
    return this.baseDNs;
  }
  /**
   * Gets the mapping of registered public naming contexts to their
   * associated backend.
   *
   * @return mapping from naming context to backend
   */
  Map<DN,Backend> getPublicNamingContextsMap() {
    return this.publicNamingContexts;
  }
  /**
   * Gets the mapping of registered private naming contexts to their
   * associated backend.
   *
   * @return mapping from naming context to backend
   */
  Map<DN,Backend> 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() {
    if (baseDNs != null)
    {
      baseDNs.clear();
    }
    if (privateNamingContexts != null)
    {
      privateNamingContexts.clear();
    }
    if (publicNamingContexts != null)
    {
      publicNamingContexts.clear();
    }
  }
}
opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -674,14 +674,10 @@
  // The thread group for all threads associated with the Directory Server.
  private ThreadGroup directoryThreadGroup;
  // The set of base DNs registered with the server.
  private TreeMap<DN,Backend> baseDNs;
  // The set of private naming contexts registered with the server.
  private TreeMap<DN,Backend> privateNamingContexts;
  // Registry for base DN and naming context information.
  private BaseDnRegistry baseDnRegistry;
  // The set of public naming contexts registered with the server.
  private TreeMap<DN,Backend> publicNamingContexts;
  // The set of backends registered with the server.
  private TreeMap<String,Backend> backends;
@@ -895,9 +891,7 @@
           new ConcurrentHashMap<String,Long>();
      directoryServer.backendInitializationListeners =
           new CopyOnWriteArraySet<BackendInitializationListener>();
      directoryServer.baseDNs = new TreeMap<DN,Backend>();
      directoryServer.publicNamingContexts = new TreeMap<DN,Backend>();
      directoryServer.privateNamingContexts = new TreeMap<DN,Backend>();
      directoryServer.baseDnRegistry = new BaseDnRegistry();
      directoryServer.changeNotificationListeners =
           new CopyOnWriteArrayList<ChangeNotificationListener>();
      directoryServer.persistentSearches =
@@ -6307,7 +6301,7 @@
   */
  public static Map<DN,Backend> getBaseDNs()
  {
    return directoryServer.baseDNs;
    return directoryServer.baseDnRegistry.getBaseDnMap();
  }
@@ -6323,7 +6317,7 @@
   */
  public static Backend getBackendWithBaseDN(DN baseDN)
  {
    return directoryServer.baseDNs.get(baseDN);
    return directoryServer.baseDnRegistry.getBaseDnMap().get(baseDN);
  }
@@ -6346,7 +6340,7 @@
      return directoryServer.rootDSEBackend;
    }
    TreeMap<DN,Backend> baseDNs = directoryServer.baseDNs;
    Map<DN,Backend> baseDNs = directoryServer.baseDnRegistry.getBaseDnMap();
    Backend b = baseDNs.get(entryDN);
    while (b == null)
    {
@@ -6363,6 +6357,20 @@
  }
  /**
   * 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, Backend, boolean)} and
   * {@link #deregisterBaseDN(DN)}.
   *
   * @return copy of the base DN regsitry
   */
  public static BaseDnRegistry copyBaseDnRegistry()
  {
    return directoryServer.baseDnRegistry.copy();
  }
  /**
   * Registers the provided base DN with the server.
@@ -6375,200 +6383,29 @@
   *                    private base DN.  If the provided base DN is a naming
   *                    context, then this controls whether it is public or
   *                    private.
   * @param  testOnly   Indicates whether to only test whether the new base DN
   *                    registration would be successful without actually
   *                    applying any changes.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to
   *                              register the provided base DN.
   */
  public static void registerBaseDN(DN baseDN, Backend backend,
                                    boolean isPrivate, boolean testOnly)
                                    boolean isPrivate)
         throws DirectoryException
  {
    ensureNotNull(baseDN, backend);
    synchronized (directoryServer)
    {
      TreeMap<DN,Backend> newBaseDNs =
           new TreeMap<DN,Backend>(directoryServer.baseDNs);
      TreeMap<DN,Backend> newPublicNamingContexts =
           new TreeMap<DN,Backend>(directoryServer.publicNamingContexts);
      TreeMap<DN,Backend> newPrivateNamingContexts =
           new TreeMap<DN,Backend>(directoryServer.privateNamingContexts);
      List<Message> warnings =
              directoryServer.baseDnRegistry.registerBaseDN(
                      baseDN, backend, isPrivate);
      // Check to see if the base DN is already registered with the server.
      Backend existingBackend = newBaseDNs.get(baseDN);
      if (existingBackend != null)
      {
        Message message = ERR_REGISTER_BASEDN_ALREADY_EXISTS.
            get(String.valueOf(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<DN>();
      for (DN dn : newBaseDNs.keySet())
      {
        Backend b = newBaseDNs.get(dn);
        if (b.equals(backend))
        {
          otherBaseDNs.add(dn);
          if (baseDN.isAncestorOf(dn) || baseDN.isDescendantOf(dn))
          {
            Message message = ERR_REGISTER_BASEDN_HIERARCHY_CONFLICT.
                get(String.valueOf(baseDN), backend.getBackendID(),
                    String.valueOf(dn));
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message);
      // Since we've committed the changes we need to log any issues
      // that this registration has caused
      if (warnings != null) {
        for (Message warning : warnings) {
          logError(warning);
          }
        }
      }
      // 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.
      Backend superiorBackend = null;
      DN      superiorBaseDN  = null;
      DN      parentDN        = baseDN.getParent();
      while (parentDN != null)
      {
        if (newBaseDNs.containsKey(parentDN))
        {
          superiorBaseDN  = parentDN;
          superiorBackend = newBaseDNs.get(parentDN);
          for (DN dn : otherBaseDNs)
          {
            if (! dn.isDescendantOf(superiorBaseDN))
            {
              Message message = ERR_REGISTER_BASEDN_DIFFERENT_PARENT_BASES.
                  get(String.valueOf(baseDN), backend.getBackendID(),
                      String.valueOf(dn));
              throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                           message);
            }
          }
          break;
        }
        parentDN = parentDN.getParent();
      }
      if (superiorBackend == null)
      {
        if (backend.getParentBackend() != null)
        {
          Message message = ERR_REGISTER_BASEDN_NEW_BASE_NOT_SUBORDINATE.
              get(String.valueOf(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<Backend> subordinateBackends = new LinkedList<Backend>();
      LinkedList<DN>      subordinateBaseDNs  = new LinkedList<DN>();
      for (DN dn : newBaseDNs.keySet())
      {
        Backend b = newBaseDNs.get(dn);
        parentDN = dn.getParent();
        while (parentDN != null)
        {
          if (parentDN.equals(baseDN))
          {
            subordinateBaseDNs.add(dn);
            subordinateBackends.add(b);
            break;
          }
          else if (newBaseDNs.containsKey(parentDN))
          {
            break;
          }
          parentDN = parentDN.getParent();
        }
      }
      // If we've gotten here, then the new base DN is acceptable.  If we should
      // actually apply the changes then do so now.
      if (! testOnly)
      {
        // 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))
          {
            Message message = WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS.
                get(superiorBackend.getBackendID(), String.valueOf(baseDN),
                    backend.getBackendID());
            logError(message);
          }
        }
        newBaseDNs.put(baseDN, backend);
        if (superiorBackend == null)
        {
          if (isPrivate)
          {
            backend.setPrivateBackend(true);
            newPrivateNamingContexts.put(baseDN, backend);
          }
          else
          {
            backend.setPrivateBackend(false);
            newPublicNamingContexts.put(baseDN, backend);
          }
        }
        else if (otherBaseDNs.isEmpty())
        {
          backend.setParentBackend(superiorBackend);
          superiorBackend.addSubordinateBackend(backend);
        }
        for (Backend b : subordinateBackends)
        {
          Backend oldParentBackend = b.getParentBackend();
          if (oldParentBackend != null)
          {
            oldParentBackend.removeSubordinateBackend(b);
          }
          b.setParentBackend(backend);
          backend.addSubordinateBackend(b);
        }
        for (DN dn : subordinateBaseDNs)
        {
          newPublicNamingContexts.remove(dn);
          newPrivateNamingContexts.remove(dn);
        }
        directoryServer.baseDNs               = newBaseDNs;
        directoryServer.publicNamingContexts  = newPublicNamingContexts;
        directoryServer.privateNamingContexts = newPrivateNamingContexts;
        // Now create a workflow for the registered baseDN and register
        // the workflow with the network groups, but don't register the
@@ -6580,7 +6417,6 @@
        }
      }
    }
  }
@@ -6589,147 +6425,32 @@
   *
   * @param  baseDN     The base DN to deregister with the server.  It must not
   *                    be {@code null}.
   * @param  testOnly   Indicates whether to only test whether the new base DN
   *                    registration would be successful without actually
   *                    applying any changes.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to
   *                              deregister the provided base DN.
   */
  public static void deregisterBaseDN(DN baseDN, boolean testOnly)
  public static void deregisterBaseDN(DN baseDN)
         throws DirectoryException
  {
    ensureNotNull(baseDN);
    synchronized (directoryServer)
    {
      TreeMap<DN,Backend> newBaseDNs =
           new TreeMap<DN,Backend>(directoryServer.baseDNs);
      TreeMap<DN,Backend> newPublicNamingContexts =
           new TreeMap<DN,Backend>(directoryServer.publicNamingContexts);
      TreeMap<DN,Backend> newPrivateNamingContexts =
           new TreeMap<DN,Backend>(directoryServer.privateNamingContexts);
    synchronized(directoryServer) {
      List<Message> warnings =
              directoryServer.baseDnRegistry.deregisterBaseDN(baseDN);
      // Make sure that the Directory Server actually contains a backend with
      // the specified base DN.
      Backend backend = newBaseDNs.get(baseDN);
      if (backend == null)
      {
        Message message =
            ERR_DEREGISTER_BASEDN_NOT_REGISTERED.get(String.valueOf(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.
      Backend             superiorBackend     = backend.getParentBackend();
      LinkedList<Backend> subordinateBackends = new LinkedList<Backend>();
      if (backend.getSubordinateBackends() != null)
      {
        for (Backend b : backend.getSubordinateBackends())
        {
          for (DN dn : b.getBaseDNs())
          {
            if (dn.isDescendantOf(baseDN))
            {
              subordinateBackends.add(b);
              break;
      // Since we've committed the changes we need to log any issues
      // that this registration has caused
      if (warnings != null) {
        for (Message error : warnings) {
          logError(error);
            }
          }
        }
      }
      // See if there are any other base DNs registered within the same backend.
      LinkedList<DN> otherBaseDNs = new LinkedList<DN>();
      for (DN dn : newBaseDNs.keySet())
      {
        if (dn.equals(baseDN))
        {
          continue;
        }
        Backend b = newBaseDNs.get(dn);
        if (backend.equals(b))
        {
          otherBaseDNs.add(dn);
        }
      }
      // If we've gotten here, then it's OK to make the changes.
      if (! testOnly)
      {
        // Get rid of the references to this base DN in the mapping tree
        // information.
        newBaseDNs.remove(baseDN);
        newPublicNamingContexts.remove(baseDN);
        newPrivateNamingContexts.remove(baseDN);
        if (superiorBackend == null)
        {
          // If there were any subordinate backends, then all of their base DNs
          // will now be promoted to naming contexts.
          for (Backend b : subordinateBackends)
          {
            b.setParentBackend(null);
            backend.removeSubordinateBackend(b);
            for (DN dn : b.getBaseDNs())
            {
              if (b.isPrivateBackend())
              {
                newPrivateNamingContexts.put(dn, b);
              }
              else
              {
                newPublicNamingContexts.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())
          {
            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())
          {
            Message message = WARN_DEREGISTER_BASEDN_MISSING_HIERARCHY.get(
                String.valueOf(baseDN), backend.getBackendID());
            logError(message);
            for (Backend b : subordinateBackends)
            {
              backend.removeSubordinateBackend(b);
              superiorBackend.addSubordinateBackend(b);
              b.setParentBackend(superiorBackend);
            }
          }
        }
        directoryServer.baseDNs               = newBaseDNs;
        directoryServer.publicNamingContexts  = newPublicNamingContexts;
        directoryServer.privateNamingContexts = newPrivateNamingContexts;
        // Now deregister the workflow that was associated with the base DN.
        deregisterWorkflow(baseDN);
      }
    }
  }
@@ -6741,7 +6462,7 @@
   */
  public static Map<DN,Backend> getPublicNamingContexts()
  {
    return directoryServer.publicNamingContexts;
    return directoryServer.baseDnRegistry.getPublicNamingContextsMap();
  }
@@ -6755,7 +6476,7 @@
   */
  public static Map<DN,Backend> getPrivateNamingContexts()
  {
    return directoryServer.privateNamingContexts;
    return directoryServer.baseDnRegistry.getPrivateNamingContextsMap();
  }
@@ -6771,8 +6492,7 @@
   */
  public static boolean isNamingContext(DN dn)
  {
    return (directoryServer.publicNamingContexts.containsKey(dn) ||
            directoryServer.privateNamingContexts.containsKey(dn));
    return directoryServer.baseDnRegistry.containsNamingContext(dn);
  }
@@ -8578,22 +8298,10 @@
    shutdownHook             = null;
    workQueue                = null;
    if (privateNamingContexts != null)
    if (baseDnRegistry != null)
    {
      privateNamingContexts.clear();
      privateNamingContexts = null;
    }
    if (publicNamingContexts != null)
    {
      publicNamingContexts.clear();
      publicNamingContexts = null;
    }
    if (baseDNs != null)
    {
      baseDNs.clear();
      baseDNs = null;
      baseDnRegistry.clear();
      baseDnRegistry = null;
    }
    if (backends != null)
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -735,8 +735,7 @@
      // conflict with user backend identifiers.
      setBackendID("__config.ldif__");
      DirectoryServer.registerBaseDN(configRootEntry.getDN(), this, true,
                                     false);
      DirectoryServer.registerBaseDN(configRootEntry.getDN(), this, true);
    }
    catch (Exception e)
    {
@@ -1026,7 +1025,7 @@
  {
    try
    {
      DirectoryServer.deregisterBaseDN(configRootEntry.getDN(), false);
      DirectoryServer.deregisterBaseDN(configRootEntry.getDN());
    }
    catch (Exception e)
    {
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -232,7 +232,7 @@
    {
      try
      {
        DirectoryServer.registerBaseDN(dn, this, false, false);
        DirectoryServer.registerBaseDN(dn, this, false);
      }
      catch (Exception e)
      {
@@ -269,7 +269,7 @@
    {
      try
      {
        DirectoryServer.deregisterBaseDN(dn, false);
        DirectoryServer.deregisterBaseDN(dn);
      }
      catch (Exception e)
      {
opends/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java
@@ -111,7 +111,7 @@
  public void testDeregisterNonExistentBaseDN()
         throws Exception
  {
    DirectoryServer.deregisterBaseDN(DN.decode("o=unregistered"), false);
    DirectoryServer.deregisterBaseDN(DN.decode("o=unregistered"));
  }