2593N/A/*
2593N/A * CDDL HEADER START
2593N/A *
2593N/A * The contents of this file are subject to the terms of the
2593N/A * Common Development and Distribution License, Version 1.0 only
2593N/A * (the "License"). You may not use this file except in compliance
2593N/A * with the License.
2593N/A *
6983N/A * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
6983N/A * or http://forgerock.org/license/CDDLv1.0.html.
2593N/A * See the License for the specific language governing permissions
2593N/A * and limitations under the License.
2593N/A *
2593N/A * When distributing Covered Code, include this CDDL HEADER in each
6983N/A * file and include the License file at legal-notices/CDDLv1_0.txt.
6983N/A * If applicable, add the following below this CDDL HEADER, with the
6983N/A * fields enclosed by brackets "[]" replaced with your own identifying
6983N/A * information:
2593N/A * Portions Copyright [yyyy] [name of copyright owner]
2593N/A *
2593N/A * CDDL HEADER END
2593N/A *
2593N/A *
3215N/A * Copyright 2007-2008 Sun Microsystems, Inc.
2593N/A */
2593N/A
2593N/Apackage org.opends.server.core;
2593N/A
2593N/Aimport org.opends.server.types.DN;
2593N/Aimport org.opends.server.types.DirectoryException;
2593N/Aimport org.opends.server.types.ResultCode;
2593N/Aimport org.opends.server.api.Backend;
2593N/Aimport static org.opends.server.util.Validator.ensureNotNull;
2593N/Aimport org.opends.messages.Message;
2593N/Aimport static org.opends.messages.CoreMessages.*;
2593N/A
2593N/Aimport java.util.TreeMap;
2593N/Aimport java.util.List;
2593N/Aimport java.util.LinkedList;
2593N/Aimport java.util.Map;
2593N/A
2593N/A/**
2593N/A * Registry for maintaining the set of registered base DN's, assocated
2593N/A * backends and naming context information.
2593N/A */
2593N/Apublic class BaseDnRegistry {
2593N/A
2593N/A // The set of base DNs registered with the server.
2593N/A private TreeMap<DN,Backend> baseDNs;
2593N/A
2593N/A // The set of private naming contexts registered with the server.
2593N/A private TreeMap<DN,Backend> privateNamingContexts;
2593N/A
2593N/A // The set of public naming contexts registered with the server.
2593N/A private TreeMap<DN,Backend> publicNamingContexts;
2593N/A
2593N/A // Indicates whether or not this base DN registry is in test mode.
2593N/A // A registry instance that is in test mode will not modify backend
2593N/A // objects referred to in the above maps.
2593N/A private boolean testOnly;
2593N/A
2593N/A /**
2593N/A * Registers a base DN with this registry.
2593N/A *
2593N/A * @param baseDN to register
2593N/A * @param backend with which the base DN is assocated
2593N/A * @param isPrivate indicates whether or not this base DN is private
2593N/A * @return list of error messages generated by registering the base DN
2593N/A * that should be logged if the changes to this registry are
2593N/A * committed to the server
2593N/A * @throws DirectoryException if the base DN cannot be registered
2593N/A */
2593N/A public List<Message> registerBaseDN(DN baseDN, Backend backend,
2593N/A boolean isPrivate)
2593N/A throws DirectoryException
2593N/A {
2593N/A
2593N/A List<Message> errors = new LinkedList<Message>();
2593N/A
2593N/A // Check to see if the base DN is already registered with the server.
2593N/A Backend existingBackend = baseDNs.get(baseDN);
2593N/A if (existingBackend != null)
2593N/A {
2593N/A Message message = ERR_REGISTER_BASEDN_ALREADY_EXISTS.
2593N/A get(String.valueOf(baseDN), backend.getBackendID(),
2593N/A existingBackend.getBackendID());
2593N/A throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
2593N/A }
2593N/A
2593N/A
2593N/A // Check to see if the backend is already registered with the server for
2593N/A // any other base DN(s). The new base DN must not have any hierarchical
2593N/A // relationship with any other base Dns for the same backend.
2593N/A LinkedList<DN> otherBaseDNs = new LinkedList<DN>();
2593N/A for (DN dn : baseDNs.keySet())
2593N/A {
2593N/A Backend b = baseDNs.get(dn);
2593N/A if (b.equals(backend))
2593N/A {
2593N/A otherBaseDNs.add(dn);
2593N/A
2593N/A if (baseDN.isAncestorOf(dn) || baseDN.isDescendantOf(dn))
2593N/A {
2593N/A Message message = ERR_REGISTER_BASEDN_HIERARCHY_CONFLICT.
2593N/A get(String.valueOf(baseDN), backend.getBackendID(),
2593N/A String.valueOf(dn));
2593N/A throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
2593N/A message);
2593N/A }
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // Check to see if the new base DN is subordinate to any other base DN
2593N/A // already defined. If it is, then any other base DN(s) for the same
2593N/A // backend must also be subordinate to the same base DN.
2593N/A Backend superiorBackend = null;
2593N/A DN superiorBaseDN ;
2593N/A DN parentDN = baseDN.getParent();
2593N/A while (parentDN != null)
2593N/A {
2593N/A if (baseDNs.containsKey(parentDN))
2593N/A {
2593N/A superiorBaseDN = parentDN;
2593N/A superiorBackend = baseDNs.get(parentDN);
2593N/A
2593N/A for (DN dn : otherBaseDNs)
2593N/A {
2593N/A if (! dn.isDescendantOf(superiorBaseDN))
2593N/A {
2593N/A Message message = ERR_REGISTER_BASEDN_DIFFERENT_PARENT_BASES.
2593N/A get(String.valueOf(baseDN), backend.getBackendID(),
2593N/A String.valueOf(dn));
2593N/A throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
2593N/A message);
2593N/A }
2593N/A }
2593N/A
2593N/A break;
2593N/A }
2593N/A
2593N/A parentDN = parentDN.getParent();
2593N/A }
2593N/A
2593N/A if (superiorBackend == null)
2593N/A {
2593N/A if (backend.getParentBackend() != null)
2593N/A {
2593N/A Message message = ERR_REGISTER_BASEDN_NEW_BASE_NOT_SUBORDINATE.
2593N/A get(String.valueOf(baseDN), backend.getBackendID(),
2593N/A backend.getParentBackend().getBackendID());
2593N/A throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
2593N/A message);
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // Check to see if the new base DN should be the superior base DN for any
2593N/A // other base DN(s) already defined.
2593N/A LinkedList<Backend> subordinateBackends = new LinkedList<Backend>();
2593N/A LinkedList<DN> subordinateBaseDNs = new LinkedList<DN>();
2593N/A for (DN dn : baseDNs.keySet())
2593N/A {
2593N/A Backend b = baseDNs.get(dn);
2593N/A parentDN = dn.getParent();
2593N/A while (parentDN != null)
2593N/A {
2593N/A if (parentDN.equals(baseDN))
2593N/A {
2593N/A subordinateBaseDNs.add(dn);
2593N/A subordinateBackends.add(b);
2593N/A break;
2593N/A }
2593N/A else if (baseDNs.containsKey(parentDN))
2593N/A {
2593N/A break;
2593N/A }
2593N/A
2593N/A parentDN = parentDN.getParent();
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // If we've gotten here, then the new base DN is acceptable. If we should
2593N/A // actually apply the changes then do so now.
2593N/A
2593N/A // Check to see if any of the registered backends already contain an
2593N/A // entry with the DN specified as the base DN. This could happen if
2593N/A // we're creating a new subordinate backend in an existing directory
2593N/A // (e.g., moving the "ou=People,dc=example,dc=com" branch to its own
2593N/A // backend when that data already exists under the "dc=example,dc=com"
2593N/A // backend). This condition shouldn't prevent the new base DN from
2593N/A // being registered, but it's definitely important enough that we let
2593N/A // the administrator know about it and remind them that the existing
2593N/A // backend will need to be reinitialized.
2593N/A if (superiorBackend != null)
2593N/A {
2593N/A if (superiorBackend.entryExists(baseDN))
2593N/A {
2593N/A Message message = WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS.
2593N/A get(superiorBackend.getBackendID(), String.valueOf(baseDN),
2593N/A backend.getBackendID());
2593N/A errors.add(message);
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A baseDNs.put(baseDN, backend);
2593N/A
2593N/A if (superiorBackend == null)
2593N/A {
2593N/A if (isPrivate)
2593N/A {
2593N/A if (!testOnly)
2593N/A {
2593N/A backend.setPrivateBackend(true);
2593N/A }
2593N/A privateNamingContexts.put(baseDN, backend);
2593N/A }
2593N/A else
2593N/A {
2593N/A if (!testOnly)
2593N/A {
2593N/A backend.setPrivateBackend(false);
2593N/A }
2593N/A publicNamingContexts.put(baseDN, backend);
2593N/A }
2593N/A }
2593N/A else if (otherBaseDNs.isEmpty())
2593N/A {
2593N/A if (!testOnly)
2593N/A {
2593N/A backend.setParentBackend(superiorBackend);
2593N/A superiorBackend.addSubordinateBackend(backend);
2593N/A }
2593N/A }
2593N/A
2593N/A if (!testOnly)
2593N/A {
2593N/A for (Backend b : subordinateBackends)
2593N/A {
2593N/A Backend oldParentBackend = b.getParentBackend();
2593N/A if (oldParentBackend != null)
2593N/A {
2593N/A oldParentBackend.removeSubordinateBackend(b);
2593N/A }
2593N/A
2593N/A b.setParentBackend(backend);
2593N/A backend.addSubordinateBackend(b);
2593N/A }
2593N/A }
2593N/A
2593N/A for (DN dn : subordinateBaseDNs)
2593N/A {
2593N/A publicNamingContexts.remove(dn);
2593N/A privateNamingContexts.remove(dn);
2593N/A }
2593N/A
2593N/A return errors;
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Deregisters a base DN with this registry.
2593N/A *
2593N/A * @param baseDN to deregister
2593N/A * @return list of error messages generated by deregistering the base DN
2593N/A * that should be logged if the changes to this registry are
2593N/A * committed to the server
2593N/A * @throws DirectoryException if the base DN could not be deregistered
2593N/A */
2593N/A public List<Message> deregisterBaseDN(DN baseDN)
2593N/A throws DirectoryException
2593N/A {
2593N/A LinkedList<Message> errors = new LinkedList<Message>();
2593N/A
2593N/A ensureNotNull(baseDN);
2593N/A
2593N/A // Make sure that the Directory Server actually contains a backend with
2593N/A // the specified base DN.
2593N/A Backend backend = baseDNs.get(baseDN);
2593N/A if (backend == null)
2593N/A {
2593N/A Message message =
2593N/A ERR_DEREGISTER_BASEDN_NOT_REGISTERED.get(String.valueOf(baseDN));
2593N/A throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
2593N/A }
2593N/A
2593N/A
2593N/A // Check to see if the backend has a parent backend, and whether it has
2593N/A // any subordinates with base DNs that are below the base DN to remove.
2593N/A Backend superiorBackend = backend.getParentBackend();
2593N/A LinkedList<Backend> subordinateBackends = new LinkedList<Backend>();
2593N/A if (backend.getSubordinateBackends() != null)
2593N/A {
2593N/A for (Backend b : backend.getSubordinateBackends())
2593N/A {
2593N/A for (DN dn : b.getBaseDNs())
2593N/A {
2593N/A if (dn.isDescendantOf(baseDN))
2593N/A {
2593N/A subordinateBackends.add(b);
2593N/A break;
2593N/A }
2593N/A }
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // See if there are any other base DNs registered within the same backend.
2593N/A LinkedList<DN> otherBaseDNs = new LinkedList<DN>();
2593N/A for (DN dn : baseDNs.keySet())
2593N/A {
2593N/A if (dn.equals(baseDN))
2593N/A {
2593N/A continue;
2593N/A }
2593N/A
2593N/A Backend b = baseDNs.get(dn);
2593N/A if (backend.equals(b))
2593N/A {
2593N/A otherBaseDNs.add(dn);
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // If we've gotten here, then it's OK to make the changes.
2593N/A
2593N/A // Get rid of the references to this base DN in the mapping tree
2593N/A // information.
2593N/A baseDNs.remove(baseDN);
2593N/A publicNamingContexts.remove(baseDN);
2593N/A privateNamingContexts.remove(baseDN);
2593N/A
2593N/A if (superiorBackend == null)
2593N/A {
2593N/A // If there were any subordinate backends, then all of their base DNs
2593N/A // will now be promoted to naming contexts.
2593N/A for (Backend b : subordinateBackends)
2593N/A {
2593N/A if (!testOnly)
2593N/A {
2593N/A b.setParentBackend(null);
2593N/A backend.removeSubordinateBackend(b);
2593N/A }
2593N/A
2593N/A for (DN dn : b.getBaseDNs())
2593N/A {
2593N/A if (b.isPrivateBackend())
2593N/A {
2593N/A privateNamingContexts.put(dn, b);
2593N/A }
2593N/A else
2593N/A {
2593N/A publicNamingContexts.put(dn, b);
2593N/A }
2593N/A }
2593N/A }
2593N/A }
2593N/A else
2593N/A {
2593N/A // If there are no other base DNs for the associated backend, then
2593N/A // remove this backend as a subordinate of the parent backend.
2593N/A if (otherBaseDNs.isEmpty())
2593N/A {
2593N/A if (!testOnly)
2593N/A {
2593N/A superiorBackend.removeSubordinateBackend(backend);
2593N/A }
2593N/A }
2593N/A
2593N/A
2593N/A // If there are any subordinate backends, then they need to be made
2593N/A // subordinate to the parent backend. Also, we should log a warning
2593N/A // message indicating that there may be inconsistent search results
2593N/A // because some of the structural entries will be missing.
2593N/A if (! subordinateBackends.isEmpty())
2593N/A {
3168N/A // Suppress this warning message on server shutdown.
3168N/A if (!DirectoryServer.getInstance().isShuttingDown()) {
3168N/A Message message = WARN_DEREGISTER_BASEDN_MISSING_HIERARCHY.get(
2593N/A String.valueOf(baseDN), backend.getBackendID());
3168N/A errors.add(message);
3168N/A }
2593N/A
2593N/A if (!testOnly)
2593N/A {
2593N/A for (Backend b : subordinateBackends)
2593N/A {
2593N/A backend.removeSubordinateBackend(b);
2593N/A superiorBackend.addSubordinateBackend(b);
2593N/A b.setParentBackend(superiorBackend);
2593N/A }
2593N/A }
2593N/A }
2593N/A }
2593N/A return errors;
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Creates a default instance.
2593N/A */
2593N/A BaseDnRegistry()
2593N/A {
2593N/A this(new TreeMap<DN,Backend>(), new TreeMap<DN,Backend>(),
2593N/A new TreeMap<DN,Backend>(), false);
2593N/A }
2593N/A
2593N/A /**
2593N/A * Returns a copy of this registry.
2593N/A *
2593N/A * @return copy of this registry
2593N/A */
2593N/A BaseDnRegistry copy()
2593N/A {
2593N/A return new BaseDnRegistry(
2593N/A new TreeMap<DN,Backend>(baseDNs),
2593N/A new TreeMap<DN,Backend>(publicNamingContexts),
2593N/A new TreeMap<DN,Backend>(privateNamingContexts),
2593N/A true);
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Creates a parameterized instance.
2593N/A *
2593N/A * @param baseDNs map
2593N/A * @param publicNamingContexts map
2593N/A * @param privateNamingContexts map
2593N/A * @param testOnly indicates whether this registry will be used for testing;
2593N/A * when <code>true</code> this registry will not modify backends
2593N/A */
2593N/A private BaseDnRegistry(TreeMap<DN, Backend> baseDNs,
2593N/A TreeMap<DN, Backend> publicNamingContexts,
2593N/A TreeMap<DN, Backend> privateNamingContexts,
2593N/A boolean testOnly)
2593N/A {
2593N/A this.baseDNs = baseDNs;
2593N/A this.publicNamingContexts = publicNamingContexts;
2593N/A this.privateNamingContexts = privateNamingContexts;
2593N/A this.testOnly = testOnly;
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Gets the mapping of registered base DNs to their associated backend.
2593N/A *
2593N/A * @return mapping from base DN to backend
2593N/A */
2593N/A Map<DN,Backend> getBaseDnMap() {
2593N/A return this.baseDNs;
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Gets the mapping of registered public naming contexts to their
2593N/A * associated backend.
2593N/A *
2593N/A * @return mapping from naming context to backend
2593N/A */
2593N/A Map<DN,Backend> getPublicNamingContextsMap() {
2593N/A return this.publicNamingContexts;
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Gets the mapping of registered private naming contexts to their
2593N/A * associated backend.
2593N/A *
2593N/A * @return mapping from naming context to backend
2593N/A */
2593N/A Map<DN,Backend> getPrivateNamingContextsMap() {
2593N/A return this.privateNamingContexts;
2593N/A }
2593N/A
2593N/A
2593N/A
2593N/A
2593N/A /**
2593N/A * Indicates whether the specified DN is contained in this registry as
2593N/A * a naming contexts.
2593N/A *
2593N/A * @param dn The DN for which to make the determination.
2593N/A *
2593N/A * @return {@code true} if the specified DN is a naming context in this
2593N/A * registry, or {@code false} if it is not.
2593N/A */
2593N/A boolean containsNamingContext(DN dn)
2593N/A {
2593N/A return (privateNamingContexts.containsKey(dn) ||
2593N/A publicNamingContexts.containsKey(dn));
2593N/A }
2593N/A
2593N/A
2593N/A /**
2593N/A * Clear and nullify this registry's internal state.
2593N/A */
2593N/A void clear() {
2593N/A
2593N/A if (baseDNs != null)
2593N/A {
2593N/A baseDNs.clear();
2593N/A }
2593N/A
2593N/A if (privateNamingContexts != null)
2593N/A {
2593N/A privateNamingContexts.clear();
2593N/A }
2593N/A
2593N/A if (publicNamingContexts != null)
2593N/A {
2593N/A publicNamingContexts.clear();
2593N/A }
2593N/A
2593N/A }
2593N/A
2593N/A}