Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BaseBlock |
|
| 2.1666666666666665;2.167 |
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 | 0 | 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 | 0 | protected Step firstStep = null; |
51 | ||
52 | ||
53 | /** | |
54 | * The last Step associated with this Block. | |
55 | */ | |
56 | 0 | 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 | 0 | return (this.firstStep); |
68 | ||
69 | } | |
70 | ||
71 | ||
72 | /** | |
73 | * Return the last Step associated with this Activity. | |
74 | */ | |
75 | public Step getLastStep() { | |
76 | ||
77 | 0 | 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 | 0 | step.setOwner(this); |
98 | 0 | if (firstStep == null) { |
99 | 0 | step.setPreviousStep(null); |
100 | 0 | step.setNextStep(this); |
101 | 0 | firstStep = step; |
102 | 0 | lastStep = step; |
103 | } else { | |
104 | 0 | step.setPreviousStep(lastStep); |
105 | 0 | step.setNextStep(this); |
106 | 0 | lastStep.setNextStep(step); |
107 | 0 | lastStep = step; |
108 | } | |
109 | ||
110 | 0 | } |
111 | ||
112 | ||
113 | /** | |
114 | * Clear any existing Steps associated with this Block. | |
115 | */ | |
116 | public void clearSteps() { | |
117 | ||
118 | 0 | Step current = firstStep; |
119 | 0 | while ((current != null) && (current != this)) { |
120 | 0 | Step next = current.getNextStep(); |
121 | 0 | if (current instanceof Block) |
122 | 0 | ((Block) current).clearSteps(); |
123 | 0 | current.setOwner(null); |
124 | 0 | current.setPreviousStep(null); |
125 | 0 | current.setNextStep(null); |
126 | 0 | current = next; |
127 | 0 | } |
128 | 0 | firstStep = null; |
129 | 0 | lastStep = null; |
130 | ||
131 | 0 | } |
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 | 0 | Step currentStep = getFirstStep(); |
143 | 0 | while (currentStep != null) { |
144 | 0 | if (id.equals(currentStep.getId())) |
145 | 0 | return (currentStep); |
146 | 0 | if (currentStep == lastStep) |
147 | 0 | break; |
148 | 0 | currentStep = currentStep.getNextStep(); |
149 | } | |
150 | 0 | return (null); |
151 | ||
152 | } | |
153 | ||
154 | ||
155 | /** | |
156 | * Return the set of Steps associated with this Block. | |
157 | */ | |
158 | public Step[] getSteps() { | |
159 | ||
160 | 0 | ArrayList list = new ArrayList(); |
161 | 0 | Step currentStep = firstStep; |
162 | 0 | while (currentStep != null) { |
163 | 0 | list.add(currentStep); |
164 | 0 | if (currentStep == lastStep) |
165 | 0 | break; |
166 | 0 | currentStep = currentStep.getNextStep(); |
167 | } | |
168 | 0 | Step steps[] = new Step[list.size()]; |
169 | 0 | 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 | 0 | clearSteps(); |
183 | 0 | for (int i = 0; i < steps.length; i++) |
184 | 0 | addStep(steps[i]); |
185 | ||
186 | 0 | } |
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 | 0 | BlockState state = state(context); |
203 | 0 | if (state == null) |
204 | 0 | initial(context); |
205 | else | |
206 | 0 | subsequent(context, state); |
207 | ||
208 | 0 | } |
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 | 0 | 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 | 0 | context.setNextStep(getNextStep()); |
237 | ||
238 | 0 | } |
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 | 0 | BlockState state = context.peekBlockState(); |
252 | 0 | if (this == state.getBlock()) |
253 | 0 | return (state); |
254 | 0 | } catch (EmptyStackException e) { |
255 | ; | |
256 | 0 | } |
257 | 0 | 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 | 0 | context.popBlockState(); |
274 | 0 | context.setNextStep(getNextStep()); |
275 | ||
276 | 0 | } |
277 | ||
278 | ||
279 | } |