From eedbc609a3b3920a2c402c51f894939b114410f8 Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Thu, 20 Sep 2007 07:08:29 +0000
Subject: [PATCH]
---
opends/src/server/org/opends/server/core/DirectoryServer.java | 134 ++++++++++------
opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java | 165 ++++++++++++++++++++
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java | 132 ++++++++++++++++
opends/src/server/org/opends/server/backends/RootDSEBackend.java | 7
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java | 4
5 files changed, 387 insertions(+), 55 deletions(-)
diff --git a/opends/src/server/org/opends/server/backends/RootDSEBackend.java b/opends/src/server/org/opends/server/backends/RootDSEBackend.java
index 0f5528d..aeef964 100644
--- a/opends/src/server/org/opends/server/backends/RootDSEBackend.java
+++ b/opends/src/server/org/opends/server/backends/RootDSEBackend.java
@@ -289,10 +289,9 @@
supportedFeatures = new HashSet<String>(0);
- // Set the backend ID for this backend. We don't have to worry about
- // potential conflicts because this backend will never get registered with
- // the Directory Server like other backends.
- setBackendID("rootdse");
+ // Set the backend ID for this backend. The identifier needs to be
+ // specific enough to avoid conflict with user backend identifiers.
+ setBackendID("__root.dse__");
// Register as a change listener.
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 1f448f2..ab214a2 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -2587,32 +2587,49 @@
/**
- * Deregister a workflow from a network group.
+ * Deregisters a set of workflows each of which is identified with
+ * a baseDN.
*
* In the first implementation, workflows are stored in the default network
- * group.
+ * group only.
*
- * @param backend the backend which is handled by the workflows to
- * deregister
+ * @param baseDNs the DNs of the workflows to deregister
*/
private static void deregisterWorkflows(
- Backend backend
+ DN[] baseDNs
+ )
+ {
+ for (DN baseDN: baseDNs)
+ {
+ deregisterWorkflow(baseDN);
+ }
+ }
+
+
+ /**
+ * Deregisters one workflow with the appropriate network group.
+ *
+ * In the first implementation, workflows are stored in the default network
+ * group only.
+ *
+ * @param baseDN the DN of the workflow to deregister
+ */
+ private static void deregisterWorkflow(
+ DN baseDN
)
{
// Get the default network group and deregister all the workflows
// being configured for the backend (reminder: there is one worklfow
// per base DN configured in the backend).
NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
- for (DN baseDN: backend.getBaseDNs())
- {
- defaultNetworkGroup.deregisterWorkflow (baseDN);
- }
+ defaultNetworkGroup.deregisterWorkflow (baseDN);
}
/**
- * Create a workflow for the a backend then register the workflow
- * with the appropriate network group.
+ * Creates a set of workflows for a given backend. There are as many
+ * workflows as base DNs defined in the backend. Each workflow is
+ * registered with the appropriate network group.
*
* TODO implement the registration with the appropriate network group.
*
@@ -2622,28 +2639,55 @@
* workflow conflicts with the workflow
* ID of an existing workflow.
*/
- private static void createAndRegisterWorkflows(
+ public static void createAndRegisterWorkflows(
Backend backend
) throws DirectoryException
{
- // Create a root workflow element to encapsulate the backend
- LocalBackendWorkflowElement rootWE =
- new LocalBackendWorkflowElement(backend.getBackendID(), backend);
-
// Create a worklfow for each baseDN being configured
// in the backend and register the workflow with the network groups.
- // The workflow identifier is the same as the backend ID.
+ // In the automatic configuration mode, the workflow identifier is
+ // set to the backend ID.
for (DN curBaseDN: backend.getBaseDNs())
{
- WorkflowImpl workflowImpl = new WorkflowImpl(
- curBaseDN.toString(), curBaseDN, (WorkflowElement) rootWE);
- registerWorkflowInNetworkGroups(workflowImpl);
+ createAndRegisterWorkflow(curBaseDN, backend);
}
}
/**
- * Register a workflow with the appropriate network groups.
+ * Creates one workflow for a given base DN in a backend. The workflow
+ * is registered with the appropriate network group.
+ *
+ * TODO implement the registration with the appropriate network group.
+ *
+ * @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.
+ */
+ public static void createAndRegisterWorkflow(
+ DN baseDN,
+ Backend backend
+ ) throws DirectoryException
+ {
+ String backendID = backend.getBackendID();
+
+ // Create a root workflow element to encapsulate the backend
+ LocalBackendWorkflowElement rootWE =
+ LocalBackendWorkflowElement.create(backendID, backend);
+
+ // Create the worklfow for the base DN and register the workflow with
+ // the appropriate network groups.
+ WorkflowImpl workflowImpl = new WorkflowImpl(
+ baseDN.toString(), baseDN, (WorkflowElement) rootWE);
+ registerWorkflowInNetworkGroups(workflowImpl);
+ }
+
+
+ /**
+ * Registers a workflow with the appropriate network groups.
*
* In the first implementation, the workflow is registered with the
* default network group only.
@@ -2661,7 +2705,6 @@
WorkflowImpl workflowImpl
) throws DirectoryException
{
- // Register first the workflow with the default network group
NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
defaultNetworkGroup.registerWorkflow(workflowImpl);
@@ -2674,14 +2717,8 @@
/**
- * Create the workflows for the backends that were not registered through
- * registerBackend method, nemely cn=config and RootDSE.
- *
- * TODO jdemendi - read the Workflow config and create them accordingly
- *
- * For the prototype: there is no configuration for the workflows.
- * So we create one workflow per local backend, and we register it
- * to the pool.
+ * Creates the workflows for the backends whose baseDNs were not registered
+ * with registerBaseDN method, namely config backend and RootDSE backend.
*
* @throws ConfigException If there is a configuration problem with any of
* the workflows.
@@ -2691,10 +2728,7 @@
{
try
{
- // Create a workflow for the cn=config backend
createAndRegisterWorkflows (configHandler);
-
- // Create a workflows for the rootDSE backend
createAndRegisterWorkflows (rootDSEBackend);
}
catch (DirectoryException de)
@@ -6190,15 +6224,6 @@
monitor.initializeMonitorProvider(null);
backend.setBackendMonitor(monitor);
registerMonitorProvider(monitor);
-
- // FIXME jdemendi - temporary code: create one workflow for each
- // base DN being configured in the backend. We should not rely on the
- // backend registration to create and register workflows because
- // a workflow can be created for different type of "backend", including
- // remote lDAP server. Instead, we should create the workflows using
- // the administration framework. We will be doing so as soon as we
- // have a configuration section for the workflows.
- createAndRegisterWorkflows (backend);
}
}
}
@@ -6225,12 +6250,9 @@
directoryServer.backends = newBackends;
- // Delete all the workflows registered for the backend.
- // FIXME jdemendi - This task should be performed in the scope of the
- // administration framework. However the administration framework
- // requires a configuration section for the workflows which we don't have
- // as of today.
- deregisterWorkflows (backend);
+ // Don't need anymore the local backend workflow element
+ LocalBackendWorkflowElement.remove(backend.getBackendID());
+
BackendMonitor monitor = backend.getBackendMonitor();
if (monitor != null)
@@ -6547,6 +6569,15 @@
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
+ // workflow if the backend happens to be the configuration backend
+ // because it's too soon.
+ if (! baseDN.equals(DN.decode("cn=config")))
+ {
+ createAndRegisterWorkflow(baseDN, backend);
+ }
}
}
}
@@ -6693,6 +6724,9 @@
directoryServer.baseDNs = newBaseDNs;
directoryServer.publicNamingContexts = newPublicNamingContexts;
directoryServer.privateNamingContexts = newPrivateNamingContexts;
+
+ // Now deregister the workflow that was associated with the base DN.
+ deregisterWorkflow(baseDN);
}
}
}
@@ -8396,6 +8430,10 @@
{
try
{
+ // Deregister all the local backend workflow elements that have been
+ // registered with the server.
+ LocalBackendWorkflowElement.removeAll();
+
for (BackendInitializationListener listener :
directoryServer.backendInitializationListeners)
{
diff --git a/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java b/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
index 9cd1262..1a54df8 100644
--- a/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
+++ b/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -731,6 +731,10 @@
try
{
+ // Set a backend ID for the config backend. Try to avoid potential
+ // conflict with user backend identifiers.
+ setBackendID("__config.ldif__");
+
DirectoryServer.registerBaseDN(configRootEntry.getDN(), this, true,
false);
}
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index 255cd3f..c6f4b33 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -46,6 +46,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn;
@@ -139,8 +140,17 @@
*/
private static final DebugTracer TRACER = DebugLogger.getTracer();
- // the backend associated to that workflow element
- Backend backend;
+ // the backend associated with the local workflow element
+ private Backend backend;
+
+ // the set of local backend workflow elements registered with the server
+ private static
+ TreeMap<String, LocalBackendWorkflowElement> registeredLocalBackends =
+ new TreeMap<String, LocalBackendWorkflowElement>();
+
+ // a lock to guarantee safe concurrent access to the registeredLocalBackends
+ // variable
+ private static Object registeredLocalBackendsLock = new Object();
/**
@@ -149,7 +159,7 @@
* @param workflowElementID the workflow element identifier
* @param backend the backend associated to that workflow element
*/
- public LocalBackendWorkflowElement(
+ private LocalBackendWorkflowElement(
String workflowElementID,
Backend backend
)
@@ -166,6 +176,122 @@
/**
+ * Creates and registers a local backend with the server.
+ *
+ * @param workflowElementID the identifier of the workflow element to create
+ * @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 create(
+ String workflowElementID,
+ Backend backend
+ )
+ {
+ LocalBackendWorkflowElement localBackend = null;
+
+ // If the requested workflow element does not exist then create one.
+ localBackend = registeredLocalBackends.get(workflowElementID);
+ if (localBackend == null)
+ {
+ localBackend = new LocalBackendWorkflowElement(
+ workflowElementID, backend);
+
+ // store the new local backend in the list of registered backends
+ registerLocalBackend(localBackend);
+ }
+
+ return localBackend;
+ }
+
+
+ /**
+ * Removes a local backend that was registered with the server.
+ *
+ * @param workflowElementID the identifier of the workflow element to remove
+ */
+ public static void remove(
+ String workflowElementID
+ )
+ {
+ deregisterLocalBackend(workflowElementID);
+ }
+
+
+ /**
+ * 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.getWorkflowElementID());
+ }
+ }
+ }
+
+
+ /**
+ * 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)
+ {
+ String localBackendID = localBackend.getWorkflowElementID();
+ LocalBackendWorkflowElement existingLocalBackend =
+ registeredLocalBackends.get(localBackendID);
+
+ if (existingLocalBackend == null)
+ {
+ TreeMap<String, LocalBackendWorkflowElement> newLocalBackends =
+ new TreeMap
+ <String, LocalBackendWorkflowElement>(registeredLocalBackends);
+ newLocalBackends.put(localBackendID, localBackend);
+ registeredLocalBackends = newLocalBackends;
+ }
+ }
+ }
+
+
+ /**
+ * Deregisters a local backend with the server.
+ *
+ * @param workflowElementID the identifier of the workflow element to remove
+ */
+ private static void deregisterLocalBackend(
+ String workflowElementID
+ )
+ {
+ synchronized (registeredLocalBackendsLock)
+ {
+ LocalBackendWorkflowElement existingLocalBackend =
+ registeredLocalBackends.get(workflowElementID);
+
+ if (existingLocalBackend != null)
+ {
+ TreeMap<String, LocalBackendWorkflowElement> newLocalBackends =
+ new TreeMap
+ <String, LocalBackendWorkflowElement>(registeredLocalBackends);
+ newLocalBackends.remove(workflowElementID);
+ registeredLocalBackends = newLocalBackends;
+ }
+ }
+ }
+
+
+ /**
* {@inheritDoc}
*/
public void execute(Operation operation)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java
index c341d7f..67d8e1a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java
@@ -31,11 +31,22 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
+import static org.opends.server.config.ConfigConstants.DN_BACKEND_BASE;
+
+import java.util.ArrayList;
import org.opends.server.TestCaseUtils;
import org.opends.server.DirectoryServerTestCase;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.types.Attribute;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchScope;
import org.opends.server.workflowelement.WorkflowElement;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -473,6 +484,160 @@
/**
+ * This test checks that network groups are updated as appropriate when
+ * backend base DNs are added or removed. When a new backend base DN is
+ * added, the new suffix should be accessible for the route process - ie.
+ * a workflow should be created and be a potential candidate for the route
+ * process. Simillarly, when a backend base DN is removed its associated
+ * workflow should be removed; subsequently, any request targetting the
+ * removed suffix should be rejected and a no such entry status code be
+ * returned.
+ */
+ @Test
+ public void testBackendBaseDNModification()
+ throws Exception
+ {
+ String suffix = "dc=example,dc=com";
+ String suffix2 = "o=networkgroup suffix";
+ String backendBaseDNName = "ds-cfg-backend-base-dn";
+
+ // Initialize a backend with a base entry.
+ TestCaseUtils.clearJEBackend(true, "userRoot", suffix);
+
+ // Create a client connection for the test.
+ InternalClientConnection connection =
+ InternalClientConnection.getRootConnection();
+
+ // Check that suffix is accessible while suffix2 is not.
+ searchEntry(connection, suffix, true);
+ searchEntry(connection, suffix2, false);
+
+ // Add a new suffix in the backend and create a base entry for the
+ // new suffix.
+ String backendConfigDN = "ds-cfg-backend-id=userRoot," + DN_BACKEND_BASE;
+ modifyAttribute(
+ connection, backendConfigDN,
+ ModificationType.ADD, backendBaseDNName, suffix2);
+ addBaseEntry(connection, suffix2, "networkgroup suffix");
+
+ // Both old and new suffix should be accessible.
+ searchEntry(connection, suffix, true);
+ searchEntry(connection, suffix2, true);
+
+ // Remove the new suffix...
+ modifyAttribute(
+ connection, backendConfigDN,
+ ModificationType.DELETE, backendBaseDNName, suffix2);
+
+ // ...and check that the removed suffix is no more accessible.
+ searchEntry(connection, suffix, true);
+ searchEntry(connection, suffix2, false);
+
+ // Replace the suffix with suffix2 in the backend
+ modifyAttribute(
+ connection, backendConfigDN,
+ ModificationType.REPLACE, backendBaseDNName, suffix2);
+
+ // Now none of the suffixes are accessible: this means the entries
+ // under the old suffix are not moved to the new suffix.
+ searchEntry(connection, suffix, false);
+ searchEntry(connection, suffix2, false);
+
+ // Add a base entry for the new suffix
+ addBaseEntry(connection, suffix2, "networkgroup suffix");
+
+ // The new suffix is accessible while the old one is not.
+ searchEntry(connection, suffix, false);
+ searchEntry(connection, suffix2, true);
+ }
+
+
+ /**
+ * Searches an entry on a given connection.
+ *
+ * @param connection the connection to use for the search request
+ * @param baseDN the request base DN string
+ * @param shouldExist if true the searched entry is expected to be found
+ */
+ private void searchEntry(
+ InternalClientConnection connection,
+ String baseDN,
+ boolean shouldExist
+ ) throws Exception
+ {
+ SearchOperation search = connection.processSearch(
+ DN.decode(baseDN),
+ SearchScope.BASE_OBJECT,
+ LDAPFilter.decode("(objectClass=*)").toSearchFilter());
+
+ // Compare the result code with the expected one
+ ResultCode resultCode = search.getResultCode();
+ if (shouldExist)
+ {
+ assertEquals(resultCode, ResultCode.SUCCESS);
+ }
+ else
+ {
+ assertEquals(resultCode, ResultCode.NO_SUCH_OBJECT);
+ }
+ }
+
+
+ /**
+ * Creates a base entry for the given suffix.
+ *
+ * @param connection the connection to use for the add request
+ * @param suffix the suffix for which the base entry is to be created
+ */
+ private void addBaseEntry(
+ InternalClientConnection connection,
+ String suffix,
+ String namingAttribute
+ ) throws Exception
+ {
+ Entry e = TestCaseUtils.makeEntry(
+ "dn: " + suffix,
+ "objectClass: top",
+ "objectClass: organization",
+ "o: " + namingAttribute);
+
+ AddOperation addOperation = connection.processAdd(
+ e.getDN(),
+ e.getObjectClasses(),
+ e.getUserAttributes(),
+ e.getOperationalAttributes());
+
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
+ * Adds/Deletes/Replaces an attribute in a given entry.
+ *
+ * @param connection the connection to use for the modify request
+ * @param baseDN the request base DN string
+ * @param modType the modification type (add/delete/replace)
+ * @param attributeName the name of the attribute to add/delete/replace
+ * @param attributeValue the value of the attribute to add/delete/replace
+ */
+ private void modifyAttribute(
+ InternalClientConnection connection,
+ String baseDN,
+ ModificationType modType,
+ String attributeName,
+ String attributeValue
+ ) throws Exception
+ {
+ ArrayList<Modification> mods = new ArrayList<Modification>();
+ Attribute attributeToModify = new Attribute(attributeName, attributeValue);
+ mods.add(new Modification(modType, attributeToModify));
+ ModifyOperation modifyOperation = connection.processModify(
+ DN.decode(baseDN), mods);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+
+ /**
* Checks the DN routing through a network group.
*
* @param networkGroup the network group to use for the check
--
Gitblit v1.10.0