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 }