Source Code Cross Referenced for SCXMLSemanticsImpl.java in  » Library » Apache-commons-scxml-0.6-src » org » apache » commons » scxml » semantics » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache commons scxml 0.6 src » org.apache.commons.scxml.semantics 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.commons.scxml.semantics;
018:
019:        import java.io.Serializable;
020:        import java.util.Arrays;
021:        import java.util.Collection;
022:        import java.util.Collections;
023:        import java.util.Comparator;
024:        import java.util.HashMap;
025:        import java.util.HashSet;
026:        import java.util.Iterator;
027:        import java.util.LinkedList;
028:        import java.util.List;
029:        import java.util.Map;
030:        import java.util.Set;
031:
032:        import org.apache.commons.logging.Log;
033:        import org.apache.commons.logging.LogFactory;
034:        import org.apache.commons.scxml.Context;
035:        import org.apache.commons.scxml.ErrorReporter;
036:        import org.apache.commons.scxml.Evaluator;
037:        import org.apache.commons.scxml.EventDispatcher;
038:        import org.apache.commons.scxml.NotificationRegistry;
039:        import org.apache.commons.scxml.PathResolver;
040:        import org.apache.commons.scxml.SCInstance;
041:        import org.apache.commons.scxml.SCXMLExpressionException;
042:        import org.apache.commons.scxml.SCXMLHelper;
043:        import org.apache.commons.scxml.SCXMLSemantics;
044:        import org.apache.commons.scxml.Step;
045:        import org.apache.commons.scxml.TriggerEvent;
046:        import org.apache.commons.scxml.invoke.Invoker;
047:        import org.apache.commons.scxml.invoke.InvokerException;
048:        import org.apache.commons.scxml.model.Action;
049:        import org.apache.commons.scxml.model.Finalize;
050:        import org.apache.commons.scxml.model.History;
051:        import org.apache.commons.scxml.model.Initial;
052:        import org.apache.commons.scxml.model.Invoke;
053:        import org.apache.commons.scxml.model.ModelException;
054:        import org.apache.commons.scxml.model.OnEntry;
055:        import org.apache.commons.scxml.model.OnExit;
056:        import org.apache.commons.scxml.model.Parallel;
057:        import org.apache.commons.scxml.model.Param;
058:        import org.apache.commons.scxml.model.Path;
059:        import org.apache.commons.scxml.model.SCXML;
060:        import org.apache.commons.scxml.model.State;
061:        import org.apache.commons.scxml.model.Transition;
062:        import org.apache.commons.scxml.model.TransitionTarget;
063:
064:        /**
065:         * <p>This class encapsulates a particular SCXML semantics, that is, a
066:         * particular semantic interpretation of Harel Statecharts, which aligns
067:         * mostly with W3C SCXML July 5 public draft (that is, UML 1.5). However,
068:         * certain aspects are taken from STATEMATE.</p>
069:         *
070:         * <p>Specific semantics can be created by subclassing this class.</p>
071:         */
072:        public class SCXMLSemanticsImpl implements  SCXMLSemantics, Serializable {
073:
074:            /**
075:             * Serial version UID.
076:             */
077:            private static final long serialVersionUID = 1L;
078:
079:            /**
080:             * SCXML Logger for the application.
081:             */
082:            private Log appLog = LogFactory.getLog("scxml.app.log");
083:
084:            /**
085:             * The TransitionTarget comparator.
086:             */
087:            private TransitionTargetComparator targetComparator = new TransitionTargetComparator();
088:
089:            /**
090:             * Current document namespaces are saved under this key in the parent
091:             * state's context.
092:             */
093:            private static final String NAMESPACES_KEY = "_ALL_NAMESPACES";
094:
095:            /**
096:             * @param input
097:             *            SCXML state machine
098:             * @return normalized SCXML state machine, pseudo states are removed, etc.
099:             * @param errRep
100:             *            ErrorReporter callback
101:             */
102:            public SCXML normalizeStateMachine(final SCXML input,
103:                    final ErrorReporter errRep) {
104:                //it is a no-op for now
105:                return input;
106:            }
107:
108:            /**
109:             * @param input
110:             *            SCXML state machine [in]
111:             * @param states
112:             *            a set of States to populate [out]
113:             * @param entryList
114:             *            a list of States and Parallels to enter [out]
115:             * @param errRep
116:             *            ErrorReporter callback [inout]
117:             * @param scInstance
118:             *            The state chart instance [in]
119:             * @throws ModelException
120:             *             in case there is a fatal SCXML object model problem.
121:             */
122:            public void determineInitialStates(final SCXML input,
123:                    final Set states, final List entryList,
124:                    final ErrorReporter errRep, final SCInstance scInstance)
125:                    throws ModelException {
126:                State tmp = input.getInitialState();
127:                if (tmp == null) {
128:                    errRep.onError(ErrorConstants.NO_INITIAL,
129:                            "SCXML initialstate is missing!", input);
130:                } else {
131:                    states.add(tmp);
132:                    determineTargetStates(states, errRep, scInstance);
133:                    //set of ALL entered states (even if initialState is a jump-over)
134:                    Set onEntry = SCXMLHelper.getAncestorClosure(states, null);
135:                    // sort onEntry according state hierarchy
136:                    Object[] oen = onEntry.toArray();
137:                    onEntry.clear();
138:                    Arrays.sort(oen, getTTComparator());
139:                    // we need to impose reverse order for the onEntry list
140:                    List entering = Arrays.asList(oen);
141:                    Collections.reverse(entering);
142:                    entryList.addAll(entering);
143:
144:                }
145:            }
146:
147:            /**
148:             * Executes all OnExit/Transition/OnEntry transitional actions.
149:             *
150:             * @param step
151:             *            provides EntryList, TransitList, ExitList gets
152:             *            updated its AfterStatus/Events
153:             * @param stateMachine
154:             *            state machine - SCXML instance
155:             * @param evtDispatcher
156:             *            the event dispatcher - EventDispatcher instance
157:             * @param errRep
158:             *            error reporter
159:             * @param scInstance
160:             *            The state chart instance
161:             * @throws ModelException
162:             *             in case there is a fatal SCXML object model problem.
163:             */
164:            public void executeActions(final Step step,
165:                    final SCXML stateMachine,
166:                    final EventDispatcher evtDispatcher,
167:                    final ErrorReporter errRep, final SCInstance scInstance)
168:                    throws ModelException {
169:                NotificationRegistry nr = scInstance.getNotificationRegistry();
170:                Collection internalEvents = step.getAfterStatus().getEvents();
171:                Map invokers = scInstance.getInvokers();
172:                // ExecutePhaseActions / OnExit
173:                for (Iterator i = step.getExitList().iterator(); i.hasNext();) {
174:                    TransitionTarget tt = (TransitionTarget) i.next();
175:                    OnExit oe = tt.getOnExit();
176:                    try {
177:                        for (Iterator onExitIter = oe.getActions().iterator(); onExitIter
178:                                .hasNext();) {
179:                            ((Action) onExitIter.next()).execute(evtDispatcher,
180:                                    errRep, scInstance, appLog, internalEvents);
181:                        }
182:                    } catch (SCXMLExpressionException e) {
183:                        errRep.onError(ErrorConstants.EXPRESSION_ERROR, e
184:                                .getMessage(), oe);
185:                    }
186:                    // check if invoke is active in this state
187:                    if (invokers.containsKey(tt)) {
188:                        Invoker toCancel = (Invoker) invokers.get(tt);
189:                        try {
190:                            toCancel.cancel();
191:                        } catch (InvokerException ie) {
192:                            TriggerEvent te = new TriggerEvent(tt.getId()
193:                                    + ".invoke.cancel.failed",
194:                                    TriggerEvent.ERROR_EVENT);
195:                            internalEvents.add(te);
196:                        }
197:                        // done here, don't wait for cancel response
198:                        invokers.remove(tt);
199:                    }
200:                    nr.fireOnExit(tt, tt);
201:                    nr.fireOnExit(stateMachine, tt);
202:                    TriggerEvent te = new TriggerEvent(tt.getId() + ".exit",
203:                            TriggerEvent.CHANGE_EVENT);
204:                    internalEvents.add(te);
205:                }
206:                // ExecutePhaseActions / Transitions
207:                for (Iterator i = step.getTransitList().iterator(); i.hasNext();) {
208:                    Transition t = (Transition) i.next();
209:                    try {
210:                        for (Iterator transitIter = t.getActions().iterator(); transitIter
211:                                .hasNext();) {
212:                            ((Action) transitIter.next()).execute(
213:                                    evtDispatcher, errRep, scInstance, appLog,
214:                                    internalEvents);
215:                        }
216:                    } catch (SCXMLExpressionException e) {
217:                        errRep.onError(ErrorConstants.EXPRESSION_ERROR, e
218:                                .getMessage(), t);
219:                    }
220:                    nr.fireOnTransition(t, t.getParent(), t.getRuntimeTarget(),
221:                            t);
222:                    nr.fireOnTransition(stateMachine, t.getParent(), t
223:                            .getRuntimeTarget(), t);
224:                }
225:                // ExecutePhaseActions / OnEntry
226:                for (Iterator i = step.getEntryList().iterator(); i.hasNext();) {
227:                    TransitionTarget tt = (TransitionTarget) i.next();
228:                    OnEntry oe = tt.getOnEntry();
229:                    try {
230:                        for (Iterator onEntryIter = oe.getActions().iterator(); onEntryIter
231:                                .hasNext();) {
232:                            ((Action) onEntryIter.next()).execute(
233:                                    evtDispatcher, errRep, scInstance, appLog,
234:                                    internalEvents);
235:                        }
236:                    } catch (SCXMLExpressionException e) {
237:                        errRep.onError(ErrorConstants.EXPRESSION_ERROR, e
238:                                .getMessage(), oe);
239:                    }
240:                    nr.fireOnEntry(tt, tt);
241:                    nr.fireOnEntry(stateMachine, tt);
242:                    TriggerEvent te = new TriggerEvent(tt.getId() + ".entry",
243:                            TriggerEvent.CHANGE_EVENT);
244:                    internalEvents.add(te);
245:                    //3.2.1 and 3.4 (.done events)
246:                    if (tt instanceof  State) {
247:                        State ts = (State) tt;
248:                        if (ts.getIsFinal()) {
249:                            State parent = (State) ts.getParent();
250:                            String prefix = "";
251:                            if (parent != null) {
252:                                prefix = parent.getId();
253:                            }
254:                            te = new TriggerEvent(prefix + ".done",
255:                                    TriggerEvent.CHANGE_EVENT);
256:                            internalEvents.add(te);
257:                            if (parent != null) {
258:                                parent.setDone(true);
259:                            }
260:                            if (parent != null && parent.isRegion()) {
261:                                //3.4 we got a region, which is finalized
262:                                //let's check its siblings too
263:                                Parallel p = (Parallel) parent.getParent();
264:                                int finCount = 0;
265:                                int pCount = p.getStates().size();
266:                                for (Iterator regions = p.getStates()
267:                                        .iterator(); regions.hasNext();) {
268:                                    State reg = (State) regions.next();
269:                                    if (reg.isDone()) {
270:                                        finCount++;
271:                                    }
272:                                }
273:                                if (finCount == pCount) {
274:                                    te = new TriggerEvent(p.getId() + ".done",
275:                                            TriggerEvent.CHANGE_EVENT);
276:                                    internalEvents.add(te);
277:                                    te = new TriggerEvent(p.getParent().getId()
278:                                            + ".done",
279:                                            TriggerEvent.CHANGE_EVENT);
280:                                    internalEvents.add(te);
281:                                    //this is not in the specs, but is makes sense
282:                                    p.getParentState().setDone(true);
283:                                }
284:                            }
285:                        }
286:                    }
287:                }
288:            }
289:
290:            /**
291:             * @param stateMachine
292:             *            a SM to traverse [in]
293:             * @param step
294:             *            with current status and list of transitions to populate
295:             *            [inout]
296:             * @param errRep
297:             *            ErrorReporter callback [inout]
298:             */
299:            public void enumerateReachableTransitions(final SCXML stateMachine,
300:                    final Step step, final ErrorReporter errRep) {
301:                // prevents adding the same transition multiple times
302:                Set transSet = new HashSet();
303:                // prevents visiting the same state multiple times
304:                Set stateSet = new HashSet(step.getBeforeStatus().getStates());
305:                // breath-first search to-do list
306:                LinkedList todoList = new LinkedList(stateSet);
307:                while (!todoList.isEmpty()) {
308:                    State st = (State) todoList.removeFirst();
309:                    for (Iterator i = st.getTransitionsList().iterator(); i
310:                            .hasNext();) {
311:                        Transition t = (Transition) i.next();
312:                        if (!transSet.contains(t)) {
313:                            transSet.add(t);
314:                            step.getTransitList().add(t);
315:                        }
316:                    }
317:                    State parent = st.getParentState();
318:                    if (parent != null && !stateSet.contains(parent)) {
319:                        stateSet.add(parent);
320:                        todoList.addLast(parent);
321:                    }
322:                }
323:                transSet.clear();
324:                stateSet.clear();
325:                todoList.clear();
326:            }
327:
328:            /**
329:             * @param step
330:             *            [inout]
331:             * @param evtDispatcher
332:             *            The {@link EventDispatcher} [in]
333:             * @param errRep
334:             *            ErrorReporter callback [inout]
335:             * @param scInstance
336:             *            The state chart instance [in]
337:             * @throws ModelException
338:             *             in case there is a fatal SCXML object model problem.
339:             */
340:            public void filterTransitionsSet(final Step step,
341:                    final EventDispatcher evtDispatcher,
342:                    final ErrorReporter errRep, final SCInstance scInstance)
343:                    throws ModelException {
344:                /*
345:                 * - filter transition set by applying events
346:                 * (step/beforeStatus/events + step/externalEvents) (local check)
347:                 * - evaluating guard conditions for
348:                 * each transition (local check) - transition precedence (bottom-up)
349:                 * as defined by SCXML specs
350:                 */
351:                Set allEvents = new HashSet(step.getBeforeStatus().getEvents()
352:                        .size()
353:                        + step.getExternalEvents().size());
354:                //for now, we only match against event names
355:                for (Iterator ei = step.getBeforeStatus().getEvents()
356:                        .iterator(); ei.hasNext();) {
357:                    TriggerEvent te = (TriggerEvent) ei.next();
358:                    allEvents.add(te.getName());
359:                }
360:                for (Iterator ei = step.getExternalEvents().iterator(); ei
361:                        .hasNext();) {
362:                    TriggerEvent te = (TriggerEvent) ei.next();
363:                    allEvents.add(te.getName());
364:                }
365:                // Finalize invokes, if applicable
366:                for (Iterator iter = scInstance.getInvokers().keySet()
367:                        .iterator(); iter.hasNext();) {
368:                    State s = (State) iter.next();
369:                    if (finalizeMatch(s.getId(), allEvents)) {
370:                        Finalize fn = s.getInvoke().getFinalize();
371:                        if (fn != null) {
372:                            try {
373:                                for (Iterator fnIter = fn.getActions()
374:                                        .iterator(); fnIter.hasNext();) {
375:                                    ((Action) fnIter.next()).execute(
376:                                            evtDispatcher, errRep, scInstance,
377:                                            appLog, step.getAfterStatus()
378:                                                    .getEvents());
379:                                }
380:                            } catch (SCXMLExpressionException e) {
381:                                errRep.onError(ErrorConstants.EXPRESSION_ERROR,
382:                                        e.getMessage(), fn);
383:                            }
384:                        }
385:                    }
386:                }
387:                //remove list (filtered-out list)
388:                List removeList = new LinkedList();
389:                //iterate over non-filtered transition set
390:                for (Iterator iter = step.getTransitList().iterator(); iter
391:                        .hasNext();) {
392:                    Transition t = (Transition) iter.next();
393:                    // event check
394:                    String event = t.getEvent();
395:                    if (!eventMatch(event, allEvents)) {
396:                        // t has a non-empty event which is not triggered
397:                        removeList.add(t);
398:                        continue; //makes no sense to eval guard cond.
399:                    }
400:                    // guard condition check
401:                    Boolean rslt;
402:                    String expr = t.getCond();
403:                    if (SCXMLHelper.isStringEmpty(expr)) {
404:                        rslt = Boolean.TRUE;
405:                    } else {
406:                        try {
407:                            Context ctx = scInstance.getContext(t.getParent());
408:                            ctx.setLocal(NAMESPACES_KEY, t.getNamespaces());
409:                            rslt = scInstance.getEvaluator().evalCond(ctx,
410:                                    t.getCond());
411:                            ctx.setLocal(NAMESPACES_KEY, null);
412:                        } catch (SCXMLExpressionException e) {
413:                            rslt = Boolean.FALSE;
414:                            errRep.onError(ErrorConstants.EXPRESSION_ERROR, e
415:                                    .getMessage(), t);
416:                        }
417:                    }
418:                    if (!rslt.booleanValue()) {
419:                        // guard condition has not passed
420:                        removeList.add(t);
421:                    }
422:                }
423:                // apply event + guard condition filter
424:                step.getTransitList().removeAll(removeList);
425:                // cleanup temporary structures
426:                allEvents.clear();
427:                removeList.clear();
428:                // optimization - global precedence potentially applies
429:                // only if there are multiple enabled transitions
430:                if (step.getTransitList().size() > 1) {
431:                    // global transition precedence check
432:                    Object[] trans = step.getTransitList().toArray();
433:                    Set currentStates = step.getBeforeStatus().getStates();
434:                    // non-determinism candidates
435:                    Set nonDeterm = new HashSet();
436:                    for (int i = 0; i < trans.length; i++) {
437:                        Transition t = (Transition) trans[i];
438:                        TransitionTarget tsrc = t.getParent();
439:                        for (int j = i + 1; j < trans.length; j++) {
440:                            Transition t2 = (Transition) trans[j];
441:                            boolean conflict = SCXMLHelper.inConflict(t, t2,
442:                                    currentStates);
443:                            if (conflict) {
444:                                //potentially conflicting transitions
445:                                TransitionTarget t2src = t2.getParent();
446:                                if (SCXMLHelper.isDescendant(t2src, tsrc)) {
447:                                    //t2 takes precedence over t
448:                                    removeList.add(t);
449:                                    break; //it makes no sense to waste cycles with t
450:                                } else if (SCXMLHelper
451:                                        .isDescendant(tsrc, t2src)) {
452:                                    //t takes precendence over t2
453:                                    removeList.add(t2);
454:                                } else {
455:                                    //add both to the non-determinism candidates
456:                                    nonDeterm.add(t);
457:                                    nonDeterm.add(t2);
458:                                }
459:                            }
460:                        }
461:                    }
462:                    // check if all non-deterministic situations have been resolved
463:                    nonDeterm.removeAll(removeList);
464:                    if (nonDeterm.size() > 0) {
465:                        errRep.onError(ErrorConstants.NON_DETERMINISTIC,
466:                                "Multiple conflicting transitions enabled.",
467:                                nonDeterm);
468:                    }
469:                    // apply global transition filter
470:                    step.getTransitList().removeAll(removeList);
471:                    removeList.clear();
472:                    nonDeterm.clear();
473:                }
474:            }
475:
476:            /**
477:             * Populate the target set.
478:             * <ul>
479:             * <li>take targets of selected transitions</li>
480:             * <li>take exited regions into account and make sure every active
481:             * parallel region has all siblings active
482:             * [that is, explicitly visit or sibling regions in case of newly visited
483:             * (revisited) orthogonal states]</li>
484:             * </ul>
485:             * @param residual [in]
486:             * @param transitList [in]
487:             * @param errRep
488:             *            ErrorReporter callback [inout]
489:             * @return Set The target set
490:             */
491:            public Set seedTargetSet(final Set residual,
492:                    final List transitList, final ErrorReporter errRep) {
493:                Set seedSet = new HashSet();
494:                Set regions = new HashSet();
495:                for (Iterator i = transitList.iterator(); i.hasNext();) {
496:                    Transition t = (Transition) i.next();
497:                    //iterate over transitions and add target states
498:                    if (t.getTarget() != null) {
499:                        seedSet.add(t.getTarget());
500:                    }
501:                    //build a set of all entered regions
502:                    Path p = t.getPath();
503:                    if (p.isCrossRegion()) {
504:                        List regs = p.getRegionsEntered();
505:                        for (Iterator j = regs.iterator(); j.hasNext();) {
506:                            State region = (State) j.next();
507:                            regions.addAll(((Parallel) region.getParent())
508:                                    .getStates());
509:                        }
510:                    }
511:                }
512:                //check whether all active regions have their siblings active too
513:                Set allStates = new HashSet(residual);
514:                allStates.addAll(seedSet);
515:                allStates = SCXMLHelper.getAncestorClosure(allStates, null);
516:                regions.removeAll(allStates);
517:                //iterate over inactive regions and visit them implicitly using initial
518:                for (Iterator i = regions.iterator(); i.hasNext();) {
519:                    State reg = (State) i.next();
520:                    seedSet.add(reg);
521:                }
522:                return seedSet;
523:            }
524:
525:            /**
526:             * @param states
527:             *            a set seeded in previous step [inout]
528:             * @param errRep
529:             *            ErrorReporter callback [inout]
530:             * @param scInstance
531:             *            The state chart instance [in]
532:             * @throws ModelException On illegal configuration
533:             * @see #seedTargetSet(Set, List, ErrorReporter)
534:             */
535:            public void determineTargetStates(final Set states,
536:                    final ErrorReporter errRep, final SCInstance scInstance)
537:                    throws ModelException {
538:                LinkedList wrkSet = new LinkedList(states);
539:                // clear the seed-set - will be populated by leaf states
540:                states.clear();
541:                while (!wrkSet.isEmpty()) {
542:                    TransitionTarget tt = (TransitionTarget) wrkSet
543:                            .removeFirst();
544:                    if (tt instanceof  State) {
545:                        State st = (State) tt;
546:                        //state can either have parallel or substates w. initial
547:                        //or it is a leaf state
548:                        // NOTE: Digester has to verify this precondition!
549:                        if (st.isSimple()) {
550:                            states.add(st); //leaf
551:                        } else if (st.isOrthogonal()) {
552:                            wrkSet.addLast(st.getParallel()); //parallel
553:                        } else {
554:                            // composite state
555:                            Initial ini = st.getInitial();
556:                            if (ini == null) {
557:                                errRep.onError(ErrorConstants.NO_INITIAL,
558:                                        "Initial pseudostate is missing!", st);
559:                            } else {
560:                                // If we are here, transition target must be a State
561:                                // or History
562:                                Transition initialTransition = ini
563:                                        .getTransition();
564:                                if (initialTransition == null) {
565:                                    errRep.onError(
566:                                            ErrorConstants.ILLEGAL_INITIAL,
567:                                            "Initial transition is null!", st);
568:                                } else {
569:                                    TransitionTarget init = initialTransition
570:                                            .getTarget();
571:                                    if (init == null
572:                                            || !(init instanceof  State || init instanceof  History)) {
573:                                        errRep
574:                                                .onError(
575:                                                        ErrorConstants.ILLEGAL_INITIAL,
576:                                                        "Initial not pointing to a State or History!",
577:                                                        st);
578:                                    } else {
579:                                        wrkSet.addLast(init);
580:                                    }
581:                                }
582:                            }
583:                        }
584:                    } else if (tt instanceof  Parallel) {
585:                        Parallel prl = (Parallel) tt;
586:                        for (Iterator i = prl.getStates().iterator(); i
587:                                .hasNext();) {
588:                            //fork
589:                            wrkSet.addLast(i.next());
590:                        }
591:                    } else if (tt instanceof  History) {
592:                        History h = (History) tt;
593:                        if (scInstance.isEmpty(h)) {
594:                            wrkSet
595:                                    .addLast(h.getTransition()
596:                                            .getRuntimeTarget());
597:                        } else {
598:                            wrkSet.addAll(scInstance.getLastConfiguration(h));
599:                        }
600:                    } else {
601:                        throw new ModelException(
602:                                "Unknown TransitionTarget subclass:"
603:                                        + tt.getClass().getName());
604:                    }
605:                }
606:            }
607:
608:            /**
609:             * Go over the exit list and update history information for
610:             * relevant states.
611:             *
612:             * @param step
613:             *            [inout]
614:             * @param errRep
615:             *            ErrorReporter callback [inout]
616:             * @param scInstance
617:             *            The state chart instance [inout]
618:             */
619:            public void updateHistoryStates(final Step step,
620:                    final ErrorReporter errRep, final SCInstance scInstance) {
621:                Set oldState = step.getBeforeStatus().getStates();
622:                for (Iterator i = step.getExitList().iterator(); i.hasNext();) {
623:                    Object o = i.next();
624:                    if (o instanceof  State) {
625:                        State s = (State) o;
626:                        if (s.hasHistory()) {
627:                            Set shallow = null;
628:                            Set deep = null;
629:                            for (Iterator j = s.getHistory().iterator(); j
630:                                    .hasNext();) {
631:                                History h = (History) j.next();
632:                                if (h.isDeep()) {
633:                                    if (deep == null) {
634:                                        //calculate deep history for a given state once
635:                                        deep = new HashSet();
636:                                        Iterator k = oldState.iterator();
637:                                        while (k.hasNext()) {
638:                                            State os = (State) k.next();
639:                                            if (SCXMLHelper.isDescendant(os, s)) {
640:                                                deep.add(os);
641:                                            }
642:                                        }
643:                                    }
644:                                    scInstance.setLastConfiguration(h, deep);
645:                                } else {
646:                                    if (shallow == null) {
647:                                        //calculate shallow history for a given state
648:                                        // once
649:                                        shallow = new HashSet();
650:                                        shallow
651:                                                .addAll(s.getChildren()
652:                                                        .values());
653:                                        shallow.retainAll(SCXMLHelper
654:                                                .getAncestorClosure(oldState,
655:                                                        null));
656:                                    }
657:                                    scInstance.setLastConfiguration(h, shallow);
658:                                }
659:                            }
660:                            shallow = null;
661:                            deep = null;
662:                        }
663:                    }
664:                }
665:            }
666:
667:            /**
668:             * Follow the candidate transitions for this execution Step, and update the
669:             * lists of entered and exited states accordingly.
670:             *
671:             * @param step The current Step
672:             * @param errorReporter The ErrorReporter for the current environment
673:             * @param scInstance The state chart instance
674:             *
675:             * @throws ModelException
676:             *             in case there is a fatal SCXML object model problem.
677:             */
678:            public void followTransitions(final Step step,
679:                    final ErrorReporter errorReporter,
680:                    final SCInstance scInstance) throws ModelException {
681:                Set currentStates = step.getBeforeStatus().getStates();
682:                List transitions = step.getTransitList();
683:                // DetermineExitedStates (currentStates, transitList) -> exitedStates
684:                Set exitedStates = new HashSet();
685:                for (Iterator i = transitions.iterator(); i.hasNext();) {
686:                    Transition t = (Transition) i.next();
687:                    Set ext = SCXMLHelper.getStatesExited(t, currentStates);
688:                    exitedStates.addAll(ext);
689:                }
690:                // compute residual states - these are preserved from the previous step
691:                Set residual = new HashSet(currentStates);
692:                residual.removeAll(exitedStates);
693:                // SeedTargetSet (residual, transitList) -> seedSet
694:                Set seedSet = seedTargetSet(residual, transitions,
695:                        errorReporter);
696:                // DetermineTargetStates (initialTargetSet) -> targetSet
697:                Set targetSet = step.getAfterStatus().getStates();
698:                targetSet.addAll(seedSet); //copy to preserve seedSet
699:                determineTargetStates(targetSet, errorReporter, scInstance);
700:                // BuildOnEntryList (targetSet, seedSet) -> entryList
701:                Set entered = SCXMLHelper
702:                        .getAncestorClosure(targetSet, seedSet);
703:                seedSet.clear();
704:                for (Iterator i = transitions.iterator(); i.hasNext();) {
705:                    Transition t = (Transition) i.next();
706:                    entered.addAll(t.getPath().getDownwardSegment());
707:                    // If target is a History pseudo state, remove from entered list
708:                    if (t.getRuntimeTarget() instanceof  History) {
709:                        entered.remove(t.getRuntimeTarget());
710:                    }
711:                }
712:                // Check whether the computed state config is legal
713:                targetSet.addAll(residual);
714:                residual.clear();
715:                if (!SCXMLHelper.isLegalConfig(targetSet, errorReporter)) {
716:                    throw new ModelException(
717:                            "Illegal state machine configuration!");
718:                }
719:                // sort onEntry and onExit according state hierarchy
720:                Object[] oex = exitedStates.toArray();
721:                exitedStates.clear();
722:                Object[] oen = entered.toArray();
723:                entered.clear();
724:                Arrays.sort(oex, getTTComparator());
725:                Arrays.sort(oen, getTTComparator());
726:                step.getExitList().addAll(Arrays.asList(oex));
727:                // we need to impose reverse order for the onEntry list
728:                List entering = Arrays.asList(oen);
729:                Collections.reverse(entering);
730:                step.getEntryList().addAll(entering);
731:                // reset 'done' flag
732:                for (Iterator reset = entering.iterator(); reset.hasNext();) {
733:                    Object o = reset.next();
734:                    if (o instanceof  State) {
735:                        ((State) o).setDone(false);
736:                    }
737:                }
738:            }
739:
740:            /**
741:             * Process any existing invokes, includes forwarding external events,
742:             * and executing any finalize handlers.
743:             *
744:             * @param events
745:             *            The events to be forwarded
746:             * @param errRep
747:             *            ErrorReporter callback
748:             * @param scInstance
749:             *            The state chart instance
750:             * @throws ModelException
751:             *             in case there is a fatal SCXML object model problem.
752:             */
753:            public void processInvokes(final TriggerEvent[] events,
754:                    final ErrorReporter errRep, final SCInstance scInstance)
755:                    throws ModelException {
756:                Set eventNames = new HashSet();
757:                //for now, we only match against event names
758:                for (int i = 0; i < events.length; i++) {
759:                    eventNames.add(events[i].getName());
760:                }
761:                for (Iterator invokeIter = scInstance.getInvokers().entrySet()
762:                        .iterator(); invokeIter.hasNext();) {
763:                    Map.Entry iEntry = (Map.Entry) invokeIter.next();
764:                    String parentId = ((TransitionTarget) iEntry.getKey())
765:                            .getId();
766:                    if (!finalizeMatch(parentId, eventNames)) { // prevent cycles
767:                        Invoker inv = (Invoker) iEntry.getValue();
768:                        try {
769:                            inv.parentEvents(events);
770:                        } catch (InvokerException ie) {
771:                            appLog.error(ie.getMessage(), ie);
772:                            throw new ModelException(ie.getMessage(), ie
773:                                    .getCause());
774:                        }
775:                    }
776:                }
777:            }
778:
779:            /**
780:             * Initiate any new invokes.
781:             *
782:             * @param step
783:             *            The current Step
784:             * @param errRep
785:             *            ErrorReporter callback
786:             * @param scInstance
787:             *            The state chart instance
788:             */
789:            public void initiateInvokes(final Step step,
790:                    final ErrorReporter errRep, final SCInstance scInstance) {
791:                Evaluator eval = scInstance.getEvaluator();
792:                Collection internalEvents = step.getAfterStatus().getEvents();
793:                for (Iterator iter = step.getAfterStatus().getStates()
794:                        .iterator(); iter.hasNext();) {
795:                    State s = (State) iter.next();
796:                    Context ctx = scInstance.getContext(s);
797:                    Invoke i = s.getInvoke();
798:                    if (i != null && scInstance.getInvoker(s) == null) {
799:                        String src = i.getSrc();
800:                        if (src == null) {
801:                            String srcexpr = i.getSrcexpr();
802:                            Object srcObj = null;
803:                            try {
804:                                ctx.setLocal(NAMESPACES_KEY, i.getNamespaces());
805:                                srcObj = eval.eval(ctx, srcexpr);
806:                                ctx.setLocal(NAMESPACES_KEY, null);
807:                                src = String.valueOf(srcObj);
808:                            } catch (SCXMLExpressionException see) {
809:                                errRep.onError(ErrorConstants.EXPRESSION_ERROR,
810:                                        see.getMessage(), i);
811:                            }
812:                        }
813:                        String source = src;
814:                        PathResolver pr = i.getPathResolver();
815:                        if (pr != null) {
816:                            source = i.getPathResolver().resolvePath(src);
817:                        }
818:                        String ttype = i.getTargettype();
819:                        Invoker inv = null;
820:                        try {
821:                            inv = scInstance.newInvoker(ttype);
822:                        } catch (InvokerException ie) {
823:                            TriggerEvent te = new TriggerEvent(s.getId()
824:                                    + ".invoke.failed",
825:                                    TriggerEvent.ERROR_EVENT);
826:                            internalEvents.add(te);
827:                            continue;
828:                        }
829:                        inv.setParentStateId(s.getId());
830:                        inv.setSCInstance(scInstance);
831:                        List params = i.params();
832:                        Map args = new HashMap();
833:                        for (Iterator pIter = params.iterator(); pIter
834:                                .hasNext();) {
835:                            Param p = (Param) pIter.next();
836:                            String argExpr = p.getExpr();
837:                            Object argValue = null;
838:                            if (argExpr != null && argExpr.trim().length() > 0) {
839:                                try {
840:                                    ctx.setLocal(NAMESPACES_KEY, p
841:                                            .getNamespaces());
842:                                    argValue = eval.eval(ctx, argExpr);
843:                                    ctx.setLocal(NAMESPACES_KEY, null);
844:                                } catch (SCXMLExpressionException see) {
845:                                    errRep.onError(
846:                                            ErrorConstants.EXPRESSION_ERROR,
847:                                            see.getMessage(), i);
848:                                }
849:                            }
850:                            args.put(p.getName(), argValue);
851:                        }
852:                        try {
853:                            inv.invoke(source, args);
854:                        } catch (InvokerException ie) {
855:                            TriggerEvent te = new TriggerEvent(s.getId()
856:                                    + ".invoke.failed",
857:                                    TriggerEvent.ERROR_EVENT);
858:                            internalEvents.add(te);
859:                            continue;
860:                        }
861:                        scInstance.setInvoker(s, inv);
862:                    }
863:                }
864:            }
865:
866:            /**
867:             * Implements prefix match, that is, if, for example,
868:             * &quot;mouse.click&quot; is a member of eventOccurrences and a
869:             * transition is triggered by &quot;mouse&quot;, the method returns true.
870:             *
871:             * @param transEvent
872:             *            a trigger event of a transition
873:             * @param eventOccurrences
874:             *            current events
875:             * @return true/false
876:             */
877:            protected boolean eventMatch(final String transEvent,
878:                    final Set eventOccurrences) {
879:                if (SCXMLHelper.isStringEmpty(transEvent)) {
880:                    return true;
881:                } else {
882:                    String transEventDot = transEvent + "."; // prefix event support
883:                    Iterator i = eventOccurrences.iterator();
884:                    while (i.hasNext()) {
885:                        String evt = (String) i.next();
886:                        if (evt == null) {
887:                            continue; // Unnamed events
888:                        } else if (evt.equals("*")) {
889:                            return true; // Wildcard
890:                        } else if (evt.equals(transEvent)
891:                                || evt.startsWith(transEventDot)) {
892:                            return true;
893:                        }
894:                    }
895:                    return false;
896:                }
897:            }
898:
899:            /**
900:             * Implements event prefix match to ascertain &lt;finalize&gt; execution.
901:             *
902:             * @param parentStateId
903:             *            the ID of the parent state of the &lt;invoke&gt; holding
904:             *            the &lt;finalize&gt;
905:             * @param eventOccurrences
906:             *            current events
907:             * @return true/false
908:             */
909:            protected boolean finalizeMatch(final String parentStateId,
910:                    final Set eventOccurrences) {
911:                String prefix = parentStateId + ".invoke."; // invoke prefix
912:                Iterator i = eventOccurrences.iterator();
913:                while (i.hasNext()) {
914:                    String evt = (String) i.next();
915:                    if (evt == null) {
916:                        continue; // Unnamed events
917:                    } else if (evt.startsWith(prefix)) {
918:                        return true;
919:                    }
920:                }
921:                return false;
922:            }
923:
924:            /**
925:             * TransitionTargetComparator factory method.
926:             * @return Comparator The TransitionTarget comparator
927:             */
928:            protected Comparator getTTComparator() {
929:                return targetComparator;
930:            }
931:
932:            /**
933:             * Set the log used by this <code>SCXMLSemantics</code> instance.
934:             *
935:             * @param log The new log.
936:             */
937:            protected void setLog(final Log log) {
938:                this .appLog = log;
939:            }
940:
941:            /**
942:             * Get the log used by this <code>SCXMLSemantics</code> instance.
943:             *
944:             * @return Log The log being used.
945:             */
946:            protected Log getLog() {
947:                return appLog;
948:            }
949:
950:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.