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;
18  
19  
20  import java.util.EmptyStackException;
21  import org.apache.commons.jxpath.JXPathContext;
22  
23  
24  /**
25   * <p>A <strong>Context</strong> represents the dynamic computational state of
26   * a workflow process that is currently being executed.  If multiple users
27   * are executing the same workflow process at the same time, they must have
28   * their own instance of Context.</p>
29   *
30   * <p>Workflow engine implementations can register zero or more Scope
31   * instances, to provide the Steps that are being executed with access to
32   * arbitrary collections of JavaBeans.  A Context will always have at least
33   * one Scope, called the LOCAL scope, which is the default source or
34   * destination for bean references.  Scope instances can be identified
35   * by an integer subscript (which must be in the range 0 .. MAX_SCOPES-1),
36   * or a registered name.  The registered name of the LOCAL scope is
37   * "local".</p>
38   *
39   * <p>In addition to Scopes, which can be used for storing beans under
40   * specific names, an evaluation stack is provided for the convenience of
41   * Step implementations that want to pass temporary results back and forth.
42   * As with all Stack-based implementations, it is the responsibility of
43   * the Step implementations that are executed to maintain the stack's
44   * integrity.</p>
45   *
46   * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
47   * @author Craig R. McClanahan
48   */
49  
50  public interface Context {
51  
52  
53      // ----------------------------------------------------- Manifest Constants
54  
55  
56      /**
57       * The public identifier of the LOCAL scope, which is always defined by a
58       * Context implementation.
59       */
60      public static final int LOCAL_SCOPE = 0;
61  
62  
63      /**
64       * The maximum number of Scopes (including LOCAL_SCOPE) that can be
65       * registered.
66       */
67      public static final int MAX_SCOPES = 8;
68  
69  
70  
71      // --------------------------------------------------- Scope Access Methods
72  
73  
74      // These methods provide Steps with the ability to get and set arbitrary
75      // objects in arbitrary scopes.  When a scope is not mentioned explicitly,
76      // either LOCAL_SCOPE will be used, or scopes will be searched in
77      // increasing order of their identifiers, as specified in the various
78      // method descriptions.
79  
80  
81      /**
82       * Does a bean with the specified key exist in any specified scope?
83       * Scopes will be searched in ascending order of their identifiers,
84       * starting with LOCAL_SCOPE.
85       *
86       * @param key Key of the bean to be searched for (cannot be null)
87       */
88      public boolean contains(String key);
89  
90  
91      /**
92       * Does a bean with the specified key exist in the specified scope?
93       *
94       * @param key Key of the bean to be searched for (cannot be null)
95       * @param scope Identifier of the scope to be returned.
96       */
97      public boolean contains(String key, int scope);
98  
99  
100     /**
101      * Return the bean associated with the specified key, if it exists in
102      * any scope.  Scopes will be searched in increasing order of their
103      * identifiers, starting with LOCAL_SCOPE.  If the underlying Scope
104      * allows null values, a <code>null</code> return will be ambiguous.
105      * Therefore, you can use the <code>contains()</code> method to determine
106      * whether the key actually exists.
107      *
108      * @param key Key of the bean to be retrieved (cannot be null)
109      */
110     public Object get(String key);
111 
112 
113     /**
114      * Return the bean associated with the specified key, if it exists in
115      * the specified scope.  If the underlying Scope allows null values,
116      * a <code>null</code> return will be ambiguous.  Therefore, you can
117      * use the <code>contains()</code> method to determine whether the
118      * key actually exists.
119      *
120      * @param key Key of the bean to be searched for
121      * @param scope Identifier of the scope to be searched
122      */
123     public Object get(String key, int scope);
124 
125 
126     /**
127      * Store the specified bean under the specified key, in local scope,
128      * replacing any previous value for that key.  Any previous value will
129      * be returned.
130      *
131      * @param key Key of the bean to be stored (cannot be null)
132      * @param value Value of the bean to be stored
133      */
134     public Object put(String key, Object value);
135 
136 
137     /**
138      * Store the specified bean under the specified key, in the specified
139      * scope, replacing any previous value for that key.  Any previous value
140      * will be returned.
141      *
142      * @param key Key of the bean to be stored (cannot be null)
143      * @param value Value of the bean to be stored
144      * @param scope Identifier of the scope to use for storage
145      */
146     public Object put(String key, Object value, int scope);
147 
148 
149     /**
150      * Remove any existing value for the specified key, in any scope.
151      * Scopes will be searched in ascending order of their identifiers,
152      * starting with LOCAL_SCOPE.  Any previous value for this key will
153      * be returned.
154      *
155      * @param key Key of the bean to be removed
156      */
157     public Object remove(String key);
158 
159 
160     /**
161      * Remove any existing value for the specified key, from the specified
162      * scope.  Any previous value for this key will be returned.
163      *
164      * @param key Key of the bean to be removed
165      * @param scope Scope the bean to be removed from
166      */
167     public Object remove(String key, int scope);
168 
169 
170 
171     // --------------------------------------------- Scope Registration Methods
172 
173 
174     // These methods provide capabilities to register and retrieve
175     // Scope implementations.  Workflow engine implementations will
176     // register desired scopes when they create Context instances.
177 
178 
179     /**
180      * <p>Register a Scope implementation under the specified identifier.
181      * It is not legal to replace the LOCAL_SCOPE implementation that is
182      * provided by the Context implementation.</p>
183      *
184      * <p>In addition to registering the new Scope such that it can be
185      * accessed dirctly via calls like <code>Context.get(String,int)</code>,
186      * the Scope <code>impl</code> object will also be added to the LOCAL
187      * Scope under the same name.  This makes possible a single unified
188      * namespace of all accessible objects that can be navigated by
189      * expression languages.</p>
190      *
191      * @param scope Scope identifier to register under
192      * @param name Scope name to register under
193      * @param impl Scope implementation to be registered (or null to
194      *  remove a previous registration)
195      * @exception IllegalArgumentException if you attempt to register
196      *  or deregister the local scope
197      */
198     public void addScope(int scope, String name, Scope impl);
199 
200 
201     /**
202      * Return the Scope implementation registered for the specified
203      * identifier, if any; otherwise, return <code>null</code>.
204      *
205      * @param scope Scope identifier to select
206      */
207     public Scope getScope(int scope);
208 
209 
210     /**
211      * Return the Scope implementation registered for the specified
212      * name, if any; otherwise, return <code>null</code>.
213      *
214      * @param name Scope name to select
215      */
216     public Scope getScope(String name);
217 
218 
219     /**
220      * Return the Scope identifier registered for the specified
221      * name, if any; otherwise, return <code>null</code>.
222      *
223      * @param name Scope name to select
224      */
225     public int getScopeId(String name);
226 
227 
228     // ----------------------------------------------- Evaluation Stack Methods
229 
230 
231     /**
232      * Clear the evaluation stack.
233      */
234     public void clear();
235 
236 
237     /**
238      * Is the evaluation stack currently empty?
239      */
240     public boolean isEmpty();
241 
242 
243     /**
244      * Return the top item from the evaluation stack without removing it.
245      *
246      * @exception EmptyStackException if the stack is empty
247      */
248     public Object peek() throws EmptyStackException;
249 
250 
251     /**
252      * Pop and return the top item from the evaluation stack.
253      *
254      * @exception EmptyStackException if the stack is empty
255      */
256     public Object pop() throws EmptyStackException;
257 
258 
259     /**
260      * Push a new item onto the top of the evaluation stack.
261      *
262      * @param item New item to be pushed
263      */
264     public void push(Object item);
265 
266 
267     // ----------------------------------------------- BlockState Stack Methods
268 
269 
270     /**
271      * Clear the BlockState stack.
272      */
273     public void clearBlockState();
274 
275 
276     /**
277      * Is the BlockState stack currently empty?
278      */
279     public boolean isEmptyBlockState();
280 
281 
282     /**
283      * Return the top item from the BlockState stack without removing it.
284      *
285      * @exception EmptyStackException if the stack is empty
286      */
287     public BlockState peekBlockState() throws EmptyStackException;
288 
289 
290     /**
291      * Pop and return the top item from the BlockState stack.
292      *
293      * @exception EmptyStackException if the stack is empty
294      */
295     public BlockState popBlockState() throws EmptyStackException;
296 
297 
298     /**
299      * Push a new item onto the top of the BlockState stack.
300      *
301      * @param item New item to be pushed
302      */
303     public void pushBlockState(BlockState item);
304 
305 
306     // ---------------------------------------------- Dynamic Execution Methods
307 
308 
309     // These methods are used to request the dynamic execution of the
310     // Steps related to a particular Activity.
311 
312 
313     /**
314      * <p>Save the execution state (i.e. the currently assigned next step)
315      * of the Activity we are currently executing, and begin executing the
316      * specified Activity.  When that Activity exits (either normally
317      * or by throwing an exception), the previous Activity will be resumed
318      * where it left off.
319      *
320      * @param activity The Activity to be called
321      */
322     public void call(Activity activity);
323 
324 
325     /**
326      * <p>Execute the <code>Step</code> currently identified as the next
327      * step, and continue execution until there is no next step, or until
328      * the <code>suspend</code> property has been set to true.  Upon
329      * completion of an activity, any execution state that was saved to due
330      * to utilizing the <code>call()</code> method will be restored, and
331      * the saved Activity execution shall be resumed.
332      *
333      * @exception StepException if an exception is thrown by the
334      *  <code>execute()</code> method of a Step we have executed
335      * @exception IllegalStateException if there is no defined next step
336      *  (either because there is no Activity, or because we have already
337      *  completed all the steps of this activity)
338      */
339     public void execute() throws StepException;
340 
341 
342     /**
343      * <p>Return the <code>Activity</code> we will be executing when the
344      * <code>execute()</code> method is called, if any.</p>
345      */
346     public Activity getActivity();
347 
348 
349     /**
350      * Return the JXPathContext object that represents a unified namespace
351      * covering all of our registered <code>Scopes</code>.
352      */
353     public JXPathContext getJXPathContext();
354 
355 
356     /**
357      * <p>Return the <code>Step</code> that will be executed the next time
358      * that <code>execute()</code> is called, if any.</p>
359      */
360     public Step getNextStep();
361 
362 
363     /**
364      * <p>Return the suspend flag.</p>
365      */
366     public boolean getSuspend();
367 
368 
369     /**
370      * <p>Set the <code>Step</code> that will be executed the next time
371      * that <code>execute()</code> is called.  This is called by a
372      * <code>Step</code> that wants to perform branching based on some
373      * calculated results.</p>
374      *
375      * @param nextStep The next Step to be executed
376      *
377      * @exception IllegalArgumentException if the specified Step is not
378      *  part of the current Activity
379      */
380     public void setNextStep(Step nextStep);
381 
382 
383     /**
384      * <p>Set the <code>Activity</code> to be executed, and make the first
385      * defined <code>Step</code> within this <code>Activity</code> the next
386      * action to be performed by <code>execute()</code>.</p>
387      *
388      * <p>If <code>null</code> is passed, any currently associated Activity
389      * will be released, and the evaluation stack and nested call state
390      * stack will be cleared.</p>
391      *
392      * <p><strong>WARNING</strong> - This will have to become more sophisticated
393      * in order to support calling nested Activities.</p>
394      *
395      * @param activity The new Activity to be executed, or <code>null</code>
396      *  to release resources
397      */
398     public void setActivity(Activity activity);
399 
400 
401     /**
402      * <p>Set the suspend flag.  This is called by a <code>Step</code> that
403      * wants to signal the <code>Context</code> to return control to the
404      * caller of the <code>execute()</code> method before executing the
405      * next <code>Step</code> in the current activity.</p>
406      *
407      * @param suspend The new suspend flag
408      */
409     public void setSuspend(boolean suspend);
410 
411 
412     // ------------------------------------------------- Event Listener Methods
413 
414 
415     /**
416      * Add a listener that is notified each time beans are added,
417      * replaced, or removed in this context.
418      *
419      * @param listener The ContextListener to be added
420      */
421     public void addContextListener(ContextListener listener);
422 
423 
424     /**
425      * Remove a listener that is notified each time beans are added,
426      * replaced, or removed in this context.
427      *
428      * @param listener The ContextListener to be removed
429      */
430     public void removeContextListener(ContextListener listener);
431 
432 
433 }