From a59bc5309dcfaa674d5f1a0257af8bb298c8002b Mon Sep 17 00:00:00 2001
From: mmarie <mmarie@localhost>
Date: Thu, 22 May 2008 08:59:31 +0000
Subject: [PATCH] 3264 : Workflow element creation ordering may lead to failure

---
 opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java                         |  112 +++++++++++++++++++++-
 opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java                   |    2 
 opendj-sdk/opends/src/messages/messages/core.properties                                          |    3 
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java |   69 +++++++------
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java              |   93 ------------------
 5 files changed, 149 insertions(+), 130 deletions(-)

diff --git a/opendj-sdk/opends/src/messages/messages/core.properties b/opendj-sdk/opends/src/messages/messages/core.properties
index 17e171d..a4fcb1f 100644
--- a/opendj-sdk/opends/src/messages/messages/core.properties
+++ b/opendj-sdk/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
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index 5a2f5b3..8002d69 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/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).
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java
index 2faf2da..8ea5280 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java
+++ b/opendj-sdk/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();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
index 21c7194..9911ff7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
+++ b/opendj-sdk/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>();
-    }
-  }
-
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
index 113defa..411a4e7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
+++ b/opendj-sdk/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);
   }
 
 

--
Gitblit v1.10.0