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 }