From 0e47fcf59332b96c43f4737143025e07f8202638 Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Fri, 31 Oct 2008 11:12:52 +0000
Subject: [PATCH] fix 35353, Workflows are not notified when their root workflow elements are disabled

---
 opends/src/server/org/opends/server/core/WorkflowImpl.java |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 159 insertions(+), 8 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/WorkflowImpl.java b/opends/src/server/org/opends/server/core/WorkflowImpl.java
index 10208e0..ca8ce53 100644
--- a/opends/src/server/org/opends/server/core/WorkflowImpl.java
+++ b/opends/src/server/org/opends/server/core/WorkflowImpl.java
@@ -27,16 +27,19 @@
 package org.opends.server.core;
 
 import static org.opends.messages.CoreMessages.*;
-import org.opends.messages.Message;
-import org.opends.messages.MessageBuilder;
-
 import static org.opends.server.util.Validator.ensureNotNull;
 
 import java.util.Collection;
+import java.util.Observable;
+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.*;
 import org.opends.server.workflowelement.WorkflowElement;
+import org.opends.server.workflowelement.ObservableWorkflowElementState;
 
 
 /**
@@ -48,16 +51,19 @@
  * task in turn will execute its subordinate nodes and synchronizes them
  * as needed.
  */
-public class WorkflowImpl implements Workflow
+public class WorkflowImpl implements Workflow, Observer
 {
   // The workflow identifier used by the configuration.
-  private String workflowID = null;
+  private final String workflowID;
 
   // The root of the workflow task tree.
   private WorkflowElement<?> rootWorkflowElement = null;
 
+  // The root workflow element identifier.
+  private String rootWorkflowElementID = null;
+
   // The base DN of the data handled by the workflow.
-  private DN baseDN = null;
+  private final DN baseDN;
 
   // Flag indicating whether the workflow root node of the task tree is
   // handling a private local backend.
@@ -81,7 +87,7 @@
 
 
   /**
-   * Creates a new instance of a workflow implementation. To define a worfklow
+   * Creates a new instance of a workflow implementation. To define a workflow
    * one needs to provide a task tree root node (the rootWorkflowElement) and
    * a base DN to identify the data set upon which the tasks can be applied.
    *
@@ -89,11 +95,13 @@
    *
    * @param workflowId          workflow internal identifier
    * @param baseDN              identifies the data handled by the workflow
+   * @param rootWorkflowElementID  the identifier of the root workflow element
    * @param rootWorkflowElement the root node of the workflow task tree
    */
   public WorkflowImpl(
       String             workflowId,
       DN                 baseDN,
+      String             rootWorkflowElementID,
       WorkflowElement<?> rootWorkflowElement
       )
   {
@@ -103,6 +111,20 @@
     if (this.rootWorkflowElement != null)
     {
       this.isPrivate = rootWorkflowElement.isPrivate();
+      this.rootWorkflowElementID = rootWorkflowElementID;
+
+      // The workflow wants to be notified when the workflow element state
+      // is changing from enabled to disabled and vice versa.
+      WorkflowElement.registereForStateUpdate(
+        rootWorkflowElement, null, this);
+    }
+    else
+    {
+      // The root workflow element has not been loaded, let's register
+      // the workflow with the list of objects that want to be notify
+      // when the workflow element is created.
+      WorkflowElement.registereForStateUpdate(
+        null, rootWorkflowElementID, this);
     }
   }
 
@@ -198,7 +220,7 @@
       if (registeredWorkflows.containsKey(workflowID))
       {
         Message message =
-                ERR_REGISTER_WORKFLOW_ALREADY_EXISTS.get(workflowID);
+            ERR_REGISTER_WORKFLOW_ALREADY_EXISTS.get(workflowID);
         throw new DirectoryException(
             ResultCode.UNWILLING_TO_PERFORM, message);
       }
@@ -218,6 +240,12 @@
   {
     ensureNotNull(workflowID);
 
+    // Deregister the workflow with the list of objects to notify when
+    // a workflow element is created or deleted.
+    WorkflowElement.deregistereForStateUpdate(
+      null, rootWorkflowElementID, this);
+
+    // Deregister the workflow with the list of registered workflows.
     synchronized (registeredWorkflowsLock)
     {
       TreeMap<String, Workflow> newWorkflows =
@@ -315,4 +343,127 @@
     }
   }
 
+
+  /**
+   * Updates the workflow configuration. This method should be invoked
+   * whenever an existing workflow is modified.
+   *
+   * @param configuration  the new workflow configuration
+   */
+  public void updateConfig(WorkflowCfg configuration)
+  {
+    // The only parameter that can be changed is the root workflow element.
+    String rootWorkflowElementID = configuration.getWorkflowElement();
+    WorkflowElement<?> rootWorkflowElement =
+      DirectoryServer.getWorkflowElement(rootWorkflowElementID);
+
+    // Update the ID of the new root workflow element
+    // and deregister the workflow with the list of objects to notify
+    // when the former root workflow element is created
+    String previousRootWorkflowElement = this.rootWorkflowElementID;
+    WorkflowElement.deregistereForStateUpdate(
+      null, previousRootWorkflowElement, this);
+    this.rootWorkflowElementID = rootWorkflowElementID;
+
+    // Does the new root workflow element exist?
+    if (rootWorkflowElement == null)
+    {
+      // The new root workflow element does not exist yet then do nothing
+      // but register with the list of object to notify when the workflow
+      // element is created (and deregister first in case the workflow
+      // was already registered)
+      WorkflowElement.registereForStateUpdate(
+        null, rootWorkflowElementID, this);
+      rootWorkflowElement = null;
+    }
+    else
+    {
+      // The new root workflow element exists, let's use it and don't forget
+      // to register with the list of objects to notify when the workflow
+      // element is deleted.
+      this.rootWorkflowElement = rootWorkflowElement;
+      WorkflowElement.registereForStateUpdate(
+        rootWorkflowElement, null, this);
+    }
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void update(Observable observable, Object arg)
+  {
+    if (observable instanceof ObservableWorkflowElementState)
+    {
+      ObservableWorkflowElementState weState =
+        (ObservableWorkflowElementState) observable;
+      updateRootWorkflowElementState(weState);
+    }
+  }
+
+
+  /**
+   * Display the workflow object.
+   * @return a string identifying the workflow.
+   */
+  public String toString()
+  {
+    String id = "Workflow " + workflowID;
+    return id;
+  }
+
+
+  /**
+   * Takes into account an update of the root workflow element.
+   * <p>
+   * This method is called when a workflow element is created or
+   * deleted. If the workflow element is the root workflow element
+   * then the workflow processes it as follow:
+   * <br>
+   * If the workflow element is disabled then the workflow reset
+   * its root workflow element (ie. the workflow has no more workflow
+   * element, hence the workflow cannot process requests anymore).
+   * <br>
+   * If the workflow element is enabled then the workflow adopts the
+   * workflow element as its new root workflow element. The workflow
+   * then can process requests again.
+   *
+   * @param weState  the new state of the root workflow element
+   */
+  private void updateRootWorkflowElementState(
+      ObservableWorkflowElementState weState)
+  {
+    // Check that the workflow element maps the root workflow element.
+    // If not then ignore the workflow element.
+    WorkflowElement<?> we = weState.getObservedWorkflowElement();
+    String newWorkflowElementID = we.getWorkflowElementID();
+    if (! rootWorkflowElementID.equalsIgnoreCase(newWorkflowElementID))
+    {
+      return;
+    }
+
+    // The workflow element maps the root workflow element, let's process it.
+    if (weState.workflowElementIsEnabled())
+    {
+      // The root workflow element is enabled, let's use it
+      // and don't forget to register the workflow with the list
+      // of objects to notify when the root workflow element
+      // is disabled...
+      rootWorkflowElement = weState.getObservedWorkflowElement();
+      WorkflowElement.registereForStateUpdate(
+        rootWorkflowElement, null, this);
+      WorkflowElement.deregistereForStateUpdate(
+        null, rootWorkflowElementID, this);
+    }
+    else
+    {
+      // The root workflow element has been disabled. Reset the current
+      // reference to the root workflow element and register the workflow
+      // with the list of objects to notify when new workflow elements
+      // are created.
+      WorkflowElement.registereForStateUpdate(
+        null, rootWorkflowElement.getWorkflowElementID(), this);
+      rootWorkflowElement = null;
+    }
+  }
 }

--
Gitblit v1.10.0