Merge pull request #1419 from aledsage/fix/policy-persistence-20140527

Fixes in policy persistence (against branch feature/policy-persistence)
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index 4346be5..c80c9a7 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -27,7 +27,7 @@
         super(flags);
         enricherType = new EnricherTypeImpl(getAdjunctType());
         
-        if (isLegacyConstruction()) {
+        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
             init();
         }
     }
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
index 6ab1e58..4a5747c 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
@@ -32,12 +32,16 @@
 
         enricher.setName(memento.getDisplayName());
         
-        // FIXME Will this set config keys that are not marked with `@SetFromFlag`?
-        // Note that the flags may have been set in the constructor; but some have no-arg constructors
+        // TODO entity does config-lookup differently; the memento contains the config keys.
+        // BasicEntityMemento.postDeserialize uses the injectTypeClass to call EntityTypes.getDefinedConfigKeys(clazz)
+        // 
+        // Note that the flags may have been set in the constructor; but some enrichers have no-arg constructors
         ConfigBag configBag = ConfigBag.newInstance(memento.getConfig());
         FlagUtils.setFieldsFromFlags(enricher, configBag);
+        FlagUtils.setAllConfigKeys(enricher, configBag, false);
         
         doReconsruct(rebindContext, memento);
+        ((AbstractEnricher)enricher).rebind();
     }
 
 
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
index 5f32f7f..39202cb 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
@@ -31,13 +31,17 @@
         if (LOG.isTraceEnabled()) LOG.trace("Reconstructing policy: {}", memento.toVerboseString());
 
         policy.setName(memento.getDisplayName());
-        
-        // FIXME Will this set config keys that are not marked with `@SetFromFlag`?
-        // Note that the flags may have been set in the constructor; but some have no-arg constructors
+
+        // TODO entity does config-lookup differently; the memento contains the config keys.
+        // BasicEntityMemento.postDeserialize uses the injectTypeClass to call EntityTypes.getDefinedConfigKeys(clazz)
+        // 
+        // Note that the flags may have been set in the constructor; but some policies have no-arg constructors
         ConfigBag configBag = ConfigBag.newInstance(memento.getConfig());
         FlagUtils.setFieldsFromFlags(policy, configBag);
+        FlagUtils.setAllConfigKeys(policy, configBag, false);
         
         doReconsruct(rebindContext, memento);
+        ((AbstractPolicy)policy).rebind();
     }
 
     /**
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 1317bb2..f9e28f4 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -496,7 +496,10 @@
             // There are several possibilities for the constructor; find one that works.
             // Prefer passing in the flags because required for Application to set the management context
             // TODO Feels very hacky!
-            Map<String, Object> flags = MutableMap.<String, Object>of("id", id, "deferConstructionChecks", true);
+            Map<String, Object> flags = MutableMap.<String, Object>of(
+                    "id", id, 
+                    "deferConstructionChecks", true,
+                    "noConstructionInit", true);
             flags.putAll(memento.getConfig());
 
             return (Policy) invokeConstructor(reflections, policyClazz, new Object[] {flags});
@@ -525,7 +528,10 @@
             // There are several possibilities for the constructor; find one that works.
             // Prefer passing in the flags because required for Application to set the management context
             // TODO Feels very hacky!
-            Map<String, Object> flags = MutableMap.<String, Object>of("id", id, "deferConstructionChecks", true);
+            Map<String, Object> flags = MutableMap.<String, Object>of(
+                    "id", id, 
+                    "deferConstructionChecks", true,
+                    "noConstructionInit", true);
             flags.putAll(memento.getConfig());
 
             return (Enricher) invokeConstructor(reflections, enricherClazz, new Object[] {flags});
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BasicPolicyMemento.java b/core/src/main/java/brooklyn/entity/rebind/dto/BasicPolicyMemento.java
index 2b71ad3..795ea2e 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BasicPolicyMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicPolicyMemento.java
@@ -43,6 +43,7 @@
 
     // Trusts the builder to not mess around with mutability after calling build()
 	protected BasicPolicyMemento(Builder builder) {
+	    super(builder);
 	    config = toPersistedMap(builder.config);
 	}
 	
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index fd0dd02..8d3bc01 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -52,6 +52,7 @@
     protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
 
     private boolean _legacyConstruction;
+    private boolean _legacyNoConstructionInit;
     
     // TODO not sure if we need this -- never read
     @SuppressWarnings("unused")
@@ -87,6 +88,8 @@
     public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map flags) {
         inConstruction = true;
         _legacyConstruction = !InternalPolicyFactory.FactoryConstructionTracker.isConstructing();
+        _legacyNoConstructionInit = (flags != null) && Boolean.TRUE.equals(flags.get("noConstructionInit"));
+        
         if (!_legacyConstruction && flags!=null && !flags.isEmpty()) {
             log.debug("Using direct construction for "+getClass().getName()+" because properties were specified ("+flags+")");
             _legacyConstruction = true;
@@ -158,6 +161,15 @@
     protected boolean isLegacyConstruction() {
         return _legacyConstruction;
     }
+
+    /**
+     * Used for legacy-style policies/enrichers on rebind, to indicate that init() should not be called.
+     * Will likely be deleted in a future release; should not be called apart from by framework code.
+     */
+    @Beta
+    protected boolean isLegacyNoConstructionInit() {
+        return _legacyNoConstructionInit;
+    }
     
     public void setManagementContext(ManagementContext managementContext) {
         this.managementContext = managementContext;
@@ -168,7 +180,7 @@
     }
 
     /**
-     * Called by framework (in new-style policies where PolicySpec was used) after configuring, setting parent, etc,
+     * Called by framework (in new-style policies where PolicySpec was used) after configuring etc,
      * but before a reference to this policy is shared.
      * 
      * To preserve backwards compatibility for if the policy is constructed directly, one
@@ -186,6 +198,15 @@
         // no-op
     }
     
+    /**
+     * Called by framework (in new-style policies/enrichers where PolicySpec/EnricherSpec was used) on rebind, 
+     * after configuring but before {@link #setEntity(EntityLocal)} and before a reference to this policy is shared.
+     * Note that {@link #init()} will not be called on rebind.
+     */
+    public void rebind() {
+        // no-op
+    }
+    
     public <T> T getConfig(ConfigKey<T> key) {
         return configsInternal.getConfig(key);
     }
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
index 6be9544..c6b932c 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
@@ -40,7 +40,7 @@
         super(flags);
         policyType = new PolicyTypeImpl(getAdjunctType());
         
-        if (isLegacyConstruction()) {
+        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
             init();
         }
     }
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
new file mode 100644
index 0000000..f48a114
--- /dev/null
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@ -0,0 +1,186 @@
+package brooklyn.entity.rebind;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.Enrichers;
+import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.policy.EnricherSpec;
+import brooklyn.test.EntityTestUtils;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.text.StringFunctions;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class RebindEnricherTest extends RebindTestFixtureWithApp {
+
+    public static AttributeSensor<String> METRIC1 = Sensors.newStringSensor("RebindEnricherTest.metric1");
+    public static AttributeSensor<String> METRIC2 = Sensors.newStringSensor("RebindEnricherTest.metric2");
+    
+    private DynamicCluster origCluster;
+    private TestEntity origEntity;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        origCluster = origApp.createAndManageChild(EntitySpec.create(DynamicCluster.class).configure("memberSpec", EntitySpec.create(TestEntity.class)));
+        origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class));
+    }
+    
+    @Test
+    public void testPropagatingEnricher() throws Exception {
+        origApp.addEnricher(Enrichers.builder()
+                .propagating(METRIC1)
+                .from(origEntity)
+                .build());
+        
+        TestApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));
+
+        newEntity.setAttribute(METRIC1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(newApp, METRIC1, "myval");
+    }
+
+    @Test
+    public void testPropagatingAllEnricher() throws Exception {
+        origApp.addEnricher(Enrichers.builder()
+                .propagatingAll()
+                .from(origEntity)
+                .build());
+        
+        TestApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));
+
+        newEntity.setAttribute(METRIC1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(newApp, METRIC1, "myval");
+    }
+
+    @Test
+    public void testPropagatingAsEnricher() throws Exception {
+        origApp.addEnricher(Enrichers.builder()
+                .propagating(ImmutableMap.of(METRIC1, METRIC2))
+                .from(origEntity)
+                .build());
+        
+        TestApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));
+
+        newEntity.setAttribute(METRIC1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(newApp, METRIC2, "myval");
+    }
+
+    @Test
+    public void testCombiningEnricher() throws Exception {
+        origApp.addEnricher(Enrichers.builder()
+                .combining(METRIC1, METRIC2)
+                .from(origEntity)
+                .computing(StringFunctions.joiner(","))
+                .publishing(METRIC2)
+                .build());
+        
+        TestApplication newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));
+
+        newEntity.setAttribute(METRIC1, "myval");
+        newEntity.setAttribute(METRIC2, "myval2");
+        EntityTestUtils.assertAttributeEventually(newApp, METRIC2, Predicates.or(Predicates.equalTo("myval,myval2"), Predicates.equalTo("myval2,myval")));
+    }
+
+    @Test
+    public void testAggregatingMembersEnricher() throws Exception {
+        origCluster.resize(2);
+        
+        origApp.addEnricher(Enrichers.builder()
+                .aggregating(METRIC1)
+                .from(origCluster)
+                .fromMembers()
+                .computing(StringFunctions.joiner(","))
+                .publishing(METRIC2)
+                .build());
+        
+        TestApplication newApp = rebind();
+        DynamicCluster newCluster = (DynamicCluster) Iterables.find(newApp.getChildren(), Predicates.instanceOf(DynamicCluster.class));
+
+        int i = 0;
+        for (Entity member : newCluster.getMembers()) {
+            ((EntityInternal)member).setAttribute(METRIC1, "myval"+(i++));
+        }
+        EntityTestUtils.assertAttributeEventually(newApp, METRIC2, Predicates.or(Predicates.equalTo("myval1,myval2"), Predicates.equalTo("myval2,myval1")));
+    }
+    
+    @Test
+    public void testRestoresConfig() throws Exception {
+        origApp.addEnricher(EnricherSpec.create(MyEnricher.class)
+                .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
+                .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
+                .configure(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
+
+        newApp = (TestApplication) rebind();
+        MyEnricher newEnricher = (MyEnricher) Iterables.getOnlyElement(newApp.getEnrichers());
+        
+        assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
+        assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
+        assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
+    }
+
+    public static class MyEnricher extends AbstractEnricher {
+        public static final ConfigKey<String> MY_CONFIG = ConfigKeys.newStringConfigKey("myconfigkey");
+        
+        @SetFromFlag
+        public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.noShortName");
+
+        @SetFromFlag("myConfigWithSetFromFlagWithShortName")
+        public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.withShortName");
+
+        public static final ConfigKey<String> MY_CONFIG_WITHOUT_SETFROMFLAG = ConfigKeys.newStringConfigKey("myconfig.withoutSetfromflag");
+
+        @SetFromFlag
+        String myfield;
+
+        @SuppressWarnings("unused")
+        private final Object dummy = new Object(); // so not serializable
+        
+        public volatile boolean initCalled;
+        public volatile boolean rebindCalled;
+        
+        public MyEnricher() {
+        }
+        
+        public MyEnricher(Map<?,?> flags) {
+            super(flags);
+        }
+        
+        @Override
+        public void init() {
+            super.init();
+            initCalled = true;
+        }
+        
+        // TODO When AbstractEnricher declares rebind; @Override
+        public void rebind() {
+            // TODO super.rebind();
+            rebindCalled = true;
+        }
+    }
+    
+    public static class MyEnricherWithoutNoArgConstructor extends MyEnricher {
+        public MyEnricherWithoutNoArgConstructor(Map<?,?> flags) {
+            super(flags);
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
index 6de41c7..e731b33 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
@@ -108,28 +108,20 @@
         assertEquals(newLoc.myAtomicLong.get(), 124L);
     }
     
-    @SetFromFlag
-    public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.noShortName");
-
-    @SetFromFlag("myConfigWithSetFromFlagWithShortName")
-    public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.withShortName");
-
-    public static final ConfigKey<String> MY_CONFIG_WITHOUT_SETFROMFLAG = ConfigKeys.newStringConfigKey("myconfig.withoutSetfromflag");
-
     @Test
     public void testRestoresConfig() throws Exception {
         MyLocation origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class)
-                .configure(MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
-                .configure(MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
-                .configure(MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
+                .configure(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
+                .configure(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
+                .configure(MyLocation.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
         origApp.start(ImmutableList.of(origLoc));
 
         newApp = (TestApplication) rebind();
         MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
         
-        assertEquals(newLoc.getConfig(MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
-        assertEquals(newLoc.getConfig(MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
-        assertEquals(newLoc.getConfig(MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
+        assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
+        assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
+        assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index bf6e943..bacb4df 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@ -1,13 +1,16 @@
 package brooklyn.entity.rebind;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
-import java.util.Collection;
 import java.util.Map;
 
 import org.testng.annotations.Test;
 
-import brooklyn.policy.Policy;
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.policy.PolicySpec;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.collections.MutableMap;
@@ -26,30 +29,103 @@
      * See RebindManagerImpl.CheckpointingChangeListener.onChanged(Entity) and
      * MementosGenerator.newEntityMementoBuilder()
      */
-    @Test(enabled=false)
-    public void testRestoresSimplePolicy() throws Exception {
-        MyPolicy origPolicy = new MyPolicy(MutableMap.of("myfield", "myval"));
+    
+    @Test
+    public void testRestoresSimplePolicyFromConstructor() throws Exception {
+        MyPolicy origPolicy = new MyPolicy(MutableMap.of("myfield", "myFieldVal", "myconfigkey", "myConfigVal"));
         origApp.addPolicy(origPolicy);
+        runRestoresSimplePolicy();
+    }
+
+    @Test
+    public void testRestoresDeprecatedPolicyFromConstructorWithoutNoArgs() throws Exception {
+        MyPolicyWithoutNoArgConstructor origPolicy = new MyPolicyWithoutNoArgConstructor(MutableMap.of("myfield", "myFieldVal", "myconfigkey", "myConfigVal"));
+        origApp.addPolicy(origPolicy);
+        runRestoresSimplePolicy();
+    }
+
+    @Test
+    public void testRestoresSimplePolicyFromPolicySpec() throws Exception {
+        origApp.addPolicy(PolicySpec.create(MyPolicy.class)
+                .configure("myfield", "myFieldVal")
+                .configure(MyPolicy.MY_CONFIG, "myConfigVal"));
+        runRestoresSimplePolicy();
+    }
+    
+    protected void runRestoresSimplePolicy() throws Exception {
+        MyPolicy origPolicy = (MyPolicy) Iterables.getOnlyElement(origApp.getPolicies());
+        assertTrue(origPolicy.isRunning());
+        assertTrue(origPolicy.initCalled);
+        assertFalse(origPolicy.rebindCalled);
         
         TestApplication newApp = rebind();
-        Collection<Policy> policies = newApp.getPolicies();
-        MyPolicy newPolicy = (MyPolicy) Iterables.get(policies, 0);
+        MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
         
-        assertEquals(newPolicy.myfield, origPolicy.myfield);
+        assertEquals(newPolicy.myfield, "myFieldVal");
+        assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG), "myConfigVal");
+        assertTrue(newPolicy.isRunning());
+        assertFalse(newPolicy.initCalled);
+        assertTrue(newPolicy.rebindCalled);
+    }
+
+    @Test
+    public void testRestoresConfig() throws Exception {
+        origApp.addPolicy(PolicySpec.create(MyPolicy.class)
+                .configure(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
+                .configure(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
+                .configure(MyPolicy.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
+
+        newApp = (TestApplication) rebind();
+        MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
+        
+        assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
+        assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
+        assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
     }
 
     public static class MyPolicy extends AbstractPolicy {
+        public static final ConfigKey<String> MY_CONFIG = ConfigKeys.newStringConfigKey("myconfigkey");
+        
+        @SetFromFlag
+        public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.noShortName");
+
+        @SetFromFlag("myConfigWithSetFromFlagWithShortName")
+        public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.withShortName");
+
+        public static final ConfigKey<String> MY_CONFIG_WITHOUT_SETFROMFLAG = ConfigKeys.newStringConfigKey("myconfig.withoutSetfromflag");
+
         @SetFromFlag
         String myfield;
 
         @SuppressWarnings("unused")
         private final Object dummy = new Object(); // so not serializable
         
+        public transient volatile boolean initCalled;
+        public transient volatile boolean rebindCalled;
+        
         public MyPolicy() {
         }
         
         public MyPolicy(Map<?,?> flags) {
             super(flags);
         }
+        
+        @Override
+        public void init() {
+            super.init();
+            initCalled = true;
+        }
+        
+        // TODO When AbstractPolicy declares rebind; @Override
+        public void rebind() {
+            // TODO super.rebind();
+            rebindCalled = true;
+        }
     }
-}
+    
+    public static class MyPolicyWithoutNoArgConstructor extends MyPolicy {
+        public MyPolicyWithoutNoArgConstructor(Map<?,?> flags) {
+            super(flags);
+        }
+    }
+}
\ No newline at end of file