Repository: commons-scxml Updated Branches: refs/heads/master de735810f -> 251bf6b18
fix EffectiveContextMap.entrySet using parent first merging of variables to ensure local variables 'shadow' parent variables Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/251bf6b1 Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/251bf6b1 Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/251bf6b1 Branch: refs/heads/master Commit: 251bf6b18f83b8391ef3dfe83157ef5c51148fea Parents: de73581 Author: Ate Douma <[email protected]> Authored: Sat Jan 2 15:12:21 2016 +0100 Committer: Ate Douma <[email protected]> Committed: Sat Jan 2 15:12:21 2016 +0100 ---------------------------------------------------------------------- .../commons/scxml2/env/EffectiveContextMap.java | 31 +++++++--- .../commons/scxml2/env/SimpleContextTest.java | 63 +++++++++++++++----- 2 files changed, 71 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/251bf6b1/src/main/java/org/apache/commons/scxml2/env/EffectiveContextMap.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/scxml2/env/EffectiveContextMap.java b/src/main/java/org/apache/commons/scxml2/env/EffectiveContextMap.java index 0640062..127cb6f 100644 --- a/src/main/java/org/apache/commons/scxml2/env/EffectiveContextMap.java +++ b/src/main/java/org/apache/commons/scxml2/env/EffectiveContextMap.java @@ -18,7 +18,9 @@ package org.apache.commons.scxml2.env; import java.io.Serializable; import java.util.AbstractMap; -import java.util.HashSet; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.apache.commons.scxml2.Context; @@ -40,6 +42,13 @@ public final class EffectiveContextMap extends AbstractMap<String, Object> imple */ public EffectiveContextMap(final Context ctx) { super(); + Context current = ctx; + while (current != null) { + if (current.getVars() instanceof EffectiveContextMap) { + throw new IllegalArgumentException("Context or parent Context already wrapped by EffectiveContextMap"); + } + current = current.getParent(); + } this.leaf = ctx; } @@ -48,13 +57,21 @@ public final class EffectiveContextMap extends AbstractMap<String, Object> imple */ @Override public Set<Entry<String, Object>> entrySet() { - Set<Entry<String, Object>> entrySet = new HashSet<Entry<String, Object>>(); - Context current = leaf; - while (current != null) { - entrySet.addAll(current.getVars().entrySet()); - current = current.getParent(); + Map<String, Object> map = new HashMap<>(); + mergeVars(leaf, map); + return Collections.unmodifiableMap(map).entrySet(); + } + + /** + * Parent Context first merging of all Context vars, to ensure same named 'local' vars shadows parent var + * @param leaf current leaf Context + * @param map Map to merge vars into + */ + protected void mergeVars(Context leaf, Map<String, Object> map) { + if (leaf != null) { + mergeVars(leaf.getParent(), map); + map.putAll(leaf.getVars()); } - return entrySet; } /** http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/251bf6b1/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java b/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java index 32fe49a..f3ab7b9 100644 --- a/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java +++ b/src/test/java/org/apache/commons/scxml2/env/SimpleContextTest.java @@ -34,7 +34,7 @@ public class SimpleContextTest { @Test public void testHasTrue() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -44,7 +44,7 @@ public class SimpleContextTest { @Test public void testHasNullParent() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -54,12 +54,12 @@ public class SimpleContextTest { @Test public void testHasParentWrongKey() { - Map<String, Object> parentVars = new HashMap<String, Object>(); + Map<String, Object> parentVars = new HashMap<>(); parentVars.put("key", "value"); SimpleContext parentContext = new SimpleContext(null, parentVars); - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -70,12 +70,12 @@ public class SimpleContextTest { @Test public void testHasParentCorrectKey() { - Map<String, Object> parentVars = new HashMap<String, Object>(); + Map<String, Object> parentVars = new HashMap<>(); parentVars.put("differentKey", "value"); SimpleContext parentContext = new SimpleContext(null, parentVars); - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -93,7 +93,7 @@ public class SimpleContextTest { @Test public void testGetValue() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -103,12 +103,12 @@ public class SimpleContextTest { @Test public void testGetParentValue() { - Map<String, Object> parentVars = new HashMap<String, Object>(); + Map<String, Object> parentVars = new HashMap<>(); parentVars.put("differentKey", "differentValue"); SimpleContext parentContext = new SimpleContext(null, parentVars); - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -119,7 +119,7 @@ public class SimpleContextTest { @Test public void testGetParentNull() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -129,12 +129,12 @@ public class SimpleContextTest { @Test public void testGetParentWrongValue() { - Map<String, Object> parentVars = new HashMap<String, Object>(); + Map<String, Object> parentVars = new HashMap<>(); parentVars.put("differentKey", "differentValue"); SimpleContext parentContext = new SimpleContext(null, parentVars); - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -145,7 +145,7 @@ public class SimpleContextTest { @Test public void testSetVarsChangeValue() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -157,7 +157,7 @@ public class SimpleContextTest { @Test public void testSetVarsEmpty() { - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); context.setVars(vars); context.set("key", "newValue"); @@ -167,12 +167,12 @@ public class SimpleContextTest { @Test public void testSetVarsParent() { - Map<String, Object> parentVars = new HashMap<String, Object>(); + Map<String, Object> parentVars = new HashMap<>(); parentVars.put("differentKey", "differentValue"); SimpleContext parentContext = new SimpleContext(null, parentVars); - Map<String, Object> vars = new HashMap<String, Object>(); + Map<String, Object> vars = new HashMap<>(); vars.put("key", "value"); context.setVars(vars); @@ -182,4 +182,35 @@ public class SimpleContextTest { Assert.assertEquals("newValue", context.get("differentKey")); } + + @Test + public void testNestedEffectiveContextMapWrappingFails() { + SimpleContext rootContext = new SimpleContext(); + rootContext.set("key", "root"); + SimpleContext rootEffectiveContext = new SimpleContext(rootContext, new EffectiveContextMap(rootContext)); + SimpleContext parentContext = new SimpleContext(rootEffectiveContext); + try { + new EffectiveContextMap(parentContext); + Assert.fail("Nested EffectiveContextMap wrapping should fail"); + } + catch (IllegalArgumentException e) { + // good + } + } + + @Test + public void testEffectiveContextMapMergeStragegy() { + SimpleContext rootContext = new SimpleContext(); + rootContext.set("key", "root"); + SimpleContext parentContext = new SimpleContext(rootContext); + parentContext.setLocal("key", "parent"); + SimpleContext effectiveContext = new SimpleContext(parentContext, new EffectiveContextMap(parentContext)); + Assert.assertEquals("parent", effectiveContext.get("key")); + // ensure EffectiveContextMap provides complete local variable shadowing + for (Map.Entry<String,Object> entry : effectiveContext.getVars().entrySet()) { + if (entry.getKey().equals("key")) { + Assert.assertEquals("parent", entry.getValue()); + } + } + } }
