Fix memento/rebind of AbstractController

- serverPoolTargets has entities as keys, so needed to fix
  MementoTransformer.transformIdsToEntities so it converted
  keys and values correctly.
- Can revisit this in the future for instead using serialised
  form of an entity-ref, rather than just String perhaps.


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e5d21855
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e5d21855
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e5d21855

Branch: refs/heads/0.5.0
Commit: e5d2185546a40281d7f5117c85a82f4568a4d210
Parents: 64da3fc
Author: Aled Sage <[email protected]>
Authored: Wed Apr 10 13:01:17 2013 +0100
Committer: Aled Sage <[email protected]>
Committed: Wed Apr 10 14:34:36 2013 +0100

----------------------------------------------------------------------
 .../entity/rebind/MementoTransformer.java       |  69 ++++++++----
 .../entity/rebind/MementoTransformerTest.java   | 107 +++++++++++++++++++
 2 files changed, 157 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e5d21855/core/src/main/java/brooklyn/entity/rebind/MementoTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/MementoTransformer.java 
b/core/src/main/java/brooklyn/entity/rebind/MementoTransformer.java
index 493b5c2..1706138 100644
--- a/core/src/main/java/brooklyn/entity/rebind/MementoTransformer.java
+++ b/core/src/main/java/brooklyn/entity/rebind/MementoTransformer.java
@@ -15,6 +15,7 @@ import brooklyn.location.Location;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
 
 /**
  * Helpers for transforming references to locations into location ids, and 
vice versa.
@@ -99,29 +100,35 @@ public class MementoTransformer {
             throw new IllegalStateException("Cannot transform ids to locations 
of type "+requiredType);
         }
     }
-    
+
     public static <T> T transformIdsToEntities(RebindContext rebindContext, 
Object value, Class<T> requiredType, boolean removeDanglingRefs) {
+        return transformIdsToEntities(rebindContext, value, 
TypeToken.of(requiredType), removeDanglingRefs);
+    }
+    
+    public static <T> T transformIdsToEntities(RebindContext rebindContext, 
Object value, TypeToken<T> requiredType, boolean removeDanglingRefs) {
+        Class<? super T> requiredRawType = requiredType.getRawType();
+        
         if (value == null) {
             return null;
             
-        } else if (Entity.class.isAssignableFrom(requiredType)) {
+        } else if (Entity.class.isAssignableFrom(requiredRawType)) {
             Entity entity = rebindContext.getEntity((String)value);
             if (entity == null) {
                 if (removeDanglingRefs) {
-                    LOG.warn("No entity found for "+value+"; return null for 
"+requiredType.getSimpleName());
+                    LOG.warn("No entity found for "+value+"; return null for 
"+requiredRawType.getSimpleName());
                 } else {
                     throw new IllegalStateException("No entity found for 
"+value);
                 }
             }
             return (T) entity;
             
-        } else if (Iterable.class.isAssignableFrom(requiredType)) {
+        } else if (Iterable.class.isAssignableFrom(requiredRawType)) {
             Collection<Entity> result = Lists.newArrayList();
             for (String id : (Iterable<String>)value) {
                 Entity entity = rebindContext.getEntity(id);
                 if (entity == null) {
                     if (removeDanglingRefs) {
-                        LOG.warn("No entity found for "+id+"; discarding 
reference from "+requiredType.getSimpleName());
+                        LOG.warn("No entity found for "+id+"; discarding 
reference from "+requiredRawType.getSimpleName());
                     } else {
                         throw new IllegalStateException("No entity found for 
"+id);
                     }
@@ -130,7 +137,7 @@ public class MementoTransformer {
                 }
             }
 
-            if (Set.class.isAssignableFrom(requiredType)) {
+            if (Set.class.isAssignableFrom(requiredRawType)) {
                 result = Sets.newLinkedHashSet(result);
             }
             if (!requiredType.isAssignableFrom(result.getClass())) {
@@ -139,19 +146,41 @@ public class MementoTransformer {
             return (T) result;
                 
         } else if (value instanceof Map) {
-            Map<Object,Entity> result = Maps.newLinkedHashMap();
-            for (Map.Entry<?, String> entry : 
((Map<?,String>)value).entrySet()) {
-                String id = entry.getValue();
-                Entity entity = rebindContext.getEntity(id);
-                if (entity == null) {
-                    if (removeDanglingRefs) {
-                        LOG.warn("No entity found for "+id+"; discarding 
reference from "+requiredType.getSimpleName());
-                    } else {
-                        throw new IllegalStateException("No entity found for 
"+id);
+            // If told explicitly the generics, then use that; but otherwise 
default to the value being of type Entity
+            TypeToken<?> keyType = 
requiredType.resolveType(Map.class.getTypeParameters()[0]);
+            TypeToken<?> valueType = 
requiredType.resolveType(Map.class.getTypeParameters()[1]);
+            boolean keyIsEntity = 
Entity.class.isAssignableFrom(keyType.getRawType());
+            boolean valueIsEntity = 
Entity.class.isAssignableFrom(valueType.getRawType()) || !keyIsEntity;
+            
+            Map<Object,Object> result = Maps.newLinkedHashMap();
+            for (Map.Entry<?, ?> entry : ((Map<?,?>)value).entrySet()) {
+                Object key = entry.getKey();
+                Object val = entry.getValue();
+                
+                if (keyIsEntity) {
+                    key = rebindContext.getEntity((String)key);
+                    if (key == null) {
+                        if (removeDanglingRefs) {
+                            LOG.warn("No entity found for "+entry.getKey()+"; 
discarding reference from "+requiredRawType.getSimpleName());
+                            continue;
+                        } else {
+                            throw new IllegalStateException("No entity found 
for "+entry.getKey());
+                        }
                     }
-                } else {
-                    result.put(entry.getKey(), entity);
                 }
+                if (valueIsEntity) {
+                    val = rebindContext.getEntity((String)val);
+                    if (val == null) {
+                        if (removeDanglingRefs) {
+                            LOG.warn("No entity found for 
"+entry.getValue()+"; discarding reference from 
"+requiredRawType.getSimpleName());
+                            continue;
+                        } else {
+                            throw new IllegalStateException("No entity found 
for "+entry.getValue());
+                        }
+                    }
+                }
+                
+                result.put(key, val);
             }
             
             if (!requiredType.isAssignableFrom(LinkedHashMap.class)) {
@@ -232,13 +261,15 @@ public class MementoTransformer {
     }
 
     private static Map<?,?> transformEntitiesToIds(Map<?,?> vs) {
-        if (containsType(vs.values(), Entity.class)) {
+        if (containsType(vs.values(), Entity.class) || 
containsType(vs.keySet(), Entity.class)) {
             // requires transforming for serialization
             Map<Object,Object> result = Maps.newLinkedHashMap();
             for (Map.Entry<?,?> entry : vs.entrySet()) {
                 Object k = entry.getKey();
                 Object v = entry.getValue();
-                result.put(k, ((Entity)v).getId());
+                Object k2 = (k instanceof Entity) ? ((Entity)k).getId() : k;
+                Object v2 = (v instanceof Entity) ? ((Entity)v).getId() : v;
+                result.put(k2, v2);
             }
             return result;
         } else {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e5d21855/core/src/test/java/brooklyn/entity/rebind/MementoTransformerTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/brooklyn/entity/rebind/MementoTransformerTest.java 
b/core/src/test/java/brooklyn/entity/rebind/MementoTransformerTest.java
new file mode 100644
index 0000000..3a2237b
--- /dev/null
+++ b/core/src/test/java/brooklyn/entity/rebind/MementoTransformerTest.java
@@ -0,0 +1,107 @@
+package brooklyn.entity.rebind;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.location.Location;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.test.entity.TestEntityImpl;
+import brooklyn.util.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+public class MementoTransformerTest {
+
+    private Entity entity;
+    private RebindContextImpl rebindContext;
+    private SshMachineLocation location;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        location = new SshMachineLocation(MutableMap.of("address", 
"localhost"));
+        entity = new TestEntityImpl();
+        rebindContext = new 
RebindContextImpl(MementoTransformerTest.class.getClassLoader());
+        rebindContext.registerLocation(location.getId(), location);
+        rebindContext.registerEntity(entity.getId(), entity);
+    }
+    
+    @Test
+    public void testTransformLocation() throws Exception {
+        assertTransformsLocationIds(location, Location.class);
+    }
+    
+    @Test
+    public void testTransformLocationSet() throws Exception {
+        assertTransformsLocationIds(ImmutableSet.of(location), Set.class);
+    }
+    
+    @Test
+    public void testTransformLocationList() throws Exception {
+        assertTransformsLocationIds(ImmutableList.of(location), List.class);
+    }
+    
+    @Test
+    public void testTransformLocationMaop() throws Exception {
+        assertTransformsLocationIds(ImmutableMap.of("a", location), Map.class);
+    }
+    
+    @Test
+    public void testTransformEntity() throws Exception {
+        assertTransformsEntityIds(entity, Entity.class);
+    }
+    
+    @Test
+    public void testTransformEntitySet() throws Exception {
+        assertTransformsEntityIds(ImmutableSet.of(entity), Set.class);
+    }
+    
+    @Test
+    public void testTransformEntityList() throws Exception {
+        assertTransformsEntityIds(ImmutableList.of(entity), List.class);
+    }
+    
+    @Test
+    public void testTransformMapWithEntityValueUsingClazz() throws Exception {
+        assertTransformsEntityIds(ImmutableMap.of("a", entity), Map.class);
+    }
+    
+    @SuppressWarnings("serial")
+    @Test
+    public void testTransformMapWithEntityValueUsingTypeToken() throws 
Exception {
+        assertTransformsEntityIds(ImmutableMap.of("a", entity), new 
TypeToken<Map<String,Entity>>() {});
+    }
+    
+    @SuppressWarnings("serial")
+    @Test
+    public void testTransformMapWithEntityKey() throws Exception {
+        assertTransformsEntityIds(ImmutableMap.of(entity, "a"), new 
TypeToken<Map<Entity,String>>() {});
+    }
+    
+    private void assertTransformsLocationIds(Object orig, Class<?> type) 
throws Exception {
+        Object transformed = MementoTransformer.transformLocationsToIds(orig);
+        Object result = 
MementoTransformer.transformIdsToLocations(rebindContext, transformed, type, 
true);
+        assertEquals(result, orig, "transformed="+transformed);
+    }
+    
+    private void assertTransformsEntityIds(Object orig, Class<?> type) throws 
Exception {
+        Object transformed = MementoTransformer.transformEntitiesToIds(orig);
+        Object result = 
MementoTransformer.transformIdsToEntities(rebindContext, transformed, type, 
true);
+        assertEquals(result, orig, "transformed="+transformed);
+    }
+    
+    private void assertTransformsEntityIds(Object orig, TypeToken<?> type) 
throws Exception {
+        Object transformed = MementoTransformer.transformEntitiesToIds(orig);
+        Object result = 
MementoTransformer.transformIdsToEntities(rebindContext, transformed, type, 
true);
+        assertEquals(result, orig, "transformed="+transformed);
+    }
+}

Reply via email to