Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BaseContext |
|
| 2.27027027027027;2.27 |
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.EmptyStackException; | |
21 | import org.apache.commons.collections.ArrayStack; | |
22 | import org.apache.commons.jxpath.JXPathContext; | |
23 | import org.apache.commons.workflow.Activity; | |
24 | import org.apache.commons.workflow.Block; | |
25 | import org.apache.commons.workflow.BlockState; | |
26 | import org.apache.commons.workflow.Context; | |
27 | import org.apache.commons.workflow.ContextEvent; | |
28 | import org.apache.commons.workflow.ContextListener; | |
29 | import org.apache.commons.workflow.Owner; | |
30 | import org.apache.commons.workflow.Step; | |
31 | import org.apache.commons.workflow.StepException; | |
32 | import org.apache.commons.workflow.Scope; | |
33 | import org.apache.commons.workflow.util.ContextSupport; | |
34 | ||
35 | ||
36 | /** | |
37 | * <strong>BaseContext</strong> is a basic <code>Context</code> implementation | |
38 | * that can serve as a convenient base class for more sophisticated | |
39 | * <code>Context</code> implementations. | |
40 | * | |
41 | * <p><strong>WARNING</strong> - No synchronization is performed within this | |
42 | * class. If it is used in a multiple thread environment, callers must | |
43 | * take suitable precations.</p> | |
44 | * | |
45 | * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $ | |
46 | * @author Craig R. McClanahan | |
47 | */ | |
48 | ||
49 | public class BaseContext implements Context { | |
50 | ||
51 | ||
52 | ||
53 | // ----------------------------------------------------------- Constructors | |
54 | ||
55 | ||
56 | /** | |
57 | * Construct a new BaseContext with all default values. | |
58 | */ | |
59 | public BaseContext() { | |
60 | ||
61 | 0 | super(); |
62 | 0 | names[LOCAL_SCOPE] = "local"; |
63 | 0 | scopes[LOCAL_SCOPE] = new BaseScope(); |
64 | ||
65 | 0 | } |
66 | ||
67 | ||
68 | // ----------------------------------------------------- Instance Variables | |
69 | ||
70 | ||
71 | /** | |
72 | * The <code>Activity</code> that we are associated with and executing | |
73 | * <code>Steps</code> from (if any). | |
74 | */ | |
75 | 0 | protected Activity activity = null; |
76 | ||
77 | ||
78 | /** | |
79 | * The bean representing the information about this Context made visible | |
80 | * through JXPath. | |
81 | */ | |
82 | 0 | protected BaseContextBean bean = null; |
83 | ||
84 | ||
85 | /** | |
86 | * The suspended "next step" Step for each in-progress Activity that has | |
87 | * issued a <code>call()</code> to execute a subordinate Activity. | |
88 | */ | |
89 | 0 | protected ArrayStack calls = new ArrayStack(); |
90 | ||
91 | ||
92 | /** | |
93 | * The set of names associated with the registered <code>Scopes</code>. | |
94 | */ | |
95 | 0 | protected String names[] = new String[MAX_SCOPES]; |
96 | ||
97 | ||
98 | /** | |
99 | * The <code>Step</code> that will be executed first the next time that | |
100 | * <code>execute()</code> is called. This is maintained dynamically as | |
101 | * execution proceeds, much like the "next instruction pointer" of a | |
102 | * CPU tracks what instruction will be executed next. | |
103 | */ | |
104 | 0 | protected Step nextStep = null; |
105 | ||
106 | ||
107 | /** | |
108 | * The set of <code>Scopes</code> that have been associated with | |
109 | * this Context. When initially created, every Context has a | |
110 | * Scope attached to identifier LOCAL_SCOPE already created. | |
111 | */ | |
112 | 0 | protected Scope scopes[] = new Scope[MAX_SCOPES]; |
113 | ||
114 | ||
115 | /** | |
116 | * The evaluation stack of nameless objects being processed. | |
117 | */ | |
118 | 0 | protected ArrayStack stack = new ArrayStack(); |
119 | ||
120 | ||
121 | /** | |
122 | * The BlockState stack of BlockState objects used to manage iteration. | |
123 | */ | |
124 | 0 | protected ArrayStack state = new ArrayStack(); |
125 | ||
126 | ||
127 | /** | |
128 | * The event listener support object for this <code>Context</code>. | |
129 | */ | |
130 | 0 | protected ContextSupport support = new ContextSupport(this); |
131 | ||
132 | ||
133 | /** | |
134 | * The suspension flag. If this is set when a particular <code>Step</code> | |
135 | * returns, control will be returned from our <code>execute()</code> | |
136 | * method to allow interaction with the rest of the application. The | |
137 | * next time that <code>execute()</code> is called, execution will | |
138 | * resume with the next scheduled step. | |
139 | */ | |
140 | 0 | protected boolean suspend = false; |
141 | ||
142 | ||
143 | // --------------------------------------------------- Scope Access Methods | |
144 | ||
145 | ||
146 | // These methods provide Steps with the ability to get and set arbitrary | |
147 | // objects in arbitrary scopes. When a scope is not mentioned explicitly, | |
148 | // either LOCAL_SCOPE will be used, or scopes will be searched in | |
149 | // increasing order of their identifiers, as specified in the various | |
150 | // method descriptions. | |
151 | ||
152 | ||
153 | /** | |
154 | * Return true if a bean with the specified key exist in any specified | |
155 | * scope. Scopes will be searched in ascending order of their identifiers, | |
156 | * starting with LOCAL_SCOPE. | |
157 | * | |
158 | * @param key Key of the bean to be searched for (cannot be null) | |
159 | */ | |
160 | public boolean contains(String key) { | |
161 | ||
162 | 0 | for (int i = 0; i < MAX_SCOPES; i++) { |
163 | 0 | if (scopes[i] == null) |
164 | 0 | continue; |
165 | 0 | if (scopes[i].containsKey(key)) |
166 | 0 | return (true); |
167 | } | |
168 | 0 | return (false); |
169 | ||
170 | } | |
171 | ||
172 | ||
173 | /** | |
174 | * Does a bean with the specified key exist in the specified scope? | |
175 | * | |
176 | * @param key Key of the bean to be searched for (cannot be null) | |
177 | * @param scope Identifier of the scope to be returned. | |
178 | */ | |
179 | public boolean contains(String key, int scope) { | |
180 | ||
181 | 0 | if (scopes[scope] == null) |
182 | 0 | return (false); |
183 | else | |
184 | 0 | return (scopes[scope].containsKey(key)); |
185 | ||
186 | } | |
187 | ||
188 | ||
189 | /** | |
190 | * Return the bean associated with the specified key, if it exists in | |
191 | * any scope. Scopes will be searched in increasing order of their | |
192 | * identifiers, starting with LOCAL_SCOPE. If the underlying Scope | |
193 | * allows null values, a <code>null</code> return will be ambiguous. | |
194 | * Therefore, you can use the <code>contains()</code> method to determine | |
195 | * whether the key actually exists. | |
196 | * | |
197 | * @param key Key of the bean to be retrieved (cannot be null) | |
198 | */ | |
199 | public Object get(String key) { | |
200 | ||
201 | 0 | for (int i = 0; i < MAX_SCOPES; i++) { |
202 | 0 | if (scopes[i] == null) |
203 | 0 | continue; |
204 | 0 | Object bean = scopes[i].get(key); |
205 | 0 | if (bean != null) |
206 | 0 | return (bean); |
207 | } | |
208 | 0 | return (null); |
209 | ||
210 | } | |
211 | ||
212 | ||
213 | /** | |
214 | * Return the bean associated with the specified key, if it exists in | |
215 | * the specified scope. If the underlying Scope allows null values, | |
216 | * a <code>null</code> return will be ambiguous. Therefore, you can | |
217 | * use the <code>contains()</code> method to determine whether the | |
218 | * key actually exists. | |
219 | * | |
220 | * @param key Key of the bean to be searched for | |
221 | * @param scope Identifier of the scope to be searched | |
222 | */ | |
223 | public Object get(String key, int scope) { | |
224 | ||
225 | 0 | if (scopes[scope] == null) |
226 | 0 | return (null); |
227 | else | |
228 | 0 | return (scopes[scope].get(key)); |
229 | ||
230 | } | |
231 | ||
232 | ||
233 | /** | |
234 | * Store the specified bean under the specified key, in local scope, | |
235 | * replacing any previous value for that key. Any previous value will | |
236 | * be returned. | |
237 | * | |
238 | * @param key Key of the bean to be stored (cannot be null) | |
239 | * @param value Value of the bean to be stored | |
240 | */ | |
241 | public Object put(String key, Object value) { | |
242 | ||
243 | 0 | return (scopes[LOCAL_SCOPE].put(key, value)); |
244 | ||
245 | } | |
246 | ||
247 | ||
248 | /** | |
249 | * Store the specified bean under the specified key, in the specified | |
250 | * scope, replacing any previous value for that key. Any previous value | |
251 | * will be returned. | |
252 | * | |
253 | * @param key Key of the bean to be stored (cannot be null) | |
254 | * @param value Value of the bean to be stored | |
255 | * @param scope Identifier of the scope to use for storage | |
256 | */ | |
257 | public Object put(String key, Object value, int scope) { | |
258 | ||
259 | 0 | if (scopes[scope] == null) |
260 | 0 | return (null); |
261 | else | |
262 | 0 | return (scopes[scope].put(key, value)); |
263 | ||
264 | } | |
265 | ||
266 | ||
267 | /** | |
268 | * Remove any existing value for the specified key, in any scope. | |
269 | * Scopes will be searched in ascending order of their identifiers, | |
270 | * starting with LOCAL_SCOPE. Any previous value for this key will | |
271 | * be returned. | |
272 | * | |
273 | * @param key Key of the bean to be removed | |
274 | */ | |
275 | public Object remove(String key) { | |
276 | ||
277 | 0 | return (scopes[LOCAL_SCOPE].remove(key)); |
278 | ||
279 | } | |
280 | ||
281 | ||
282 | /** | |
283 | * Remove any existing value for the specified key, from the specified | |
284 | * scope. Any previous value for this key will be returned. | |
285 | * | |
286 | * @param key Key of the bean to be removed | |
287 | * @param scope Scope the bean to be removed from | |
288 | */ | |
289 | public Object remove(String key, int scope) { | |
290 | ||
291 | 0 | if (scopes[scope] == null) |
292 | 0 | return (null); |
293 | else | |
294 | 0 | return (scopes[scope].remove(key)); |
295 | ||
296 | } | |
297 | ||
298 | ||
299 | ||
300 | // --------------------------------------------- Scope Registration Methods | |
301 | ||
302 | ||
303 | // These methods provide capabilities to register and retrieve | |
304 | // Scope implementations. Workflow engine implementations will | |
305 | // register desired scopes when they create Context instances. | |
306 | ||
307 | ||
308 | /** | |
309 | * <p>Register a Scope implementation under the specified identifier. | |
310 | * It is not legal to replace the LOCAL_SCOPE implementation that is | |
311 | * provided by the Context implementation.</p> | |
312 | * | |
313 | * <p>In addition to registering the new Scope such that it can be | |
314 | * accessed dirctly via calls like <code>Context.get(String,int)</code>, | |
315 | * the Scope <code>impl</code> object will also be added to the LOCAL | |
316 | * Scope under the same name. This makes possible a single unified | |
317 | * namespace of all accessible objects that can be navigated by | |
318 | * expression languages.</p> | |
319 | * | |
320 | * @param scope Scope identifier to register under | |
321 | * @param name Scope name to register under | |
322 | * @param impl Scope implementation to be registered (or null to | |
323 | * remove a previous registration) | |
324 | * @exception IllegalArgumentException if you attempt to register | |
325 | * or deregister the local scope | |
326 | */ | |
327 | public void addScope(int scope, String name, Scope impl) { | |
328 | ||
329 | 0 | if (scope == LOCAL_SCOPE) |
330 | 0 | throw new IllegalArgumentException("Cannot replace local scope"); |
331 | 0 | if (impl == null) { |
332 | 0 | getScope(LOCAL_SCOPE).remove(name); |
333 | 0 | names[scope] = null; |
334 | 0 | scopes[scope] = null; |
335 | } else { | |
336 | 0 | getScope(LOCAL_SCOPE).put(name, impl); |
337 | 0 | names[scope] = name; |
338 | 0 | scopes[scope] = impl; |
339 | } | |
340 | 0 | bean = null; |
341 | ||
342 | 0 | } |
343 | ||
344 | ||
345 | /** | |
346 | * Return the Scope instance for our local Scope as a simple property. | |
347 | */ | |
348 | public Scope getLocal() { | |
349 | ||
350 | 0 | return (getScope(LOCAL_SCOPE)); |
351 | ||
352 | } | |
353 | ||
354 | ||
355 | /** | |
356 | * Return the Scope implementation registered for the specified | |
357 | * identifier, if any; otherwise, return <code>null</code>. | |
358 | * | |
359 | * @param scope Scope identifier to select | |
360 | */ | |
361 | public Scope getScope(int scope) { | |
362 | ||
363 | 0 | if ((scope >= 0) && (scope < MAX_SCOPES)) |
364 | 0 | return (scopes[scope]); |
365 | else | |
366 | 0 | return (null); |
367 | ||
368 | } | |
369 | ||
370 | ||
371 | /** | |
372 | * Return the Scope implementation registered for the specified | |
373 | * name, if any; otherwise, return <code>null</code>. | |
374 | * | |
375 | * @param name Scope name to select | |
376 | */ | |
377 | public Scope getScope(String name) { | |
378 | ||
379 | 0 | return (getScope(getScopeId(name))); |
380 | ||
381 | } | |
382 | ||
383 | ||
384 | /** | |
385 | * Return the Scope identifier registered for the specified | |
386 | * name, if any; otherwise, return <code>-1</code>. | |
387 | * | |
388 | * @param name Scope name to select | |
389 | */ | |
390 | public int getScopeId(String name) { | |
391 | ||
392 | 0 | for (int i = 0; i < names.length; i++) { |
393 | 0 | if (names[i] == null) |
394 | 0 | continue; |
395 | 0 | if (names[i].equals(name)) |
396 | 0 | return (i); |
397 | } | |
398 | 0 | return (-1); |
399 | ||
400 | } | |
401 | ||
402 | ||
403 | // ----------------------------------------------- Evaluation Stack Methods | |
404 | ||
405 | ||
406 | /** | |
407 | * Clear the evaluation stack. | |
408 | */ | |
409 | public void clear() { | |
410 | ||
411 | 0 | stack.clear(); |
412 | ||
413 | 0 | } |
414 | ||
415 | ||
416 | /** | |
417 | * Is the evaluation stack currently empty? | |
418 | */ | |
419 | public boolean isEmpty() { | |
420 | ||
421 | 0 | return (stack.size() == 0); |
422 | ||
423 | } | |
424 | ||
425 | ||
426 | /** | |
427 | * Return the top item from the evaluation stack without removing it. | |
428 | * | |
429 | * @exception EmptyStackException if the stack is empty | |
430 | */ | |
431 | public Object peek() throws EmptyStackException { | |
432 | ||
433 | 0 | return (stack.peek()); |
434 | ||
435 | } | |
436 | ||
437 | ||
438 | /** | |
439 | * Pop and return the top item from the evaluation stack. | |
440 | * | |
441 | * @exception EmptyStackException if the stack is empty | |
442 | */ | |
443 | public Object pop() throws EmptyStackException { | |
444 | ||
445 | 0 | return (stack.pop()); |
446 | ||
447 | } | |
448 | ||
449 | ||
450 | /** | |
451 | * Push a new item onto the top of the evaluation stack. | |
452 | * | |
453 | * @param item New item to be pushed | |
454 | */ | |
455 | public void push(Object item) { | |
456 | ||
457 | 0 | stack.push(item); |
458 | ||
459 | 0 | } |
460 | ||
461 | ||
462 | // ----------------------------------------------- BlockState Stack Methods | |
463 | ||
464 | ||
465 | /** | |
466 | * Clear the BlockState stack. | |
467 | */ | |
468 | public void clearBlockState() { | |
469 | ||
470 | 0 | state.clear(); |
471 | ||
472 | 0 | } |
473 | ||
474 | ||
475 | /** | |
476 | * Is the BlockState stack currently empty? | |
477 | */ | |
478 | public boolean isEmptyBlockState() { | |
479 | ||
480 | 0 | return (state.size() == 0); |
481 | ||
482 | } | |
483 | ||
484 | ||
485 | /** | |
486 | * Return the top item from the BlockState stack without removing it. | |
487 | * | |
488 | * @exception EmptyStackException if the stack is empty | |
489 | */ | |
490 | public BlockState peekBlockState() throws EmptyStackException { | |
491 | ||
492 | 0 | return ((BlockState) state.peek()); |
493 | ||
494 | } | |
495 | ||
496 | ||
497 | /** | |
498 | * Pop and return the top item from the BlockState stack. | |
499 | * | |
500 | * @exception EmptyStackException if the stack is empty | |
501 | */ | |
502 | public BlockState popBlockState() throws EmptyStackException { | |
503 | ||
504 | 0 | return ((BlockState) state.pop()); |
505 | ||
506 | } | |
507 | ||
508 | ||
509 | /** | |
510 | * Push a new item onto the top of the BlockState stack. | |
511 | * | |
512 | * @param item New item to be pushed | |
513 | */ | |
514 | public void pushBlockState(BlockState item) { | |
515 | ||
516 | 0 | state.push(item); |
517 | ||
518 | 0 | } |
519 | ||
520 | ||
521 | // ---------------------------------------------- Dynamic Execution Methods | |
522 | ||
523 | ||
524 | // These methods are used to request the dynamic execution of the | |
525 | // Steps related to a particular Activity. | |
526 | ||
527 | ||
528 | /** | |
529 | * <p>Save the execution state (ie the currently assigned next step) | |
530 | * of the Activity we are currently executing, and begin executing the | |
531 | * specified Activity. When that Activity exits (either normally | |
532 | * or by throwing an exception), the previous Activity will be resumed | |
533 | * where it left off. | |
534 | * | |
535 | * @param activity The Activity to be called | |
536 | */ | |
537 | public void call(Activity activity) { | |
538 | ||
539 | // Save the next Step for the current Activity (if we have | |
540 | // any remaining steps to worry about -- a call on the last | |
541 | // step of an activity is more like a non-local goto) | |
542 | 0 | if (this.nextStep != null) |
543 | 0 | calls.push(this.nextStep); |
544 | ||
545 | // Forward control to the first Step of the new Activity | |
546 | 0 | this.activity = activity; |
547 | 0 | this.nextStep = activity.getFirstStep(); |
548 | ||
549 | 0 | } |
550 | ||
551 | ||
552 | /** | |
553 | * <p>Execute the <code>Step</code> currently identified as the next | |
554 | * step, and continue execution until there is no next step, or until | |
555 | * the <code>suspend</code> property has been set to true. Upon | |
556 | * completion of an activity, any execution state that was saved to due | |
557 | * to utilizing the <code>call()</code> method will be restored, and | |
558 | * the saved Activity execution shall be resumed. | |
559 | * | |
560 | * @exception StepException if an exception is thrown by the | |
561 | * <code>execute()</code> method of a Step we have executed | |
562 | * @exception IllegalStateException if there is no defined next step | |
563 | * (either because there is no Activity, or because we have already | |
564 | * completed all the steps of this activity) | |
565 | */ | |
566 | public void execute() throws StepException { | |
567 | ||
568 | // Do we actually have a next step to be performed | |
569 | 0 | if (activity == null) |
570 | 0 | throw new IllegalStateException("No Activity has been selected"); |
571 | 0 | if (nextStep == null) |
572 | 0 | nextStep = activity.getFirstStep(); |
573 | 0 | if (nextStep == null) |
574 | 0 | throw new IllegalStateException("Activity has been completed"); |
575 | ||
576 | // Reset the suspend flag until set by another step | |
577 | 0 | suspend = false; |
578 | ||
579 | // Send a beforeActivity() event to interested listeners | |
580 | 0 | support.fireBeforeActivity(nextStep); |
581 | ||
582 | // Perform execution until suspended or completed | |
583 | 0 | Step thisStep = null; |
584 | 0 | StepException exception = null; |
585 | while (true) { | |
586 | ||
587 | // Process a suspension of Activity execution | |
588 | 0 | if (suspend) |
589 | 0 | break; // Suspend set by a Step |
590 | ||
591 | // Process completion of an Activity | |
592 | 0 | if (nextStep == null) { |
593 | ||
594 | // If there are no active calls, we are done | |
595 | 0 | if (calls.empty()) |
596 | 0 | break; |
597 | ||
598 | // If there are active calls, resume the most recent one | |
599 | try { | |
600 | 0 | nextStep = (Step) calls.pop(); |
601 | 0 | Owner owner = nextStep.getOwner(); |
602 | 0 | while (!(owner instanceof Activity)) { |
603 | 0 | owner = ((Step) owner).getOwner(); |
604 | } | |
605 | 0 | this.activity = (Activity) owner; |
606 | 0 | } catch (EmptyStackException e) { |
607 | ; // Can not happen | |
608 | 0 | } |
609 | 0 | continue; |
610 | ||
611 | } | |
612 | ||
613 | // Execute the (now) current Step | |
614 | 0 | thisStep = nextStep; |
615 | 0 | nextStep = thisStep.getNextStep(); // Assume sequential execution |
616 | try { | |
617 | 0 | support.fireBeforeStep(thisStep); |
618 | 0 | thisStep.execute(this); |
619 | 0 | support.fireAfterStep(thisStep); |
620 | 0 | } catch (StepException e) { |
621 | 0 | exception = e; |
622 | 0 | support.fireAfterStep(thisStep, exception); |
623 | 0 | break; |
624 | 0 | } catch (Throwable t) { |
625 | 0 | exception = new StepException(t, thisStep); |
626 | 0 | support.fireAfterStep(thisStep, exception); |
627 | 0 | break; |
628 | 0 | } |
629 | ||
630 | } | |
631 | ||
632 | // Send an afterActivity event to interested listeners | |
633 | 0 | support.fireAfterActivity(thisStep, exception); |
634 | ||
635 | // Rethrow any StepException that was thrown | |
636 | 0 | if (exception != null) |
637 | 0 | throw exception; |
638 | ||
639 | 0 | } |
640 | ||
641 | ||
642 | /** | |
643 | * <p>Return the <code>Activity</code> we will be executing when the | |
644 | * <code>execute()</code> method is called, if any.</p> | |
645 | */ | |
646 | public Activity getActivity() { | |
647 | ||
648 | 0 | return (this.activity); |
649 | ||
650 | } | |
651 | ||
652 | ||
653 | /** | |
654 | * Return the set of pending Step executions that are pending because | |
655 | * of calls to subordinate Activities have occurred. If there are | |
656 | * no pending Step executions, a zero-length array is returned. | |
657 | */ | |
658 | public Step[] getCalls() { | |
659 | ||
660 | 0 | Step steps[] = new Step[calls.size()]; |
661 | 0 | return ((Step[]) calls.toArray(steps)); |
662 | ||
663 | } | |
664 | ||
665 | ||
666 | /** | |
667 | * Return the JXPathContext object that represents a unified namespace | |
668 | * covering all of our registered <code>Scopes</code>. | |
669 | */ | |
670 | public JXPathContext getJXPathContext() { | |
671 | ||
672 | 0 | if (bean == null) |
673 | 0 | bean = new BaseContextBean(this); |
674 | 0 | return (JXPathContext.newContext(bean)); |
675 | ||
676 | } | |
677 | ||
678 | ||
679 | /** | |
680 | * <p>Return the <code>Step</code> that will be executed the next time | |
681 | * that <code>execute()</code> is called, if any.</p> | |
682 | */ | |
683 | public Step getNextStep() { | |
684 | ||
685 | 0 | return (this.nextStep); |
686 | ||
687 | } | |
688 | ||
689 | ||
690 | /** | |
691 | * <p>Return the suspend flag.</p> | |
692 | */ | |
693 | public boolean getSuspend() { | |
694 | ||
695 | 0 | return (this.suspend); |
696 | ||
697 | } | |
698 | ||
699 | ||
700 | /** | |
701 | * <p>Set the <code>Activity</code> to be executed, and make the first | |
702 | * defined <code>Step</code> within this <code>Activity</code> the next | |
703 | * action to be performed by <code>execute()</code>.</p> | |
704 | * | |
705 | * <p>If <code>null</code> is passed, any currently associated Activity | |
706 | * will be released, and the evaluation stack and nested call state | |
707 | * stack will be cleared.</p> | |
708 | * | |
709 | * <p><strong>WARNING</strong> - This will have to become more sophisticated | |
710 | * in order to support calling nested Activities.</p> | |
711 | * | |
712 | * @param activity The new Activity to be executed, or <code>null</code> | |
713 | * to release resources | |
714 | */ | |
715 | public void setActivity(Activity activity) { | |
716 | ||
717 | 0 | if (activity == null) { |
718 | 0 | this.activity = null; |
719 | 0 | this.nextStep = null; |
720 | 0 | clear(); |
721 | 0 | clearBlockState(); |
722 | } else { | |
723 | 0 | this.activity = activity; |
724 | 0 | this.nextStep = activity.getFirstStep(); |
725 | } | |
726 | 0 | calls.clear(); |
727 | ||
728 | 0 | } |
729 | ||
730 | ||
731 | /** | |
732 | * <p>Set the <code>Step</code> that will be executed the next time | |
733 | * that <code>execute()</code> is called. This is called by a | |
734 | * <code>Step</code> that wants to perform branching based on some | |
735 | * calculated results.</p> | |
736 | * | |
737 | * @param nextStep The next Step to be executed | |
738 | * | |
739 | * @exception IllegalArgumentException if the specified Step is not | |
740 | * part of the current Activity | |
741 | */ | |
742 | public void setNextStep(Step nextStep) { | |
743 | ||
744 | // Make sure the specified next Step is within the current Activity | |
745 | 0 | if (nextStep != null) { |
746 | 0 | Owner owner = nextStep.getOwner(); |
747 | 0 | while (owner instanceof Block) |
748 | 0 | owner = ((Block) owner).getOwner(); |
749 | 0 | if (this.activity != (Activity) owner) |
750 | 0 | throw new IllegalArgumentException |
751 | ("Step is not part of the current Activity"); | |
752 | } | |
753 | 0 | this.nextStep = nextStep; |
754 | ||
755 | 0 | } |
756 | ||
757 | ||
758 | /** | |
759 | * <p>Set the suspend flag. This is called by a <code>Step</code> that | |
760 | * wants to signal the <code>Context</code> to return control to the | |
761 | * caller of the <code>execute()</code> method before executing the | |
762 | * next <code>Step</code> in the current activity.</p> | |
763 | * | |
764 | * @param suspend The new suspend flag | |
765 | */ | |
766 | public void setSuspend(boolean suspend) { | |
767 | ||
768 | 0 | this.suspend = suspend; |
769 | ||
770 | 0 | } |
771 | ||
772 | ||
773 | // ------------------------------------------------- Event Listener Methods | |
774 | ||
775 | ||
776 | /** | |
777 | * Add a listener that is notified each time beans are added, | |
778 | * replaced, or removed in this context. | |
779 | * | |
780 | * @param listener The ContextListener to be added | |
781 | */ | |
782 | public void addContextListener(ContextListener listener) { | |
783 | ||
784 | 0 | support.addContextListener(listener); |
785 | ||
786 | 0 | } |
787 | ||
788 | ||
789 | /** | |
790 | * Remove a listener that is notified each time beans are added, | |
791 | * replaced, or removed in this context. | |
792 | * | |
793 | * @param listener The ContextListener to be removed | |
794 | */ | |
795 | public void removeContextListener(ContextListener listener) { | |
796 | ||
797 | 0 | support.removeContextListener(listener); |
798 | ||
799 | 0 | } |
800 | ||
801 | ||
802 | // -------------------------------------------------------- Package Methods | |
803 | ||
804 | ||
805 | /** | |
806 | * Return the array of registered <code>Scope</code> names for this | |
807 | * <code>Context</code>. | |
808 | */ | |
809 | String[] getScopeNames() { | |
810 | ||
811 | 0 | return (this.names); |
812 | ||
813 | } | |
814 | ||
815 | ||
816 | } |