From 7d9f9ebbdd79002266e85efa0f7f19aeb7339e9b 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

---
 opendj-sdk/opends/src/server/org/opends/server/core/WorkflowResultCode.java                                     |   11 
 opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java                                        |    7 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java      |   39 ++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java           |   30 +-
 opendj-sdk/opends/src/server/org/opends/server/core/WorkflowConfigManager.java                                  |   14 
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml                          |    2 
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java                |   52 +++-
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java                             |  184 ++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/core/WorkflowImpl.java                                           |  167 ++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java              |   99 +++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java |   10 
 11 files changed, 542 insertions(+), 73 deletions(-)

diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml
index adef53f..35f8a24 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml
@@ -107,7 +107,7 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
-  <adm:property name="base-dn" mandatory="true">
+  <adm:property name="base-dn" mandatory="true" read-only="true">
     <adm:synopsis>
       Specifies the base DN of the data targeted by the
       <adm:user-friendly-name />
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index 2e69d06..5d5c9ff 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -2735,10 +2735,13 @@
     // backendID and baseDN should be ok.
     String workflowID = backend.getBackendID() + "#" + baseDN.toString();
 
-    // Create the worklfow for the base DN and register the workflow with
+    // Create the workflow for the base DN and register the workflow with
     // the server.
     WorkflowImpl workflowImpl = new WorkflowImpl(
-        workflowID, baseDN, (WorkflowElement) rootWE);
+        workflowID,
+        baseDN,
+        rootWE.getWorkflowElementID(),
+        (WorkflowElement) rootWE);
     workflowImpl.register();
 
     return workflowImpl;
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 b51ce36..a0d79a6 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
@@ -234,10 +234,10 @@
       new ConfigChangeResult(resultCode, adminActionRequired, messages);
 
 
-    // Get the existing network group if it's already enabled.
+    // Get the existing workflow if it's already enabled.
     WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
 
-    // If the new configuration has the validator disabled, then disable it if
+    // If the new configuration has the workflow disabled, then disable it if
     // it is enabled, or do nothing if it's already disabled.
     if (! configuration.isEnabled())
     {
@@ -251,7 +251,7 @@
       return configChangeResult;
     }
 
-    // If the network group is disabled then create and register it.
+    // If the workflow is disabled then create and register it.
     if (existingWorkflow == null)
     {
       try
@@ -268,6 +268,11 @@
         messages.add(de.getMessageObject());
       }
     }
+    else
+    {
+      // The workflow already exist, just notify the changes to the workflow
+      existingWorkflow.updateConfig(configuration);
+    }
 
     return configChangeResult;
   }
@@ -302,7 +307,8 @@
 
     // Create the workflow and register it with the server
     WorkflowImpl workflowImpl =
-      new WorkflowImpl(workflowId, baseDN, rootWorkflowElement);
+      new WorkflowImpl(
+        workflowId, baseDN, rootWorkflowElementID, rootWorkflowElement);
     workflows.put(workflowCfg.dn(), workflowImpl);
     workflowImpl.register();
 
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 10208e0..ca8ce53 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
@@ -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;
+    }
+  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowResultCode.java b/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowResultCode.java
index 5b54e3b..9a9ec53 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowResultCode.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/WorkflowResultCode.java
@@ -207,16 +207,7 @@
             errorMessage = new MessageBuilder (newErrorMessage);
             break;
           default:
-            // global resultCode remains the same but append the new
-            // error message into the current error message
-            if (errorMessage == null)
-            {
-              errorMessage =  new MessageBuilder (newErrorMessage);
-            }
-            else
-            {
-              errorMessage.append(newErrorMessage);
-            }
+            // Do nothing (we don't want to override the first error)
             break;
         }
         break;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java
new file mode 100644
index 0000000..6ba7914
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.workflowelement;
+
+import java.util.Observable;
+
+
+/**
+ * This class implements an observable workflow element state.
+ * The observable workflow element state notifies observers when the
+ * state of the workflow element has changed. Typically, observers are
+ * notified when a workflow element is enabled or disabled.
+ */
+public class ObservableWorkflowElementState extends Observable
+{
+  // The observed workflow element
+  private final WorkflowElement<?> observedWorkflowElement;
+
+
+  // The "enabled" state of the observed workflow element.
+  // By default, a workflow element is enabled (otherwise this
+  // instance of workflow element state would not exist).
+  private boolean enabled = true;
+
+
+  /**
+   * Creates an instance of an observable object for a given workflow
+   * element.
+   *
+   * @param observedWorkflowElement  the workflow element to observe
+   */
+  public ObservableWorkflowElementState(
+      WorkflowElement<?> observedWorkflowElement)
+  {
+    this.observedWorkflowElement = observedWorkflowElement;
+  }
+
+
+  /**
+   * Gets the observed workflow element.
+   * @return the observed workflow element.
+   */
+  public WorkflowElement<?> getObservedWorkflowElement()
+  {
+    return observedWorkflowElement;
+  }
+
+
+  /**
+   * Allows the observed workflow element to indicate its new state
+   * (enabled or disabled).
+   *
+   * @param enabled  the new "enabled" state of the observed workflow element
+   */
+  public void setWorkflowElementEnabled(
+      boolean enabled)
+  {
+    if (this.enabled != enabled)
+    {
+      setChanged();
+      this.enabled = enabled;
+    }
+  }
+
+
+  /**
+   * Indicates whether the observed workflow element is enabled or not.
+   *
+   * @return <code>true</code> if the observed workflow element is enabled.
+   */
+  public boolean workflowElementIsEnabled()
+  {
+    return enabled;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
index 7b8a29b..80eaff5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElement.java
@@ -27,7 +27,13 @@
 package org.opends.server.workflowelement;
 
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 import org.opends.server.admin.std.server.WorkflowElementCfg;
 import org.opends.server.types.Operation;
 import org.opends.server.types.CanceledOperationException;
@@ -44,8 +50,8 @@
  *
  * @param  <T>  The type of configuration handled by this workflow element.
  */
-public abstract class WorkflowElement
-       <T extends WorkflowElementCfg>
+public abstract class WorkflowElement <T extends WorkflowElementCfg>
+    implements Observer
 {
   // Indicates whether the workflow element encapsulates a private local
   // backend.
@@ -61,6 +67,170 @@
   private String workflowElementID = null;
 
 
+  // The observable state of the workflow element.
+  private ObservableWorkflowElementState observableState =
+    new ObservableWorkflowElementState(this);
+
+
+  // The list of observers who want to be notified when a workflow element
+  // required by the observer is created. The key of the map is a string
+  // that identifies the newly created workflow element.
+  private static ConcurrentMap<String, List<Observer>>
+    newWorkflowElementNotificationList =
+      new ConcurrentHashMap<String, List<Observer>>();
+
+
+  /**
+   * Provides the observable state of the workflow element.
+   * This method is intended to be called by the WorkflowElementConfigManager
+   * that wants to notify observers that the workflow element state has
+   * changed (in particular when a workflow element has been disabled).
+   *
+   * @return the observable state of the workflow element
+   */
+  protected ObservableWorkflowElementState getObservableState()
+  {
+    return observableState;
+  }
+
+
+  /**
+   * Registers with a specific workflow element to be notified when the
+   * workflow element state has changed. This notification system is
+   * mainly used to be warned when a workflow element is enabled or
+   * disabled.
+   * <p>
+   * If the workflow element <code>we</code> is not <code>null</code>
+   * then the <code>observer</code> is registered with the list of objects
+   * to notify when <code>we</code> has changed.
+   * <p>
+   * If the workflow element <code>we</code> is <code>null</code> then
+   * the <code>observer</code> is registered with a static list of objects
+   * to notify when a workflow element named <code>weid</code> is created.
+   *
+   * @param we        the workflow element. If <code>null</code> then observer
+   *                  is registered with a list of workflow element
+   *                  identifiers.
+   * @param weid      the identifier of the workflow element. This parameter
+   *                  is useless when <code>we</code> is not <code>null</code>
+   * @param observer  the observer to notify when the workflow element state
+   *                  has been modified
+   */
+  public static void registereForStateUpdate(
+      WorkflowElement<?> we,
+      String weid,
+      Observer observer
+      )
+  {
+    // If the workflow element "we" exists then register the observer with "we"
+    // else register the observer with a static list of workflow element
+    // identifiers
+    if (we != null)
+    {
+      ObservableWorkflowElementState westate = we.getObservableState();
+      westate.addObserver(observer);
+    }
+    else
+    {
+      if (weid == null)
+      {
+        return;
+      }
+
+      List<Observer> observers = newWorkflowElementNotificationList.get(weid);
+      if (observers == null)
+      {
+        // create the list of observers
+        observers = new ArrayList<Observer>();
+        observers.add(observer);
+        newWorkflowElementNotificationList.put(weid, observers);
+      }
+      else
+      {
+        // update the observer list
+        observers.add(observer);
+      }
+    }
+  }
+
+
+  /**
+   * Deregisters an observer that was registered with a specific workflow
+   * element.
+   * <p>
+   * If the workflow element <code>we</code> is not <code>null</code>
+   * then the <code>observer</code> is deregistered with the list of objects
+   * to notify when <code>we</code> has changed.
+   * <p>
+   * If the workflow element <code>we</code> is <code>null</code> then
+   * the <code>observer</code> is deregistered with a static list of objects
+   * to notify when a workflow element named <code>weid</code> is created.
+   *
+   * @param we        the workflow element. If <code>null</code> then observer
+   *                  is deregistered with a list of workflow element
+   *                  identifiers.
+   * @param weid      the identifier of the workflow element. This parameter
+   *                  is useless when <code>we</code> is not <code>null</code>
+   * @param observer  the observer to deregister
+   */
+  public static void deregistereForStateUpdate(
+      WorkflowElement<?> we,
+      String weid,
+      Observer observer
+      )
+  {
+    // If the workflow element "we" exists then deregister the observer
+    // with "we" else deregister the observer with a static list of
+    // workflow element identifiers
+    if (we != null)
+    {
+      ObservableWorkflowElementState westate = we.getObservableState();
+      westate.deleteObserver(observer);
+    }
+    else
+    {
+      List<Observer> observers = newWorkflowElementNotificationList.get(weid);
+      if (observers != null)
+      {
+        observers.remove(observer);
+      }
+    }
+  }
+
+
+  /**
+   * Notifies all the observers who want to be warn when a workflow element
+   * is created.
+   *
+   * @param workflowElement  the newly created workflow element
+   */
+  public static void notifyStateUpdate(
+      WorkflowElement<?> workflowElement)
+  {
+    // Go through the list of observers and notify them all
+    String weID = workflowElement.getWorkflowElementID();
+
+    List<Observer> observers = newWorkflowElementNotificationList.get(weID);
+    if (observers != null)
+    {
+      for (Observer observer: observers)
+      {
+        // The update might fail because an observer could have been
+        // terminated. In this case, just ignore the failure and remove
+        // the observer from the list of objects to notify.
+        try
+        {
+          observer.update(workflowElement.getObservableState(), null);
+        }
+        catch(Exception e)
+        {
+          observers.remove(observer);
+        }
+      }
+    }
+  }
+
+
   /**
    * Creates a new instance of the workflow element.
    */
@@ -69,6 +239,7 @@
     // There is nothing to do in the constructor.
   }
 
+
   /**
    * Initializes the instance of the workflow element.
    *
@@ -89,6 +260,15 @@
 
 
   /**
+   * {@inheritDoc}
+   */
+  public void update(Observable o, Object arg)
+  {
+    // By default, do nothing when notification hits the workflow element.
+  }
+
+
+  /**
    * Get the type of the workflow element. The type is a string information
    * indicating which type is the current workflow element. This information
    * is intended to be used by tools for trace and debug purpose.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
index 2d43211..95e62bd 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java
@@ -121,7 +121,7 @@
    * @throws org.opends.server.types.InitializationException Exception while
    *         initializing the workflow element
    */
-  public WorkflowElement loadAndRegisterWorkflowElement(String workflowName)
+  public WorkflowElement<?> loadAndRegisterWorkflowElement(String workflowName)
           throws ConfigException, InitializationException {
     ServerManagementContext managementContext =
          ServerManagementContext.getInstance();
@@ -188,7 +188,11 @@
     {
       try
       {
-        loadAndRegisterWorkflowElement(configuration);
+        WorkflowElement<?> we = loadAndRegisterWorkflowElement(configuration);
+
+        // Notify observers who want to be notify when new workflow elements
+        // are created.
+        WorkflowElement.notifyStateUpdate(we);
       }
       catch (InitializationException de)
       {
@@ -214,7 +218,7 @@
       List<Message> unacceptableReasons)
   {
     // FIXME -- We should try to perform some check to determine whether the
-    // worklfow element is in use.
+    // workflow element is in use.
     return true;
   }
 
@@ -232,11 +236,18 @@
         );
 
 
-    WorkflowElement workflowElement =
+    WorkflowElement<?> workflowElement =
             DirectoryServer.getWorkflowElement(
             configuration.getWorkflowElementId());
     if (workflowElement != null)
     {
+      // Notify to observers that the workflow element is now disabled
+      ObservableWorkflowElementState observableState =
+        workflowElement.getObservableState();
+      observableState.setWorkflowElementEnabled(false);
+      observableState.notifyObservers();
+
+      // Remove the workflow element
       DirectoryServer.deregisterWorkflowElement(workflowElement);
       workflowElement.finalizeWorkflowElement();
     }
@@ -291,9 +302,8 @@
 
 
     // Get the existing workflow element if it's already enabled.
-    WorkflowElement existingWorkflowElement =
-            DirectoryServer.getWorkflowElement(
-            configuration.getWorkflowElementId());
+    WorkflowElement<?> existingWorkflowElement =
+      DirectoryServer.getWorkflowElement(configuration.getWorkflowElementId());
 
     // If the new configuration has the workflow element disabled,
     // then disable it if it is enabled, or do nothing if it's already disabled.
@@ -301,6 +311,13 @@
     {
       if (existingWorkflowElement != null)
       {
+        // Notify to observers that the workflow element is now disabled
+        ObservableWorkflowElementState observableState =
+          existingWorkflowElement.getObservableState();
+        observableState.setWorkflowElementEnabled(false);
+        observableState.notifyObservers();
+
+        // Remove the workflow element
         DirectoryServer.deregisterWorkflowElement(existingWorkflowElement);
         existingWorkflowElement.finalizeWorkflowElement();
       }
@@ -313,7 +330,11 @@
     {
       try
       {
-        loadAndRegisterWorkflowElement(configuration);
+        WorkflowElement<?> we = loadAndRegisterWorkflowElement(configuration);
+
+        // Notify observers who want to be notify when new workflow elements
+        // are created.
+        WorkflowElement.notifyStateUpdate(we);
       }
       catch (InitializationException de)
       {
@@ -343,13 +364,13 @@
    *                            ID of an existing workflow during workflow
    *                            registration.
    */
-  WorkflowElement loadAndRegisterWorkflowElement(
+  WorkflowElement<?> loadAndRegisterWorkflowElement(
       WorkflowElementCfg workflowElementCfg
       ) throws InitializationException
   {
     // Load the workflow element class
     String className = workflowElementCfg.getJavaClass();
-    WorkflowElement workflowElement =
+    WorkflowElement<?> workflowElement =
       loadWorkflowElement(className, workflowElementCfg, true);
 
     try
@@ -381,7 +402,7 @@
    * @throws  InitializationException  If a problem occurred while attempting
    *                                   to initialize the workflow element.
    */
-  private WorkflowElement loadWorkflowElement(
+  private WorkflowElement<?> loadWorkflowElement(
       String className,
       WorkflowElementCfg configuration,
       boolean initialize
@@ -391,15 +412,20 @@
     {
       WorkflowElementCfgDefn              definition;
       ClassPropertyDefinition             propertyDefinition;
+      // I cannot use the parameterized type WorflowElement<?>
+      // because it would break the line WorkflowElement.class below.
+      // Use SuppressWarning because we know the cast is safe.
+      @SuppressWarnings("unchecked")
       Class<? extends WorkflowElement>    workflowElementClass;
-      WorkflowElement<? extends WorkflowElementCfg> workflowElement;
 
       definition = WorkflowElementCfgDefn.getInstance();
       propertyDefinition =
         definition.getJavaClassPropertyDefinition();
       workflowElementClass =
         propertyDefinition.loadClass(className, WorkflowElement.class);
-      workflowElement =
+      // Again, use SuppressWarning because we know the cast is safe
+      @SuppressWarnings("unchecked")
+      WorkflowElement<? extends WorkflowElementCfg> workflowElement =
         (WorkflowElement<? extends WorkflowElementCfg>)
           workflowElementClass.newInstance();
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
index deb1328..243c76f 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
@@ -54,6 +54,7 @@
 import org.opends.server.types.SearchScope;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.UtilTestCase;
+import org.opends.server.workflowelement.WorkflowElement;
 import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -307,7 +308,7 @@
     // Create a workflow and register it with the server
     String workflowID = baseDN + "#" + backendID;
     WorkflowImpl workflowImpl = new WorkflowImpl(
-        workflowID, DN.decode(baseDN), workflowElement);
+        workflowID, DN.decode(baseDN), workflowElementID, workflowElement);
     workflowImpl.register();
     
     // Register the workflow with the internal network group
@@ -431,6 +432,11 @@
   }
 
   
+  //===========================================================================
+  //                 U T I L S  using  dsconfig
+  //===========================================================================
+
+
   /**
    * Initializes a memory-based backend.
    *
@@ -439,9 +445,10 @@
    * @param  createBaseEntry  indicate whether to automatically create the base
    *                          entry and add it to the backend.
    *
+   * @return the newly created backend
    * @throws  Exception  If an unexpected problem occurs.
    */
-  private static void createBackend(
+  private static Backend dsconfigCreateMemoryBackend(
       String  backendID,
       String  baseDN,
       boolean createBaseEntry
@@ -455,15 +462,16 @@
         "--set", "writability-mode:enabled",
         "--set", "enabled:true");
     
+    Backend backend = DirectoryServer.getBackend(backendID);
     if (createBaseEntry)
     {
-      Backend backend = DirectoryServer.getBackend(backendID);
       Entry e = createEntry(DN.decode(baseDN));
       backend.addEntry(e, null);
     }
+    return backend;
   }
 
-
+  
   /**
    * Remove a backend.
    *
@@ -471,7 +479,7 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  private static void removeMemoryBackend(
+  private static void dsconfigRemoveMemoryBackend(
       String backendID
       ) throws Exception
   {
@@ -481,7 +489,6 @@
   }
 
 
-
   //===========================================================================
   //                      T E S T    C A S E S
   //===========================================================================
@@ -536,7 +543,7 @@
 
     // Set the workflow configuration mode to manual. In this mode
     // no there is no workflow by default (but the config and rootDSE
-    // workflows) so seaarches on the test backend should fail.
+    // workflows) so searches on the test backend should fail.
     setModeManual();
     checkBackendIsNotAccessible(testBaseDN);
     
@@ -545,6 +552,10 @@
     createWorkflow(testBaseDN, testBackendID);
     checkBackendIsAccessible(testBaseDN);
     
+    // Remove the workflow and check that searches are failing.
+    removeWorkflow(testBaseDN, testBackendID);
+    checkBackendIsNotAccessible(testBaseDN);
+    
     // Change workflow configuration mode back to auto and check that
     // test backend is still accessible
     setModeAuto();
@@ -624,11 +635,11 @@
     checkBackendIsNotAccessible(baseDN1);
     
     // Create a backend and check that the base entry is accessible.
-    createBackend(backendID1, baseDN1, true);
+    dsconfigCreateMemoryBackend(backendID1, baseDN1, true);
     checkBackendIsAccessible(baseDN1);
     
     // Remove the backend and check that the suffix is no more accessible.
-    removeMemoryBackend(backendID1);
+    dsconfigRemoveMemoryBackend(backendID1);
     checkBackendIsNotAccessible(baseDN1);
     
     // Now move to the manual mode
@@ -637,21 +648,21 @@
     
     // Create a backend and create a workflow to route operations to that
     // new backend. Then check that the base entry is accessible.
-    createBackend(backendID2, baseDN2, true);
+    dsconfigCreateMemoryBackend(backendID2, baseDN2, true);
     createWorkflow(baseDN2, backendID2);
     checkBackendIsAccessible(baseDN2);
     
     // Remove the workflow and the backend and check that the base entry
     // is no more accessible.
     removeWorkflow(baseDN2, backendID2);
-    removeMemoryBackend(backendID2);
+    dsconfigRemoveMemoryBackend(backendID2);
     checkBackendIsNotAccessible(baseDN2);
 
     // Back to the original configuration mode
     setModeAuto();
   }
-  
-  
+
+
   /**
    * This test checks the creation and utilization of network group
    * in the route process.
@@ -688,7 +699,7 @@
     searchOperation.run();
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     
-    // Put back the internal network group in the client conenction
+    // Put back the internal network group in the client connection
     // and check that searches are still working.
     clientConnection.setNetworkGroup(NetworkGroup.getInternalNetworkGroup());
     searchOperation.run();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java
index 4d5d083..20113c8 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java
@@ -440,7 +440,7 @@
     // create a DIT set with the baseDN (no workflow element in the DIT).
     WorkflowElement nullWE = null;
     WorkflowImpl workflow =
-      new WorkflowImpl (baseDN.toString(), baseDN, nullWE);
+      new WorkflowImpl (baseDN.toString(), baseDN, null, nullWE);
 
     // Create a worflow with the dit, no pre/post-workflow element.
     WorkflowTopologyNode workflowNode =
@@ -503,18 +503,20 @@
     WorkflowImpl unrelatedWorkflow = null;
     {
       WorkflowElement nullWE = null;
-      workflow = new WorkflowImpl (baseDN.toString(), baseDN, nullWE);
-      subWorkflow = new WorkflowImpl (subordinateDN.toString(), subordinateDN, nullWE);
+      workflow = new WorkflowImpl (baseDN.toString(), baseDN, null, nullWE);
+      subWorkflow = new WorkflowImpl (
+        subordinateDN.toString(), subordinateDN, null, nullWE);
       if (unrelatedDN != null)
       {
-        unrelatedWorkflow = new WorkflowImpl (unrelatedDN.toString(), unrelatedDN, nullWE);
+        unrelatedWorkflow = new WorkflowImpl (
+          unrelatedDN.toString(), unrelatedDN, null, nullWE);
       }
     }
 
     // Create a worflow for each dit, no pre/post-workflow element
-    WorkflowTopologyNode w1    = new WorkflowTopologyNode (workflow, null, null);
-    WorkflowTopologyNode w1bis = new WorkflowTopologyNode (workflow, null, null);
-    WorkflowTopologyNode w2    = new WorkflowTopologyNode (subWorkflow, null, null);
+    WorkflowTopologyNode w1    = new WorkflowTopologyNode(workflow, null, null);
+    WorkflowTopologyNode w1bis = new WorkflowTopologyNode(workflow, null, null);
+    WorkflowTopologyNode w2    = new WorkflowTopologyNode(subWorkflow, null, null);
 
     WorkflowTopologyNode w3 = null;
     if (unrelatedWorkflow != null)
@@ -648,9 +650,9 @@
       WorkflowImpl workflow3;
       {
         WorkflowElement nullWE = null;
-        workflow1 = new WorkflowImpl (baseDN1.toString(), baseDN1, nullWE);
-        workflow2 = new WorkflowImpl (baseDN2.toString(), baseDN2, nullWE);
-        workflow3 = new WorkflowImpl (baseDN3.toString(), baseDN3, nullWE);
+        workflow1 = new WorkflowImpl(baseDN1.toString(), baseDN1, null, nullWE);
+        workflow2 = new WorkflowImpl(baseDN2.toString(), baseDN2, null, nullWE);
+        workflow3 = new WorkflowImpl(baseDN3.toString(), baseDN3, null, nullWE);
       }
 
       w1 = new WorkflowTopologyNode (workflow1, null, null);
@@ -830,9 +832,9 @@
       {
         WorkflowElement nullWE = null;
 
-        workflow1 = new WorkflowImpl (baseDN1.toString(), baseDN1, nullWE);
-        workflow2 = new WorkflowImpl (baseDN2.toString(), baseDN2, nullWE);
-        workflow3 = new WorkflowImpl (baseDN3.toString(), baseDN3, nullWE);
+        workflow1 = new WorkflowImpl(baseDN1.toString(), baseDN1, null, nullWE);
+        workflow2 = new WorkflowImpl(baseDN2.toString(), baseDN2, null, nullWE);
+        workflow3 = new WorkflowImpl(baseDN3.toString(), baseDN3, null, nullWE);
       }
 
       w1 = new WorkflowTopologyNode (workflow1, null, null);
@@ -957,7 +959,7 @@
 
     // Create a workflow to handle the baseDN with no workflow element
     WorkflowImpl workflow = new WorkflowImpl(
-        baseDN.toString(), baseDN, nullWE);
+        baseDN.toString(), baseDN, null, nullWE);
 
     // Register the workflow with the server. Don't catch the
     // DirectoryException that could be thrown by the register() method.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
index 65b607e..b79c3ec 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
@@ -486,7 +486,7 @@
     // of the workflow base DN.
     WorkflowElement nullWE = null;
     WorkflowImpl workflow = new WorkflowImpl(
-        workflowBaseDN.toString(), workflowBaseDN, nullWE);
+        workflowBaseDN.toString(), workflowBaseDN, null, nullWE);
 
     // Register the workflow with the network group.
     networkGroup.registerWorkflow(workflow);
@@ -779,7 +779,7 @@
     // of the workflow base DN.
     WorkflowElement nullWE = null;
     WorkflowImpl workflow = new WorkflowImpl(
-        workflowBaseDN.toString(), workflowBaseDN, nullWE);
+        workflowBaseDN.toString(), workflowBaseDN, null, nullWE);
 
     // Register the workflow with the network group.
     networkGroup.registerWorkflow(workflow);
@@ -835,9 +835,9 @@
     // of the workflow base DN.
     WorkflowElement nullWE = null;
     WorkflowImpl workflow1 = new WorkflowImpl(
-        dn1.toString(), dn1, nullWE);
+        dn1.toString(), dn1, null, nullWE);
     WorkflowImpl workflow2 = new WorkflowImpl(
-        dn2.toString(), dn2, nullWE);
+        dn2.toString(), dn2, null, nullWE);
 
     // Register the workflow with the network group.
     networkGroup1.registerWorkflow(workflow1);
@@ -1210,7 +1210,7 @@
     WorkflowElement rootWE = null;
     String workflowId = workflowBaseDN.toString();
     WorkflowImpl workflow = new WorkflowImpl(
-        workflowId, workflowBaseDN, rootWE);
+        workflowId, workflowBaseDN, null, rootWE);
     assertNotNull(workflow);
 
     // Register the workflow with the network group.

--
Gitblit v1.10.0