001    /*
002     * Copyright 1999-2001,2004 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */ 
016    
017    package org.apache.commons.workflow;
018    
019    
020    import java.util.EmptyStackException;
021    import org.apache.commons.jxpath.JXPathContext;
022    
023    
024    /**
025     * <p>A <strong>Context</strong> represents the dynamic computational state of
026     * a workflow process that is currently being executed.  If multiple users
027     * are executing the same workflow process at the same time, they must have
028     * their own instance of Context.</p>
029     *
030     * <p>Workflow engine implementations can register zero or more Scope
031     * instances, to provide the Steps that are being executed with access to
032     * arbitrary collections of JavaBeans.  A Context will always have at least
033     * one Scope, called the LOCAL scope, which is the default source or
034     * destination for bean references.  Scope instances can be identified
035     * by an integer subscript (which must be in the range 0 .. MAX_SCOPES-1),
036     * or a registered name.  The registered name of the LOCAL scope is
037     * "local".</p>
038     *
039     * <p>In addition to Scopes, which can be used for storing beans under
040     * specific names, an evaluation stack is provided for the convenience of
041     * Step implementations that want to pass temporary results back and forth.
042     * As with all Stack-based implementations, it is the responsibility of
043     * the Step implementations that are executed to maintain the stack's
044     * integrity.</p>
045     *
046     * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
047     * @author Craig R. McClanahan
048     */
049    
050    public interface Context {
051    
052    
053        // ----------------------------------------------------- Manifest Constants
054    
055    
056        /**
057         * The public identifier of the LOCAL scope, which is always defined by a
058         * Context implementation.
059         */
060        public static final int LOCAL_SCOPE = 0;
061    
062    
063        /**
064         * The maximum number of Scopes (including LOCAL_SCOPE) that can be
065         * registered.
066         */
067        public static final int MAX_SCOPES = 8;
068    
069    
070    
071        // --------------------------------------------------- Scope Access Methods
072    
073    
074        // These methods provide Steps with the ability to get and set arbitrary
075        // objects in arbitrary scopes.  When a scope is not mentioned explicitly,
076        // either LOCAL_SCOPE will be used, or scopes will be searched in
077        // increasing order of their identifiers, as specified in the various
078        // method descriptions.
079    
080    
081        /**
082         * Does a bean with the specified key exist in any specified scope?
083         * Scopes will be searched in ascending order of their identifiers,
084         * starting with LOCAL_SCOPE.
085         *
086         * @param key Key of the bean to be searched for (cannot be null)
087         */
088        public boolean contains(String key);
089    
090    
091        /**
092         * Does a bean with the specified key exist in the specified scope?
093         *
094         * @param key Key of the bean to be searched for (cannot be null)
095         * @param scope Identifier of the scope to be returned.
096         */
097        public boolean contains(String key, int scope);
098    
099    
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    }