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