craigmcc    01/08/26 22:57:26

  Modified:    workflow/src/java/org/apache/commons/workflow Context.java
               workflow/src/java/org/apache/commons/workflow/base
                        BaseContext.java
               workflow/src/java/org/apache/commons/workflow/core
                        CoreRuleSet.java
               workflow/src/test/org/apache/commons/workflow/core
                        CoreExecuteTestCase.java
  Added:       workflow/src/java/org/apache/commons/workflow/core
                        CallStep.java
  Log:
  Add the ability to call nested Activities, and an appropriate <core:call>
  Step definition to trigger it.  This Step assumes that the Activity to be
  called has been pushed onto the top of the evaluation stack, but it makes
  *no* assumpations about how the Activity got there.
  
  Revision  Changes    Path
  1.7       +39 -23    
jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/Context.java
  
  Index: Context.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/Context.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Context.java      2001/08/23 03:52:17     1.6
  +++ Context.java      2001/08/27 05:57:25     1.7
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/Context.java,v
 1.6 2001/08/23 03:52:17 craigmcc Exp $
  - * $Revision: 1.6 $
  - * $Date: 2001/08/23 03:52:17 $
  + * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/Context.java,v
 1.7 2001/08/27 05:57:25 craigmcc Exp $
  + * $Revision: 1.7 $
  + * $Date: 2001/08/27 05:57:25 $
    *
    * ====================================================================
    * 
  @@ -88,7 +88,7 @@
    * the Step implementations that are executed to maintain the stack's
    * integrity.</p>
    *
  - * @version $Revision: 1.6 $ $Date: 2001/08/23 03:52:17 $
  + * @version $Revision: 1.7 $ $Date: 2001/08/27 05:57:25 $
    * @author Craig R. McClanahan
    */
   
  @@ -317,9 +317,24 @@
   
   
       /**
  +     * <p>Save the execution state (i.e. the currently assigned next step)
  +     * of the Activity we are currently executing, and begin executing the
  +     * specified Activity.  When that Activity exits (either normally
  +     * or by throwing an exception), the previous Activity will be resumed
  +     * where it left off.
  +     *
  +     * @param activity The Activity to be called
  +     */
  +    public void call(Activity activity);
  +
  +
  +    /**
        * <p>Execute the <code>Step</code> currently identified as the next
        * step, and continue execution until there is no next step, or until
  -     * the <code>suspend</code> property has been set to true.
  +     * the <code>suspend</code> property has been set to true.  Upon
  +     * completion of an activity, any execution state that was saved to due
  +     * to utilizing the <code>call()</code> method will be restored, and
  +     * the saved Activity execution shall be resumed.
        *
        * @exception StepException if an exception is thrown by the
        *  <code>execute()</code> method of a Step we have executed
  @@ -345,27 +360,16 @@
   
   
       /**
  -     * <p>Set the <code>Activity</code> to be executed, and make the first
  -     * defined <code>Step</code> within this <code>Activity</code> the next
  -     * action to be performed by <code>execute()</code>.</p>
  -     *
  -     * <p>If <code>null</code> is passed, any currently associated Activity
  -     * will be released, and the evaluation stack will be cleared.</p>
  -     *
  -     * <p><strong>WARNING</strong> - This will have to become more sophisticated
  -     * in order to support calling nested Activities.</p>
  -     *
  -     * @param activity The new Activity to be executed, or <code>null</code>
  -     *  to release resources
  +     * <p>Return the <code>Step</code> that will be executed the next time
  +     * that <code>execute()</code> is called, if any.</p>
        */
  -    public void setActivity(Activity activity);
  +    public Step getNextStep();
   
   
       /**
  -     * <p>Return the <code>Step</code> that will be executed the next time
  -     * that <code>execute()</code> is called, if any.</p>
  +     * <p>Return the suspend flag.</p>
        */
  -    public Step getNextStep();
  +    public boolean getSuspend();
   
   
       /**
  @@ -383,9 +387,21 @@
   
   
       /**
  -     * <p>Return the suspend flag.</p>
  +     * <p>Set the <code>Activity</code> to be executed, and make the first
  +     * defined <code>Step</code> within this <code>Activity</code> the next
  +     * action to be performed by <code>execute()</code>.</p>
  +     *
  +     * <p>If <code>null</code> is passed, any currently associated Activity
  +     * will be released, and the evaluation stack and nested call state
  +     * stack will be cleared.</p>
  +     *
  +     * <p><strong>WARNING</strong> - This will have to become more sophisticated
  +     * in order to support calling nested Activities.</p>
  +     *
  +     * @param activity The new Activity to be executed, or <code>null</code>
  +     *  to release resources
        */
  -    public boolean getSuspend();
  +    public void setActivity(Activity activity);
   
   
       /**
  
  
  
  1.10      +96 -29    
jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/base/BaseContext.java
  
  Index: BaseContext.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/base/BaseContext.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- BaseContext.java  2001/08/23 03:52:18     1.9
  +++ BaseContext.java  2001/08/27 05:57:26     1.10
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/base/BaseContext.java,v
 1.9 2001/08/23 03:52:18 craigmcc Exp $
  - * $Revision: 1.9 $
  - * $Date: 2001/08/23 03:52:18 $
  + * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/base/BaseContext.java,v
 1.10 2001/08/27 05:57:26 craigmcc Exp $
  + * $Revision: 1.10 $
  + * $Date: 2001/08/27 05:57:26 $
    *
    * ====================================================================
    * 
  @@ -84,7 +84,7 @@
    * class.  If it is used in a multiple thread environment, callers must
    * take suitable precations.</p>
    *
  - * @version $Revision: 1.9 $ $Date: 2001/08/23 03:52:18 $
  + * @version $Revision: 1.10 $ $Date: 2001/08/27 05:57:26 $
    * @author Craig R. McClanahan
    */
   
  @@ -125,6 +125,13 @@
   
   
       /**
  +     * The suspended "next step" Step for each in-progress Activity that has
  +     * issued a <code>call()</code> to execute a subordinate Activity.
  +     */
  +    protected ArrayStack calls = new ArrayStack();
  +
  +
  +    /**
        * The set of names associated with the registered <code>Scopes</code>.
        */
       protected String names[] = new String[MAX_SCOPES];
  @@ -496,9 +503,36 @@
   
   
       /**
  +     * <p>Save the execution state (i.e. the currently assigned next step)
  +     * of the Activity we are currently executing, and begin executing the
  +     * specified Activity.  When that Activity exits (either normally
  +     * or by throwing an exception), the previous Activity will be resumed
  +     * where it left off.
  +     *
  +     * @param activity The Activity to be called
  +     */
  +    public void call(Activity activity) {
  +
  +        // Save the next Step for the current Activity (if we have
  +        // any remaining steps to worry about -- a call on the last
  +        // step of an activity is more like a non-local goto)
  +        if (this.nextStep != null)
  +            calls.push(this.nextStep);
  +
  +        // Forward control to the first Step of the new Activity
  +        this.activity = activity;
  +        this.nextStep = activity.getFirstStep();
  +
  +    }
  +
  +
  +    /**
        * <p>Execute the <code>Step</code> currently identified as the next
        * step, and continue execution until there is no next step, or until
  -     * the <code>suspend</code> property has been set to true.
  +     * the <code>suspend</code> property has been set to true.  Upon
  +     * completion of an activity, any execution state that was saved to due
  +     * to utilizing the <code>call()</code> method will be restored, and
  +     * the saved Activity execution shall be resumed.
        *
        * @exception StepException if an exception is thrown by the
        *  <code>execute()</code> method of a Step we have executed
  @@ -527,11 +561,29 @@
           StepException exception = null;
           while (true) {
   
  +            // Process a suspension of Activity execution
               if (suspend)
                   break;                // Suspend set by a Step
  -            if (nextStep == null)
  -                break;                // We have completed this Activity
   
  +            // Process completion of an Activity
  +            if (nextStep == null) {
  +
  +                // If there are no active calls, we are done
  +                if (calls.empty())
  +                    break;
  +
  +                // If there are active calls, resume the most recent one
  +                try {
  +                    nextStep = (Step) calls.pop();
  +                    this.activity = nextStep.getActivity();
  +                } catch (EmptyStackException e) {
  +                    ; // Can not happen
  +                }
  +                continue;
  +
  +            }
  +
  +            // Execute the (now) current Step
               thisStep = nextStep;
               nextStep = thisStep.getNextStep();
               try {
  @@ -572,6 +624,19 @@
   
   
       /**
  +     * Return the set of pending Step executions that are pending because
  +     * of calls to subordinate Activities have occurred.  If there are
  +     * no pending Step executions, a zero-length array is returned.
  +     */
  +    public Step[] getCalls() {
  +
  +        Step steps[] = new Step[calls.size()];
  +        return ((Step[]) calls.toArray(steps));
  +
  +    }
  +
  +
  +    /**
        * Return the JXPathContext object that represents a unified namespace
        * covering all of our registered <code>Scopes</code>.
        */
  @@ -585,12 +650,34 @@
   
   
       /**
  +     * <p>Return the <code>Step</code> that will be executed the next time
  +     * that <code>execute()</code> is called, if any.</p>
  +     */
  +    public Step getNextStep() {
  +
  +        return (this.nextStep);
  +
  +    }
  +
  +
  +    /**
  +     * <p>Return the suspend flag.</p>
  +     */
  +    public boolean getSuspend() {
  +
  +        return (this.suspend);
  +
  +    }
  +
  +
  +    /**
        * <p>Set the <code>Activity</code> to be executed, and make the first
        * defined <code>Step</code> within this <code>Activity</code> the next
        * action to be performed by <code>execute()</code>.</p>
        *
        * <p>If <code>null</code> is passed, any currently associated Activity
  -     * will be released, and the evaluation stack will be cleared.</p>
  +     * will be released, and the evaluation stack and nested call state
  +     * stack will be cleared.</p>
        *
        * <p><strong>WARNING</strong> - This will have to become more sophisticated
        * in order to support calling nested Activities.</p>
  @@ -608,22 +695,12 @@
               this.activity = activity;
               this.nextStep = activity.getFirstStep();
           }
  +        calls.clear();
   
       }
   
   
       /**
  -     * <p>Return the <code>Step</code> that will be executed the next time
  -     * that <code>execute()</code> is called, if any.</p>
  -     */
  -    public Step getNextStep() {
  -
  -        return (this.nextStep);
  -
  -    }
  -
  -
  -    /**
        * <p>Set the <code>Step</code> that will be executed the next time
        * that <code>execute()</code> is called.  This is called by a
        * <code>Step</code> that wants to perform branching based on some
  @@ -641,16 +718,6 @@
               throw new IllegalArgumentException
                   ("Step is not part of the current Activity");
           this.nextStep = nextStep;
  -
  -    }
  -
  -
  -    /**
  -     * <p>Return the suspend flag.</p>
  -     */
  -    public boolean getSuspend() {
  -
  -        return (this.suspend);
   
       }
   
  
  
  
  1.3       +13 -4     
jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CoreRuleSet.java
  
  Index: CoreRuleSet.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CoreRuleSet.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CoreRuleSet.java  2001/08/27 02:55:54     1.2
  +++ CoreRuleSet.java  2001/08/27 05:57:26     1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CoreRuleSet.java,v
 1.2 2001/08/27 02:55:54 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/08/27 02:55:54 $
  + * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CoreRuleSet.java,v
 1.3 2001/08/27 05:57:26 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/08/27 05:57:26 $
    *
    * ====================================================================
    *
  @@ -76,7 +76,7 @@
    * </pre>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2001/08/27 02:55:54 $
  + * @version $Revision: 1.3 $ $Date: 2001/08/27 05:57:26 $
    */
   
   public class CoreRuleSet extends BaseRuleSet {
  @@ -127,6 +127,15 @@
           digester.addSetNext
               (prefix + "and/descriptor", "addDescriptor",
                "org.apache.commons.workflow.Descriptor");
  +
  +        digester.addObjectCreate
  +            (prefix + "call",
  +             "org.apache.commons.workflow.core.CallStep");
  +        digester.addSetProperties
  +            (prefix + "call");
  +        digester.addSetNext
  +            (prefix + "call", "addStep",
  +             "org.apache.commons.workflow.Step");
   
           digester.addObjectCreate
               (prefix + "duplicate",
  
  
  
  1.1                  
jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CallStep.java
  
  Index: CallStep.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/java/org/apache/commons/workflow/core/CallStep.java,v
 1.1 2001/08/27 05:57:26 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2001/08/27 05:57:26 $
   *
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  
  package org.apache.commons.workflow.core;
  
  
  import java.util.EmptyStackException;
  import org.apache.commons.workflow.Activity;
  import org.apache.commons.workflow.Context;
  import org.apache.commons.workflow.StepException;
  import org.apache.commons.workflow.base.BaseStep;
  
  
  /**
   * <p>Pop the top value from the evaluation stack, which must be an
   * <code>Activity</code>, and initiate a "subroutine call" to execute
   * this Activity before resuming the current one.</p>
   *
   * <p><strong>NOTE</strong> - The means by which the Activity on the top
   * of the stack was acquired is NOT mandated by this Step implementation.</p>
   *
   * @version $Revision: 1.1 $ $Date: 2001/08/27 05:57:26 $
   * @author Craig R. McClanahan
   */
  
  public class CallStep extends BaseStep {
  
  
      // ----------------------------------------------------------= Constructors
  
  
      /**
       * Construct a default instance of this Step.
       */
      public CallStep() {
  
          super();
  
      }
  
  
      /**
       * Construct an instance of this Step with the specified identifier.
       *
       * @param id Step identifier
       */
      public CallStep(String id) {
  
          super();
          setId(id);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Perform the executable actions related to this Step, in the context of
       * the specified Context.
       *
       * @param context The Context that is tracking our execution state
       *
       * @exception StepException if a processing error has occurred
       */
      public void execute(Context context) throws StepException {
  
          // Pop the evaluation stack
          Object value = null;
          try {
              value = context.pop();
          } catch (EmptyStackException e) {
              throw new StepException("Evaluation stack is empty", e, this);
          }
  
          // Call the requested Activity 
          if (!(value instanceof Activity))
              throw new StepException("Top of stack is not an Activity", this);
          context.call((Activity) value);
  
      }
  
  
  }
  
  
  
  1.6       +94 -4     
jakarta-commons-sandbox/workflow/src/test/org/apache/commons/workflow/core/CoreExecuteTestCase.java
  
  Index: CoreExecuteTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons-sandbox/workflow/src/test/org/apache/commons/workflow/core/CoreExecuteTestCase.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- CoreExecuteTestCase.java  2001/08/26 03:38:11     1.5
  +++ CoreExecuteTestCase.java  2001/08/27 05:57:26     1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/test/org/apache/commons/workflow/core/CoreExecuteTestCase.java,v
 1.5 2001/08/26 03:38:11 craigmcc Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/08/26 03:38:11 $
  + * $Header: 
/home/cvs/jakarta-commons-sandbox/workflow/src/test/org/apache/commons/workflow/core/CoreExecuteTestCase.java,v
 1.6 2001/08/27 05:57:26 craigmcc Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/08/27 05:57:26 $
    *
    * ====================================================================
    *
  @@ -85,7 +85,7 @@
    * implementations.</p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.5 $ $Date: 2001/08/26 03:38:11 $
  + * @version $Revision: 1.6 $ $Date: 2001/08/27 05:57:26 $
    */
   
   public class CoreExecuteTestCase extends TestCase
  @@ -166,6 +166,96 @@
   
   
       // ------------------------------------------------ Individual Test Methods
  +
  +
  +    /**
  +     * Call a nested Activity.
  +     */
  +    public void testCallNested() {
  +
  +        // Configure the steps in this activity
  +        activity.addStep(new StringStep("01", "Original activity"));
  +        activity.addStep(new SuspendStep("02"));
  +        // Manually push a nested activity here
  +        activity.addStep(new CallStep("03"));
  +        /*
  +        activity.addStep(new DuplicateStep("04"));
  +        activity.addStep(new PopStep("05"));
  +        */
  +
  +        // Execute the activity and validate results #1
  +        try {
  +            context.execute();
  +            assertEquals("Trail contents",
  +                         "beforeActivity()/" +
  +                         "beforeStep(01)/afterStep(01)/" +
  +                         "beforeStep(02)/afterStep(02)/" +
  +                         "afterActivity()/",
  +                         trail.toString());
  +            assertTrue("Stack is not empty",
  +                       !context.isEmpty());
  +            assertEquals("Top of stack string",
  +                         "Original activity",
  +                         (String) context.peek());
  +            assertTrue("Context was suspended",
  +                       context.getSuspend());
  +        } catch (StepException e) {
  +            e.printStackTrace(System.out);
  +            if (e.getCause() != null) {
  +                System.out.println("ROOT CAUSE");
  +                e.getCause().printStackTrace(System.out);
  +            }
  +            fail("Threw StepException " + e);
  +        } catch (Throwable e) {
  +            e.printStackTrace();
  +            fail("Threw exception " + e);
  +        }
  +
  +        // Manually push a nested Activity onto the evaluation stack
  +        Activity nested = new BaseActivity();
  +        nested.addStep(new StringStep("11", "Nested activity"));
  +        nested.addStep(new SwapStep("12"));
  +        context.push(nested);
  +
  +        // Execute the activity and validate results #2
  +        try {
  +            context.execute();
  +            assertEquals("Trail contents",
  +                         "beforeActivity()/" +
  +                         "beforeStep(03)/afterStep(03)/" +
  +                         "beforeStep(11)/afterStep(11)/" +
  +                         "beforeStep(12)/afterStep(12)/" +
  +                         /*
  +                         "beforeStep(04)/afterStep(04)/" +
  +                         "beforeStep(05)/afterStep(05)/" +
  +                         */
  +                         "afterActivity()/",
  +                         trail.toString());
  +            assertTrue("Stack is not empty",
  +                       !context.isEmpty());
  +            assertEquals("Top of stack string",
  +                         "Original activity",
  +                         (String) context.pop());
  +            assertEquals("Bottom of stack string",
  +                         "Nested activity",
  +                         (String) context.pop());
  +            assertTrue("Stack is empty",
  +                       context.isEmpty());
  +            assertTrue("Context was not suspended",
  +                       !context.getSuspend());
  +        } catch (StepException e) {
  +            e.printStackTrace(System.out);
  +            if (e.getCause() != null) {
  +                System.out.println("ROOT CAUSE");
  +                e.getCause().printStackTrace(System.out);
  +            }
  +            fail("Threw StepException " + e);
  +        } catch (Throwable e) {
  +            e.printStackTrace();
  +            fail("Threw exception " + e);
  +        }
  +
  +    }
   
   
       /**
  
  
  

Reply via email to