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

jdemendi
20.08.2007 eedbc609a3b3920a2c402c51f894939b114410f8

Before the fix I was registering the workflows with the server whenever a backend was registered with the server (in the automatic configuration mode). However when a new base DN was added to an existing backend, the corresponding workflow was not created nor registered with the server! So I have moved the workflow creation and registration to the DirectoryServer.registerBaseDN() method. That way, any change to the backends and/or backend baseDNs are taken into account and the workflows are updated accordingly:

- Workflows are created and registered with the server
1) at server startup for each and every enabled backend
2) when a backend is dynamically added or enabled
3) when a backend baseDN is added to an enabled backend

- Workflows are deregistered and removed when
1) server is shutting down
2) a backend is disabled
3) a backend baseDN is removed


--This line, and these below, wll be ignored--

M tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java
M src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
M src/server/org/opends/server/core/DirectoryServer.java
M src/server/org/opends/server/extensions/ConfigFileHandler.java
M src/server/org/opends/server/backends/RootDSEBackend.java
5 files modified
442 ■■■■ changed files
opends/src/server/org/opends/server/backends/RootDSEBackend.java 7 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 134 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java 132 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/NetworkGroupTest.java 165 ●●●●● patch | view | raw | blame | history
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.
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)
        {
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);
    }
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)
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