📄 modelupdater.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.scxml.io;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.scxml.SCXMLHelper;
import org.apache.commons.scxml.model.History;
import org.apache.commons.scxml.model.Initial;
import org.apache.commons.scxml.model.Invoke;
import org.apache.commons.scxml.model.ModelException;
import org.apache.commons.scxml.model.Parallel;
import org.apache.commons.scxml.model.SCXML;
import org.apache.commons.scxml.model.State;
import org.apache.commons.scxml.model.Transition;
import org.apache.commons.scxml.model.TransitionTarget;
/**
* The ModelUpdater provides the utility methods to check the Commons
* SCXML model for inconsistencies, detect errors, and wire the Commons
* SCXML model appropriately post document parsing by the digester to make
* it executor ready.
*/
final class ModelUpdater {
/*
* Post-processing methods to make the SCXML object SCXMLExecutor ready.
*/
/**
* <p>Update the SCXML object model and make it SCXMLExecutor ready.
* This is part of post-digester processing, and sets up the necessary
* object references throughtout the SCXML object model for the parsed
* document.</p>
*
* @param scxml The SCXML object (output from Digester)
* @throws ModelException If the object model is flawed
*/
static void updateSCXML(final SCXML scxml) throws ModelException {
String initial = scxml.getInitial();
//we have to use getTargets() here since the initialTarget can be
//an indirect descendant
TransitionTarget initialTarget = (TransitionTarget) scxml.getTargets().
get(initial);
if (initialTarget == null) {
// Where do we, where do we go?
logAndThrowModelError(ERR_SCXML_NO_INIT, new Object[] {
initial });
}
scxml.setInitialTarget(initialTarget);
Map targets = scxml.getTargets();
Map children = scxml.getChildren();
Iterator i = children.keySet().iterator();
while (i.hasNext()) {
TransitionTarget tt = (TransitionTarget) children.get(i.next());
if (tt instanceof State) {
updateState((State) tt, targets);
} else {
updateParallel((Parallel) tt, targets);
}
}
}
/**
* Update this State object (part of post-digestion processing).
* Also checks for any errors in the document.
*
* @param s The State object
* @param targets The global Map of all transition targets
* @throws ModelException If the object model is flawed
*/
private static void updateState(final State s, final Map targets)
throws ModelException {
//initialize next / inital
Initial ini = s.getInitial();
Map c = s.getChildren();
List initialStates = null;
if (!c.isEmpty()) {
if (ini == null) {
logAndThrowModelError(ERR_STATE_NO_INIT,
new Object[] {getStateName(s)});
}
Transition initialTransition = ini.getTransition();
updateTransition(initialTransition, targets);
initialStates = initialTransition.getTargets();
// we have to allow for an indirect descendant initial (targets)
//check that initialState is a descendant of s
if (initialStates.size() == 0) {
logAndThrowModelError(ERR_STATE_BAD_INIT,
new Object[] {getStateName(s)});
} else {
for (int i = 0; i < initialStates.size(); i++) {
TransitionTarget initialState = (TransitionTarget)
initialStates.get(i);
if (!SCXMLHelper.isDescendant(initialState, s)) {
logAndThrowModelError(ERR_STATE_BAD_INIT,
new Object[] {getStateName(s)});
}
}
}
}
List histories = s.getHistory();
Iterator histIter = histories.iterator();
while (histIter.hasNext()) {
if (s.isSimple()) {
logAndThrowModelError(ERR_HISTORY_SIMPLE_STATE,
new Object[] {getStateName(s)});
}
History h = (History) histIter.next();
Transition historyTransition = h.getTransition();
if (historyTransition == null) {
// try to assign initial as default
if (initialStates != null && initialStates.size() > 0) {
for (int i = 0; i < initialStates.size(); i++) {
if (initialStates.get(i) instanceof History) {
logAndThrowModelError(ERR_HISTORY_BAD_DEFAULT,
new Object[] {h.getId(), getStateName(s)});
}
}
historyTransition = new Transition();
historyTransition.getTargets().addAll(initialStates);
h.setTransition(historyTransition);
} else {
logAndThrowModelError(ERR_HISTORY_NO_DEFAULT,
new Object[] {h.getId(), getStateName(s)});
}
}
updateTransition(historyTransition, targets);
List historyStates = historyTransition.getTargets();
if (historyStates.size() == 0) {
logAndThrowModelError(ERR_STATE_NO_HIST,
new Object[] {getStateName(s)});
}
for (int i = 0; i < historyStates.size(); i++) {
TransitionTarget historyState = (TransitionTarget)
historyStates.get(i);
if (!h.isDeep()) {
if (!c.containsValue(historyState)) {
logAndThrowModelError(ERR_STATE_BAD_SHALLOW_HIST,
new Object[] {getStateName(s)});
}
} else {
if (!SCXMLHelper.isDescendant(historyState, s)) {
logAndThrowModelError(ERR_STATE_BAD_DEEP_HIST,
new Object[] {getStateName(s)});
}
}
}
}
List t = s.getTransitionsList();
for (int i = 0; i < t.size(); i++) {
Transition trn = (Transition) t.get(i);
updateTransition(trn, targets);
}
Parallel p = s.getParallel(); //TODO: Remove in v1.0
Invoke inv = s.getInvoke();
if ((inv != null && p != null)
|| (inv != null && !c.isEmpty())
|| (p != null && !c.isEmpty())) {
logAndThrowModelError(ERR_STATE_BAD_CONTENTS,
new Object[] {getStateName(s)});
}
if (p != null) {
updateParallel(p, targets);
} else if (inv != null) {
String ttype = inv.getTargettype();
if (ttype == null || ttype.trim().length() == 0) {
logAndThrowModelError(ERR_INVOKE_NO_TARGETTYPE,
new Object[] {getStateName(s)});
}
String src = inv.getSrc();
boolean noSrc = (src == null || src.trim().length() == 0);
String srcexpr = inv.getSrcexpr();
boolean noSrcexpr = (srcexpr == null
|| srcexpr.trim().length() == 0);
if (noSrc && noSrcexpr) {
logAndThrowModelError(ERR_INVOKE_NO_SRC,
new Object[] {getStateName(s)});
}
if (!noSrc && !noSrcexpr) {
logAndThrowModelError(ERR_INVOKE_AMBIGUOUS_SRC,
new Object[] {getStateName(s)});
}
} else {
Iterator j = c.keySet().iterator();
while (j.hasNext()) {
TransitionTarget tt = (TransitionTarget) c.get(j.next());
if (tt instanceof State) {
updateState((State) tt, targets);
} else if (tt instanceof Parallel) {
updateParallel((Parallel) tt, targets);
}
}
}
}
/**
* Update this Parallel object (part of post-digestion processing).
*
* @param p The Parallel object
* @param targets The global Map of all transition targets
* @throws ModelException If the object model is flawed
*/
private static void updateParallel(final Parallel p, final Map targets)
throws ModelException {
Iterator i = p.getChildren().iterator();
while (i.hasNext()) {
updateState((State) i.next(), targets);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -