1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package org.apache.commons.scxml2.semantics;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.commons.scxml2.ActionExecutionContext;
29  import org.apache.commons.scxml2.Context;
30  import org.apache.commons.scxml2.ErrorReporter;
31  import org.apache.commons.scxml2.SCInstance;
32  import org.apache.commons.scxml2.SCXMLExecutionContext;
33  import org.apache.commons.scxml2.SCXMLExpressionException;
34  import org.apache.commons.scxml2.SCXMLSemantics;
35  import org.apache.commons.scxml2.SCXMLSystemContext;
36  import org.apache.commons.scxml2.StateConfiguration;
37  import org.apache.commons.scxml2.TriggerEvent;
38  import org.apache.commons.scxml2.invoke.Invoker;
39  import org.apache.commons.scxml2.invoke.InvokerException;
40  import org.apache.commons.scxml2.model.Action;
41  import org.apache.commons.scxml2.model.DocumentOrder;
42  import org.apache.commons.scxml2.model.EnterableState;
43  import org.apache.commons.scxml2.model.Executable;
44  import org.apache.commons.scxml2.model.Final;
45  import org.apache.commons.scxml2.model.History;
46  import org.apache.commons.scxml2.model.Invoke;
47  import org.apache.commons.scxml2.model.OnEntry;
48  import org.apache.commons.scxml2.model.OnExit;
49  import org.apache.commons.scxml2.model.Script;
50  import org.apache.commons.scxml2.model.SimpleTransition;
51  import org.apache.commons.scxml2.model.TransitionalState;
52  import org.apache.commons.scxml2.model.ModelException;
53  import org.apache.commons.scxml2.model.Parallel;
54  import org.apache.commons.scxml2.model.SCXML;
55  import org.apache.commons.scxml2.model.State;
56  import org.apache.commons.scxml2.model.Transition;
57  import org.apache.commons.scxml2.model.TransitionTarget;
58  import org.apache.commons.scxml2.system.EventVariable;
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  public class SCXMLSemanticsImpl implements SCXMLSemantics {
70  
71      
72  
73  
74  
75      public static final String ERR_ILLEGAL_ALLOC = ".error.illegalalloc";
76  
77      
78  
79  
80  
81  
82  
83  
84  
85      public SCXML normalizeStateMachine(final SCXML input, final ErrorReporter errRep) {
86          
87          return input;
88      }
89  
90      
91  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111     public void firstStep(final SCXMLExecutionContext exctx) throws ModelException {
112         
113         exctx.initialize();
114         
115         executeGlobalScript(exctx);
116         
117         HashSet<TransitionalState> statesToInvoke = new HashSet<TransitionalState>();
118         Step step = new Step(null);
119         step.getTransitList().add(exctx.getStateMachine().getInitialTransition());
120         microStep(exctx, step, statesToInvoke);
121         
122 
123         if (exctx.isRunning()) {
124             macroStep(exctx, statesToInvoke);
125         }
126 
127         if (!exctx.isRunning()) {
128             finalStep(exctx);
129         }
130     }
131 
132     
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158     public void nextStep(final SCXMLExecutionContext exctx, final TriggerEvent event) throws ModelException {
159         if (!exctx.isRunning()) {
160             return;
161         }
162         if (isCancelEvent(event)) {
163             exctx.stopRunning();
164         }
165         else {
166             setSystemEventVariable(exctx.getScInstance(), event, false);
167             processInvokes(exctx, event);
168             Step step = new Step(event);
169             selectTransitions(exctx, step);
170             if (!step.getTransitList().isEmpty()) {
171                 HashSet<TransitionalState> statesToInvoke = new HashSet<TransitionalState>();
172                 microStep(exctx, step, statesToInvoke);
173                 if (exctx.isRunning()) {
174                     macroStep(exctx, statesToInvoke);
175                 }
176             }
177         }
178         if (!exctx.isRunning()) {
179             finalStep(exctx);
180         }
181     }
182 
183     
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202     public void finalStep(SCXMLExecutionContext exctx) throws ModelException {
203         if (exctx.isRunning()) {
204             return;
205         }
206         ArrayList<EnterableState> configuration = new ArrayList<EnterableState>(exctx.getScInstance().getStateConfiguration().getActiveStates());
207         Collections.sort(configuration, DocumentOrder.reverseDocumentOrderComparator);
208         for (EnterableState es : configuration) {
209             for (OnExit onexit : es.getOnExits()) {
210                 executeContent(exctx, onexit);
211             }
212             if (es instanceof TransitionalState) {
213                 
214                 for (Invoke inv : ((TransitionalState)es).getInvokes()) {
215                     exctx.cancelInvoker(inv);
216                 }
217             }
218             exctx.getNotificationRegistry().fireOnExit(es, es);
219             exctx.getNotificationRegistry().fireOnExit(exctx.getStateMachine(), es);
220             if (!(es instanceof Final && es.getParent() == null)) {
221                 exctx.getScInstance().getStateConfiguration().exitState(es);
222             }
223             
224             
225         }
226     }
227 
228     
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239     public void microStep(final SCXMLExecutionContext exctx, final Step step,
240                           final Set<TransitionalState> statesToInvoke)
241             throws ModelException {
242         buildStep(exctx, step);
243         exitStates(exctx, step, statesToInvoke);
244         executeTransitionContent(exctx, step);
245         enterStates(exctx, step, statesToInvoke);
246         step.clearIntermediateState();
247     }
248 
249     
250 
251 
252 
253 
254 
255 
256     public void buildStep(final SCXMLExecutionContext exctx, final Step step) throws ModelException {
257         step.clearIntermediateState();
258 
259         
260         if (!exctx.getScInstance().getStateConfiguration().getActiveStates().isEmpty()) {
261             computeExitSet(step, exctx.getScInstance().getStateConfiguration());
262         }
263         
264         computeEntrySet(exctx, step);
265 
266         
267         Set<EnterableState> states = step.getEntrySet();
268         if (!step.getExitSet().isEmpty()) {
269             
270             states = new HashSet<EnterableState>(exctx.getScInstance().getStateConfiguration().getStates());
271             states.removeAll(step.getExitSet());
272             states.addAll(step.getEntrySet());
273         }
274         
275         if (exctx.isCheckLegalConfiguration() && !isLegalConfiguration(states, exctx.getErrorReporter())) {
276             throw new ModelException("Illegal state machine configuration!");
277         }
278     }
279 
280     
281 
282 
283 
284 
285 
286 
287 
288 
289 
290 
291 
292     public void macroStep(final SCXMLExecutionContext exctx, final Set<TransitionalState> statesToInvoke)
293             throws ModelException {
294         do {
295             boolean macroStepDone = false;
296             do {
297                 Step step = new Step(null);
298                 selectTransitions(exctx, step);
299                 if (step.getTransitList().isEmpty()) {
300                     TriggerEvent event = exctx.nextInternalEvent();
301                     if (event != null) {
302                         if (isCancelEvent(event)) {
303                             exctx.stopRunning();
304                         }
305                         else {
306                             setSystemEventVariable(exctx.getScInstance(), event, true);
307                             step = new Step(event);
308                             selectTransitions(exctx, step);
309                         }
310                     }
311                 }
312                 if (step.getTransitList().isEmpty()) {
313                     macroStepDone = true;
314                 }
315                 else {
316                     microStep(exctx, step, statesToInvoke);
317                 }
318 
319             } while (exctx.isRunning() && !macroStepDone);
320 
321             if (exctx.isRunning() && !statesToInvoke.isEmpty()) {
322                 initiateInvokes(exctx, statesToInvoke);
323                 statesToInvoke.clear();
324             }
325         } while (exctx.isRunning() && exctx.hasPendingInternalEvent());
326     }
327 
328     
329 
330 
331 
332 
333 
334 
335 
336     public void computeExitSet(final Step step, final StateConfiguration stateConfiguration) {
337         if (!stateConfiguration.getActiveStates().isEmpty()) {
338             for (SimpleTransition st : step.getTransitList()) {
339                 computeExitSet(st, step.getExitSet(), stateConfiguration.getActiveStates());
340             }
341             recordHistory(step, stateConfiguration.getStates(), stateConfiguration.getActiveStates());
342         }
343     }
344 
345     
346 
347 
348 
349 
350 
351 
352 
353 
354     public void computeExitSet(SimpleTransition transition, Set<EnterableState> exitSet, Set<EnterableState> activeStates) {
355         if (!transition.getTargets().isEmpty()) {
356             TransitionalState transitionDomain = transition.getTransitionDomain();
357             if (transitionDomain == null) {
358                 
359                 exitSet.addAll(activeStates);
360             }
361             else {
362                 for (EnterableState state : activeStates) {
363                     if (state.isDescendantOf(transitionDomain)) {
364                         exitSet.add(state);
365                     }
366                 }
367             }
368         }
369     }
370 
371     
372 
373 
374 
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386     public void recordHistory(final Step step, final Set<EnterableState> atomicStates, final Set<EnterableState> activeStates) {
387         for (EnterableState es : step.getExitSet()) {
388             if (es instanceof TransitionalState && ((TransitionalState)es).hasHistory()) {
389                 TransitionalState ts = (TransitionalState)es;
390                 Set<EnterableState> shallow = null;
391                 Set<EnterableState> deep = null;
392                 for (History h : ts.getHistory()) {
393                     if (h.isDeep()) {
394                         if (deep == null) {
395                             
396                             deep = new HashSet<EnterableState>();
397                             for (EnterableState ott : atomicStates) {
398                                 if (ott.isDescendantOf(es)) {
399                                     deep.add(ott);
400                                 }
401                             }
402                         }
403                         step.getNewHistoryConfigurations().put(h, deep);
404                     } else {
405                         if (shallow == null) {
406                             
407                             shallow = new HashSet<EnterableState>(ts.getChildren());
408                             shallow.retainAll(activeStates);
409                         }
410                         step.getNewHistoryConfigurations().put(h, shallow);
411                     }
412                 }
413             }
414         }
415     }
416 
417     
418 
419 
420 
421 
422 
423 
424 
425     public void computeEntrySet(final SCXMLExecutionContext exctx, final Step step) {
426         Set<History> historyTargets = new HashSet<History>();
427         Set<EnterableState> entrySet = new HashSet<EnterableState>();
428         for (SimpleTransition st : step.getTransitList()) {
429             for (TransitionTarget tt : st.getTargets()) {
430                 if (tt instanceof EnterableState) {
431                     entrySet.add((EnterableState) tt);
432                 }
433                 else {
434                     
435                     historyTargets.add((History)tt);
436                 }
437             }
438         }
439         for (EnterableState es : entrySet) {
440             addDescendantStatesToEnter(exctx, step, es);
441         }
442         for (History h : historyTargets) {
443             addDescendantStatesToEnter(exctx, step, h);
444         }
445         for (SimpleTransition st : step.getTransitList()) {
446             TransitionalState ancestor = st.getTransitionDomain();
447             for (TransitionTarget tt : st.getTargets()) {
448                 addAncestorStatesToEnter(exctx, step, tt, ancestor);
449             }
450         }
451     }
452 
453     
454 
455 
456 
457 
458 
459 
460     public void addDescendantStatesToEnter(final SCXMLExecutionContext exctx, final Step step,
461                                               final TransitionTarget tt) {
462         if (tt instanceof History) {
463             History h = (History) tt;
464             Set<EnterableState> lastConfiguration = step.getNewHistoryConfigurations().get(h);
465             if (lastConfiguration == null) {
466                 lastConfiguration = exctx.getScInstance().getLastConfiguration(h);
467             }
468             if (lastConfiguration.isEmpty()) {
469                 step.getDefaultHistoryTransitions().put(h.getParent(), h.getTransition());
470                 for (TransitionTarget dtt : h.getTransition().getTargets()) {
471                     addDescendantStatesToEnter(exctx, step, dtt);
472                 }
473                 for (TransitionTarget dtt : h.getTransition().getTargets()) {
474                     addAncestorStatesToEnter(exctx, step, dtt, tt.getParent());
475                 }
476             } else {
477                 for (TransitionTarget dtt : lastConfiguration) {
478                     addDescendantStatesToEnter(exctx, step, dtt);
479                 }
480                 for (TransitionTarget dtt : lastConfiguration) {
481                     addAncestorStatesToEnter(exctx, step, dtt, tt.getParent());
482                 }
483             }
484         }
485         else { 
486             EnterableState es = (EnterableState)tt;
487             step.getEntrySet().add(es);
488             if (es instanceof Parallel) {
489                 for (EnterableState child : ((Parallel)es).getChildren()) {
490                     if (!containsDescendant(step.getEntrySet(), child)) {
491                         addDescendantStatesToEnter(exctx, step, child);
492                     }
493                 }
494             }
495             else if (es instanceof State && ((State) es).isComposite()) {
496                 step.getDefaultEntrySet().add(es);
497                 for (TransitionTarget dtt : ((State)es).getInitial().getTransition().getTargets()) {
498                     addDescendantStatesToEnter(exctx, step, dtt);
499                 }
500                 for (TransitionTarget dtt : ((State)es).getInitial().getTransition().getTargets()) {
501                     addAncestorStatesToEnter(exctx, step, dtt, tt);
502                 }
503             }
504         }
505     }
506 
507     
508 
509 
510 
511 
512 
513 
514 
515     public void addAncestorStatesToEnter(final SCXMLExecutionContext exctx, final Step step,
516                                             final TransitionTarget tt, TransitionTarget ancestor) {
517         
518         for (int i = tt.getNumberOfAncestors()-1; i > -1; i--) {
519             EnterableState anc = tt.getAncestor(i);
520             if (anc == ancestor) {
521                 break;
522             }
523             step.getEntrySet().add(anc);
524             if (anc instanceof Parallel) {
525                 for (EnterableState child : ((Parallel)anc).getChildren()) {
526                     if (!containsDescendant(step.getEntrySet(), child)) {
527                         addDescendantStatesToEnter(exctx, step, child);
528                     }
529                 }
530 
531             }
532         }
533     }
534 
535     
536 
537 
538 
539 
540     public boolean containsDescendant(Set<EnterableState> states, EnterableState state) {
541         for (EnterableState es : states) {
542             if (es.isDescendantOf(state)) {
543                 return true;
544             }
545         }
546         return false;
547     }
548 
549     
550 
551 
552 
553 
554 
555 
556     public void selectTransitions(final SCXMLExecutionContext exctx, final Step step) throws ModelException {
557         step.getTransitList().clear();
558         ArrayList<Transition> enabledTransitions = new ArrayList<Transition>();
559 
560         ArrayList<EnterableState> configuration = new ArrayList<EnterableState>(exctx.getScInstance().getStateConfiguration().getActiveStates());
561         Collections.sort(configuration,DocumentOrder.documentOrderComparator);
562 
563         HashSet<EnterableState> visited = new HashSet<EnterableState>();
564 
565         String eventName = step.getEvent() != null ? step.getEvent().getName() : null;
566         for (EnterableState es : configuration) {
567             if (es.isAtomicState()) {
568                 if (es instanceof Final) {
569                     
570                     if (es.getParent() == null) {
571                         
572                         throw new ModelException("Illegal state machine configuration: encountered top level <final> "
573                                 + "state while processing an event");
574                     }
575                     else {
576                         es = es.getParent();
577                     }
578                 }
579                 TransitionalState state = (TransitionalState)es;
580                 TransitionalState current = state;
581                 int ancestorIndex = state.getNumberOfAncestors()-1;
582                 boolean transitionMatched = false;
583                 do {
584                     for (Transition transition : current.getTransitionsList()) {
585                         if (transitionMatched = matchTransition(exctx, transition, eventName)) {
586                             enabledTransitions.add(transition);
587                             break;
588                         }
589                     }
590                     current = (!transitionMatched && ancestorIndex > -1) ? state.getAncestor(ancestorIndex--) : null;
591                 } while (!transitionMatched && current != null && visited.add(current));
592             }
593         }
594         removeConflictingTransitions(exctx, step, enabledTransitions);
595     }
596 
597     
598 
599 
600 
601 
602 
603 
604     public void removeConflictingTransitions(final SCXMLExecutionContext exctx, final Step step,
605                                              final List<Transition> enabledTransitions) {
606         LinkedHashSet<Transition> filteredTransitions = new LinkedHashSet<Transition>();
607         LinkedHashSet<Transition> preemptedTransitions = new LinkedHashSet<Transition>();
608         Map<Transition, Set<EnterableState>> exitSets = new HashMap<Transition, Set<EnterableState>>();
609 
610         Set<EnterableState> configuration = exctx.getScInstance().getStateConfiguration().getActiveStates();
611         Collections.sort(enabledTransitions, DocumentOrder.documentOrderComparator);
612 
613         for (Transition t1 : enabledTransitions) {
614             boolean t1Preempted = false;
615             Set<EnterableState> t1ExitSet = exitSets.get(t1);
616             for (Transition t2 : filteredTransitions) {
617                 if (t1ExitSet == null) {
618                     t1ExitSet = new HashSet<EnterableState>();
619                     computeExitSet(t1, t1ExitSet, configuration);
620                     exitSets.put(t1, t1ExitSet);
621                 }
622                 Set<EnterableState> t2ExitSet = exitSets.get(t2);
623                 if (t2ExitSet == null) {
624                     t2ExitSet = new HashSet<EnterableState>();
625                     computeExitSet(t2, t2ExitSet, configuration);
626                     exitSets.put(t2, t2ExitSet);
627                 }
628                 Set<EnterableState> smaller = t1ExitSet.size() < t2ExitSet.size() ? t1ExitSet : t2ExitSet;
629                 Set<EnterableState> larger = smaller == t1ExitSet ? t2ExitSet : t1ExitSet;
630                 boolean hasIntersection = false;
631                 for (EnterableState s1 : smaller) {
632                     hasIntersection = larger.contains(s1);
633                     if (hasIntersection) {
634                         break;
635                     }
636                 }
637                 if (hasIntersection) {
638                     if (t1.getParent().isDescendantOf(t2.getParent())) {
639                         preemptedTransitions.add(t2);
640                     }
641                     else {
642                         t1Preempted = true;
643                         break;
644                     }
645                 }
646             }
647             if (t1Preempted) {
648                 exitSets.remove(t1);
649             }
650             else {
651                 for (Transition preempted : preemptedTransitions) {
652                     filteredTransitions.remove(preempted);
653                     exitSets.remove(preempted);
654                 }
655                 filteredTransitions.add(t1);
656             }
657         }
658         step.getTransitList().addAll(filteredTransitions);
659     }
660 
661     
662 
663 
664 
665 
666 
667 
668     public boolean matchTransition(final SCXMLExecutionContext exctx, final Transition transition, final String eventName) {
669         if (eventName != null) {
670             if (!(transition.isNoEventsTransition() || transition.isAllEventsTransition())) {
671                 boolean eventMatch = false;
672                 for (String event : transition.getEvents()) {
673                     if (eventName.startsWith(event)) {
674                         if (eventName.length() == event.length() || eventName.charAt(event.length())=='.')
675                             eventMatch = true;
676                         break;
677                     }
678                 }
679                 if (!eventMatch) {
680                     return false;
681                 }
682             }
683             else if (!transition.isAllEventsTransition()) {
684                 return false;
685             }
686         }
687         else if (!transition.isNoEventsTransition()) {
688             return false;
689         }
690         if (transition.getCond() != null) {
691             Boolean result = Boolean.FALSE;
692             Context context = exctx.getScInstance().getContext(transition.getParent());
693             context.setLocal(Context.NAMESPACES_KEY, transition.getNamespaces());
694             try {
695                 if ((result = exctx.getEvaluator().evalCond(context, transition.getCond())) == null) {
696                     result = Boolean.FALSE;
697                     if (exctx.getAppLog().isDebugEnabled()) {
698                         exctx.getAppLog().debug("Treating as false because the cond expression was evaluated as null: '"
699                                 + transition.getCond() + "'");
700                     }
701                 }
702             }
703             catch (SCXMLExpressionException e) {
704                 exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
705                 exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, "Treating as false due to error: "
706                         + e.getMessage(), transition);
707             }
708             finally {
709                 context.setLocal(Context.NAMESPACES_KEY, null);
710             }
711             return result;
712         }
713         return true;
714     }
715 
716     
717 
718 
719 
720 
721 
722 
723 
724     public boolean isInFinalState(final EnterableState es, final Set<EnterableState> configuration) {
725         if (es instanceof State) {
726             for (EnterableState child : ((State)es).getChildren()) {
727                 if (child instanceof Final && configuration.contains(child)) {
728                     return true;
729                 }
730             }
731         }
732         else if (es instanceof Parallel) {
733             for (EnterableState child : ((Parallel)es).getChildren()) {
734                 if (!isInFinalState(child, configuration)) {
735                     return false;
736                 }
737             }
738             return true;
739         }
740         return false;
741     }
742 
743     
744 
745 
746 
747 
748 
749 
750 
751     public boolean isInvokerEvent(final String invokerId, final TriggerEvent event) {
752         return event.getName().equals("done.invoke."+invokerId) ||
753                 event.getName().startsWith("done.invoke."+invokerId+".");
754     }
755 
756     
757 
758 
759 
760 
761 
762     public boolean isCancelEvent(TriggerEvent event) {
763         return (event.getType() == TriggerEvent.CANCEL_EVENT);
764     }
765 
766     
767 
768 
769 
770 
771 
772 
773 
774 
775     public boolean isLegalConfiguration(final Set<EnterableState> states, final ErrorReporter errRep) {
776         
777 
778 
779 
780 
781 
782 
783 
784         boolean legalConfig = true; 
785         Map<EnterableState, Set<EnterableState>> counts = new HashMap<EnterableState, Set<EnterableState>>();
786         Set<EnterableState> scxmlCount = new HashSet<EnterableState>();
787         for (EnterableState es : states) {
788             EnterableState parent;
789             while ((parent = es.getParent()) != null) {
790                 Set<EnterableState> cnt = counts.get(parent);
791                 if (cnt == null) {
792                     cnt = new HashSet<EnterableState>();
793                     counts.put(parent, cnt);
794                 }
795                 cnt.add(es);
796                 es = parent;
797             }
798             
799             scxmlCount.add(es);
800         }
801         if (scxmlCount.size() > 1) {
802             errRep.onError(ErrorConstants.ILLEGAL_CONFIG, "Multiple top-level OR states active!", scxmlCount);
803             legalConfig = false;
804         }
805         else {
806             
807             for (Map.Entry<EnterableState, Set<EnterableState>> entry : counts.entrySet()) {
808                 EnterableState es = entry.getKey();
809                 Set<EnterableState> count = entry.getValue();
810                 if (es instanceof Parallel) {
811                     Parallel p = (Parallel) es;
812                     if (count.size() < p.getChildren().size()) {
813                         errRep.onError(ErrorConstants.ILLEGAL_CONFIG, "Not all AND states active for parallel " + p.getId(), entry);
814                         legalConfig = false;
815                     }
816                 } else {
817                     if (count.size() > 1) {
818                         errRep.onError(ErrorConstants.ILLEGAL_CONFIG, "Multiple OR states active for state " + es.getId(), entry);
819                         legalConfig = false;
820                     }
821                 }
822                 count.clear(); 
823             }
824         }
825         
826         scxmlCount.clear();
827         counts.clear();
828         return legalConfig;
829     }
830 
831     
832 
833 
834 
835 
836 
837 
838 
839 
840 
841     public void setSystemEventVariable(final SCInstance scInstance, final TriggerEvent event, boolean internal) {
842         Context systemContext = scInstance.getSystemContext();
843         EventVariable eventVar = null;
844         if (event != null) {
845             String eventType = internal ? EventVariable.TYPE_INTERNAL : EventVariable.TYPE_EXTERNAL;
846 
847             final int triggerEventType = event.getType();
848             if (triggerEventType == TriggerEvent.ERROR_EVENT || triggerEventType == TriggerEvent.CHANGE_EVENT) {
849                 eventType = EventVariable.TYPE_PLATFORM;
850             }
851 
852             
853             eventVar = new EventVariable(event.getName(), eventType, null, null, null, null, event.getPayload());
854         }
855         systemContext.setLocal(SCXMLSystemContext.EVENT_KEY, eventVar);
856     }
857 
858     
859 
860 
861 
862 
863 
864     public void executeGlobalScript(final SCXMLExecutionContext exctx) throws ModelException {
865         Script globalScript = exctx.getStateMachine().getGlobalScript();
866         if ( globalScript != null) {
867             try {
868                 globalScript.execute(exctx.getActionExecutionContext());
869             } catch (SCXMLExpressionException e) {
870                 exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
871                 exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, e.getMessage(), exctx.getStateMachine());
872             }
873         }
874     }
875 
876     
877 
878 
879 
880 
881 
882 
883 
884 
885 
886     public void exitStates(final SCXMLExecutionContext exctx, final Step step,
887                            final Set<TransitionalState> statesToInvoke)
888             throws ModelException {
889         if (step.getExitSet().isEmpty()) {
890             return;
891         }
892         ArrayList<EnterableState> exitList = new ArrayList<EnterableState>(step.getExitSet());
893         Collections.sort(exitList, DocumentOrder.reverseDocumentOrderComparator);
894 
895         for (EnterableState es : exitList) {
896 
897             if (es instanceof TransitionalState && ((TransitionalState)es).hasHistory()) {
898                 
899                 for (History h : ((TransitionalState)es).getHistory()) {
900                     exctx.getScInstance().setLastConfiguration(h, step.getNewHistoryConfigurations().get(h));
901                 }
902             }
903 
904             boolean onexitEventRaised = false;
905             for (OnExit onexit : es.getOnExits()) {
906                 executeContent(exctx, onexit);
907                 if (!onexitEventRaised && onexit.isRaiseEvent()) {
908                     onexitEventRaised = true;
909                     exctx.getInternalIOProcessor().addEvent(new TriggerEvent("exit.state."+es.getId(), TriggerEvent.CHANGE_EVENT));
910                 }
911             }
912             exctx.getNotificationRegistry().fireOnExit(es, es);
913             exctx.getNotificationRegistry().fireOnExit(exctx.getStateMachine(), es);
914 
915             if (es instanceof TransitionalState && !statesToInvoke.remove(es)) {
916                 
917                 for (Invoke inv : ((TransitionalState)es).getInvokes()) {
918                     exctx.cancelInvoker(inv);
919                 }
920             }
921             exctx.getScInstance().getStateConfiguration().exitState(es);
922         }
923     }
924 
925     
926 
927 
928 
929 
930 
931 
932     public void executeTransitionContent(final SCXMLExecutionContext exctx, final Step step) throws ModelException {
933         for (SimpleTransition transition : step.getTransitList()) {
934             executeContent(exctx, transition);
935         }
936     }
937 
938     
939 
940 
941 
942 
943 
944 
945     public void executeContent(SCXMLExecutionContext exctx, Executable exec) throws ModelException {
946         try {
947             for (Action action : exec.getActions()) {
948                 action.execute(exctx.getActionExecutionContext());
949             }
950         } catch (SCXMLExpressionException e) {
951             exctx.getInternalIOProcessor().addEvent(new TriggerEvent(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT));
952             exctx.getErrorReporter().onError(ErrorConstants.EXPRESSION_ERROR, e.getMessage(), exec);
953         }
954         if (exec instanceof Transition) {
955             Transition t = (Transition)exec;
956             if (t.getTargets().isEmpty()) {
957                 notifyOnTransition(exctx, t, t.getParent());
958             }
959             else {
960                 for (TransitionTarget tt : t.getTargets()) {
961                     notifyOnTransition(exctx, t, tt);
962                 }
963             }
964         }
965     }
966 
967     
968 
969 
970 
971 
972 
973 
974     public void notifyOnTransition(final SCXMLExecutionContext exctx, final Transition t,
975                                       final TransitionTarget target) {
976         EventVariable event = (EventVariable)exctx.getScInstance().getSystemContext().getVars().get(SCXMLSystemContext.EVENT_KEY);
977         String eventName = event != null ? event.getName() : null;
978         exctx.getNotificationRegistry().fireOnTransition(t, t.getParent(), target, t, eventName);
979         exctx.getNotificationRegistry().fireOnTransition(exctx.getStateMachine(), t.getParent(), target, t, eventName);
980     }
981 
982     
983 
984 
985 
986 
987 
988 
989 
990 
991 
992     public void enterStates(final SCXMLExecutionContext exctx, final Step step,
993                             final Set<TransitionalState> statesToInvoke)
994             throws ModelException {
995         if (step.getEntrySet().isEmpty()) {
996             return;
997         }
998         ArrayList<EnterableState> entryList = new ArrayList<EnterableState>(step.getEntrySet());
999         Collections.sort(entryList, DocumentOrder.documentOrderComparator);
1000         for (EnterableState es : entryList) {
1001             exctx.getScInstance().getStateConfiguration().enterState(es);
1002             if (es instanceof TransitionalState && !((TransitionalState)es).getInvokes().isEmpty()) {
1003                 statesToInvoke.add((TransitionalState) es);
1004             }
1005 
1006             boolean onentryEventRaised = false;
1007             for (OnEntry onentry : es.getOnEntries()) {
1008                 executeContent(exctx, onentry);
1009                 if (!onentryEventRaised && onentry.isRaiseEvent()) {
1010                     onentryEventRaised = true;
1011                     exctx.getInternalIOProcessor().addEvent(new TriggerEvent("entry.state."+es.getId(), TriggerEvent.CHANGE_EVENT));
1012                 }
1013             }
1014             exctx.getNotificationRegistry().fireOnEntry(es, es);
1015             exctx.getNotificationRegistry().fireOnEntry(exctx.getStateMachine(), es);
1016 
1017             if (es instanceof State && step.getDefaultEntrySet().contains(es) && ((State)es).getInitial() != null) {
1018                 executeContent(exctx, ((State)es).getInitial().getTransition());
1019             }
1020             if (es instanceof TransitionalState) {
1021                 SimpleTransition hTransition = step.getDefaultHistoryTransitions().get(es);
1022                 if (hTransition != null) {
1023                     executeContent(exctx, hTransition);
1024                 }
1025             }
1026 
1027             if (es instanceof Final) {
1028                 State parent = (State)es.getParent();
1029                 if (parent == null) {
1030                     exctx.stopRunning();
1031                 }
1032                 else {
1033                     exctx.getInternalIOProcessor().addEvent(new TriggerEvent("done.state."+parent.getId(),TriggerEvent.CHANGE_EVENT));
1034                     if (parent.isRegion()) {
1035                         if (isInFinalState(parent.getParent(), exctx.getScInstance().getStateConfiguration().getActiveStates())) {
1036                             exctx.getInternalIOProcessor().addEvent(new TriggerEvent("done.state."+parent.getParent().getId()
1037                                     , TriggerEvent.CHANGE_EVENT));
1038                         }
1039                     }
1040                 }
1041             }
1042         }
1043     }
1044 
1045     
1046 
1047 
1048 
1049 
1050 
1051     public void initiateInvokes(final SCXMLExecutionContext exctx,
1052                                 final Set<TransitionalState> statesToInvoke) throws ModelException {
1053         ActionExecutionContext aexctx = exctx.getActionExecutionContext();
1054         for (TransitionalState ts : statesToInvoke) {
1055             for (Invoke invoke : ts.getInvokes()) {
1056                 Context ctx = aexctx.getContext(invoke.getParentEnterableState());
1057                 String exctxKey = invoke.getCurrentSCXMLExecutionContextKey();
1058                 ctx.setLocal(exctxKey, exctx);
1059                 invoke.execute(aexctx);
1060                 ctx.setLocal(exctxKey, null);
1061             }
1062         }
1063     }
1064 
1065     
1066 
1067 
1068 
1069 
1070 
1071 
1072 
1073     public void processInvokes(final SCXMLExecutionContext exctx, final TriggerEvent event) throws ModelException {
1074         for (Map.Entry<Invoke, String> entry : exctx.getInvokeIds().entrySet()) {
1075             if (!isInvokerEvent(entry.getValue(), event)) {
1076                 if (entry.getKey().isAutoForward()) {
1077                     Invoker inv = exctx.getInvoker(entry.getKey());
1078                     try {
1079                         inv.parentEvent(event);
1080                     } catch (InvokerException ie) {
1081                         exctx.getAppLog().error(ie.getMessage(), ie);
1082                         throw new ModelException(ie.getMessage(), ie.getCause());
1083                     }
1084                 }
1085             }
1086             
1087 
1088 
1089 
1090 
1091         }
1092     }
1093 }
1094