View Javadoc

1   /*
2    * Copyright 1999-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16  
17  package org.apache.commons.workflow.base;
18  
19  
20  import java.util.ArrayList;
21  import java.util.EmptyStackException;
22  import org.apache.commons.workflow.Activity;
23  import org.apache.commons.workflow.Block;
24  import org.apache.commons.workflow.BlockState;
25  import org.apache.commons.workflow.Context;
26  import org.apache.commons.workflow.Owner;
27  import org.apache.commons.workflow.Step;
28  import org.apache.commons.workflow.StepException;
29  
30  
31  /**
32   * <p><strong>BaseBlock</strong> is a convenient base class for more
33   * sophisticated <code>Block</code> implementations.  It includes management
34   * of the static relationships of nested Steps for this Step (each of which
35   * could conceptually also be a Block and have its own nested Steps).</p>
36   *
37   * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
38   * @author Craig R. McClanahan
39   */
40  
41  public abstract class BaseBlock extends DescriptorStep implements Block {
42  
43  
44      // ----------------------------------------------------- Instance Variables
45  
46  
47      /**
48       * The first Step associated with this Block.
49       */
50      protected Step firstStep = null;
51  
52  
53      /**
54       * The last Step associated with this Block.
55       */
56      protected Step lastStep = null;
57  
58  
59      // ------------------------------------------------------------- Properties
60  
61  
62      /**
63       * Return the first Step associated with this Block.
64       */
65      public Step getFirstStep() {
66  
67          return (this.firstStep);
68  
69      }
70  
71  
72      /**
73       * Return the last Step associated with this Activity.
74       */
75      public Step getLastStep() {
76  
77          return (this.lastStep);
78  
79      }
80  
81  
82      // ---------------------------------------------------------- Owner Methods
83  
84  
85      /**
86       * <p>Add a new Step to the end of the sequence of Steps associated with
87       * this Block.</p>
88       *
89       * <p><strong>IMPLEMENTATION NOTE</strong> - The last nested Step is looped
90       * back to the owning Block in order to support the execution flow of
91       * control required by our BaseContext.</p>
92       *
93       * @param step The new step to be added
94       */
95      public void addStep(Step step) {
96  
97          step.setOwner(this);
98          if (firstStep == null) {
99              step.setPreviousStep(null);
100             step.setNextStep(this);
101             firstStep = step;
102             lastStep = step;
103         } else {
104             step.setPreviousStep(lastStep);
105             step.setNextStep(this);
106             lastStep.setNextStep(step);
107             lastStep = step;
108         }
109 
110     }
111 
112 
113     /**
114      * Clear any existing Steps associated with this Block.
115      */
116     public void clearSteps() {
117 
118         Step current = firstStep;
119         while ((current != null) && (current != this)) {
120             Step next = current.getNextStep();
121             if (current instanceof Block)
122                 ((Block) current).clearSteps();
123             current.setOwner(null);
124             current.setPreviousStep(null);
125             current.setNextStep(null);
126             current = next;
127         }
128         firstStep = null;
129         lastStep = null;
130 
131     }
132 
133 
134     /**
135      * Return the identified Step from this Block, if it exists.
136      * Otherwise, return <code>null</code>.
137      *
138      * @param id Identifier of the desired Step
139      */
140     public Step findStep(String id) {
141 
142         Step currentStep = getFirstStep();
143         while (currentStep != null) {
144             if (id.equals(currentStep.getId()))
145                 return (currentStep);
146             if (currentStep == lastStep)
147                 break;
148             currentStep = currentStep.getNextStep();
149         }
150         return (null);
151 
152     }
153 
154 
155     /**
156      * Return the set of Steps associated with this Block.
157      */
158     public Step[] getSteps() {
159 
160         ArrayList list = new ArrayList();
161         Step currentStep = firstStep;
162         while (currentStep != null) {
163             list.add(currentStep);
164             if (currentStep == lastStep)
165                 break;
166             currentStep = currentStep.getNextStep();
167         }
168         Step steps[] = new Step[list.size()];
169         return ((Step[]) list.toArray(steps));
170 
171     }
172 
173 
174     /**
175      * Set the set of Steps associated with this Block, replacing any
176      * existing ones.
177      *
178      * @param steps The new set of steps.
179      */
180     public void setSteps(Step steps[]) {
181 
182         clearSteps();
183         for (int i = 0; i < steps.length; i++)
184             addStep(steps[i]);
185 
186     }
187 
188 
189     // --------------------------------------------------------- Public Methods
190 
191 
192     /**
193      * Perform the executable actions related to this Step, in the context of
194      * the specified Context.
195      *
196      * @param context The Context that is tracking our execution state
197      *
198      * @exception StepException if a processing error has occurred
199      */
200     public void execute(Context context) throws StepException {
201 
202         BlockState state = state(context);
203         if (state == null)
204             initial(context);
205         else
206             subsequent(context, state);
207 
208     }
209 
210 
211     // ------------------------------------------------------ Protected Methods
212 
213 
214     /**
215      * <p>Evaluate the condition specified by the Descriptors associated with
216      * this Block, and return the resulting boolean value.  The default
217      * implementation returns <code>false</code> unconditionally.</p>
218      *
219      * @param context Context within which to evaluate the descriptors
220      */
221     protected boolean evaluate(Context context) {
222 
223         return (false);
224 
225     }
226 
227 
228     /**
229      * <p>Process the initial entry into this Block.  The default
230      * implementation unconditionally skips the nested Steps.</p>
231      *
232      * @param context Context within which to evaluate the condition
233      */
234     protected void initial(Context context) {
235 
236         context.setNextStep(getNextStep());
237 
238     }
239 
240 
241     /**
242      * <p>Peek at the top <code>BlockState</code> element on the stack
243      * maintained by our <code>Context</code>, and return it.  If there
244      * is no such top element, return <code>null</code> instead.</p>
245      *
246      * @param context Context within which to evaluate the current BlockState
247      */
248     protected BlockState state(Context context) {
249 
250         try {
251             BlockState state = context.peekBlockState();
252             if (this == state.getBlock())
253                 return (state);
254         } catch (EmptyStackException e) {
255             ;
256         }
257         return (null);
258 
259     }
260 
261 
262     /**
263      * <p>Process the return from nested execution of the Steps associated
264      * with this Block.  The default implementation unconditionally
265      * proceeds to the next Step at the current nesting level, without
266      * iterating again.</p>
267      *
268      * @param context Context within which to evaluate the condition
269      * @param state BlockState for our block
270      */
271     protected void subsequent(Context context, BlockState state) {
272 
273         context.popBlockState();
274         context.setNextStep(getNextStep());
275 
276     }
277 
278 
279 }