From 58a50508676500a29b29075f66e454b113a08791 Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Wed, 08 Aug 2007 09:57:42 +0000
Subject: [PATCH] This set of changes add ID to identify network groups, workflows and workflow elements. These identifiers pave the way for the network group and workflow configuration.

---
 opends/src/server/org/opends/server/core/NetworkGroup.java |  361 ++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 270 insertions(+), 91 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/NetworkGroup.java b/opends/src/server/org/opends/server/core/NetworkGroup.java
index 516e24d..a510884 100644
--- a/opends/src/server/org/opends/server/core/NetworkGroup.java
+++ b/opends/src/server/org/opends/server/core/NetworkGroup.java
@@ -27,31 +27,42 @@
 package org.opends.server.core;
 
 
-import java.util.ArrayList;
+import static org.opends.server.messages.CoreMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.TreeMap;
 
 import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
 import org.opends.server.workflowelement.WorkflowElement;
 
 
 /**
  * This class defines the network group. A network group is used to categorize
  * client connections. A network group is defined by a set of criteria, a
- * set of policies and a set of workflows. A client connection belongs to a
- * network group whenever it satisfies all the network group criteria. As soon
- * as a client connection belongs to a network group, it has to comply with
- * all the network group policies and all the client operation can be routed
- * to one the network group workflows.
+ * set of policies and a set of workflow nodes. A client connection belongs to
+ * a network group whenever it satisfies all the network group criteria. As
+ * soon as a client connection belongs to a network group, it has to comply
+ * with all the network group policies. Any cleared client operation can be
+ * routed to one the network group workflow nodes.
  */
 public class NetworkGroup
 {
-  // Workflows registered with the current network group.
-  private ArrayList<WorkflowTopologyNode> registeredWorkflows =
-      new ArrayList<WorkflowTopologyNode>();
+  // Workflow nodes registered with the current network group.
+  // Keys are workflowIDs.
+  private TreeMap<String, WorkflowTopologyNode> registeredWorkflowNodes =
+      new TreeMap<String, WorkflowTopologyNode>();
 
 
-  // The workflow for the rootDSE entry. The RootDSE workflow
-  // is not stored in the list of registered workflows.
-  private RootDseWorkflowTopology rootDSEWorkflow = null;
+  // A lock to protect concurrent access to the registered Workflow nodes.
+  private static Object registeredWorkflowNodesLock = new Object();
+
+
+  // The workflow node for the rootDSE entry. The RootDSE workflow node
+  // is not stored in the list of registered workflow nodes.
+  private RootDseWorkflowTopology rootDSEWorkflowNode = null;
 
 
   // List of naming contexts handled by the network group.
@@ -68,39 +79,77 @@
       new NetworkGroup ("default");
 
 
-  // The list of all network groups that have been created.
-  // The default network group is not stored in that pool.
-  private static ArrayList<NetworkGroup> networkGroupPool =
-      new ArrayList<NetworkGroup>();
+  // The list of all network groups that are registered with the server.
+  // The defaultNetworkGroup is not in the list of registered network groups.
+  private static TreeMap<String, NetworkGroup> registeredNetworkGroups =
+      new TreeMap<String, NetworkGroup>();
 
 
-  // Human readable network group name.
-  private String networkGroupName = null;
+  // A lock to protect concurrent access to the registeredNetworkGroups.
+  private static Object registeredNetworkGroupsLock = new Object();
+
+
+  // The network group internal identifier.
+  private String networkGroupID = null;
+
 
 
   /**
    * Creates a new instance of the network group.
    *
-   * @param networkGroupName  the name of the network group for debug purpose
+   * @param networkGroupID  the network group internal identifier
    */
-  public NetworkGroup (
-      String networkGroupName
+  public NetworkGroup(
+      String networkGroupID
       )
   {
-    this.networkGroupName = networkGroupName;
+    this.networkGroupID = networkGroupID;
   }
 
 
   /**
-   * Registers a network group with the pool of network groups.
+   * Registers the current network group (this) with the server.
    *
-   * @param networkGroup  the network group to register
+   * @throws  DirectoryException  If the network group ID for the provided
+   *                              network group conflicts with the network
+   *                              group ID of an existing network group.
    */
-  public static void registerNetworkGroup(
-      NetworkGroup networkGroup
-      )
+  public void register()
+      throws DirectoryException
   {
-    networkGroupPool.add(networkGroup);
+    ensureNotNull(networkGroupID);
+
+    synchronized (registeredNetworkGroupsLock)
+    {
+      // The network group must not be already registered
+      if (registeredNetworkGroups.containsKey(networkGroupID))
+      {
+        int msgID = MSGID_REGISTER_NETWORK_GROUP_ALREADY_EXISTS;
+        String message = getMessage(msgID, networkGroupID);
+        throw new DirectoryException(
+            ResultCode.UNWILLING_TO_PERFORM, message, msgID);
+      }
+
+      TreeMap<String, NetworkGroup> newRegisteredNetworkGroups =
+        new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
+      newRegisteredNetworkGroups.put(networkGroupID, this);
+      registeredNetworkGroups = newRegisteredNetworkGroups;
+    }
+  }
+
+
+  /**
+   * Deregisters the current network group (this) with the server.
+   */
+  public void deregister()
+  {
+    synchronized (registeredNetworkGroupsLock)
+    {
+      TreeMap<String, NetworkGroup> networkGroups =
+        new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
+      networkGroups.remove(networkGroupID);
+      registeredNetworkGroups = networkGroups;
+    }
   }
 
 
@@ -108,10 +157,14 @@
    * Registers a workflow with the network group.
    *
    * @param workflow  the workflow to register
+   *
+   * @throws  DirectoryException  If the workflow ID for the provided
+   *                              workflow conflicts with the workflow
+   *                              ID of an existing workflow.
    */
   public void registerWorkflow(
       WorkflowImpl workflow
-      )
+      ) throws DirectoryException
   {
     // The workflow is rgistered with no pre/post workflow element.
     registerWorkflow(workflow, null, null);
@@ -125,12 +178,16 @@
    * @param workflow              the workflow to register
    * @param preWorkflowElements   the tasks to execute before the workflow
    * @param postWorkflowElements  the tasks to execute after the workflow
+   *
+   * @throws  DirectoryException  If the workflow ID for the provided
+   *                              workflow conflicts with the workflow
+   *                              ID of an existing workflow.
    */
   private void registerWorkflow(
       WorkflowImpl workflow,
       WorkflowElement[] preWorkflowElements,
       WorkflowElement[] postWorkflowElements
-      )
+      ) throws DirectoryException
   {
     // true as soon as the workflow has been registered
     boolean registered = false;
@@ -139,45 +196,44 @@
     DN baseDN = workflow.getBaseDN();
     if (baseDN.isNullDN())
     {
-      // NOTE - The rootDSE workflow is not stored in the pool.
-      rootDSEWorkflow = new RootDseWorkflowTopology(workflow, namingContexts);
+      // NOTE - The rootDSE workflow is stored with the registeredWorkflows.
+      rootDSEWorkflowNode =
+        new RootDseWorkflowTopology(workflow, namingContexts);
       registered = true;
     }
     else
     {
       // This workflow is not the rootDSE workflow. Try to insert it in the
       // workflow topology.
-      if (! baseDNAlreadyRegistered(baseDN))
+      WorkflowTopologyNode workflowNode = new WorkflowTopologyNode(
+          workflow, preWorkflowElements, postWorkflowElements);
+
+      // Register the workflow node with the network group. If the workflow
+      // ID is already existing then an exception is raised.
+      registerWorkflowNode(workflowNode);
+      registered = true;
+
+      // Now add the workflow in the workflow topology...
+      for (WorkflowTopologyNode curNode: registeredWorkflowNodes.values())
       {
-        WorkflowTopologyNode workflowTopology = new WorkflowTopologyNode(
-            workflow, preWorkflowElements, postWorkflowElements);
-
-        // Add the workflow in the workflow topology...
-        for (WorkflowTopologyNode curWorkflow: registeredWorkflows)
+        // Try to insert the new workflow under an existing workflow...
+        if (curNode.insertSubordinate(workflowNode))
         {
-          // Try to insert the new workflow under an existing workflow...
-          if (curWorkflow.insertSubordinate(workflowTopology))
-          {
-            // new workflow has been inserted in the topology
-            break;
-          }
-
-          // ... or try to insert the existing workflow below the new
-          // workflow
-          if (workflowTopology.insertSubordinate(curWorkflow))
-          {
-            // new workflow has been inserted in the topology
-            break;
-          }
+          // new workflow has been inserted in the topology
+          break;
         }
 
-        // ... then register the workflow with the pool.
-        registeredWorkflows.add(workflowTopology);
-        registered = true;
-
-        // Rebuild the list of naming context handled by the network group
-        rebuildNamingContextList();
+        // ... or try to insert the existing workflow below the new
+        // workflow
+        if (workflowNode.insertSubordinate(curNode))
+        {
+          // new workflow has been inserted in the topology
+          break;
+        }
       }
+
+      // Rebuild the list of naming context handled by the network group
+      rebuildNamingContextList();
     }
 
     // If the workflow has been registered successfully then register it
@@ -194,26 +250,98 @@
 
 
   /**
-   * Deregisters a workflow with the network group.
+   * Deregisters a workflow with the network group. The workflow to
+   * deregister is identified by its baseDN.
    *
-   * @param baseDN  the baseDN of the workflow to deregister
+   * @param baseDN  the baseDN of the workflow to deregister, may be null
    */
-  public void deregisterWorkflow (
+  public void deregisterWorkflow(
       DN baseDN
       )
   {
-    Workflow workflow = getWorkflowCandidate(baseDN);
-    if (workflow != null)
+    if (baseDN == null)
     {
-      deregisterWorkflow(workflow);
+      return;
+    }
+
+    if (baseDN.isNullDN())
+    {
+      // deregister the rootDSE
+      deregisterWorkflow(rootDSEWorkflowNode);
+    }
+    else
+    {
+      // deregister a workflow node
+      synchronized (registeredWorkflowNodesLock)
+      {
+        for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
+        {
+          DN curDN = node.getBaseDN();
+          if (curDN.equals(baseDN))
+          {
+            // Call deregisterWorkflow() instead of deregisterWorkflowNode()
+            // because we want the naming context list to be updated as well.
+            deregisterWorkflow(node);
+
+            // Only one workflow can match the baseDN, so we can break
+            // the loop here.
+            break;
+          }
+        }
+      }
     }
   }
 
 
   /**
-   * Deregisters a workflow with the network group.
+   * Deregisters a workflow with the network group. The workflow to
+   * deregister is identified by its workflow ID.
    *
-   * @param workflow  the workflow to deregister
+   * @param workflowID the workflow identifier of the workflow to deregister
+   */
+  public void deregisterWorkflow(
+      String workflowID
+      )
+  {
+    String rootDSEWorkflowID = null;
+    if (rootDSEWorkflowNode != null)
+    {
+      rootDSEWorkflowID = rootDSEWorkflowNode.getWorkflowImpl().getWorkflowId();
+    }
+
+    if (workflowID.equalsIgnoreCase(rootDSEWorkflowID))
+    {
+      // deregister the rootDSE
+      deregisterWorkflow(rootDSEWorkflowNode);
+    }
+    else
+    {
+      // deregister a workflow node
+      synchronized (registeredWorkflowNodesLock)
+      {
+        for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
+        {
+          String curID = node.getWorkflowImpl().getWorkflowId();
+          if (curID.equals(workflowID))
+          {
+            // Call deregisterWorkflow() instead of deregisterWorkflowNode()
+            // because we want the naming context list to be updated as well.
+            deregisterWorkflow(node);
+
+            // Only one workflow can match the baseDN, so we can break
+            // the loop here.
+            break;
+          }
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Deregisters a workflow node with the network group.
+   *
+   * @param workflowNode  the workflow node to deregister
    */
   private void deregisterWorkflow(
       Workflow workflow
@@ -223,21 +351,21 @@
     boolean deregistered = false;
 
     // Is it the rootDSE workflow?
-    if (workflow == rootDSEWorkflow)
+    if (workflow == rootDSEWorkflowNode)
     {
-      rootDSEWorkflow = null;
+      rootDSEWorkflowNode = null;
       deregistered = true;
     }
     else
     {
+      // Deregister the workflow with the network group.
+      WorkflowTopologyNode workflowNode = (WorkflowTopologyNode) workflow;
+      deregisterWorkflowNode(workflowNode);
+      deregistered = true;
+
       // The workflow to deregister is not the root DSE workflow.
       // Remove it from the workflow topology.
-      WorkflowTopologyNode workflowTopology = (WorkflowTopologyNode) workflow;
-      workflowTopology.remove();
-
-      // Then deregister the workflow with the network group.
-      registeredWorkflows.remove(workflow);
-      deregistered = true;
+      workflowNode.remove();
 
       // Rebuild the list of naming context handled by the network group
       rebuildNamingContextList();
@@ -245,12 +373,63 @@
 
     // If the workflow has been deregistered then deregister it with
     // the default network group as well
-    if (deregistered)
+    if (deregistered && (this != defaultNetworkGroup))
     {
-      if (this != defaultNetworkGroup)
+      defaultNetworkGroup.deregisterWorkflow(workflow);
+    }
+  }
+
+
+  /**
+   * Registers a workflow node with the network group.
+   *
+   * @param workflowNode  the workflow node to register
+   *
+   * @throws  DirectoryException  If the workflow node ID for the provided
+   *                              workflow node conflicts with the workflow
+   *                              node ID of an existing workflow node.
+   */
+  private void registerWorkflowNode(
+      WorkflowTopologyNode workflowNode
+      ) throws DirectoryException
+  {
+    String workflowID = workflowNode.getWorkflowImpl().getWorkflowId();
+    ensureNotNull(workflowID);
+
+    synchronized (registeredWorkflowNodesLock)
+    {
+      // The workflow must not be already registered
+      if (registeredWorkflowNodes.containsKey(workflowID))
       {
-        defaultNetworkGroup.deregisterWorkflow(workflow);
+        int msgID = MSGID_REGISTER_WORKFLOW_NODE_ALREADY_EXISTS;
+        String message = getMessage(msgID, workflowID, networkGroupID);
+        throw new DirectoryException(
+            ResultCode.UNWILLING_TO_PERFORM, message, msgID);
       }
+
+      TreeMap<String, WorkflowTopologyNode> newRegisteredWorkflowNodes =
+        new TreeMap<String, WorkflowTopologyNode>(registeredWorkflowNodes);
+      newRegisteredWorkflowNodes.put(workflowID, workflowNode);
+      registeredWorkflowNodes = newRegisteredWorkflowNodes;
+    }
+  }
+
+
+  /**
+   * Deregisters the current worklow (this) with the server.
+   *
+   * @param workflowNode  the workflow node to deregister
+   */
+  private void deregisterWorkflowNode(
+      WorkflowTopologyNode workflowNode
+      )
+  {
+    synchronized (registeredWorkflowNodesLock)
+    {
+      TreeMap<String, WorkflowTopologyNode> newWorkflowNodes =
+        new TreeMap<String, WorkflowTopologyNode>(registeredWorkflowNodes);
+      newWorkflowNodes.remove(workflowNode.getWorkflowImpl().getWorkflowId());
+      registeredWorkflowNodes = newWorkflowNodes;
     }
   }
 
@@ -262,7 +441,7 @@
    * @return the highest workflow in the topology that can handle the base DN,
    *         <code>null</code> if none was found
    */
-  public Workflow getWorkflowCandidate (
+  public Workflow getWorkflowCandidate(
       DN baseDN
       )
   {
@@ -273,7 +452,7 @@
     if (baseDN.isNullDN())
     {
       // The rootDSE workflow is the candidate.
-      workflowCandidate = rootDSEWorkflow;
+      workflowCandidate = rootDSEWorkflowNode;
     }
     else
     {
@@ -317,12 +496,12 @@
     namingContexts.resetLists();
 
     // a registered workflow with no parent is a naming context
-    for (WorkflowTopologyNode curWorkflow: registeredWorkflows)
+    for (WorkflowTopologyNode workflowNode: registeredWorkflowNodes.values())
     {
-      WorkflowTopologyNode parent = curWorkflow.getParent();
+      WorkflowTopologyNode parent = workflowNode.getParent();
       if (parent == null)
       {
-        namingContexts.addNamingContext (curWorkflow);
+        namingContexts.addNamingContext (workflowNode);
       }
     }
   }
@@ -336,7 +515,7 @@
    * @return <code>false</code> if the base DN is registered with the
    *         network group, <code>false</code> otherwise
    */
-  private boolean baseDNAlreadyRegistered (
+  private boolean baseDNAlreadyRegistered(
       DN baseDN
       )
   {
@@ -345,9 +524,9 @@
 
     // go through the list of registered workflow and check whether a base DN
     // has already been used in a registered workflow
-    for (WorkflowTopologyNode curWorkflow: registeredWorkflows)
+    for (WorkflowTopologyNode workflowNode: registeredWorkflowNodes.values())
     {
-      DN curDN = curWorkflow.getBaseDN();
+      DN curDN = workflowNode.getBaseDN();
       if (baseDN.equals (curDN))
       {
         alreadyRegistered = true;
@@ -377,28 +556,28 @@
    * @param  leftMargin  white spaces used to indent traces
    * @return a string buffer that contains trace information
    */
-  public StringBuffer toString (String leftMargin)
+  public StringBuffer toString(String leftMargin)
   {
     StringBuffer sb = new StringBuffer();
     String newMargin = leftMargin + "   ";
 
-    sb.append (leftMargin + "Networkgroup (" + networkGroupName+ "\n");
+    sb.append (leftMargin + "Networkgroup (" + networkGroupID+ "\n");
     sb.append (leftMargin + "List of registered workflows:\n");
-    for (WorkflowTopologyNode w: registeredWorkflows)
+    for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
     {
-      sb.append (w.toString (newMargin));
+      sb.append (node.toString (newMargin));
     }
 
     namingContexts.toString (leftMargin);
 
     sb.append (leftMargin + "rootDSEWorkflow:\n");
-    if (rootDSEWorkflow == null)
+    if (rootDSEWorkflowNode == null)
     {
       sb.append (newMargin + "null\n");
     }
     else
     {
-      sb.append (rootDSEWorkflow.toString (newMargin));
+      sb.append (rootDSEWorkflowNode.toString (newMargin));
     }
 
     return sb;

--
Gitblit v1.10.0