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                 throw (WorkflowException) e;
882             }
883
884             throw new WorkflowException("Unknown exception encountered when trying condition: " + clazz, e);
885         }
886     }
887
888     protected boolean passesConditions(String JavaDoc conditionType, List conditions, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException {
889         if ((conditions == null) || (conditions.size() == 0)) {
890             return true;
891         }
892
893         boolean and = "AND".equals(conditionType);
894         boolean or = !and;
895
896         for (Iterator iterator = conditions.iterator(); iterator.hasNext();) {
897             AbstractDescriptor descriptor = (AbstractDescriptor) iterator.next();
898             boolean result;
899
900             if (descriptor instanceof ConditionsDescriptor) {
901                 ConditionsDescriptor conditionsDescriptor = (ConditionsDescriptor) descriptor;
902                 result = passesConditions(conditionsDescriptor.getType(), conditionsDescriptor.getConditions(), transientVars, ps, currentStepId);
903             } else {
904                 result = passesCondition((ConditionDescriptor) descriptor, transientVars, ps, currentStepId);
905             }
906
907             if (and && !result) {
908                 return false;
909             } else if (or && result) {
910                 return true;
911             }
912         }
913
914         if (and) {
915             return true;
916         } else if (or) {
917             return false;
918         } else {
919             return false;
920         }
921     }
922
923     protected void populateTransientMap(WorkflowEntry entry, Map transientVars, List registers, Integer JavaDoc actionId, Collection currentSteps) throws WorkflowException {
924         transientVars.put("context", context);
925         transientVars.put("entry", entry);
926         transientVars.put("store", getPersistence());
927         transientVars.put("descriptor", getConfiguration().getWorkflow(entry.getWorkflowName()));
928
929         if (actionId != null) {
930             transientVars.put("actionId", actionId);
931         }
932
933         transientVars.put("currentSteps", Collections.unmodifiableCollection(currentSteps));
934
935         // now talk to the registers for any extra objects needed in scope
936
for (Iterator iterator = registers.iterator(); iterator.hasNext();) {
937             RegisterDescriptor register = (RegisterDescriptor) iterator.next();
938             Map args = register.getArgs();
939
940             String JavaDoc type = register.getType();
941             String JavaDoc clazz;
942
943             if ("remote-ejb".equals(type)) {
944                 clazz = RemoteEJBRegister.class.getName();
945             } else if ("local-ejb".equals(type)) {
946                 clazz = LocalEJBRegister.class.getName();
947             } else if ("jndi".equals(type)) {
948                 clazz = JNDIRegister.class.getName();
949             } else if ("bsf".equals(type)) {
950                 clazz = BSFRegister.class.getName();
951             } else if ("beanshell".equals(type)) {
952                 clazz = BeanShellRegister.class.getName();
953             } else {
954                 clazz = (String JavaDoc) args.get(CLASS_NAME);
955             }
956
957             Register r = (Register) loadObject(clazz);
958
959             if (r == null) {
960                 String JavaDoc message = "Could not load register class: " + clazz;
961                 throw new WorkflowException(message);
962             }
963
964             try {
965                 transientVars.put(register.getVariableName(), r.registerVariable(context, entry, args));
966             } catch (Exception JavaDoc e) {
967                 context.setRollbackOnly();
968
969                 if (e instanceof WorkflowException) {
970                     throw (WorkflowException) e;
971                 }
972
973                 throw new WorkflowException("An unknown exception occured while registering variable using class: " + clazz, e);
974             }
975         }
976     }
977
978     /**
979      * Validates input against a list of ValidatorDescriptor objects.
980      *
981      * @param entry the workflow instance
982      * @param validators the list of ValidatorDescriptors
983      * @param transientVars the transientVars
984      * @param ps the persistence variables
985      * @throws InvalidInputException if the input is deemed invalid by any validator
986      */

987     protected void verifyInputs(WorkflowEntry entry, List validators, Map transientVars, PropertySet ps) throws WorkflowException {
988         for (Iterator iterator = validators.iterator(); iterator.hasNext();) {
989             ValidatorDescriptor input = (ValidatorDescriptor) iterator.next();
990
991             if (input != null) {
992                 String JavaDoc type = input.getType();
993                 HashMap args = new HashMap(input.getArgs());
994
995                 for (Iterator iterator2 = args.entrySet().iterator();
996                         iterator2.hasNext();) {
997                     Map.Entry mapEntry = (Map.Entry) iterator2.next();
998                     mapEntry.setValue(ScriptVariableParser.translateVariables((String JavaDoc) mapEntry.getValue(), transientVars, ps));
999                 }
1000
1001                String JavaDoc clazz;
1002
1003                if ("remote-ejb".equals(type)) {
1004                    clazz = RemoteEJBValidator.class.getName();
1005                } else if ("local-ejb".equals(type)) {
1006                    clazz = LocalEJBValidator.class.getName();
1007                } else if ("jndi".equals(type)) {
1008                    clazz = JNDIValidator.class.getName();
1009                } else if ("bsf".equals(type)) {
1010                    clazz = BSFValidator.class.getName();
1011                } else if ("beanshell".equals(type)) {
1012                    clazz = BeanShellValidator.class.getName();
1013                } else {
1014                    clazz = (String JavaDoc) args.get(CLASS_NAME);
1015                }
1016
1017                Validator validator = (Validator) loadObject(clazz);
1018
1019                if (validator == null) {
1020                    String JavaDoc message = "Could not load validator class: " + clazz;
1021                    throw new WorkflowException(message);
1022                }
1023
1024                try {
1025                    validator.validate(transientVars, args, ps);
1026                } catch (InvalidInputException e) {
1027                    throw e;
1028                } catch (Exception JavaDoc e) {
1029                    context.setRollbackOnly();
1030
1031                    if (e instanceof WorkflowException) {
1032                        throw (WorkflowException) e;
1033                    }
1034
1035                    String JavaDoc message = "An unknown exception occured executing Validator: " + clazz;
1036                    throw new WorkflowException(message, e);
1037                }
1038            }
1039        }
1040    }
1041
1042    /**
1043     * check if an action is available or not
1044     * @param action The action descriptor
1045     * @return true if the action is available
1046     */

1047    private boolean isActionAvailable(ActionDescriptor action, Map transientVars, PropertySet ps, int stepId) throws WorkflowException {
1048        if (action == null) {
1049            return false;
1050        }
1051
1052        RestrictionDescriptor restriction = action.getRestriction();
1053        List conditions = null;
1054
1055        if (restriction != null) {
1056            conditions = restriction.getConditions();
1057        }
1058
1059        return passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, stepId);
1060    }
1061
1062    private Step getCurrentStep(WorkflowDescriptor wfDesc, int actionId, List currentSteps, Map transientVars, PropertySet ps) throws WorkflowException {
1063        if (currentSteps.size() == 1) {
1064            return (Step) currentSteps.get(0);
1065        }
1066
1067        for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) {
1068            Step step = (Step) iterator.next();
1069            ActionDescriptor action = wfDesc.getStep(step.getStepId()).getAction(actionId);
1070
1071            //$AR init
1072
if (isActionAvailable(action, transientVars, ps, step.getStepId())) {
1073                return step;
1074            }
1075
1076            //$AR end
1077
}
1078
1079        return null;
1080    }
1081
1082    private boolean canInitialize(String JavaDoc workflowName, int initialAction, Map transientVars, PropertySet ps) throws WorkflowException {
1083        WorkflowDescriptor wf = getConfiguration().getWorkflow(workflowName);
1084
1085        ActionDescriptor actionDescriptor = wf.getInitialAction(initialAction);
1086
1087        if (actionDescriptor == null) {
1088            throw new InvalidActionException("Invalid Initial Action #" + initialAction);
1089        }
1090
1091        RestrictionDescriptor restriction = actionDescriptor.getRestriction();
1092        List conditions = null;
1093
1094        if (restriction != null) {
1095            conditions = restriction.getConditions();
1096        }
1097
1098        return passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, 0);
1099    }
1100
1101    private Step createNewCurrentStep(ResultDescriptor theResult, WorkflowEntry entry, WorkflowStore store, int actionId, Step currentStep, long[] previousIds, Map transientVars, PropertySet ps) throws WorkflowException {
1102        try {
1103            int nextStep = theResult.getStep();
1104
1105            if (nextStep == -1) {
1106                if (currentStep != null) {
1107                    nextStep = currentStep.getStepId();
1108                } else {
1109                    throw new StoreException("Illegal argument: requested new current step same as current step, but current step not specified");
1110                }
1111            }
1112
1113            if (log.isDebugEnabled()) {
1114                log.debug("Outcome: stepId=" + nextStep + ", status=" + theResult.getStatus() + ", owner=" + theResult.getOwner() + ", actionId=" + actionId + ", currentStep=" + ((currentStep != null) ? currentStep.getStepId() : 0));
1115            }
1116
1117            if (previousIds == null) {
1118                previousIds = new long[0];
1119            }
1120
1121            String JavaDoc owner = TextUtils.noNull(theResult.getOwner());
1122
1123            if (owner.equals("")) {
1124                owner = null;
1125            } else {
1126                Object JavaDoc o = ScriptVariableParser.translateVariables(owner, transientVars, ps);
1127                owner = (o != null) ? o.toString() : null;
1128            }
1129
1130            String JavaDoc oldStatus = theResult.getOldStatus();
1131            oldStatus = ScriptVariableParser.translateVariables(oldStatus, transientVars, ps).toString();
1132
1133            String JavaDoc status = theResult.getStatus();
1134            status = ScriptVariableParser.translateVariables(status, transientVars, ps).toString();
1135
1136            if (currentStep != null) {
1137                store.markFinished(currentStep, actionId, new Date(), oldStatus, context.getCaller());
1138                store.moveToHistory(currentStep);
1139
1140                //store.moveToHistory(actionId, new Date(), currentStep, oldStatus, context.getCaller());
1141
}
1142
1143            // construct the start date and optional due date
1144
Date startDate = new Date();
1145            Date dueDate = null;
1146
1147            if ((theResult.getDueDate() != null) && (theResult.getDueDate().length() > 0)) {
1148                Object JavaDoc dueDateObject = ScriptVariableParser.translateVariables(theResult.getDueDate(), transientVars, ps);
1149
1150                if (dueDateObject instanceof Date) {
1151                    dueDate = (Date) dueDateObject;
1152                } else if (dueDateObject instanceof String JavaDoc) {
1153                    long offset = TextUtils.parseLong((String JavaDoc) dueDateObject);
1154
1155                    if (offset > 0) {
1156                        dueDate = new Date(startDate.getTime() + offset);
1157                    }
1158                } else if (dueDateObject instanceof Number JavaDoc) {
1159                    Number JavaDoc num = (Number JavaDoc) dueDateObject;
1160                    long offset = num.longValue();
1161
1162                    if (offset > 0) {
1163                        dueDate = new Date(startDate.getTime() + offset);
1164                    }
1165                }
1166            }
1167
1168            Step newStep = store.createCurrentStep(entry.getId(), nextStep, owner, startDate, dueDate, status, previousIds);
1169            WorkflowDescriptor descriptor = (WorkflowDescriptor) transientVars.get("descriptor");
1170            List preFunctions = descriptor.getStep(nextStep).getPreFunctions();
1171
1172            for (Iterator iterator = preFunctions.iterator();
1173                    iterator.hasNext();) {
1174                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1175                executeFunction(function, transientVars, ps);
1176            }
1177
1178            return newStep;
1179        } catch (WorkflowException e) {
1180            context.setRollbackOnly();
1181            throw e;
1182        }
1183    }
1184
1185    /**
1186     * Executes a function.
1187     *
1188     * @param function the function to execute
1189     * @param transientVars the transientVars given by the end-user
1190     * @param ps the persistence variables
1191     */

1192    private void executeFunction(FunctionDescriptor function, Map transientVars, PropertySet ps) throws WorkflowException {
1193        if (function != null) {
1194            String JavaDoc type = function.getType();
1195
1196            HashMap args = new HashMap(function.getArgs());
1197
1198            for (Iterator iterator = args.entrySet().iterator();
1199                    iterator.hasNext();) {
1200                Map.Entry mapEntry = (Map.Entry) iterator.next();
1201                mapEntry.setValue(ScriptVariableParser.translateVariables((String JavaDoc) mapEntry.getValue(), transientVars, ps));
1202            }
1203
1204            String JavaDoc clazz;
1205
1206            if ("remote-ejb".equals(type)) {
1207                clazz = RemoteEJBFunctionProvider.class.getName();
1208            } else if ("local-ejb".equals(type)) {
1209                clazz = LocalEJBFunctionProvider.class.getName();
1210            } else if ("jndi".equals(type)) {
1211                clazz = JNDIFunctionProvider.class.getName();
1212            } else if ("bsf".equals(type)) {
1213                clazz = BSFFunctionProvider.class.getName();
1214            } else if ("beanshell".equals(type)) {
1215                clazz = BeanShellFunctionProvider.class.getName();
1216            } else {
1217                clazz = (String JavaDoc) args.get(CLASS_NAME);
1218            }
1219
1220            FunctionProvider provider = (FunctionProvider) loadObject(clazz);
1221
1222            if (provider == null) {
1223                String JavaDoc message = "Could not load FunctionProvider class: " + clazz;
1224                context.setRollbackOnly();
1225                throw new WorkflowException(message);
1226            }
1227
1228            try {
1229                provider.execute(transientVars, args, ps);
1230            } catch (WorkflowException e) {
1231                context.setRollbackOnly();
1232                throw e;
1233            }
1234        }
1235    }
1236
1237    /**
1238     * @return true if the instance has been explicitly completed is this transition, false otherwise
1239     * @throws WorkflowException
1240     */

1241    private boolean transitionWorkflow(WorkflowEntry entry, List currentSteps, WorkflowStore store, WorkflowDescriptor wf, ActionDescriptor action, Map transientVars, Map inputs, PropertySet ps) throws WorkflowException {
1242        Step step = getCurrentStep(wf, action.getId(), currentSteps, transientVars, ps);
1243
1244        // validate transientVars (optional)
1245
Map unmodifiableTransients = Collections.unmodifiableMap(transientVars);
1246
1247        if (action.getValidators().size() > 0) {
1248            verifyInputs(entry, action.getValidators(), unmodifiableTransients, ps);
1249        }
1250
1251        //we're leaving the current step, so let's execute its post-functions
1252
//check if we actually have a current step
1253
if (step != null) {
1254            List stepPostFunctions = wf.getStep(step.getStepId()).getPostFunctions();
1255
1256            for (Iterator iterator = stepPostFunctions.iterator();
1257                    iterator.hasNext();) {
1258                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1259                executeFunction(function, transientVars, ps);
1260            }
1261        }
1262
1263        // preFunctions
1264
List preFunctions = action.getPreFunctions();
1265
1266        for (Iterator iterator = preFunctions.iterator(); iterator.hasNext();) {
1267            FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1268            executeFunction(function, transientVars, ps);
1269        }
1270
1271        // check each conditional result
1272
List conditionalResults = action.getConditionalResults();
1273        List extraPreFunctions = null;
1274        List extraPostFunctions = null;
1275        ResultDescriptor[] theResults = new ResultDescriptor[1];
1276
1277        for (Iterator iterator = conditionalResults.iterator();
1278                iterator.hasNext();) {
1279            ConditionalResultDescriptor conditionalResult = (ConditionalResultDescriptor) iterator.next();
1280
1281            if (passesConditions(null, conditionalResult.getConditions(), unmodifiableTransients, ps, step.getStepId())) {
1282                //if (evaluateExpression(conditionalResult.getCondition(), entry, wf.getRegisters(), null, transientVars)) {
1283
theResults[0] = conditionalResult;
1284
1285                if (conditionalResult.getValidators().size() > 0) {
1286                    verifyInputs(entry, conditionalResult.getValidators(), unmodifiableTransients, ps);
1287                }
1288
1289                extraPreFunctions = conditionalResult.getPreFunctions();
1290                extraPostFunctions = conditionalResult.getPostFunctions();
1291
1292                break;
1293            }
1294        }
1295
1296        // use unconditional-result if a condition hasn't been met
1297
if (theResults[0] == null) {
1298            theResults[0] = action.getUnconditionalResult();
1299            verifyInputs(entry, theResults[0].getValidators(), unmodifiableTransients, ps);
1300            extraPreFunctions = theResults[0].getPreFunctions();
1301            extraPostFunctions = theResults[0].getPostFunctions();
1302        }
1303
1304        if (log.isDebugEnabled()) {
1305            log.debug("theResult=" + theResults[0].getStep() + " " + theResults[0].getStatus());
1306        }
1307
1308        if ((extraPreFunctions != null) && (extraPreFunctions.size() > 0)) {
1309            // run any extra pre-functions that haven't been run already
1310
for (Iterator iterator = extraPreFunctions.iterator();
1311                    iterator.hasNext();) {
1312                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1313                executeFunction(function, transientVars, ps);
1314            }
1315        }
1316
1317        // go to next step
1318
if (theResults[0].getSplit() != 0) {
1319            // the result is a split request, handle it correctly
1320
SplitDescriptor splitDesc = wf.getSplit(theResults[0].getSplit());
1321            Collection results = splitDesc.getResults();
1322            List splitPreFunctions = new ArrayList();
1323            List splitPostFunctions = new ArrayList();
1324
1325            //check all results in the split and verify the input against any validators specified
1326
//also build up all the pre and post functions that should be called.
1327
for (Iterator iterator = results.iterator(); iterator.hasNext();) {
1328                ResultDescriptor resultDescriptor = (ResultDescriptor) iterator.next();
1329
1330                if (resultDescriptor.getValidators().size() > 0) {
1331                    verifyInputs(entry, resultDescriptor.getValidators(), unmodifiableTransients, ps);
1332                }
1333
1334                splitPreFunctions.addAll(resultDescriptor.getPreFunctions());
1335                splitPostFunctions.addAll(resultDescriptor.getPostFunctions());
1336            }
1337
1338            // now execute the pre-functions
1339
for (Iterator iterator = splitPreFunctions.iterator();
1340                    iterator.hasNext();) {
1341                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1342                executeFunction(function, transientVars, ps);
1343            }
1344
1345            // now make these steps...
1346
boolean moveFirst = true;
1347
1348            theResults = new ResultDescriptor[results.size()];
1349            results.toArray(theResults);
1350
1351            for (Iterator iterator = results.iterator(); iterator.hasNext();) {
1352                ResultDescriptor resultDescriptor = (ResultDescriptor) iterator.next();
1353                Step moveToHistoryStep = null;
1354
1355                if (moveFirst) {
1356                    moveToHistoryStep = step;
1357                }
1358
1359                long[] previousIds = null;
1360
1361                if (step != null) {
1362                    previousIds = new long[] {step.getId()};
1363                }
1364
1365                createNewCurrentStep(resultDescriptor, entry, store, action.getId(), moveToHistoryStep, previousIds, transientVars, ps);
1366                moveFirst = false;
1367            }
1368
1369            // now execute the post-functions
1370
for (Iterator iterator = splitPostFunctions.iterator();
1371                    iterator.hasNext();) {
1372                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1373                executeFunction(function, transientVars, ps);
1374            }
1375        } else if (theResults[0].getJoin() != 0) {
1376            // this is a join, finish this step...
1377
JoinDescriptor joinDesc = wf.getJoin(theResults[0].getJoin());
1378            step = store.markFinished(step, action.getId(), new Date(), theResults[0].getOldStatus(), context.getCaller());
1379            store.moveToHistory(step);
1380
1381            // ... now check to see if the expression evaluates
1382
// (get only current steps that have a result to this join)
1383
Collection joinSteps = new ArrayList();
1384            joinSteps.add(step);
1385
1386            //currentSteps = store.findCurrentSteps(id); // shouldn't need to refresh the list
1387
for (Iterator iterator = currentSteps.iterator();
1388                    iterator.hasNext();) {
1389                Step currentStep = (Step) iterator.next();
1390
1391                if (currentStep.getId() != step.getId()) {
1392                    StepDescriptor stepDesc = wf.getStep(currentStep.getStepId());
1393
1394                    if (stepDesc.resultsInJoin(theResults[0].getJoin())) {
1395                        joinSteps.add(currentStep);
1396                    }
1397                }
1398            }
1399
1400            //we also need to check history steps that were finished before this one
1401
//that might be part of the join
1402
List historySteps = store.findHistorySteps(entry.getId());
1403
1404            for (Iterator i = historySteps.iterator(); i.hasNext();) {
1405                Step historyStep = (Step) i.next();
1406
1407                if (historyStep.getId() != step.getId()) {
1408                    StepDescriptor stepDesc = wf.getStep(historyStep.getStepId());
1409
1410                    if (stepDesc.resultsInJoin(theResults[0].getJoin())) {
1411                        joinSteps.add(historyStep);
1412                    }
1413                }
1414            }
1415
1416            JoinNodes jn = new JoinNodes(joinSteps);
1417            transientVars.put("jn", jn);
1418
1419            //todo verify that 0 is the right value for currentstep here
1420
if (passesConditions(null, joinDesc.getConditions(), unmodifiableTransients, ps, 0)) {
1421                // move the rest without creating a new step ...
1422
ResultDescriptor joinresult = joinDesc.getResult();
1423
1424                if (joinresult.getValidators().size() > 0) {
1425                    verifyInputs(entry, joinresult.getValidators(), unmodifiableTransients, ps);
1426                }
1427
1428                // now execute the pre-functions
1429
for (Iterator iterator = joinresult.getPreFunctions().iterator();
1430                        iterator.hasNext();) {
1431                    FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1432                    executeFunction(function, transientVars, ps);
1433                }
1434
1435                long[] previousIds = new long[joinSteps.size()];
1436                int i = 1;
1437
1438                for (Iterator iterator = joinSteps.iterator();
1439                        iterator.hasNext();) {
1440                    Step currentStep = (Step) iterator.next();
1441
1442                    if (currentStep.getId() != step.getId()) {
1443                        //if this is already a history step (eg, for all join steps completed prior to this one),
1444
//we don't move it, since it's already history.
1445
if (!historySteps.contains(currentStep)) {
1446                            store.moveToHistory(currentStep);
1447                        }
1448
1449                        previousIds[i] = currentStep.getId();
1450                        i++;
1451                    }
1452                }
1453
1454                // ... now finish this step normally
1455
previousIds[0] = step.getId();
1456                theResults[0] = joinDesc.getResult();
1457
1458                //we pass in null for the current step since we've already moved it to history above
1459
createNewCurrentStep(joinDesc.getResult(), entry, store, action.getId(), null, previousIds, transientVars, ps);
1460
1461                // now execute the post-functions
1462
for (Iterator iterator = joinresult.getPostFunctions().iterator();
1463                        iterator.hasNext();) {
1464                    FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1465                    executeFunction(function, transientVars, ps);
1466                }
1467            }
1468        } else {
1469            // normal finish, no splits or joins
1470
long[] previousIds = null;
1471
1472            if (step != null) {
1473                previousIds = new long[] {step.getId()};
1474            }
1475
1476            createNewCurrentStep(theResults[0], entry, store, action.getId(), step, previousIds, transientVars, ps);
1477        }
1478
1479        // postFunctions (BOTH)
1480
if (extraPostFunctions != null) {
1481            for (Iterator iterator = extraPostFunctions.iterator();
1482                    iterator.hasNext();) {
1483                FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1484                executeFunction(function, transientVars, ps);
1485            }
1486        }
1487
1488        List postFunctions = action.getPostFunctions();
1489
1490        for (Iterator iterator = postFunctions.iterator(); iterator.hasNext();) {
1491            FunctionDescriptor function = (FunctionDescriptor) iterator.next();
1492            executeFunction(function, transientVars, ps);
1493        }
1494
1495        //if executed action was an initial action then workflow is activated
1496
if ((wf.getInitialAction(action.getId()) != null) && (entry.getState() != WorkflowEntry.ACTIVATED)) {
1497            changeEntryState(entry.getId(), WorkflowEntry.ACTIVATED);
1498        }
1499
1500        //if it's a finish action, then we halt
1501
if (action.isFinish()) {
1502            completeEntry(entry.getId(), getCurrentSteps(entry.getId()));
1503
1504            return true;
1505        }
1506
1507        //get available autoexec actions
1508
int[] availableAutoActions = getAvailableAutoActions(entry.getId(), inputs);
1509
1510        for (int j = 0; j < availableAutoActions.length; j++) {
1511            int actionId = availableAutoActions[j];
1512            doAction(entry.getId(), actionId, inputs);
1513
1514            break;
1515        }
1516
1517        return false;
1518    }
1519}
1520
Popular Tags