Author: ate
Date: Mon Apr 21 19:36:00 2014
New Revision: 1588973
URL: http://svn.apache.org/r1588973
Log:
SCXML-203: Calculation of states to be entered can be depending on states to be
exited and thereby also their possible history
- fixing this bug by temporarily pre-recording the histories of exited states
in the Step
- this allows to still ensure that the resulting active states represent a
valid configuration, before actually taking the step
- also cleanup and improve the naming of the state history management APIs
Modified:
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
Modified:
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
URL:
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java?rev=1588973&r1=1588972&r2=1588973&view=diff
==============================================================================
---
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
(original)
+++
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/SCInstance.java
Mon Apr 21 19:36:00 2014
@@ -17,6 +17,7 @@
package org.apache.commons.scxml2;
import java.io.Serializable;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -437,8 +438,7 @@ public class SCInstance implements Seria
public Set<EnterableState> getLastConfiguration(final History history) {
Set<EnterableState> lastConfiguration = histories.get(history);
if (lastConfiguration == null) {
- lastConfiguration = new HashSet<EnterableState>();
- histories.put(history, lastConfiguration);
+ lastConfiguration = Collections.emptySet();
}
return lastConfiguration;
}
@@ -451,20 +451,7 @@ public class SCInstance implements Seria
*/
public void setLastConfiguration(final History history,
final Set<EnterableState> lc) {
- Set<EnterableState> lastConfiguration = getLastConfiguration(history);
- lastConfiguration.clear();
- lastConfiguration.addAll(lc);
- }
-
- /**
- * Check whether we have prior history.
- *
- * @param history The history.
- * @return Whether we have a non-empty last configuration
- */
- public boolean isEmpty(final History history) {
- Set<EnterableState> lastConfiguration = histories.get(history);
- return lastConfiguration == null || lastConfiguration.isEmpty();
+ histories.put(history, new HashSet<EnterableState>(lc));
}
/**
@@ -474,11 +461,8 @@ public class SCInstance implements Seria
*
* @param history The history.
*/
- public void reset(final History history) {
- Set<EnterableState> lastConfiguration = histories.get(history);
- if (lastConfiguration != null) {
- lastConfiguration.clear();
- }
+ public void resetConfiguration(final History history) {
+ histories.remove(history);
}
}
Modified:
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
URL:
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java?rev=1588973&r1=1588972&r2=1588973&view=diff
==============================================================================
---
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
(original)
+++
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/SCXMLSemanticsImpl.java
Mon Apr 21 19:36:00 2014
@@ -248,6 +248,7 @@ public class SCXMLSemanticsImpl implemen
exitStates(exctx, step, statesToInvoke);
executeTransitionContent(exctx, step);
enterStates(exctx, step, statesToInvoke);
+ step.clearIntermediateState();
}
/**
@@ -258,14 +259,11 @@ public class SCXMLSemanticsImpl implemen
* @throws ModelException if the result of taking the transitions would
lead to an illegal configuration
*/
public void buildStep(final SCXMLExecutionContext exctx, final Step step)
throws ModelException {
- step.getExitSet().clear();
- step.getEntrySet().clear();
- step.getDefaultEntrySet().clear();
- step.getDefaultHistoryTransitionEntryMap().clear();
+ step.clearIntermediateState();
- // compute exitSet, if there is something to exit
+ // compute exitSet, if there is something to exit and record their
History configurations if applicable
if (!exctx.getScInstance().getCurrentStatus().getStates().isEmpty()) {
- computeExitSet(step,
exctx.getScInstance().getCurrentStatus().getAllStates());
+ computeExitSet(step, exctx.getScInstance().getCurrentStatus());
}
// compute entrySet
computeEntrySet(exctx, step);
@@ -339,11 +337,15 @@ public class SCXMLSemanticsImpl implemen
* This method corresponds to the Algorithm for SCXML processing
computeExitSet() procedure.
* <p>
* @param step The step containing the list of transitions to be taken
- * @param configuration The current configuration of the state machine
({@link Status#getAllStates()}).
+ * @param currentStatus The current status of the state machine ({@link
SCInstance#getCurrentStatus()}).
*/
- public void computeExitSet(final Step step, final Set<EnterableState>
configuration) {
- for (SimpleTransition st : step.getTransitList()) {
- computeExitSet(st, step.getExitSet(), configuration);
+ public void computeExitSet(final Step step, final Status currentStatus) {
+ if (!currentStatus.getStates().isEmpty()) {
+ Set<EnterableState> configuration = currentStatus.getAllStates();
+ for (SimpleTransition st : step.getTransitList()) {
+ computeExitSet(st, step.getExitSet(), configuration);
+ }
+ recordHistory(step, currentStatus.getStates(), configuration);
}
}
@@ -374,6 +376,52 @@ public class SCXMLSemanticsImpl implemen
}
/**
+ * Record the history configurations for states to exit if applicable and
temporarily store this in the step.
+ * <p>
+ * These history configurations must be pre-recorded as they might impact
(re)entrance calculation during
+ * {@link #computeEntrySet(SCXMLExecutionContext, Step)}.
+ * </p>
+ * <p>
+ * Only after the new configuration has been validated (see: {@link
#isLegalConfig(Set, ErrorReporter)}), the
+ * history configurations will be persisted during the actual {@link
#exitStates(SCXMLExecutionContext, Step, Set)}
+ * processing.
+ * </p>
+ * @param step The step containing the list of states to exit, and the map
to record the new history configurations
+ * @param states The current set of active atomic states in the state
machine
+ * @param allStates The current set of all active states in the state
machine
+ */
+ public void recordHistory(final Step step, final Set<EnterableState>
states, final Set<EnterableState> allStates) {
+ for (EnterableState es : step.getExitSet()) {
+ if (es instanceof TransitionalState &&
((TransitionalState)es).hasHistory()) {
+ TransitionalState ts = (TransitionalState)es;
+ Set<EnterableState> shallow = null;
+ Set<EnterableState> deep = null;
+ for (History h : ts.getHistory()) {
+ if (h.isDeep()) {
+ if (deep == null) {
+ //calculate deep history for a given state once
+ deep = new HashSet<EnterableState>();
+ for (EnterableState ott : states) {
+ if (ott.isDescendantOf(es)) {
+ deep.add(ott);
+ }
+ }
+ }
+ step.getNewHistoryConfigurations().put(h, deep);
+ } else {
+ if (shallow == null) {
+ //calculate shallow history for a given state once
+ shallow = new
HashSet<EnterableState>(ts.getChildren());
+ shallow.retainAll(allStates);
+ }
+ step.getNewHistoryConfigurations().put(h, shallow);
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Compute and store the set of states to enter for the current list of
transitions in the provided step.
* <p>
* This method corresponds to the Algorithm for SCXML processing
computeEntrySet() procedure.
@@ -420,14 +468,18 @@ public class SCXMLSemanticsImpl implemen
final TransitionTarget tt) {
if (tt instanceof History) {
History h = (History) tt;
- if (exctx.getScInstance().isEmpty(h)) {
- step.getDefaultHistoryTransitionEntryMap().put(h.getParent(),
h.getTransition());
+ Set<EnterableState> lastConfiguration =
step.getNewHistoryConfigurations().get(h);
+ if (lastConfiguration == null) {
+ lastConfiguration =
exctx.getScInstance().getLastConfiguration(h);
+ }
+ if (lastConfiguration.isEmpty()) {
+ step.getDefaultHistoryTransitions().put(h.getParent(),
h.getTransition());
for (TransitionTarget dtt : h.getTransition().getTargets()) {
addDescendantStatesToEnter(exctx, step, dtt);
addAncestorStatesToEnter(exctx, step, dtt, tt.getParent());
}
} else {
- for (TransitionTarget dtt :
exctx.getScInstance().getLastConfiguration(h)) {
+ for (TransitionTarget dtt : lastConfiguration) {
addDescendantStatesToEnter(exctx, step, dtt);
addAncestorStatesToEnter(exctx, step, dtt, tt.getParent());
}
@@ -841,39 +893,15 @@ public class SCXMLSemanticsImpl implemen
if (step.getExitSet().isEmpty()) {
return;
}
- Set<EnterableState> configuration = null;
ArrayList<EnterableState> exitList = new
ArrayList<EnterableState>(step.getExitSet());
Collections.sort(exitList,
DocumentOrder.reverseDocumentOrderComparator);
for (EnterableState es : exitList) {
if (es instanceof TransitionalState &&
((TransitionalState)es).hasHistory()) {
- TransitionalState ts = (TransitionalState)es;
- Set<EnterableState> shallow = null;
- Set<EnterableState> deep = null;
- for (History h : ts.getHistory()) {
- if (h.isDeep()) {
- if (deep == null) {
- //calculate deep history for a given state once
- deep = new HashSet<EnterableState>();
- for (EnterableState ott :
exctx.getScInstance().getCurrentStatus().getStates()) {
- if (ott.isDescendantOf(es)) {
- deep.add(ott);
- }
- }
- }
- exctx.getScInstance().setLastConfiguration(h, deep);
- } else {
- if (shallow == null) {
- //calculate shallow history for a given state once
- if (configuration == null) {
- configuration =
exctx.getScInstance().getCurrentStatus().getAllStates();
- }
- shallow = new
HashSet<EnterableState>(ts.getChildren());
- shallow.retainAll(configuration);
- }
- exctx.getScInstance().setLastConfiguration(h, shallow);
- }
+ // persist the new history configurations for this state to
exit
+ for (History h : ((TransitionalState)es).getHistory()) {
+ exctx.getScInstance().setLastConfiguration(h,
step.getNewHistoryConfigurations().get(h));
}
}
@@ -977,7 +1005,7 @@ public class SCXMLSemanticsImpl implemen
Collections.sort(entryList, DocumentOrder.documentOrderComparator);
for (EnterableState es : entryList) {
if (es.isAtomicState()) {
- // only track actomic active states in Status
+ // only track atomic active states in Status
exctx.getScInstance().getCurrentStatus().getStates().add(es);
}
if (es instanceof TransitionalState &&
!((TransitionalState)es).getInvokes().isEmpty()) {
@@ -999,7 +1027,7 @@ public class SCXMLSemanticsImpl implemen
executeContent(exctx,
((State)es).getInitial().getTransition());
}
if (es instanceof TransitionalState) {
- SimpleTransition hTransition =
step.getDefaultHistoryTransitionEntryMap().get(es);
+ SimpleTransition hTransition =
step.getDefaultHistoryTransitions().get(es);
if (hTransition != null) {
executeContent(exctx, hTransition);
}
Modified:
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java
URL:
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java?rev=1588973&r1=1588972&r2=1588973&view=diff
==============================================================================
---
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java
(original)
+++
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/semantics/Step.java
Mon Apr 21 19:36:00 2014
@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.scxml2.TriggerEvent;
import org.apache.commons.scxml2.model.EnterableState;
+import org.apache.commons.scxml2.model.History;
import org.apache.commons.scxml2.model.SimpleTransition;
import org.apache.commons.scxml2.model.TransitionalState;
@@ -54,7 +55,16 @@ public class Step {
*/
private Set<EnterableState> defaultEntrySet;
- private Map<TransitionalState, SimpleTransition>
defaultHistoryTransitionEntryMap;
+ /**
+ * The map of default History transitions to be executed as result of
entering states in this step.
+ */
+ private Map<TransitionalState, SimpleTransition> defaultHistoryTransitions;
+
+ /**
+ * The map of new History configurations created as result of exiting
states in this step
+ */
+ private Map<History, Set<EnterableState>> newHistoryConfigurations;
+
/**
* The list of Transitions taken during this step.
*/
@@ -68,11 +78,23 @@ public class Step {
this.exitSet = new HashSet<EnterableState>();
this.entrySet = new HashSet<EnterableState>();
this.defaultEntrySet = new HashSet<EnterableState>();
- this.defaultHistoryTransitionEntryMap = new HashMap<TransitionalState,
SimpleTransition>();
+ this.defaultHistoryTransitions = new HashMap<TransitionalState,
SimpleTransition>();
+ this.newHistoryConfigurations = new HashMap<History,
Set<EnterableState>>();
this.transitList = new ArrayList<SimpleTransition>();
}
/**
+ * Ensure the intermediate state of this step is cleared before start
processing the event and/or transitions
+ */
+ public void clearIntermediateState() {
+ exitSet.clear();
+ entrySet.clear();
+ defaultEntrySet.clear();
+ defaultHistoryTransitions.clear();
+ newHistoryConfigurations.clear();
+ }
+
+ /**
* @return Returns the entrySet.
*/
public Set<EnterableState> getEntrySet() {
@@ -87,10 +109,17 @@ public class Step {
}
/**
- * @return Returns the defaultHistoryTransitionEntryMap.
+ * @return Returns the map of default History transitions to be executed
as result of entering states in this step
+ */
+ public Map<TransitionalState, SimpleTransition>
getDefaultHistoryTransitions() {
+ return defaultHistoryTransitions;
+ }
+
+ /**
+ * @return Returns the map of new History configurations created as result
of exiting states in this step
*/
- public Map<TransitionalState, SimpleTransition>
getDefaultHistoryTransitionEntryMap() {
- return defaultHistoryTransitionEntryMap;
+ public Map<History, Set<EnterableState>> getNewHistoryConfigurations() {
+ return newHistoryConfigurations;
}
/**
Modified:
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java?rev=1588973&r1=1588972&r2=1588973&view=diff
==============================================================================
---
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
(original)
+++
commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/SCInstanceTest.java
Mon Apr 21 19:36:00 2014
@@ -144,7 +144,7 @@ public class SCInstanceTest {
@Test
public void testIsEmpty() {
- Assert.assertTrue(instance.isEmpty(new History()));
+ Assert.assertTrue(instance.getLastConfiguration(new
History()).isEmpty());
}
@Test
@@ -158,7 +158,7 @@ public class SCInstanceTest {
instance.setLastConfiguration(history, configuration);
- Assert.assertFalse(instance.isEmpty(history));
+ Assert.assertFalse(instance.getLastConfiguration(history).isEmpty());
}
@Test
@@ -172,9 +172,9 @@ public class SCInstanceTest {
instance.setLastConfiguration(history, configuration);
- instance.reset(history);
+ instance.resetConfiguration(history);
- Assert.assertTrue(instance.isEmpty(history));
+ Assert.assertTrue(instance.getLastConfiguration(history).isEmpty());
}
}