📄 scxmlsemanticsimpl.java
字号:
*/
public void enumerateReachableTransitions(final SCXML stateMachine,
final Step step, final ErrorReporter errRep) {
// prevents adding the same transition multiple times
Set transSet = new HashSet();
// prevents visiting the same state multiple times
Set stateSet = new HashSet(step.getBeforeStatus().getStates());
// breath-first search to-do list
LinkedList todoList = new LinkedList(stateSet);
while (!todoList.isEmpty()) {
TransitionTarget tt = (TransitionTarget) todoList.removeFirst();
for (Iterator i = tt.getTransitionsList().iterator();
i.hasNext();) {
Transition t = (Transition) i.next();
if (!transSet.contains(t)) {
transSet.add(t);
step.getTransitList().add(t);
}
}
TransitionTarget parent = tt.getParent();
if (parent != null && !stateSet.contains(parent)) {
stateSet.add(parent);
todoList.addLast(parent);
}
}
transSet.clear();
stateSet.clear();
todoList.clear();
}
/**
* @param step
* [inout]
* @param evtDispatcher
* The {@link EventDispatcher} [in]
* @param errRep
* ErrorReporter callback [inout]
* @param scInstance
* The state chart instance [in]
* @throws ModelException
* in case there is a fatal SCXML object model problem.
*/
public void filterTransitionsSet(final Step step,
final EventDispatcher evtDispatcher,
final ErrorReporter errRep, final SCInstance scInstance)
throws ModelException {
/*
* - filter transition set by applying events
* (step/beforeStatus/events + step/externalEvents) (local check)
* - evaluating guard conditions for
* each transition (local check) - transition precedence (bottom-up)
* as defined by SCXML specs
*/
Set allEvents = new HashSet(step.getBeforeStatus().getEvents().size()
+ step.getExternalEvents().size());
allEvents.addAll(step.getBeforeStatus().getEvents());
allEvents.addAll(step.getExternalEvents());
// Finalize invokes, if applicable
for (Iterator iter = scInstance.getInvokers().keySet().iterator();
iter.hasNext();) {
State s = (State) iter.next();
if (finalizeMatch(s.getId(), allEvents)) {
Finalize fn = s.getInvoke().getFinalize();
if (fn != null) {
try {
for (Iterator fnIter = fn.getActions().iterator();
fnIter.hasNext();) {
((Action) fnIter.next()).execute(evtDispatcher,
errRep, scInstance, appLog,
step.getAfterStatus().getEvents());
}
} catch (SCXMLExpressionException e) {
errRep.onError(ErrorConstants.EXPRESSION_ERROR,
e.getMessage(), fn);
}
}
}
}
//remove list (filtered-out list)
List removeList = new LinkedList();
//iterate over non-filtered transition set
for (Iterator iter = step.getTransitList().iterator();
iter.hasNext();) {
Transition t = (Transition) iter.next();
// event check
String event = t.getEvent();
if (!eventMatch(event, allEvents)) {
// t has a non-empty event which is not triggered
removeList.add(t);
continue; //makes no sense to eval guard cond.
}
// guard condition check
Boolean rslt;
String expr = t.getCond();
if (SCXMLHelper.isStringEmpty(expr)) {
rslt = Boolean.TRUE;
} else {
try {
Context ctx = scInstance.getContext(t.getParent());
ctx.setLocal(NAMESPACES_KEY, t.getNamespaces());
rslt = scInstance.getEvaluator().evalCond(ctx,
t.getCond());
ctx.setLocal(NAMESPACES_KEY, null);
} catch (SCXMLExpressionException e) {
rslt = Boolean.FALSE;
errRep.onError(ErrorConstants.EXPRESSION_ERROR, e
.getMessage(), t);
}
}
if (!rslt.booleanValue()) {
// guard condition has not passed
removeList.add(t);
}
}
// apply event + guard condition filter
step.getTransitList().removeAll(removeList);
// cleanup temporary structures
allEvents.clear();
removeList.clear();
// optimization - global precedence potentially applies
// only if there are multiple enabled transitions
if (step.getTransitList().size() > 1) {
// global transition precedence check
Object[] trans = step.getTransitList().toArray();
// non-determinism candidates
Set nonDeterm = new LinkedHashSet();
for (int i = 0; i < trans.length; i++) {
Transition t = (Transition) trans[i];
TransitionTarget tsrc = t.getParent();
for (int j = i + 1; j < trans.length; j++) {
Transition t2 = (Transition) trans[j];
TransitionTarget t2src = t2.getParent();
if (SCXMLHelper.isDescendant(t2src, tsrc)) {
//t2 takes precedence over t
removeList.add(t);
break; //it makes no sense to waste cycles with t
} else if (SCXMLHelper.isDescendant(tsrc, t2src)) {
//t takes precendence over t2
removeList.add(t2);
} else {
//add both to the non-determinism candidates
nonDeterm.add(t);
nonDeterm.add(t2);
}
}
}
// check if all non-deterministic situations have been resolved
nonDeterm.removeAll(removeList);
if (nonDeterm.size() > 0) {
// if not, first one in each state / region (which is also
// first in document order) wins
Set regions = new HashSet();
Iterator iter = nonDeterm.iterator();
while (iter.hasNext()) {
Transition t = (Transition) iter.next();
TransitionTarget parent = t.getParent();
if (regions.contains(parent)) {
removeList.add(t);
} else {
regions.add(parent);
}
}
}
// apply global and document order transition filter
step.getTransitList().removeAll(removeList);
}
}
/**
* Populate the target set.
* <ul>
* <li>take targets of selected transitions</li>
* <li>take exited regions into account and make sure every active
* parallel region has all siblings active
* [that is, explicitly visit or sibling regions in case of newly visited
* (revisited) orthogonal states]</li>
* </ul>
* @param residual [in]
* @param transitList [in]
* @param errRep
* ErrorReporter callback [inout]
* @return Set The target set
*/
public Set seedTargetSet(final Set residual, final List transitList,
final ErrorReporter errRep) {
Set seedSet = new HashSet();
Set regions = new HashSet();
for (Iterator i = transitList.iterator(); i.hasNext();) {
Transition t = (Transition) i.next();
//iterate over transitions and add target states
if (t.getTargets().size() > 0) {
seedSet.addAll(t.getTargets());
}
//build a set of all entered regions
List paths = t.getPaths();
for (int j = 0; j < paths.size(); j++) {
Path p = (Path) paths.get(j);
if (p.isCrossRegion()) {
List regs = p.getRegionsEntered();
for (Iterator k = regs.iterator(); k.hasNext();) {
State region = (State) k.next();
regions.addAll(((Parallel) region.getParent()).
getChildren());
}
}
}
}
//check whether all active regions have their siblings active too
Set allStates = new HashSet(residual);
allStates.addAll(seedSet);
allStates = SCXMLHelper.getAncestorClosure(allStates, null);
regions.removeAll(allStates);
//iterate over inactive regions and visit them implicitly using initial
for (Iterator i = regions.iterator(); i.hasNext();) {
State reg = (State) i.next();
seedSet.add(reg);
}
return seedSet;
}
/**
* @param states
* a set seeded in previous step [inout]
* @param errRep
* ErrorReporter callback [inout]
* @param scInstance
* The state chart instance [in]
* @throws ModelException On illegal configuration
* @see #seedTargetSet(Set, List, ErrorReporter)
*/
public void determineTargetStates(final Set states,
final ErrorReporter errRep, final SCInstance scInstance)
throws ModelException {
LinkedList wrkSet = new LinkedList(states);
// clear the seed-set - will be populated by leaf states
states.clear();
while (!wrkSet.isEmpty()) {
TransitionTarget tt = (TransitionTarget) wrkSet.removeFirst();
if (tt instanceof State) {
State st = (State) tt;
//state can either have parallel or substates w. initial
//or it is a leaf state
// NOTE: Digester has to verify this precondition!
if (st.isSimple()) {
states.add(st); //leaf
} else if (st.isOrthogonal()) { //TODO: Remove else if in v1.0
wrkSet.addLast(st.getParallel()); //parallel
} else {
// composite state
List initialStates = st.getInitial().getTransition().
getTargets();
wrkSet.addAll(initialStates);
}
} else if (tt instanceof Parallel) {
Parallel prl = (Parallel) tt;
for (Iterator i = prl.getChildren().iterator(); i.hasNext();) {
//fork
wrkSet.addLast(i.next());
}
} else if (tt instanceof History) {
History h = (History) tt;
if (scInstance.isEmpty(h)) {
wrkSet.addAll(h.getTransition().getRuntimeTargets());
} else {
wrkSet.addAll(scInstance.getLastConfiguration(h));
}
} else {
throw new ModelException("Unknown TransitionTarget subclass:"
+ tt.getClass().getName());
}
}
}
/**
* Go over the exit list and update history information for
* relevant states.
*
* @param step
* [inout]
* @param errRep
* ErrorReporter callback [inout]
* @param scInstance
* The state chart instance [inout]
*/
public void updateHistoryStates(final Step step,
final ErrorReporter errRep, final SCInstance scInstance) {
Set oldState = step.getBeforeStatus().getStates();
for (Iterator i = step.getExitList().iterator(); i.hasNext();) {
Object o = i.next();
if (o instanceof State) {
State s = (State) o;
if (s.hasHistory()) {
Set shallow = null;
Set deep = null;
for (Iterator j = s.getHistory().iterator();
j.hasNext();) {
History h = (History) j.next();
if (h.isDeep()) {
if (deep == null) {
//calculate deep history for a given state once
deep = new HashSet();
Iterator k = oldState.iterator();
while (k.hasNext()) {
State os = (State) k.next();
if (SCXMLHelper.isDescendant(os, s)) {
deep.add(os);
}
}
}
scInstance.setLastConfiguration(h, deep);
} else {
if (shallow == null) {
//calculate shallow history for a given state
// once
shallow = new HashSet();
shallow.addAll(s.getChildren().values());
shallow.retainAll(SCXMLHelper
.getAncestorClosure(oldState, null));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -