From ba3f962a91112c98a32b2b70d51451baeeda23d5 Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Tue, 04 Nov 2008 09:53:59 +0000
Subject: [PATCH] fix 3560, Cannot recreate a workflow after a create/delete
---
opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java | 134 +++++++++++++++++++++-----
opendj-sdk/opends/src/messages/messages/core.properties | 6 +
opendj-sdk/opends/src/server/org/opends/server/core/WorkflowImpl.java | 61 +++++++++++
opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java | 16 +++
opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java | 53 +++++++++-
5 files changed, 234 insertions(+), 36 deletions(-)
diff --git a/opendj-sdk/opends/src/messages/messages/core.properties b/opendj-sdk/opends/src/messages/messages/core.properties
index c37eda3..008ca86 100644
--- a/opendj-sdk/opends/src/messages/messages/core.properties
+++ b/opendj-sdk/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
\ No newline at end of file
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 a0d79a6..0b30de4 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
@@ -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;
+ }
+
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowImpl.java b/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowImpl.java
index ca8ce53..6193e3f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowImpl.java
+++ b/opendj-sdk/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;
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
index 3fcb443..59b119f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
+++ b/opendj-sdk/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;
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java
index 40df1d2..35d4276 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/networkgroups/NetworkGroupConfigManager.java
+++ b/opendj-sdk/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
--
Gitblit v1.10.0