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

mmarie
22.59.2008 807c1ab12c8500ffd6b1b6e779806607adb6e654
3264 : Workflow element creation ordering may lead to failure
5 files modified
279 ■■■■ changed files
opends/src/messages/messages/core.properties 3 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 112 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowConfigManager.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/WorkflowElement.java 93 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java 69 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/core.properties
@@ -1771,3 +1771,6 @@
MILD_ERR_MODDN_NEW_SUPERIOR_IN_SUBTREE_702=The modify DN operation \
 for entry %s cannot be performed because the new superior entry %s is equal \
 to or a subordinate of the entry to be moved
SEVERE_ERR_REGISTER_WORKFLOW_ELEMENT_ALREADY_EXISTS_703=Unable to register \
 workflow element %s with the Directory Server because another workflow \
 element with the same ID is already registered
opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -170,13 +170,21 @@
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.Validator.ensureNotNull;
import org.opends.server.util.*;
import org.opends.server.util.MultiOutputStream;
import org.opends.server.util.RuntimeInformation;
import org.opends.server.util.SetupUtils;
import org.opends.server.util.StaticUtils;
import org.opends.server.util.TimeThread;
import org.opends.server.util.Validator;
import org.opends.server.util.VersionCompatibilityIssue;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.ArgumentParser;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.workflowelement.*;
import org.opends.server.workflowelement.localbackend.*;
import org.opends.server.workflowelement.WorkflowElement;
import org.opends.server.workflowelement.WorkflowElementConfigManager;
import
  org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
import org.opends.server.protocols.internal.InternalConnectionHandler;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.crypto.CryptoManagerSync;
@@ -700,6 +708,11 @@
  // The writability mode for the Directory Server.
  private WritabilityMode writabilityMode;
  // The mappings between the names and WorkflowElements
  // registered with the Directory Server
  private ConcurrentHashMap<String, WorkflowElement> workflowElements =
          new ConcurrentHashMap<String, WorkflowElement>();
  // The workflow configuration mode (auto or manual).
  private WorkflowConfigurationMode workflowConfigurationMode;
@@ -2788,7 +2801,7 @@
    // First of all re-initialize the current workflow configuration
    NetworkGroup.resetConfig();
    WorkflowImpl.resetConfig();
    WorkflowElement.resetConfig();
    directoryServer.workflowElements.clear();
    // Then configure the workflows
    workflowElementConfigManager = new WorkflowElementConfigManager();
@@ -2818,7 +2831,7 @@
    // First of all re-initialize the current workflow configuration
    NetworkGroup.resetConfig();
    WorkflowImpl.resetConfig();
    WorkflowElement.resetConfig();
    directoryServer.workflowElements.clear();
    // For each base DN in a backend create a workflow and register
    // the workflow with the default network group
@@ -9819,8 +9832,6 @@
    return isAuto;
  }
  /**
   * Retrieves the workflow configuration mode.
   *
@@ -9831,7 +9842,94 @@
    return directoryServer.workflowConfigurationMode;
  }
  /**
   * Return the WorkflowElement associated with a name.
   *
   * @param workflowElementID the name of the requested workflow element
   * @return the associated workflow element or null
   */
  public static WorkflowElement getWorkflowElement(String workflowElementID) {
    return(directoryServer.workflowElements.get(workflowElementID));
  }
  /**
   * Return the WorkflowElement associated with a name and try to
   * create it if it does not exists yet.
   *
   * @param workflowElementID the name of the requested workflow element
   * @return the associated workflow element
   * @throws ConfigException if the configuration is invalid
   * @throws InitializationException if the initialization failed
   */
  public static WorkflowElement getOrCreateWorkflowElement(
          String workflowElementID)
    throws ConfigException, InitializationException {
    WorkflowElement we = directoryServer.workflowElements.get(
      workflowElementID);
    if (we == null) {
      we = directoryServer.workflowElementConfigManager.
        loadAndRegisterWorkflowElement(workflowElementID);
    }
    return (we);
  }
  /**
   * Registers the provided workflow element from the Directory Server.
   *
   * @param  we  The workflow element to register. It must not be
   *                  {@code null}.
   * @throws  DirectoryException  If the workflow element ID for the
   *              provided workflow element conflicts with the ID of
   *              an existing workflow element.
   */
  public static void registerWorkflowElement(WorkflowElement we)
    throws DirectoryException {
    ensureNotNull(we);
    String workflowElementID = we.getWorkflowElementID();
    ensureNotNull(workflowElementID);
    synchronized (directoryServer)
    {
      if (directoryServer.workflowElements.containsKey(workflowElementID)) {
        Message message = ERR_REGISTER_WORKFLOW_ELEMENT_ALREADY_EXISTS.get(
                workflowElementID);
      } else {
        directoryServer.workflowElements.put(workflowElementID, we);
      }
    }
  }
  /**
   * Deregisters the provided workflow element from the Directory Server.
   *
   * @param  we  The workflow element to deregister. It must not be
   *                  {@code null}.
   */
  public static void deregisterWorkflowElement(WorkflowElement we) {
    ensureNotNull(we);
    String workflowElementID = we.getWorkflowElementID();
    ensureNotNull(workflowElementID);
    synchronized (directoryServer)
    {
      directoryServer.workflowElements.remove(workflowElementID);
    }
  }
  /**
   * Verifies if the provided workflow element ID is already registered.
   *
   * @param workflowElementID workflow element identifier
   * @return boolean indicating if workflow element is already registered
   */
  public static boolean isWorkflowElementRegistered(String workflowElementID) {
    return (directoryServer.workflowElements.containsKey(workflowElementID));
  }
  /**
   * Print messages for start-ds "-F" option (full version information).
opends/src/server/org/opends/server/core/WorkflowConfigManager.java
@@ -294,7 +294,7 @@
    // Create the root workflow element to associate with the workflow
    String rootWorkflowElementID = workflowCfg.getWorkflowElement();
    WorkflowElement rootWorkflowElement =
      WorkflowElement.getWorkflowElement(rootWorkflowElementID);
      DirectoryServer.getWorkflowElement(rootWorkflowElementID);
    // Get the base DN targeted by the workflow
    DN baseDN = workflowCfg.getBaseDN();
opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
@@ -26,15 +26,10 @@
 */
package org.opends.server.workflowelement;
import static org.opends.server.util.Validator.ensureNotNull;
import static org.opends.messages.ConfigMessages.*;
import java.util.List;
import java.util.TreeMap;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.WorkflowElementCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Operation;
import org.opends.server.types.CanceledOperationException;
@@ -61,17 +56,6 @@
  // The workflow element identifier.
  private String workflowElementID = null;
  // The set of workflow elements registered with the server.
  // The workflow element identifier is used as a key in the map.
  private static TreeMap<String, WorkflowElement> registeredWorkflowElements =
    new TreeMap<String, WorkflowElement>();
  // A lock to protect access to the registered workflow elements.
  private static Object registeredWorkflowElementsLock = new Object();
  // The parent of the workflow element (null if the workflow element is
  // the root of the processing tree).
  private WorkflowElement<?> parent = null;
@@ -85,7 +69,6 @@
    // There is nothing to do in the constructor.
  }
  /**
   * Initializes the instance of the workflow element.
   *
@@ -123,7 +106,7 @@
   *          for this workflow element, or {@code false} if not.
   */
  public boolean isConfigurationAcceptable(
      WorkflowElementCfg configuration,
      T configuration,
      List<String> unacceptableReasons)
  {
    // This default implementation does not perform any special
@@ -143,7 +126,6 @@
    // No action is required by default.
  }
  /**
   * Executes the workflow element for an operation.
   *
@@ -191,78 +173,5 @@
  {
    return workflowElementID;
  }
  /**
   * Registers the workflow element (this) with the server.
   *
   * @throws  ConfigException  If the workflow element ID for the provided
   *                           workflow element conflicts with the workflow
   *                           element ID of an existing workflow element.
   */
  public void register()
      throws ConfigException
  {
    ensureNotNull(workflowElementID);
    synchronized (registeredWorkflowElementsLock)
    {
      // the workflow element must not be already registered
      if (registeredWorkflowElements.containsKey(workflowElementID))
      {
        Message message = ERR_CONFIG_WORKFLOW_ELEMENT_ALREADY_REGISTERED.get(
            workflowElementID);
        throw new ConfigException(message);
      }
      TreeMap<String, WorkflowElement> newWorkflowElements =
        new TreeMap<String, WorkflowElement>(registeredWorkflowElements);
      newWorkflowElements.put(workflowElementID, this);
      registeredWorkflowElements = newWorkflowElements;
    }
  }
  /**
   * Deregisters the workflow element (this) with the server.
   */
  public void deregister()
  {
    ensureNotNull(workflowElementID);
    synchronized (registeredWorkflowElementsLock)
    {
      TreeMap<String, WorkflowElement> newWorkflowElements =
        new TreeMap<String, WorkflowElement>(registeredWorkflowElements);
      newWorkflowElements.remove(workflowElementID);
      registeredWorkflowElements = newWorkflowElements;
    }
  }
  /**
   * Gets a workflow element that was registered with the server.
   *
   * @param workflowElementID  the ID of the workflow element to get
   * @return the requested workflow element
   */
  public static WorkflowElement getWorkflowElement(
      String workflowElementID)
  {
    return registeredWorkflowElements.get(workflowElementID);
  }
  /**
   * Resets all the registered workflows.
   */
  public static void resetConfig()
  {
    synchronized (registeredWorkflowElementsLock)
    {
      registeredWorkflowElements = new TreeMap<String, WorkflowElement>();
    }
  }
}
opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
@@ -35,7 +35,6 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.opends.messages.Message;
import org.opends.server.admin.ClassPropertyDefinition;
@@ -49,7 +48,7 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
@@ -67,18 +66,12 @@
                  ConfigurationDeleteListener<WorkflowElementCfg>
{
  // A mapping between the DNs of the config entries and the associated
  // workflow elements.
  private ConcurrentHashMap<DN, WorkflowElement> workflowElements;
  /**
   * Creates a new instance of this workflow config manager.
   */
  public WorkflowElementConfigManager()
  {
    workflowElements = new ConcurrentHashMap<DN, WorkflowElement>();
  }
@@ -113,18 +106,38 @@
    //Initialize the existing workflows.
    for (String workflowName : rootConfiguration.listWorkflowElements())
    {
      WorkflowElementCfg workflowConfiguration =
        rootConfiguration.getWorkflowElement(workflowName);
      workflowConfiguration.addChangeListener(this);
      if (workflowConfiguration.isEnabled())
      {
        loadAndRegisterWorkflowElement(workflowConfiguration);
      }
      loadAndRegisterWorkflowElement(workflowName);
    }
  }
  /**
   * Return the associated workflowElement is enabled if the
   * workflow is enabled.
   *
   * @param workflowName workflow identifier
   * @return workflowelement associated with the workflowName of null
   * @throws org.opends.server.config.ConfigException Exception will reading
   *         the config
   * @throws org.opends.server.types.InitializationException Exception while
   *         initializing the workflow element
   */
  public WorkflowElement loadAndRegisterWorkflowElement(String workflowName)
          throws ConfigException, InitializationException {
    ServerManagementContext managementContext =
         ServerManagementContext.getInstance();
    RootCfg rootConfiguration =
         managementContext.getRootConfiguration();
    WorkflowElementCfg workflowConfiguration =
        rootConfiguration.getWorkflowElement(workflowName);
    workflowConfiguration.addChangeListener(this);
    if (workflowConfiguration.isEnabled())
    {
      return (loadAndRegisterWorkflowElement(workflowConfiguration));
    }
    return (null);
  }
  /**
   * {@inheritDoc}
@@ -220,10 +233,10 @@
    WorkflowElement workflowElement =
      workflowElements.remove(configuration.dn());
            DirectoryServer.getWorkflowElement(configuration.dn().toString());
    if (workflowElement != null)
    {
      workflowElement.deregister();
      DirectoryServer.deregisterWorkflowElement(workflowElement);
      workflowElement.finalizeWorkflowElement();
    }
@@ -278,7 +291,7 @@
    // Get the existing workflow element if it's already enabled.
    WorkflowElement existingWorkflowElement =
      workflowElements.get(configuration.dn());
            DirectoryServer.getWorkflowElement(configuration.dn().toString());
    // If the new configuration has the workflow element disabled,
    // then disable it if it is enabled, or do nothing if it's already disabled.
@@ -286,8 +299,7 @@
    {
      if (existingWorkflowElement != null)
      {
        workflowElements.remove(configuration.dn());
        existingWorkflowElement.deregister();
        DirectoryServer.deregisterWorkflowElement(existingWorkflowElement);
        existingWorkflowElement.finalizeWorkflowElement();
      }
@@ -320,8 +332,8 @@
   * Loads a class and instanciates it as a workflow element. The workflow
   * element is initialized and registered with the server.
   *
   * @param workflowCfg  the workflow element configuration
   *
   * @param workflowElementCfg  the workflow element configuration
   * @return WorkflowElement
   * @throws InitializationException If a problem occurs while trying to
   *                            decode a provided string as a DN or if
   *                            the workflow element ID for a provided
@@ -329,7 +341,7 @@
   *                            ID of an existing workflow during workflow
   *                            registration.
   */
  private void loadAndRegisterWorkflowElement(
  WorkflowElement loadAndRegisterWorkflowElement(
      WorkflowElementCfg workflowElementCfg
      ) throws InitializationException
  {
@@ -341,16 +353,13 @@
    try
    {
      // register the workflow element
      workflowElement.register();
      // keep the workflow element in the list of configured workflow
      // elements
      workflowElements.put(workflowElementCfg.dn(), workflowElement);
      DirectoryServer.registerWorkflowElement(workflowElement);
    }
    catch (ConfigException de)
    catch (DirectoryException de)
    {
      throw new InitializationException(de.getMessageObject());
    }
    return (workflowElement);
  }