Author: rahul Date: Sat Jan 16 00:10:18 2010 New Revision: 899849 URL: http://svn.apache.org/viewvc?rev=899849&view=rev Log: Parser post processing improvements: * Refactor the <history> post processing to correctly set up the default targets when a child of <parallel> (in addition to when a child of <state>) * Add a more generic getName() method rather than the state specific getStateName()
Modified: commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java Modified: commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java?rev=899849&r1=899848&r2=899849&view=diff ============================================================================== --- commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java (original) +++ commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java Sat Jan 16 00:10:18 2010 @@ -17,6 +17,7 @@ package org.apache.commons.scxml.io; import java.text.MessageFormat; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -94,7 +95,7 @@ if (!c.isEmpty()) { if (ini == null) { logAndThrowModelError(ERR_STATE_NO_INIT, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } Transition initialTransition = ini.getTransition(); updateTransition(initialTransition, targets); @@ -103,72 +104,36 @@ //check that initialState is a descendant of s if (initialStates.size() == 0) { logAndThrowModelError(ERR_STATE_BAD_INIT, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } else { for (TransitionTarget initialState : initialStates) { if (!SCXMLHelper.isDescendant(initialState, s)) { logAndThrowModelError(ERR_STATE_BAD_INIT, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } } } } List<History> histories = s.getHistory(); + if (histories.size() > 0 && s.isSimple()) { + logAndThrowModelError(ERR_HISTORY_SIMPLE_STATE, + new Object[] {getName(s)}); + } for (History h : histories) { - if (s.isSimple()) { - logAndThrowModelError(ERR_HISTORY_SIMPLE_STATE, - new Object[] {getStateName(s)}); - } - Transition historyTransition = h.getTransition(); - if (historyTransition == null) { - // try to assign initial as default - if (initialStates != null && initialStates.size() > 0) { - for (TransitionTarget tt : initialStates) { - if (tt 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<TransitionTarget> historyStates = historyTransition.getTargets(); - if (historyStates.size() == 0) { - logAndThrowModelError(ERR_STATE_NO_HIST, - new Object[] {getStateName(s)}); - } - for (TransitionTarget historyState : historyStates) { - 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)}); - } - } - } + updateHistory(h, s.getChildren().values(), targets, s); } for (Transition trn : s.getTransitionsList()) { updateTransition(trn, targets); } Invoke inv = s.getInvoke(); if (inv != null && !c.isEmpty()) { - logAndThrowModelError(ERR_STATE_BAD_CONTENTS, new Object[] {getStateName(s)}); + logAndThrowModelError(ERR_STATE_BAD_CONTENTS, new Object[] {getName(s)}); } if (inv != null) { String type = inv.getType(); if (type == null || type.trim().length() == 0) { logAndThrowModelError(ERR_INVOKE_NO_TYPE, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } String src = inv.getSrc(); boolean noSrc = (src == null || src.trim().length() == 0); @@ -177,11 +142,11 @@ || srcexpr.trim().length() == 0); if (noSrc && noSrcexpr) { logAndThrowModelError(ERR_INVOKE_NO_SRC, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } if (!noSrc && !noSrcexpr) { logAndThrowModelError(ERR_INVOKE_AMBIGUOUS_SRC, - new Object[] {getStateName(s)}); + new Object[] {getName(s)}); } } else { for (TransitionTarget tt : c.values()) { @@ -209,6 +174,73 @@ for (Transition trn : p.getTransitionsList()) { updateTransition(trn, targets); } + List<History> histories = p.getHistory(); + for (History h : histories) { + updateHistory(h, p.getChildren(), targets, p); + } + } + + /** + * Update this History object (part of post-digestion processing). + * + * @param h The History object + * @param defaults The default history targets + * @param targets The global Map of all transition targets + * @param parent The parent TransitionTarget for this History + * @throws ModelException If the object model is flawed + */ + private static void updateHistory(final History h, + final Collection<TransitionTarget> defaults, + final Map<String, TransitionTarget> targets, + final TransitionTarget parent) + throws ModelException { + Transition historyTransition = h.getTransition(); + if (historyTransition == null) { + // try to assign defaults + if (defaults != null && defaults.size() > 0) { + for (TransitionTarget tt : defaults) { + if (tt instanceof History) { + logAndThrowModelError(ERR_HISTORY_BAD_DEFAULT, + new Object[] {h.getId(), getName(parent)}); + } + } + historyTransition = new Transition(); + historyTransition.getTargets().addAll(defaults); + h.setTransition(historyTransition); + } else { + logAndThrowModelError(ERR_HISTORY_NO_DEFAULT, + new Object[] {h.getId(), getName(parent)}); + } + } + updateTransition(historyTransition, targets); + List<TransitionTarget> historyStates = historyTransition.getTargets(); + if (historyStates.size() == 0) { + logAndThrowModelError(ERR_STATE_NO_HIST, + new Object[] {getName(parent)}); + } + for (TransitionTarget historyState : historyStates) { + if (!h.isDeep()) { + // Shallow history + boolean shallow = false; + if (parent instanceof State) { + shallow = ((State) parent).getChildren(). + containsValue(historyState); + } else if (parent instanceof Parallel) { + shallow = ((Parallel) parent).getChildren(). + contains(historyState); + } + if (!shallow) { + logAndThrowModelError(ERR_STATE_BAD_SHALLOW_HIST, + new Object[] {getName(parent)}); + } + } else { + // Deep history + if (!SCXMLHelper.isDescendant(historyState, parent)) { + logAndThrowModelError(ERR_STATE_BAD_DEEP_HIST, + new Object[] {getName(parent)}); + } + } + } } /** @@ -266,19 +298,31 @@ } /** - * Get state identifier for error message. This method is only - * called to produce an appropriate log message in some error + * Get a transition target identifier for error messages. This method is + * only called to produce an appropriate log message in some error * conditions. * - * @param state The <code>State</code> object - * @return The state identifier for the error message + * @param tt The <code>TransitionTarget</code> object + * @return The transition target identifier for the error message */ - private static String getStateName(final State state) { - String badState = "anonymous state"; - if (!SCXMLHelper.isStringEmpty(state.getId())) { - badState = "state with ID \"" + state.getId() + "\""; + private static String getName(final TransitionTarget tt) { + String name = "anonymous transition target"; + if (tt instanceof State) { + name = "anonymous state"; + if (!SCXMLHelper.isStringEmpty(tt.getId())) { + name = "state with ID \"" + tt.getId() + "\""; + } + } else if (tt instanceof Parallel) { + name = "anonymous parallel"; + if (!SCXMLHelper.isStringEmpty(tt.getId())) { + name = "parallel with ID \"" + tt.getId() + "\""; + } + } else { + if (!SCXMLHelper.isStringEmpty(tt.getId())) { + name = "transition target with ID \"" + tt.getId() + "\""; + } } - return badState; + return name; } /**