KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > workflow > AbstractWorkflow


1 /*
2  * Copyright (c) 2002-2003 by OpenSymphony
3  * All rights reserved.
4  */

5 package com.opensymphony.workflow;
6
7 import com.opensymphony.module.propertyset.PropertySet;
8 import com.opensymphony.module.propertyset.PropertySetManager;
9
10 import com.opensymphony.util.ClassLoaderUtil;
11 import com.opensymphony.util.TextUtils;
12
13 import com.opensymphony.workflow.config.Configuration;
14 import com.opensymphony.workflow.config.DefaultConfiguration;
15 import com.opensymphony.workflow.loader.*;
16 import com.opensymphony.workflow.query.WorkflowExpressionQuery;
17 import com.opensymphony.workflow.query.WorkflowQuery;
18 import com.opensymphony.workflow.spi.*;
19 import com.opensymphony.workflow.util.ScriptVariableParser;
20 import com.opensymphony.workflow.util.beanshell.BeanShellCondition;
21 import com.opensymphony.workflow.util.beanshell.BeanShellFunctionProvider;
22 import com.opensymphony.workflow.util.beanshell.BeanShellRegister;
23 import com.opensymphony.workflow.util.beanshell.BeanShellValidator;
24 import com.opensymphony.workflow.util.bsf.BSFCondition;
25 import com.opensymphony.workflow.util.bsf.BSFFunctionProvider;
26 import com.opensymphony.workflow.util.bsf.BSFRegister;
27 import com.opensymphony.workflow.util.bsf.BSFValidator;
28 import com.opensymphony.workflow.util.ejb.local.LocalEJBCondition;
29 import com.opensymphony.workflow.util.ejb.local.LocalEJBFunctionProvider;
30 import com.opensymphony.workflow.util.ejb.local.LocalEJBRegister;
31 import com.opensymphony.workflow.util.ejb.local.LocalEJBValidator;
32 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBCondition;
33 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBFunctionProvider;
34 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBRegister;
35 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBValidator;
36 import com.opensymphony.workflow.util.jndi.JNDICondition;
37 import com.opensymphony.workflow.util.jndi.JNDIFunctionProvider;
38 import com.opensymphony.workflow.util.jndi.JNDIRegister;
39 import com.opensymphony.workflow.util.jndi.JNDIValidator;
40
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43
44 import java.util.*;
45
46
47 /**
48  * Abstract workflow instance that serves as the base for specific implementations, such as EJB or SOAP.
49  *
50  * @author <a HREF="mailto:plightbo@hotmail.com">Pat Lightbody</a>
51  * @author Hani Suleiman
52  */

53 public class AbstractWorkflow implements Workflow {
54     //~ Static fields/initializers /////////////////////////////////////////////
55

56     private static final Log log = LogFactory.getLog(AbstractWorkflow.class);
57
58     //~ Instance fields ////////////////////////////////////////////////////////
59

60     protected WorkflowContext context;
61     private Configuration configuration;
62
63     //~ Methods ////////////////////////////////////////////////////////////////
64

65     /**
66      * @ejb.interface-method
67      * @deprecated use {@link #getAvailableActions(long, Map)} with an empty Map instead.
68      */

69     public int[] getAvailableActions(long id) {
70         return getAvailableActions(id, new HashMap());
71     }
72
73     /**
74      * Get the available actions for the specified workflow instance.
75      * @ejb.interface-method
76      * @param id The workflow instance id.
77      * @param inputs The inputs map to pass on to conditions
78      * @return An array of action id's that can be performed on the specified entry.
79      * @throws IllegalArgumentException if the specified id does not exist, or if its workflow
80      * descriptor is no longer available or has become invalid.
81      */

82     public int[] getAvailableActions(long id, Map inputs) {
83         try {
84             WorkflowStore store = getPersistence();
85             WorkflowEntry entry = store.findEntry(id);
86
87             if (entry == null) {
88                 throw new IllegalArgumentException JavaDoc("No such workflow id " + id);
89             }
90
91             if (entry.getState() != WorkflowEntry.ACTIVATED) {
92                 return new int[0];
93             }
94
95             WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
96
97             if (wf == null) {
98                 throw new IllegalArgumentException JavaDoc("No such workflow " + entry.getWorkflowName());
99             }
100
101             List l = new ArrayList();
102             PropertySet ps = store.getPropertySet(id);
103             Map transientVars = (inputs == null) ? new HashMap() : new HashMap(inputs);
104             Collection currentSteps = store.findCurrentSteps(id);
105
106             populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer JavaDoc(0), currentSteps);
107
108             // get global actions
109
List globalActions = wf.getGlobalActions();
110
111             for (Iterator iterator = globalActions.iterator();
112                     iterator.hasNext();) {
113                 ActionDescriptor action = (ActionDescriptor) iterator.next();
114                 RestrictionDescriptor restriction = action.getRestriction();
115                 List conditions = null;
116
117                 if (restriction != null) {
118                     conditions = restriction.getConditions();
119                 }
120
121                 //todo verify that 0 is the right currentStepId
122
if (passesConditions(null, conditions, transientVars, ps, 0)) {
123                     l.add(new Integer JavaDoc(action.getId()));
124                 }
125             }
126
127             // get normal actions
128
for (Iterator iterator = currentSteps.iterator();
129                     iterator.hasNext();) {
130                 Step step = (Step) iterator.next();
131                 l.addAll(getAvailableActionsForStep(wf, step, transientVars, ps));
132             }
133
134             int[] actions = new int[l.size()];
135
136             for (int i = 0; i < actions.length; i++) {
137                 actions[i] = ((Integer JavaDoc) l.get(i)).intValue();
138             }
139
140             return actions;
141         } catch (Exception JavaDoc e) {
142             log.error("Error checking available actions", e);
143
144             return new int[0];
145         }
146     }
147
148     /**
149      * @ejb.interface-method
150      */

151     public void setConfiguration(Configuration configuration) {
152         this.configuration = configuration;
153     }
154
155     /**
156      * Get the configuration for this workflow.
157      * This method also checks if the configuration has been initialized, and if not, initializes it.
158      * @return The configuration that was set.
159      * If no configuration was set, then the default (static) configuration is returned.
160      *
161      */

162     public Configuration getConfiguration() {
163         Configuration config = (configuration != null) ? configuration : DefaultConfiguration.INSTANCE;
164
165         if (!config.isInitialized()) {
166             try {
167                 config.load(null);
168             } catch (FactoryException e) {
169                 log.fatal("Error initialising configuration", e);
170
171                 //fail fast, better to blow up with an NPE that hide the error
172
return null;
173             }
174         }
175
176         return config;
177     }
178
179     /**
180      * @ejb.interface-method
181      */

182     public List getCurrentSteps(long id) {
183         try {
184             WorkflowStore store = getPersistence();
185
186             return store.findCurrentSteps(id);
187         } catch (StoreException e) {
188             log.error("Error checking current steps for instance #" + id, e);
189
190             return Collections.EMPTY_LIST;
191         }
192     }
193
194     /**
195      * @ejb.interface-method
196      */

197     public int getEntryState(long id) {
198         try {
199             WorkflowStore store = getPersistence();
200
201             return store.findEntry(id).getState();
202         } catch (StoreException e) {
203             log.error("Error checking instance state for instance #" + id, e);
204         }
205
206         return WorkflowEntry.UNKNOWN;
207     }
208
209     /**
210      * @ejb.interface-method
211      */

212     public List getHistorySteps(long id) {
213         try {
214             WorkflowStore store = getPersistence();
215
216             return store.findHistorySteps(id);
217         } catch (StoreException e) {
218             log.error("Error getting history steps for instance #" + id, e);
219         }
220
221         return Collections.EMPTY_LIST;
222     }
223
224     /**
225      * @ejb.interface-method
226      */

227     public Properties getPersistenceProperties() {
228         Properties p = new Properties();
229         Iterator iter = getConfiguration().getPersistenceArgs().entrySet().iterator();
230
231         while (iter.hasNext()) {
232             Map.Entry entry = (Map.Entry) iter.next();
233             p.setProperty((String JavaDoc) entry.getKey(), (String JavaDoc) entry.getValue());
234         }
235
236         return p;
237     }
238
239     /**
240      * Get the PropertySet for the specified workflow ID
241      * @ejb.interface-method
242      * @param id The workflow ID
243      */

244     public PropertySet getPropertySet(long id) {
245         PropertySet ps = null;
246
247         try {
248             ps = getPersistence().getPropertySet(id);
249         } catch (StoreException e) {
250             log.error("Error getting propertyset for instance #" + id, e);
251         }
252
253         return ps;
254     }
255
256     /**
257      * @ejb.interface-method
258      */

259     public List getSecurityPermissions(long id) {
260         try {
261             WorkflowStore store = getPersistence();
262             WorkflowEntry entry = store.findEntry(id);
263             WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
264
265             PropertySet ps = store.getPropertySet(id);
266             Map transientVars = new HashMap();
267             Collection currentSteps = store.findCurrentSteps(id);
268             populateTransientMap(entry, transientVars, wf.getRegisters(), null, currentSteps);
269
270             List s = new ArrayList();
271
272             for (Iterator interator = currentSteps.iterator();
273                     interator.hasNext();) {
274                 Step step = (Step) interator.next();
275
276                 int stepId = step.getStepId();
277
278                 StepDescriptor xmlStep = wf.getStep(stepId);
279
280                 List securities = xmlStep.getPermissions();
281
282                 for (Iterator iterator2 = securities.iterator();
283                         iterator2.hasNext();) {
284                     PermissionDescriptor security = (PermissionDescriptor) iterator2.next();
285
286                     // to have the permission, the condition must be met or not specified
287
// securities can't have restrictions based on inputs, so it's null
288
if (passesConditions(null, security.getRestriction().getConditions(), transientVars, ps, xmlStep.getId())) {
289                         s.add(security.getName());
290                     }
291                 }
292             }
293
294             return s;
295         } catch (Exception JavaDoc e) {
296             log.error("Error getting security permissions for instance #" + id, e);
297         }
298
299         return Collections.EMPTY_LIST;
300     }
301
302     /**
303      * Returns a workflow definition object associated with the given name.
304      *
305      * @param workflowName the name of the workflow
306      * @return the object graph that represents a workflow definition
307      * @ejb.interface-method
308      */

309     public WorkflowDescriptor getWorkflowDescriptor(String JavaDoc workflowName) {
310         try {
311             return getConfiguration().getWorkflow(workflowName);
312         } catch (FactoryException e) {
313             log.error("Error loading workflow " + workflowName, e);
314         }
315
316         return null;
317     }
318
319     /**
320      * @ejb.interface-method
321      */

322     public String JavaDoc getWorkflowName(long id) {
323         try {
324             WorkflowStore store = getPersistence();
325             WorkflowEntry entry = store.findEntry(id);
326
327             if (entry != null) {
328                 return entry.getWorkflowName();
329             }
330         } catch (StoreException e) {
331             log.error("Error getting instance name for instance #" + id, e);
332         }
333
334         return null;
335     }
336
337     /**
338      * Get a list of workflow names available
339      * @return String[] an array of workflow names.
340      * @ejb.interface-method
341      */

342     public String JavaDoc[] getWorkflowNames() {
343         try {
344             return getConfiguration().getWorkflowNames();
345         } catch (FactoryException e) {
346             log.error("Error getting workflow names", e);
347         }
348
349         return new String JavaDoc[0];
350     }
351
352     /**
353      * @ejb.interface-method
354      */

355     public boolean canInitialize(String JavaDoc workflowName, int initialAction) {
356         return canInitialize(workflowName, initialAction, null);
357     }
358
359     /**
360      * @ejb.interface-method
361      * @param workflowName the name of the workflow to check
362      * @param initialAction The initial action to check
363      * @param inputs the inputs map
364      * @return true if the workflow can be initialized
365      */

366     public boolean canInitialize(String JavaDoc workflowName, int initialAction, Map inputs) {
367         final String JavaDoc mockWorkflowName = workflowName;
368         WorkflowEntry mockEntry = new WorkflowEntry() {
369             public long getId() {
370                 return 0;
371             }
372
373             public String JavaDoc getWorkflowName() {
374                 return mockWorkflowName;
375             }
376
377             public boolean isInitialized() {
378                 return false;
379             }
380
381             public int getState() {
382                 return WorkflowEntry.CREATED;
383             }
384         };
385
386         // since no state change happens here, a memory instance is just fine
387
PropertySet ps = PropertySetManager.getInstance("memory", null);
388         Map transientVars = new HashMap();
389
390         if (inputs != null) {
391             transientVars.putAll(inputs);
392         }
393
394         try {
395             populateTransientMap(mockEntry, transientVars, Collections.EMPTY_LIST, new Integer JavaDoc(initialAction), Collections.EMPTY_LIST);
396
397             return canInitialize(workflowName, initialAction, transientVars, ps);
398         } catch (InvalidActionException e) {
399             log.error(e.getMessage());
400
401             return false;
402         } catch (WorkflowException e) {
403             log.error("Error checking canInitialize", e);
404
405             return false;
406         }
407     }
408
409     /**
410      * @ejb.interface-method
411      */

412     public boolean canModifyEntryState(long id, int newState) {
413         try {
414             WorkflowStore store = getPersistence();
415             WorkflowEntry entry = store.findEntry(id);
416             int currentState = entry.getState();
417             boolean result = false;
418
419             switch (newState) {
420             case WorkflowEntry.CREATED:
421                 result = false;
422
423             case WorkflowEntry.ACTIVATED:
424
425                 if ((currentState == WorkflowEntry.CREATED) || (currentState == WorkflowEntry.SUSPENDED)) {
426                     result = true;
427                 }
428
429                 break;
430
431             case WorkflowEntry.SUSPENDED:
432
433                 if (currentState == WorkflowEntry.ACTIVATED) {
434                     result = true;
435                 }
436
437                 break;
438
439             case WorkflowEntry.KILLED:
440
441                 if ((currentState == WorkflowEntry.CREATED) || (currentState == WorkflowEntry.ACTIVATED) || (currentState == WorkflowEntry.SUSPENDED)) {
442                     result = true;
443                 }
444
445                 break;
446
447             default:
448                 result = false;
449
450                 break;
451             }
452
453             return result;
454         } catch (StoreException e) {
455             log.error("Error checking state modifiable for instance #" + id, e);
456         }
457
458         return false;
459     }
460
461     public void changeEntryState(long id, int newState) throws WorkflowException {
462         WorkflowStore store = getPersistence();
463         WorkflowEntry entry = store.findEntry(id);
464
465         if (entry.getState() == newState) {
466             return;
467         }
468
469         if (canModifyEntryState(id, newState)) {
470             if ((newState == WorkflowEntry.KILLED) || (newState == WorkflowEntry.COMPLETED)) {
471                 Collection currentSteps = getCurrentSteps(id);
472
473                 if (currentSteps.size() > 0) {
474                     completeEntry(id, currentSteps);
475                 }
476             }
477
478             store.setEntryState(id, newState);
479         } else {
480             throw new InvalidEntryStateException("Can't transition workflow instance #" + id + ". Current state is " + entry.getState() + ", requested state is " + newState);
481         }
482
483         if (log.isDebugEnabled()) {
484             log.debug(entry.getId() + " : State is now : " + entry.getState());
485         }
486     }
487
488     public void doAction(long id, int actionId, Map inputs) throws WorkflowException {
489         WorkflowStore store = getPersistence();
490         WorkflowEntry entry = store.findEntry(id);
491
492         if (entry.getState() != WorkflowEntry.ACTIVATED) {
493             return;
494         }
495
496         WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
497
498         List currentSteps = store.findCurrentSteps(id);
499         ActionDescriptor action = null;
500
501         PropertySet ps = store.getPropertySet(id);
502         Map transientVars = new HashMap();
503
504         if (inputs != null) {
505             transientVars.putAll(inputs);
506         }
507
508         populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer JavaDoc(actionId), currentSteps);
509
510         boolean validAction = false;
511
512         //check global actions
513
for (Iterator gIter = wf.getGlobalActions().iterator();
514                 !validAction && gIter.hasNext();) {
515             ActionDescriptor actionDesc = (ActionDescriptor) gIter.next();
516
517             if (actionDesc.getId() == actionId) {
518                 action = actionDesc;
519
520                 if (isActionAvailable(action, transientVars, ps, 0)) {
521                     validAction = true;
522                 }
523             }
524         }
525
526         for (Iterator iter = currentSteps.iterator();
527                 !validAction && iter.hasNext();) {
528             Step step = (Step) iter.next();
529             StepDescriptor s = wf.getStep(step.getStepId());
530
531             for (Iterator iterator = s.getActions().iterator();
532                     !validAction && iterator.hasNext();) {
533                 ActionDescriptor actionDesc = (ActionDescriptor) iterator.next();
534
535                 if (actionDesc.getId() == actionId) {
536                     action = actionDesc;
537
538                     if (isActionAvailable(action, transientVars, ps, s.getId())) {
539                         validAction = true;
540                     }
541                 }
542             }
543         }
544
545         if (!validAction) {
546             throw new InvalidActionException("Action " + actionId + " is invalid");
547         }
548
549         try {
550             //transition the workflow, if it wasn't explicitly finished, check for an implicit finish
551
if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps)) {
552                 checkImplicitFinish(id);
553             }
554         } catch (WorkflowException e) {
555             context.setRollbackOnly();
556             throw e;
557         }
558     }
559
560     public void executeTriggerFunction(long id, int triggerId) throws WorkflowException {
561         WorkflowStore store = getPersistence();
562         WorkflowEntry entry = store.findEntry(id);
563
564         if (entry == null) {
565             log.warn("Cannot execute trigger #" + triggerId + " on non-existent workflow id#" + id);
566
567             return;
568         }
569
570         WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
571
572         PropertySet ps = store.getPropertySet(id);
573         Map transientVars = new HashMap();
574         populateTransientMap(entry, transientVars, wf.getRegisters(), null, store.findCurrentSteps(id));
575         executeFunction(wf.getTriggerFunction(triggerId), transientVars, ps);
576     }
577
578     public long initialize(String JavaDoc workflowName, int initialAction, Map inputs) throws InvalidRoleException, InvalidInputException, WorkflowException {
579         WorkflowDescriptor wf = getConfiguration().getWorkflow(workflowName);
580
581         WorkflowStore store = getPersistence();
582         WorkflowEntry entry = store.createEntry(workflowName);
583
584         // start with a memory property set, but clone it after we have an ID
585
PropertySet ps = store.getPropertySet(entry.getId());
586         Map transientVars = new HashMap();
587
588         if (inputs != null) {
589             transientVars.putAll(inputs);
590         }
591
592         populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer JavaDoc(initialAction), Collections.EMPTY_LIST);
593
594         if (!canInitialize(workflowName, initialAction, transientVars, ps)) {
595             context.setRollbackOnly();
596             throw new InvalidRoleException("You are restricted from initializing this workflow");
597         }
598
599         ActionDescriptor action = wf.getInitialAction(initialAction);
600
601         try {
602             transitionWorkflow(entry, Collections.EMPTY_LIST, store, wf, action, transientVars, inputs, ps);
603         } catch (WorkflowException e) {
604             context.setRollbackOnly();
605             throw e;
606         }
607
608         long entryId = entry.getId();
609
610         // now clone the memory PS to the real PS
611
//PropertySetManager.clone(ps, store.getPropertySet(entryId));
612
return entryId;
613     }
614
615     /**
616      * @ejb.interface-method
617      */

618     public List query(WorkflowQuery query) throws StoreException {
619         return getPersistence().query(query);
620     }
621
622     /**
623      * @ejb.interface-method
624      */

625     public List query(WorkflowExpressionQuery query) throws WorkflowException {
626         return getPersistence().query(query);
627     }
628
629     /**
630      * @ejb.interface-method
631      */

632     public boolean removeWorkflowDescriptor(String JavaDoc workflowName) throws FactoryException {
633         return getConfiguration().removeWorkflow(workflowName);
634     }
635
636     /**
637      * @ejb.interface-method
638      */

639     public boolean saveWorkflowDescriptor(String JavaDoc workflowName, WorkflowDescriptor descriptor, boolean replace) throws FactoryException {
640         boolean success = getConfiguration().saveWorkflow(workflowName, descriptor, replace);
641
642         return success;
643     }
644
645     protected List getAvailableActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException {
646         List l = new ArrayList();
647         StepDescriptor s = wf.getStep(step.getStepId());
648
649         if (s == null) {
650             log.warn("getAvailableActionsForStep called for non-existent step Id #" + step.getStepId());
651
652             return l;
653         }
654
655         List actions = s.getActions();
656
657         if ((actions == null) || (actions.size() == 0)) {
658             return l;
659         }
660
661         for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) {
662             ActionDescriptor action = (ActionDescriptor) iterator2.next();
663             RestrictionDescriptor restriction = action.getRestriction();
664             List conditions = null;
665
666             if (restriction != null) {
667                 conditions = restriction.getConditions();
668             }
669
670             if (passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, s.getId())) {
671                 l.add(new Integer JavaDoc(action.getId()));
672             }
673         }
674
675         return l;
676     }
677
678     protected int[] getAvailableAutoActions(long id, Map inputs) {
679         try {
680             WorkflowStore store = getPersistence();
681             WorkflowEntry entry = store.findEntry(id);
682
683             if (entry == null) {
684                 throw new IllegalArgumentException JavaDoc("No such workflow id " + id);
685             }
686
687             if (entry.getState() != WorkflowEntry.ACTIVATED) {
688                 log.debug("--> state is " + entry.getState());
689
690                 return new int[0];
691             }
692
693             WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
694
695             if (wf == null) {
696                 throw new IllegalArgumentException JavaDoc("No such workflow " + entry.getWorkflowName());
697             }
698
699             List l = new ArrayList();
700             PropertySet ps = store.getPropertySet(id);
701             Map transientVars = (inputs == null) ? new HashMap() : new HashMap(inputs);
702             Collection currentSteps = store.findCurrentSteps(id);
703
704             populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer JavaDoc(0), currentSteps);
705
706             // get global actions
707
List globalActions = wf.getGlobalActions();
708
709             for (Iterator iterator = globalActions.iterator();
710                     iterator.hasNext();) {
711                 ActionDescriptor action = (ActionDescriptor) iterator.next();
712
713                 if (action.getAutoExecute()) {
714                     if (isActionAvailable(action, transientVars, ps, 0)) {
715                         l.add(new Integer JavaDoc(action.getId()));
716                     }
717                 }
718             }
719
720             // get normal actions
721
for (Iterator iterator = currentSteps.iterator();
722                     iterator.hasNext();) {
723                 Step step = (Step) iterator.next();
724                 l.addAll(getAvailableAutoActionsForStep(wf, step, transientVars, ps));
725             }
726
727             int[] actions = new int[l.size()];
728
729             for (int i = 0; i < actions.length; i++) {
730                 actions[i] = ((Integer JavaDoc) l.get(i)).intValue();
731             }
732
733             return actions;
734         } catch (Exception JavaDoc e) {
735             log.error("Error checking available actions", e);
736
737             return new int[0];
738         }
739     }
740
741     /**
742      * Get just auto action availables for a step
743      */

744     protected List getAvailableAutoActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException {
745         List l = new ArrayList();
746         StepDescriptor s = wf.getStep(step.getStepId());
747
748         if (s == null) {
749             log.warn("getAvailableAutoActionsForStep called for non-existent step Id #" + step.getStepId());
750
751             return l;
752         }
753
754         List actions = s.getActions();
755
756         if ((actions == null) || (actions.size() == 0)) {
757             return l;
758         }
759
760         for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) {
761             ActionDescriptor action = (ActionDescriptor) iterator2.next();
762
763             //check auto
764
if (action.getAutoExecute()) {
765                 if (isActionAvailable(action, transientVars, ps, s.getId())) {
766                     l.add(new Integer JavaDoc(action.getId()));
767                 }
768             }
769         }
770
771         return l;
772     }
773
774     protected WorkflowStore getPersistence() throws StoreException {
775         return getConfiguration().getWorkflowStore();
776     }
777
778     protected void checkImplicitFinish(long id) throws WorkflowException {
779         WorkflowStore store = getPersistence();
780         WorkflowEntry entry = store.findEntry(id);
781
782         WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName());
783
784         Collection currentSteps = store.findCurrentSteps(id);
785
786         boolean isCompleted = true;
787
788         for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) {
789             Step step = (Step) iterator.next();
790             StepDescriptor stepDes = wf.getStep(step.getStepId());
791
792             // if at least on current step have an available action
793
if (stepDes.getActions().size() > 0) {
794                 isCompleted = false;
795             }
796         }
797
798         if (isCompleted == true) {
799             completeEntry(id, currentSteps);
800         }
801     }
802
803     /**
804      * Mark the specified entry as completed, and move all current steps to history.
805      */

806     protected void completeEntry(long id, Collection currentSteps) throws StoreException {
807         getPersistence().setEntryState(id, WorkflowEntry.COMPLETED);
808
809         Iterator i = new ArrayList(currentSteps).iterator();
810
811         while (i.hasNext()) {
812             Step step = (Step) i.next();
813             getPersistence().moveToHistory(step);
814         }
815     }
816
817     protected Object JavaDoc loadObject(String JavaDoc clazz) {
818         try {
819             return ClassLoaderUtil.loadClass(clazz.trim(), getClass()).newInstance();
820         } catch (Exception JavaDoc e) {
821             log.error("Could not load object '" + clazz + "'", e);
822
823             return null;
824         }
825     }
826
827     protected boolean passesCondition(ConditionDescriptor conditionDesc, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException {
828         String JavaDoc type = conditionDesc.getType();
829
830         Map args = new HashMap(conditionDesc.getArgs());
831
832         for (Iterator iterator = args.entrySet().iterator();
833                 iterator.hasNext();) {
834             Map.Entry mapEntry = (Map.Entry) iterator.next();
835             mapEntry.setValue(ScriptVariableParser.translateVariables((String JavaDoc) mapEntry.getValue(), transientVars, ps));
836         }
837
838         if (currentStepId != -1) {
839             Object JavaDoc stepId = args.get("stepId");
840
841             if ((stepId != null) && stepId.equals("-1")) {
842                 args.put("stepId", String.valueOf(currentStepId));
843             }
844         }
845
846         String JavaDoc clazz;
847
848         if ("remote-ejb".equals(type)) {
849             clazz = RemoteEJBCondition.class.getName();
850         } else if ("local-ejb".equals(type)) {
851             clazz = LocalEJBCondition.class.getName();
852         } else if ("jndi".equals(type)) {
853             clazz = JNDICondition.class.getName();
854         } else if ("bsf".equals(type)) {
855             clazz = BSFCondition.class.getName();
856         } else if ("beanshell".equals(type)) {
857             clazz = BeanShellCondition.class.getName();
858         } else {
859             clazz = (String JavaDoc) args.get(CLASS_NAME);
860         }
861
862         Condition condition = (Condition) loadObject(clazz);
863
864         if (condition == null) {
865             String JavaDoc message = "Could not load Condition: " + clazz;
866             throw new WorkflowException(message);
867         }
868
869         try {
870             boolean passed = condition.passesCondition(transientVars, args, ps);
871
872             if (conditionDesc.isNegate()) {
873                 passed = !passed;
874             }
875
876             return passed;
877         } catch (Exception JavaDoc e) {
878             context.setRollbackOnly();
879
880             if (e instanceof WorkflowException) {
881