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

jdemendi
31.12.2008 0e47fcf59332b96c43f4737143025e07f8202638
fix 35353, Workflows are not notified when their root workflow elements are disabled
1 files added
10 files modified
615 ■■■■ changed files
opends/src/admin/defn/org/opends/server/admin/std/WorkflowConfiguration.xml 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 7 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowConfigManager.java 14 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowImpl.java 167 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkflowResultCode.java 11 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java 99 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/WorkflowElement.java 184 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/WorkflowElementConfigManager.java 52 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java 39 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowTopologyTest.java 30 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java 10 ●●●● patch | view | raw | blame | history
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 />
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;
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();
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;
    }
  }
}
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;
opends/src/server/org/opends/server/workflowelement/ObservableWorkflowElementState.java
New file
@@ -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;
  }
}
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.
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();
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();
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.
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.