| | |
| | | |
| | | package org.opends.server.core; |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.api.Backend; |
| | | import static org.forgerock.util.Reject.ifNull; |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | |
| | | import static org.forgerock.util.Reject.*; |
| | | 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. |
| | | * Registry for maintaining the set of registered base DN's, associated backends |
| | | * and naming context information. |
| | | */ |
| | | public class BaseDnRegistry { |
| | | |
| | | // The set of base DNs registered with the server. |
| | | private TreeMap<DN,Backend> baseDNs; |
| | | /** The set of base DNs registered with the server. */ |
| | | private final TreeMap<DN, Backend> baseDNs = new TreeMap<DN, Backend>(); |
| | | |
| | | // The set of private naming contexts registered with the server. |
| | | private TreeMap<DN,Backend> privateNamingContexts; |
| | | /** The set of private naming contexts registered with the server. */ |
| | | private final TreeMap<DN, Backend> privateNamingContexts = new TreeMap<DN, Backend>(); |
| | | |
| | | // The set of public naming contexts registered with the server. |
| | | private TreeMap<DN,Backend> publicNamingContexts; |
| | | /** The set of public naming contexts registered with the server. */ |
| | | private final TreeMap<DN, Backend> publicNamingContexts = new TreeMap<DN, Backend>(); |
| | | |
| | | // 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. |
| | | /** |
| | | * 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 backend with which the base DN is associated |
| | | * @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<LocalizableMessage> registerBaseDN(DN baseDN, Backend backend, |
| | | boolean isPrivate) |
| | | public List<LocalizableMessage> registerBaseDN(DN baseDN, Backend<?> backend, boolean isPrivate) |
| | | throws DirectoryException |
| | | { |
| | | |
| | | List<LocalizableMessage> errors = new LinkedList<LocalizableMessage>(); |
| | | |
| | | // Check to see if the base DN is already registered with the server. |
| | | Backend existingBackend = baseDNs.get(baseDN); |
| | | Backend<?> existingBackend = baseDNs.get(baseDN); |
| | | if (existingBackend != null) |
| | | { |
| | | LocalizableMessage message = ERR_REGISTER_BASEDN_ALREADY_EXISTS. |
| | |
| | | LinkedList<DN> otherBaseDNs = new LinkedList<DN>(); |
| | | for (DN dn : baseDNs.keySet()) |
| | | { |
| | | Backend b = baseDNs.get(dn); |
| | | Backend<?> b = baseDNs.get(dn); |
| | | if (b.equals(backend)) |
| | | { |
| | | otherBaseDNs.add(dn); |
| | |
| | | // 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; |
| | | Backend<?> superiorBackend = null; |
| | | DN superiorBaseDN ; |
| | | DN parentDN = baseDN.parent(); |
| | | while (parentDN != null) |
| | |
| | | parentDN = parentDN.parent(); |
| | | } |
| | | |
| | | if (superiorBackend == null) |
| | | { |
| | | if (backend.getParentBackend() != null) |
| | | 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<Backend> subordinateBackends = new LinkedList<Backend>(); |
| | | LinkedList<Backend<?>> subordinateBackends = new LinkedList<Backend<?>>(); |
| | | LinkedList<DN> subordinateBaseDNs = new LinkedList<DN>(); |
| | | for (DN dn : baseDNs.keySet()) |
| | | { |
| | | Backend b = baseDNs.get(dn); |
| | | Backend<?> b = baseDNs.get(dn); |
| | | parentDN = dn.parent(); |
| | | while (parentDN != null) |
| | | { |
| | |
| | | |
| | | // 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<LocalizableMessage>(); |
| | | |
| | | // 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 |
| | |
| | | // 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)) |
| | | if (superiorBackend != null && superiorBackend.entryExists(baseDN)) |
| | | { |
| | | errors.add(WARN_REGISTER_BASEDN_ENTRIES_IN_MULTIPLE_BACKENDS. |
| | | get(superiorBackend.getBackendID(), baseDN, backend.getBackendID())); |
| | | } |
| | | } |
| | | |
| | | |
| | | baseDNs.put(baseDN, backend); |
| | | |
| | | if (superiorBackend == null) |
| | | { |
| | | if (isPrivate) |
| | | { |
| | | if (!testOnly) |
| | | { |
| | | backend.setPrivateBackend(true); |
| | | backend.setPrivateBackend(isPrivate); |
| | | } |
| | | |
| | | if (isPrivate) |
| | | { |
| | | privateNamingContexts.put(baseDN, backend); |
| | | } |
| | | else |
| | | { |
| | | if (!testOnly) |
| | | { |
| | | backend.setPrivateBackend(false); |
| | | } |
| | | publicNamingContexts.put(baseDN, backend); |
| | | } |
| | | } |
| | | else if (otherBaseDNs.isEmpty()) |
| | | { |
| | | if (!testOnly) |
| | | else if (otherBaseDNs.isEmpty() && !testOnly) |
| | | { |
| | | backend.setParentBackend(superiorBackend); |
| | | superiorBackend.addSubordinateBackend(backend); |
| | | } |
| | | } |
| | | |
| | | if (!testOnly) |
| | | { |
| | | for (Backend b : subordinateBackends) |
| | | for (Backend<?> b : subordinateBackends) |
| | | { |
| | | Backend oldParentBackend = b.getParentBackend(); |
| | | Backend<?> oldParentBackend = b.getParentBackend(); |
| | | if (oldParentBackend != null) |
| | | { |
| | | oldParentBackend.removeSubordinateBackend(b); |
| | |
| | | public List<LocalizableMessage> deregisterBaseDN(DN baseDN) |
| | | throws DirectoryException |
| | | { |
| | | LinkedList<LocalizableMessage> errors = new LinkedList<LocalizableMessage>(); |
| | | |
| | | ifNull(baseDN); |
| | | |
| | | // Make sure that the Directory Server actually contains a backend with |
| | | // the specified base DN. |
| | | Backend backend = baseDNs.get(baseDN); |
| | | Backend<?> backend = baseDNs.get(baseDN); |
| | | if (backend == null) |
| | | { |
| | | LocalizableMessage 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>(); |
| | | Backend<?> superiorBackend = backend.getParentBackend(); |
| | | LinkedList<Backend<?>> subordinateBackends = new LinkedList<Backend<?>>(); |
| | | if (backend.getSubordinateBackends() != null) |
| | | { |
| | | for (Backend b : backend.getSubordinateBackends()) |
| | | for (Backend<?> b : backend.getSubordinateBackends()) |
| | | { |
| | | for (DN dn : b.getBaseDNs()) |
| | | { |
| | |
| | | continue; |
| | | } |
| | | |
| | | Backend b = baseDNs.get(dn); |
| | | Backend<?> b = baseDNs.get(dn); |
| | | if (backend.equals(b)) |
| | | { |
| | | otherBaseDNs.add(dn); |
| | |
| | | publicNamingContexts.remove(baseDN); |
| | | privateNamingContexts.remove(baseDN); |
| | | |
| | | final LinkedList<LocalizableMessage> errors = new LinkedList<LocalizableMessage>(); |
| | | 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) |
| | | for (Backend<?> b : subordinateBackends) |
| | | { |
| | | if (!testOnly) |
| | | { |
| | |
| | | { |
| | | // 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) |
| | | if (otherBaseDNs.isEmpty() && !testOnly) |
| | | { |
| | | superiorBackend.removeSubordinateBackend(backend); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there are any subordinate backends, then they need to be made |
| | |
| | | |
| | | if (!testOnly) |
| | | { |
| | | for (Backend b : subordinateBackends) |
| | | for (Backend<?> b : subordinateBackends) |
| | | { |
| | | backend.removeSubordinateBackend(b); |
| | | superiorBackend.addSubordinateBackend(b); |
| | |
| | | */ |
| | | BaseDnRegistry() |
| | | { |
| | | this(new TreeMap<DN,Backend>(), new TreeMap<DN,Backend>(), |
| | | new TreeMap<DN,Backend>(), false); |
| | | this(false); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | BaseDnRegistry copy() |
| | | { |
| | | return new BaseDnRegistry( |
| | | new TreeMap<DN,Backend>(baseDNs), |
| | | new TreeMap<DN,Backend>(publicNamingContexts), |
| | | new TreeMap<DN,Backend>(privateNamingContexts), |
| | | true); |
| | | final BaseDnRegistry registry = new BaseDnRegistry(true); |
| | | registry.baseDNs.putAll(baseDNs); |
| | | registry.publicNamingContexts.putAll(publicNamingContexts); |
| | | registry.privateNamingContexts.putAll(privateNamingContexts); |
| | | return registry; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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) |
| | | private BaseDnRegistry(boolean testOnly) |
| | | { |
| | | this.baseDNs = baseDNs; |
| | | this.publicNamingContexts = publicNamingContexts; |
| | | this.privateNamingContexts = privateNamingContexts; |
| | | this.testOnly = testOnly; |
| | | } |
| | | |
| | |
| | | */ |
| | | boolean containsNamingContext(DN dn) |
| | | { |
| | | return (privateNamingContexts.containsKey(dn) || |
| | | publicNamingContexts.containsKey(dn)); |
| | | return privateNamingContexts.containsKey(dn) || publicNamingContexts.containsKey(dn); |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | publicNamingContexts.clear(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |