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

jdemendi
08.57.2007 58a50508676500a29b29075f66e454b113a08791
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;