fix EffectiveContextMap.entrySet using parent first merging of variables to ensure local variables 'shadow' parent variables
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 @@
 
 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 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 @@
      */
     @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;
     }
 
     /**
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 @@
     
     @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 @@
 
     @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 @@
     
     @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 @@
 
     @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 @@
     
     @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 @@
     
     @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 @@
     
     @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 @@
     
     @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 @@
 
     @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 @@
 
     @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 @@
     
     @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 @@
         
         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());
+            }
+        }
+    }
 }