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

jdemendi
04.53.2008 bf135c5c0f1c9b949de97f97092780f8c3d9a8a2
fix 3560, Cannot recreate a workflow after a create/delete
5 files modified
270 ■■■■ changed files
opends/src/messages/messages/core.properties 6 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowConfigManager.java 134 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowImpl.java 61 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java 53 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java 16 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/core.properties
@@ -1807,4 +1807,10 @@
SEVERE_ERR_REGISTER_WORKFLOW_BASE_DN_ALREADY_EXISTS_716=Unable to register \
 workflow node "%s" with the network group "%s" because another workflow node \
 "%s" with the same base DN "%s" is already registered
INFO_ERR_WORKFLOW_IN_USE_717=\
Unable to remove the workflow "%s" because the workflow is still in use \
(there are still %d reference(s) to the workflow)
INFO_ERR_WORKFLOW_DOES_NOT_EXIST_718=\
Unable to register the workflow "%s" with the network group %s because \
the workflow does not exist
 
opends/src/server/org/opends/server/core/WorkflowConfigManager.java
@@ -28,6 +28,8 @@
import static org.opends.messages.CoreMessages.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -143,9 +145,9 @@
  public ConfigChangeResult applyConfigurationAdd(
      WorkflowCfg configuration)
  {
    ResultCode         resultCode          = ResultCode.SUCCESS;
    boolean            adminActionRequired = false;
    ArrayList<Message> messages            = new ArrayList<Message>();
    ResultCode    resultCode          = ResultCode.SUCCESS;
    boolean       adminActionRequired = false;
    List<Message> messages            = new ArrayList<Message>();
    configuration.addChangeListener(this);
@@ -160,7 +162,7 @@
      {
        if (resultCode == ResultCode.SUCCESS)
        {
          resultCode = DirectoryServer.getServerErrorResultCode();
          resultCode = de.getResultCode();
        }
        messages.add(de.getMessageObject());
@@ -179,7 +181,16 @@
      WorkflowCfg   configuration,
      List<Message> unacceptableReasons)
  {
    return true;
    boolean acceptable = true;
    WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
    if (existingWorkflow != null)
    {
      // check whether we can delete the workflow
      acceptable = checkReferenceCounter(
        existingWorkflow, unacceptableReasons);
    }
    return acceptable;
  }
@@ -190,16 +201,33 @@
  public ConfigChangeResult applyConfigurationDelete(
      WorkflowCfg configuration)
  {
    ResultCode         resultCode          = ResultCode.SUCCESS;
    boolean            adminActionRequired = false;
    ArrayList<Message> messages            = new ArrayList<Message>();
    ResultCode    resultCode          = ResultCode.SUCCESS;
    boolean       adminActionRequired = false;
    List<Message> messages            = new ArrayList<Message>();
    // check first whether we can remove the workflow
    WorkflowImpl workflow = workflows.remove(configuration.dn());
    if (workflow != null)
    {
      workflow.deregister();
      workflow.finalizeWorkflow();
      boolean acceptable = checkReferenceCounter(workflow, messages);
      if (acceptable)
      {
        // The workflow is not used anymore, we can remove it
        workflow.deregister();
        workflow.finalizeWorkflow();
        // Deregister the workflow with the internal network group
        NetworkGroup.getInternalNetworkGroup().deregisterWorkflow(
          workflow.getWorkflowId());
        // Deregister the workflow with the admin network group
        NetworkGroup.getAdminNetworkGroup().deregisterWorkflow(
          workflow.getWorkflowId());
      }
      else
      {
        resultCode = ResultCode.UNWILLING_TO_PERFORM;
      }
    }
    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
@@ -214,8 +242,19 @@
      WorkflowCfg   configuration,
      List<Message> unacceptableReasons)
  {
    // Nothing to check.
    return true;
    // Get the existing workflow if it's already enabled.
    WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
    // Is this a request to disable the workflow?
    boolean acceptable = true;
    if (! configuration.isEnabled() && (existingWorkflow != null))
    {
      // check whether we can disable the workflow
      acceptable = checkReferenceCounter(
        existingWorkflow, unacceptableReasons);
    }
    return acceptable;
  }
@@ -226,13 +265,9 @@
  public ConfigChangeResult applyConfigurationChange(
      WorkflowCfg configuration)
  {
    ResultCode         resultCode          = ResultCode.SUCCESS;
    boolean            adminActionRequired = false;
    ArrayList<Message> messages            = new ArrayList<Message>();
    ConfigChangeResult configChangeResult =
      new ConfigChangeResult(resultCode, adminActionRequired, messages);
    ResultCode    resultCode          = ResultCode.SUCCESS;
    boolean       adminActionRequired = false;
    List<Message> messages            = new ArrayList<Message>();
    // Get the existing workflow if it's already enabled.
    WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
@@ -243,12 +278,30 @@
    {
      if (existingWorkflow != null)
      {
        workflows.remove(configuration.dn());
        existingWorkflow.deregister();
        existingWorkflow.finalizeWorkflow();
        // check whether we can disable the workflow
        boolean acceptable = checkReferenceCounter(existingWorkflow, messages);
        if (acceptable)
        {
          // The workflow is not used anymore, we can remove it
          workflows.remove(configuration.dn());
          existingWorkflow.deregister();
          existingWorkflow.finalizeWorkflow();
          // Deregister the workflow with the internal network group
          NetworkGroup.getInternalNetworkGroup().deregisterWorkflow(
            existingWorkflow.getWorkflowId());
          // Deregister the workflow with the admin network group
          NetworkGroup.getAdminNetworkGroup().deregisterWorkflow(
            existingWorkflow.getWorkflowId());
        }
        else
        {
          resultCode = ResultCode.UNWILLING_TO_PERFORM;
        }
      }
      return configChangeResult;
      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
    }
    // If the workflow is disabled then create and register it.
@@ -262,7 +315,7 @@
      {
        if (resultCode == ResultCode.SUCCESS)
        {
          resultCode = DirectoryServer.getServerErrorResultCode();
          resultCode = de.getResultCode();
        }
        messages.add(de.getMessageObject());
@@ -274,7 +327,7 @@
      existingWorkflow.updateConfig(configuration);
    }
    return configChangeResult;
    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
@@ -319,5 +372,34 @@
    NetworkGroup.getAdminNetworkGroup().registerWorkflow(workflowImpl);
  }
  /**
   * Checks whether a workflow is no more used so that we can delete
   * or disable it.
   *
   * @param workflow  the workflow to check
   * @param messages  a list of reasons that prevent the workflow to be
   *                  deleted or disabled
   * @return <code>true</code> when the workflow can be deleted or disabled
   */
  private boolean checkReferenceCounter(
      WorkflowImpl  workflow,
      List<Message> messages
      )
  {
    boolean acceptable = true;
    int refCounter = workflow.getReferenceCounter();
    if (refCounter != 0)
    {
      Message message = INFO_ERR_WORKFLOW_IN_USE.get(
        workflow.getWorkflowId(), workflow.getReferenceCounter());
      messages.add(message);
      acceptable = false;
    }
    return acceptable;
  }
}
opends/src/server/org/opends/server/core/WorkflowImpl.java
@@ -34,7 +34,6 @@
import java.util.Observer;
import java.util.TreeMap;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.admin.std.server.WorkflowCfg;
import org.opends.server.types.*;
@@ -85,6 +84,12 @@
  // A lock to protect concurrent access to the registeredWorkflows.
  private static Object registeredWorkflowsLock = new Object();
  // A reference counter used to count the number of workflow nodes that
  // were registered with a network group. A workflow can be disabled or
  // deleted only when its reference counter value is 0.
  private int referenceCounter = 0;
  private Object referenceCounterLock = new Object();
  /**
   * Creates a new instance of a workflow implementation. To define a workflow
@@ -219,10 +224,9 @@
      // The workflow must not be already registered
      if (registeredWorkflows.containsKey(workflowID))
      {
        Message message =
            ERR_REGISTER_WORKFLOW_ALREADY_EXISTS.get(workflowID);
        throw new DirectoryException(
            ResultCode.UNWILLING_TO_PERFORM, message);
            ResultCode.UNWILLING_TO_PERFORM,
            ERR_REGISTER_WORKFLOW_ALREADY_EXISTS.get(workflowID));
      }
      TreeMap<String, Workflow> newRegisteredWorkflows =
@@ -466,4 +470,53 @@
      rootWorkflowElement = null;
    }
  }
  /**
   * Increments the workflow reference counter.
   * <p>
   * As long as the counter value is not 0 the workflow cannot be
   * disabled nor deleted.
   */
  public void incrementReferenceCounter()
  {
    synchronized (referenceCounterLock)
    {
      referenceCounter++;
    }
  }
  /**
   * Decrements the workflow reference counter.
   * <p>
   * As long as the counter value is not 0 the workflow cannot be
   * disabled nor deleted.
   */
  public void decrementReferenceCounter()
  {
    synchronized (referenceCounterLock)
    {
      if (referenceCounter == 0)
      {
        // the counter value is 0, we should not need to decrement anymore
        throw new AssertionError(
          "Reference counter of the workflow " + workflowID
          + " is already set to 0, cannot decrement it anymore"
          );
      }
      referenceCounter--;
    }
  }
  /**
   * Gets the value of the reference counter of the workflow.
   *
   * @return the reference counter of the workflow
   */
  public int getReferenceCounter()
  {
    return referenceCounter;
  }
}
opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
@@ -80,26 +80,28 @@
  // access to all the workflows. The purpose of the default network
  // group is to allow new clients to perform a first operation before
  // they can be attached to a specific network group.
  private static final String DEFAULT_NETWORK_GROUP_NAME = "default";
  private final boolean isDefaultNetworkGroup;
  private static NetworkGroup defaultNetworkGroup =
      new NetworkGroup ("default");
      new NetworkGroup (DEFAULT_NETWORK_GROUP_NAME);
  // The admin network group (singleton).
  // The admin network group has no criterion, no policy, and gives
  // access to all the workflows.
  private static final String ADMIN_NETWORK_GROUP_NAME = "admin";
  private final boolean isAdminNetworkGroup;
  private static NetworkGroup adminNetworkGroup =
      new NetworkGroup (ADMIN_NETWORK_GROUP_NAME);
  private final boolean isAdminNetworkGroup;
  // The internal network group (singleton).
  // The internal network group has no criterion, no policy, and gives
  // access to all the workflows. The purpose of the internal network
  // group is to allow internal connections to perform operations.
  private static final String INTERNAL_NETWORK_GROUP_NAME = "internal";
  private boolean isInternalNetworkGroup;
  private static NetworkGroup internalNetworkGroup =
      new NetworkGroup(INTERNAL_NETWORK_GROUP_NAME);
  private boolean isInternalNetworkGroup;
  // The list of all network groups that are registered with the server.
@@ -142,7 +144,8 @@
    this.networkGroupID = networkGroupID;
    isInternalNetworkGroup = INTERNAL_NETWORK_GROUP_NAME.equals(networkGroupID);
    isAdminNetworkGroup = ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
    isAdminNetworkGroup    = ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
    isDefaultNetworkGroup  = DEFAULT_NETWORK_GROUP_NAME.equals(networkGroupID);
  }
@@ -302,6 +305,17 @@
      // Rebuild the list of naming context handled by the network group
      rebuildNamingContextList();
      // Now that the workflow node has been registered with the network
      // group, update the reference counter of the workflow, unless
      // the network group is either default, or administration, or internal
      // network group.
      if (!isAdminNetworkGroup
          && !isInternalNetworkGroup
          && !isDefaultNetworkGroup)
      {
        workflow.incrementReferenceCounter();
      }
    }
  }
@@ -354,6 +368,17 @@
      }
    }
    // Now that the workflow node has been deregistered with the network
    // group, update the reference counter of the workflow.
    if ((workflow != null)
        && !isAdminNetworkGroup
        && !isInternalNetworkGroup
        && !isDefaultNetworkGroup)
    {
      WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
      workflowImpl.decrementReferenceCounter();
    }
    return workflow;
  }
@@ -363,11 +388,14 @@
   * deregister is identified by its workflow ID.
   *
   * @param workflowID the workflow identifier of the workflow to deregister
   * @return the deregistered workflow
   */
  public void deregisterWorkflow(
  public Workflow deregisterWorkflow(
      String workflowID
      )
  {
    Workflow workflow = null;
    String rootDSEWorkflowID = null;
    if (rootDSEWorkflowNode != null)
    {
@@ -378,6 +406,7 @@
    {
      // deregister the rootDSE
      deregisterWorkflow(rootDSEWorkflowNode);
      workflow = rootDSEWorkflowNode.getWorkflowImpl();
    }
    else
    {
@@ -392,6 +421,7 @@
            // Call deregisterWorkflow() instead of deregisterWorkflowNode()
            // because we want the naming context list to be updated as well.
            deregisterWorkflow(node);
            workflow = node.getWorkflowImpl();
            // Only one workflow can match the baseDN, so we can break
            // the loop here.
@@ -400,6 +430,19 @@
        }
      }
    }
    // Now that the workflow node has been deregistered with the network
    // group, update the reference counter of the workflow.
    if ((workflow != null)
        && !isAdminNetworkGroup
        && !isInternalNetworkGroup
        && !isDefaultNetworkGroup)
    {
      WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
      workflowImpl.decrementReferenceCounter();
    }
    return workflow;
  }
opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java
@@ -28,6 +28,9 @@
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
@@ -332,7 +335,18 @@
    {
      WorkflowImpl workflowImpl =
        (WorkflowImpl) WorkflowImpl.getWorkflow(workflowID);
      networkGroup.registerWorkflow(workflowImpl);
      if (workflowImpl == null)
      {
        // The workflow does not exist, log an error message
        // and skip the workflow
        Message message = INFO_ERR_WORKFLOW_DOES_NOT_EXIST.get(
          workflowID, networkGroupId);
        logError(message);
      }
      else
      {
        networkGroup.registerWorkflow(workflowImpl);
      }
    }
    // register the root DSE workflow with the network group