brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rich...@apache.org
Subject [20/50] [abbrv] git commit: More enricher and policy persistance changes
Date Fri, 23 May 2014 16:57:05 GMT
More enricher and policy persistance changes


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

Branch: refs/pull/1413/merge
Commit: 80532a5bcea8334f1c012657448e302230d7247d
Parents: 34d4f8a
Author: Andrew Kennedy <andrew.kennedy@cloudsoftcorp.com>
Authored: Thu May 22 17:24:03 2014 +0100
Committer: Andrew Kennedy <andrew.kennedy@cloudsoftcorp.com>
Committed: Thu May 22 17:57:52 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/rebind/ChangeListener.java  |  4 ++
 .../brooklyn/entity/rebind/RebindContext.java   | 12 ++--
 .../mementos/BrooklynMementoPersister.java      |  4 ++
 api/src/main/java/brooklyn/policy/Enricher.java | 17 +++--
 .../enricher/basic/AbstractEnricher.java        |  8 +++
 .../rebind/BasicEnricherRebindSupport.java      | 28 ++++----
 .../entity/rebind/BasicEntityRebindSupport.java | 20 +++++-
 .../rebind/ImmediateDeltaChangeListener.java    | 10 +++
 .../rebind/PeriodicDeltaChangeListener.java     | 35 +++++++--
 .../entity/rebind/PersisterDeltaImpl.java       | 13 ++++
 .../entity/rebind/RebindContextImpl.java        | 11 +++
 .../entity/rebind/RebindManagerImpl.java        | 76 +++++++++++++++++++-
 .../entity/rebind/dto/BrooklynMementoImpl.java  | 25 +++++++
 .../rebind/dto/BrooklynMementoManifestImpl.java | 14 ++++
 .../AbstractBrooklynMementoPersister.java       |  6 ++
 .../BrooklynMementoPersisterInMemory.java       | 12 ++++
 .../BrooklynMementoPersisterToMultiFile.java    | 71 +++++++++++++++---
 .../rebind/persister/XmlMementoSerializer.java  | 31 +++++++-
 .../internal/EntityChangeListener.java          |  2 +-
 .../internal/EntityManagementSupport.java       |  2 +
 .../persister/XmlMementoSerializerTest.java     | 75 ++++++++++++-------
 21 files changed, 408 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java b/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
index ffc15da..ee17ec8 100644
--- a/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
+++ b/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
@@ -2,6 +2,7 @@ package brooklyn.entity.rebind;
 
 import brooklyn.entity.Entity;
 import brooklyn.location.Location;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 
 /**
@@ -22,6 +23,7 @@ public interface ChangeListener {
         @Override public void onUnmanaged(Location location) {}
         @Override public void onChanged(Location location) {}
         @Override public void onChanged(Policy policy) {}
+        @Override public void onChanged(Enricher enricher) {}
     };
     
     void onManaged(Entity entity);
@@ -37,4 +39,6 @@ public interface ChangeListener {
     void onChanged(Location location);
     
     void onChanged(Policy policy);
+    
+    void onChanged(Enricher enricher);
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/api/src/main/java/brooklyn/entity/rebind/RebindContext.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/rebind/RebindContext.java b/api/src/main/java/brooklyn/entity/rebind/RebindContext.java
index 264b8b0..2d8e364 100644
--- a/api/src/main/java/brooklyn/entity/rebind/RebindContext.java
+++ b/api/src/main/java/brooklyn/entity/rebind/RebindContext.java
@@ -2,6 +2,7 @@ package brooklyn.entity.rebind;
 
 import brooklyn.entity.Entity;
 import brooklyn.location.Location;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 
 /**
@@ -15,11 +16,14 @@ import brooklyn.policy.Policy;
  */
 public interface RebindContext {
 
-    public Entity getEntity(String id);
+    Entity getEntity(String id);
 
-    public Location getLocation(String id);
+    Location getLocation(String id);
 
-    public Policy getPolicy(String id);
+    Policy getPolicy(String id);
+
+    Enricher getEnricher(String id);
+
+    Class<?> loadClass(String typeName) throws ClassNotFoundException;
 
-    public Class<?> loadClass(String typeName) throws ClassNotFoundException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
index e29e70e..18f9b14 100644
--- a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
+++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
@@ -8,6 +8,8 @@ import java.util.concurrent.TimeoutException;
 import brooklyn.entity.Entity;
 import brooklyn.entity.rebind.RebindManager;
 import brooklyn.location.Location;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -21,6 +23,8 @@ public interface BrooklynMementoPersister {
     public static interface LookupContext {
         Entity lookupEntity(Class<?> type, String id);
         Location lookupLocation(Class<?> type, String id);
+        Policy lookupPolicy(Class<?> type, String id);
+        Enricher lookupEnricher(Class<?> type, String id);
     }
 
     BrooklynMementoManifest loadMementoManifest() throws IOException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/api/src/main/java/brooklyn/policy/Enricher.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/Enricher.java b/api/src/main/java/brooklyn/policy/Enricher.java
index ab6b546..6be006d 100644
--- a/api/src/main/java/brooklyn/policy/Enricher.java
+++ b/api/src/main/java/brooklyn/policy/Enricher.java
@@ -3,16 +3,19 @@ package brooklyn.policy;
 import java.util.Map;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.entity.rebind.RebindSupport;
+import brooklyn.entity.rebind.Rebindable;
+import brooklyn.mementos.EnricherMemento;
 
 import com.google.common.annotations.Beta;
 
 /**
  * Publishes metrics for an entity, e.g. aggregating information from other sensors/entities.
- * 
- * Has some similarities to {@link Policy}. However, enrichers specifically do not invoke 
+ *
+ * Has some similarities to {@link Policy}. However, enrichers specifically do not invoke
  * effectors and should only function to publish new metrics.
  */
-public interface Enricher extends EntityAdjunct {
+public interface Enricher extends EntityAdjunct, Rebindable {
     /**
      * A unique id for this enricher.
      */
@@ -32,8 +35,12 @@ public interface Enricher extends EntityAdjunct {
     EnricherType getEnricherType();
 
     <T> T getConfig(ConfigKey<T> key);
-    
+
     <T> T setConfig(ConfigKey<T> key, T val);
-    
+
     Map<ConfigKey<?>, Object> getAllConfig();
+
+    @Override
+    RebindSupport<EnricherMemento> getRebindSupport();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index a83b1fc..4346be5 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -2,6 +2,9 @@ package brooklyn.enricher.basic;
 
 import java.util.Map;
 
+import brooklyn.entity.rebind.BasicEnricherRebindSupport;
+import brooklyn.entity.rebind.RebindSupport;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherType;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
@@ -28,6 +31,11 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
             init();
         }
     }
+
+    @Override
+    public RebindSupport<EnricherMemento> getRebindSupport() {
+        return new BasicEnricherRebindSupport(this);
+    }
     
     @Override
     public EnricherType getEnricherType() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
index 9d3a50e..3fca1b8 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
@@ -7,36 +7,36 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.rebind.dto.MementosGenerators;
-import brooklyn.mementos.PolicyMemento;
-import brooklyn.policy.basic.AbstractPolicy;
+import brooklyn.mementos.EnricherMemento;
+import brooklyn.enricher.basic.AbstractEnricher;
 
-public class BasicEnricherRebindSupport implements RebindSupport<PolicyMemento> {
+public class BasicEnricherRebindSupport implements RebindSupport<EnricherMemento> {
 
     private static final Logger LOG = LoggerFactory.getLogger(BasicEnricherRebindSupport.class);
     
-    private final AbstractPolicy policy;
+    private final AbstractEnricher enricher;
     
-    public BasicEnricherRebindSupport(AbstractPolicy policy) {
-        this.policy = policy;
+    public BasicEnricherRebindSupport(AbstractEnricher enricher) {
+        this.enricher = enricher;
     }
     
     @Override
-    public PolicyMemento getMemento() {
+    public EnricherMemento getMemento() {
         return getMementoWithProperties(Collections.<String,Object>emptyMap());
     }
 
-    protected PolicyMemento getMementoWithProperties(Map<String,?> props) {
-        PolicyMemento memento = MementosGenerators.newPolicyMementoBuilder(policy).customFields(props).build();
-        if (LOG.isTraceEnabled()) LOG.trace("Creating memento for policy: {}", memento.toVerboseString());
+    protected EnricherMemento getMementoWithProperties(Map<String,?> props) {
+        EnricherMemento memento = MementosGenerators.newEnricherMementoBuilder(enricher).customFields(props).build();
+        if (LOG.isTraceEnabled()) LOG.trace("Creating memento for enricher: {}", memento.toVerboseString());
         return memento;
     }
 
     @Override
-    public void reconstruct(RebindContext rebindContext, PolicyMemento memento) {
-        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing policy: {}", memento.toVerboseString());
+    public void reconstruct(RebindContext rebindContext, EnricherMemento memento) {
+        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing enricher: {}", memento.toVerboseString());
 
         // Note that the flags have been set in the constructor
-        policy.setName(memento.getDisplayName());
+        enricher.setName(memento.getDisplayName());
         
         doReconsruct(rebindContext, memento);
     }
@@ -44,7 +44,7 @@ public class BasicEnricherRebindSupport implements RebindSupport<PolicyMemento>
     /**
      * For overriding, to give custom reconsruct behaviour.
      */
-    protected void doReconsruct(RebindContext rebindContext, PolicyMemento memento) {
+    protected void doReconsruct(RebindContext rebindContext, EnricherMemento memento) {
         // default is no-op
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
index 90df2f4..e19c2fa 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -9,6 +9,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
@@ -40,14 +41,14 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
 
     protected EntityMemento getMementoWithProperties(Map<String,?> props) {
         EntityMemento memento = MementosGenerators.newEntityMementoBuilder(entity).customFields(props).build();
-    	if (LOG.isTraceEnabled()) LOG.trace("Creating memento for entity: {}", memento.toVerboseString());
-    	return memento;
+        if (LOG.isTraceEnabled()) LOG.trace("Creating memento for entity: {}", memento.toVerboseString());
+        return memento;
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public void reconstruct(RebindContext rebindContext, EntityMemento memento) {
-    	if (LOG.isTraceEnabled()) LOG.trace("Reconstructing entity: {}", memento.toVerboseString());
+        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing entity: {}", memento.toVerboseString());
 
         // Note that the id should have been set in the constructor; it is immutable
         entity.setDisplayName(memento.getDisplayName());
@@ -82,6 +83,7 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
         setParent(rebindContext, memento);
         addChildren(rebindContext, memento);
         addPolicies(rebindContext, memento);
+        addEnrichers(rebindContext, memento);
         addMembers(rebindContext, memento);
         addLocations(rebindContext, memento);
 
@@ -158,4 +160,16 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
             }
         }
     }
+    
+    protected void addEnrichers(RebindContext rebindContext, EntityMemento memento) {
+        for (String enricherId : memento.getEnrichers()) {
+            AbstractEnricher enricher = (AbstractEnricher) rebindContext.getEnricher(enricherId);
+            if (enricher != null) {
+                entity.addEnricher(enricher);
+            } else {
+                LOG.warn("Enricher not found; discarding policy {} of entity {}({})",
+                        new Object[] {enricherId, memento.getType(), memento.getId()});
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
index 077be32..a33bb12 100644
--- a/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
@@ -9,6 +9,7 @@ import brooklyn.location.Location;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.mementos.BrooklynMementoPersister;
 import brooklyn.mementos.LocationMemento;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 
 import com.google.common.collect.Maps;
@@ -126,4 +127,13 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
             persister.delta(delta);
         }
     }
+    
+    @Override
+    public void onChanged(Enricher enricher) {
+        if (running && persister != null) {
+            PersisterDeltaImpl delta = new PersisterDeltaImpl();
+            delta.enrichers.add(enricher.getRebindSupport().getMemento());
+            persister.delta(delta);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
index 1a7a8fc..d7cc8e6 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -16,6 +16,7 @@ import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.ExecutionManager;
 import brooklyn.management.Task;
 import brooklyn.mementos.BrooklynMementoPersister;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.task.BasicTask;
@@ -47,13 +48,15 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
         Set<Location> locations = Sets.newLinkedHashSet();
         Set<Entity> entities = Sets.newLinkedHashSet();
         Set<Policy> policies = Sets.newLinkedHashSet();
+        Set<Enricher> enrichers = Sets.newLinkedHashSet();
         Set<String> removedLocationIds = Sets.newLinkedHashSet();
         Set<String> removedEntityIds = Sets.newLinkedHashSet();
         Set<String> removedPolicyIds = Sets.newLinkedHashSet();
+        Set<String> removedEnricherIds = Sets.newLinkedHashSet();
         
         public boolean isEmpty() {
-            return locations.isEmpty() && entities.isEmpty() && policies.isEmpty() && 
-                    removedEntityIds.isEmpty() && removedLocationIds.isEmpty() && removedPolicyIds.isEmpty();
+            return locations.isEmpty() && entities.isEmpty() && policies.isEmpty() && enrichers.isEmpty() &&
+                    removedEntityIds.isEmpty() && removedLocationIds.isEmpty() && removedPolicyIds.isEmpty() && removedEnricherIds.isEmpty();
         }
     }
     
@@ -196,12 +199,20 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
                         try {
                             persisterDelta.policies.add(policy.getRebindSupport().getMemento());
                         } catch (Exception e) {
-                            handleGenerateMementoException(e, "location "+policy.getClass().getSimpleName()+"("+policy.getId()+")");
+                            handleGenerateMementoException(e, "policy "+policy.getClass().getSimpleName()+"("+policy.getId()+")");
+                        }
+                    }
+                    for (Enricher enricher : prevDeltaCollector.enrichers) {
+                        try {
+                            persisterDelta.enrichers.add(enricher.getRebindSupport().getMemento());
+                        } catch (Exception e) {
+                            handleGenerateMementoException(e, "enricher "+enricher.getClass().getSimpleName()+"("+enricher.getId()+")");
                         }
                     }
                     persisterDelta.removedLocationIds = prevDeltaCollector.removedLocationIds;
                     persisterDelta.removedEntityIds = prevDeltaCollector.removedEntityIds;
                     persisterDelta.removedPolicyIds = prevDeltaCollector.removedPolicyIds;
+                    persisterDelta.removedEnricherIds = prevDeltaCollector.removedEnricherIds;
                     
                     /*
                      * Need to guarantee "happens before", with any thread that subsequently reads
@@ -268,9 +279,13 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
             // (e.g. AbstractController registering a AbstractMembershipTrackingPolicy)
             // Also, the entity constructor often re-creates the policy.
             // Also see MementosGenerator.newEntityMementoBuilder()
-//            for (Policy policy : entity.getPolicies()) {
-//                delta.policies.add(policy);
-//            }
+            for (Policy policy : entity.getPolicies()) {
+                deltaCollector.policies.add(policy);
+            }
+
+            for (Enricher enricher : entity.getEnrichers()) {
+                deltaCollector.enrichers.add(enricher);
+            }
         }
     }
     
@@ -307,4 +322,12 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
             deltaCollector.policies.add(policy);
         }
     }
+    
+    @Override
+    public synchronized void onChanged(Enricher enricher) {
+        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", enricher);
+        if (!isStopped()) {
+            deltaCollector.enrichers.add(enricher);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java b/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
index b3a3d7f..0950f81 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
@@ -3,6 +3,7 @@ package brooklyn.entity.rebind;
 import java.util.Collection;
 
 import brooklyn.mementos.BrooklynMementoPersister.Delta;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
@@ -13,9 +14,11 @@ class PersisterDeltaImpl implements Delta {
     Collection<LocationMemento> locations = Sets.newLinkedHashSet();
     Collection<EntityMemento> entities = Sets.newLinkedHashSet();
     Collection<PolicyMemento> policies = Sets.newLinkedHashSet();
+    Collection<EnricherMemento> enrichers = Sets.newLinkedHashSet();
     Collection <String> removedLocationIds = Sets.newLinkedHashSet();
     Collection <String> removedEntityIds = Sets.newLinkedHashSet();
     Collection <String> removedPolicyIds = Sets.newLinkedHashSet();
+    Collection <String> removedEnricherIds = Sets.newLinkedHashSet();
     
     @Override
     public Collection<LocationMemento> locations() {
@@ -33,6 +36,11 @@ class PersisterDeltaImpl implements Delta {
     }
 
     @Override
+    public Collection<EnricherMemento> enrichers() {
+        return enrichers;
+    }
+
+    @Override
     public Collection<String> removedLocationIds() {
         return removedLocationIds;
     }
@@ -46,4 +54,9 @@ class PersisterDeltaImpl implements Delta {
     public Collection<String> removedPolicyIds() {
         return removedPolicyIds;
     }
+    
+    @Override
+    public Collection<String> removedEnricherIds() {
+        return removedEnricherIds;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java
index 90a3bb4..30c88ab 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java
@@ -4,6 +4,7 @@ import java.util.Map;
 
 import brooklyn.entity.Entity;
 import brooklyn.location.Location;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 
 import com.google.common.collect.Maps;
@@ -13,6 +14,7 @@ public class RebindContextImpl implements RebindContext {
     private final Map<String, Entity> entities = Maps.newLinkedHashMap();
     private final Map<String, Location> locations = Maps.newLinkedHashMap();
     private final Map<String, Policy> policies = Maps.newLinkedHashMap();
+    private final Map<String, Enricher> enrichers = Maps.newLinkedHashMap();
     private final ClassLoader classLoader;
     
     public RebindContextImpl(ClassLoader classLoader) {
@@ -31,6 +33,10 @@ public class RebindContextImpl implements RebindContext {
         policies.put(id, policy);
     }
     
+    public void registerEnricher(String id, Enricher enricher) {
+        enrichers.put(id, enricher);
+    }
+    
     @Override
     public Entity getEntity(String id) {
         return entities.get(id);
@@ -47,6 +53,11 @@ public class RebindContextImpl implements RebindContext {
     }
     
     @Override
+    public Enricher getEnricher(String id) {
+        return enrichers.get(id);
+    }
+    
+    @Override
     public Class<?> loadClass(String className) throws ClassNotFoundException {
         return classLoader.loadClass(className);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 821a42d..4b0ce65 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -28,10 +28,12 @@ import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.mementos.BrooklynMementoPersister;
 import brooklyn.mementos.BrooklynMementoPersister.LookupContext;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
 import brooklyn.mementos.TreeNode;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
@@ -155,6 +157,7 @@ public class RebindManagerImpl implements RebindManager {
             Map<String,Entity> entities = Maps.newLinkedHashMap();
             Map<String,Location> locations = Maps.newLinkedHashMap();
             Map<String,Policy> policies = Maps.newLinkedHashMap();
+            Map<String,Enricher> enrichers = Maps.newLinkedHashMap();
             
             final RebindContextImpl rebindContext = new RebindContextImpl(classLoader);
     
@@ -186,6 +189,32 @@ public class RebindManagerImpl implements RebindManager {
                     }
                     return result;
                 }
+                @Override public Policy lookupPolicy(Class<?> type, String id) {
+                    Policy result = rebindContext.getPolicy(id);
+                    if (result == null) {
+                        if (removeDanglingRefs) {
+                            LOG.warn("No policy found with id "+id+"; returning null");
+                        } else {
+                            throw new IllegalStateException("No policy found with id "+id);
+                        }
+                    } else if (type != null && !type.isInstance(result)) {
+                        LOG.warn("Policy with id "+id+" does not match type "+type+"; returning "+result);
+                    }
+                    return result;
+                }
+                @Override public Enricher lookupEnricher(Class<?> type, String id) {
+                    Enricher result = rebindContext.getEnricher(id);
+                    if (result == null) {
+                        if (removeDanglingRefs) {
+                            LOG.warn("No enricher found with id "+id+"; returning null");
+                        } else {
+                            throw new IllegalStateException("No enricher found with id "+id);
+                        }
+                    } else if (type != null && !type.isInstance(result)) {
+                        LOG.warn("Enricher with id "+id+" does not match type "+type+"; returning "+result);
+                    }
+                    return result;
+                }
             };
             
             // Two-phase deserialization.
@@ -234,6 +263,16 @@ public class RebindManagerImpl implements RebindManager {
                 rebindContext.registerPolicy(policyMemento.getId(), policy);
             }
             
+            // Instantiate enrichers
+            LOG.info("RebindManager instantiating enrichers: {}", memento.getEnricherIds());
+            for (EnricherMemento enricherMemento : memento.getEnricherMementos().values()) {
+                if (LOG.isDebugEnabled()) LOG.debug("RebindManager instantiating policy {}", enricherMemento);
+                
+                Enricher enricher = newEnricher(enricherMemento, reflections);
+                enrichers.put(enricherMemento.getId(), enricher);
+                rebindContext.registerEnricher(enricherMemento.getId(), enricher);
+            }
+            
             // Reconstruct locations
             LOG.info("RebindManager reconstructing locations");
             for (LocationMemento locMemento : sortParentFirst(memento.getLocationMementos()).values()) {
@@ -242,7 +281,7 @@ public class RebindManagerImpl implements RebindManager {
     
                 ((LocationInternal)location).getRebindSupport().reconstruct(rebindContext, locMemento);
             }
-    
+
             // Reconstruct policies
             LOG.info("RebindManager reconstructing policies");
             for (PolicyMemento policyMemento : memento.getPolicyMementos().values()) {
@@ -251,6 +290,15 @@ public class RebindManagerImpl implements RebindManager {
     
                 policy.getRebindSupport().reconstruct(rebindContext, policyMemento);
             }
+
+            // Reconstruct enrichers
+            LOG.info("RebindManager reconstructing enrichers");
+            for (EnricherMemento enricherMemento : memento.getEnricherMementos().values()) {
+                Enricher enricher = rebindContext.getEnricher(enricherMemento.getId());
+                if (LOG.isDebugEnabled()) LOG.debug("RebindManager reconstructing enricher {}", enricherMemento);
+    
+                enricher.getRebindSupport().reconstruct(rebindContext, enricherMemento);
+            }
     
             // Reconstruct entities
             LOG.info("RebindManager reconstructing entities");
@@ -423,7 +471,6 @@ public class RebindManagerImpl implements RebindManager {
         // note 'used' config keys get marked in BasicLocationRebindSupport
     }
 
-
     /**
      * Constructs a new policy, passing to its constructor the policy id and all of memento.getFlags().
      */
@@ -440,6 +487,22 @@ public class RebindManagerImpl implements RebindManager {
         return (Policy) invokeConstructor(reflections, policyClazz, new Object[] {flags});
     }
 
+    /**
+     * Constructs a new enricher, passing to its constructor the enricher id and all of memento.getFlags().
+     */
+    private Enricher newEnricher(EnricherMemento memento, Reflections reflections) {
+        String id = memento.getId();
+        String enricherType = checkNotNull(memento.getType(), "enricherType of "+id);
+        Class<?> enricherClazz = reflections.loadClass(enricherType);
+
+        Map<String, Object> flags = MutableMap.<String, Object>builder()
+                .put("id", id)
+                .putAll(memento.getFlags())
+                .build();
+
+        return (Enricher) invokeConstructor(reflections, enricherClazz, new Object[] {flags});
+    }
+
     private <T> T invokeConstructor(Reflections reflections, Class<T> clazz, Object[]... possibleArgs) {
         for (Object[] args : possibleArgs) {
             try {
@@ -533,5 +596,14 @@ public class RebindManagerImpl implements RebindManager {
                 LOG.error("Error persisting mememento onChanged("+policy+"); continuing.", t);
             }
         }
+        
+        @Override
+        public void onChanged(Enricher enricher) {
+            try {
+                delegate.onChanged(enricher);
+            } catch (Throwable t) {
+                LOG.error("Error persisting mememento onChanged("+enricher+"); continuing.", t);
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoImpl.java b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoImpl.java
index 7704659..b75a112 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoImpl.java
@@ -8,6 +8,7 @@ import java.util.Map;
 
 import brooklyn.BrooklynVersion;
 import brooklyn.mementos.BrooklynMemento;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
@@ -31,6 +32,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         protected final Map<String, EntityMemento> entities = Maps.newLinkedHashMap();
         protected final Map<String, LocationMemento> locations = Maps.newLinkedHashMap();
         protected final Map<String, PolicyMemento> policies = Maps.newLinkedHashMap();
+        protected final Map<String, EnricherMemento> enrichers = Maps.newLinkedHashMap();
         
         public Builder brooklynVersion(String val) {
             brooklynVersion = val; return this;
@@ -53,6 +55,9 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         public Builder policy(PolicyMemento val) {
             policies.put(val.getId(), val); return this;
         }
+        public Builder enricher(EnricherMemento val) {
+            enrichers.put(val.getId(), val); return this;
+        }
         public Builder entity(EntityMemento val) {
             entities.put(val.getId(), val); return this;
         }
@@ -62,6 +67,9 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         public Builder policies(Map<String, PolicyMemento> vals) {
             policies.putAll(vals); return this;
         }
+        public Builder enricheres(Map<String, EnricherMemento> vals) {
+            enrichers.putAll(vals); return this;
+        }
         public BrooklynMemento build() {
             return new BrooklynMementoImpl(this);
         }
@@ -74,6 +82,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     private Map<String, EntityMemento> entities;
     private Map<String, LocationMemento> locations;
     private Map<String, PolicyMemento> policies;
+    private Map<String, EnricherMemento> enrichers;
     
     private BrooklynMementoImpl(Builder builder) {
         brooklynVersion = builder.brooklynVersion;
@@ -82,6 +91,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         entities = builder.entities;
         locations = builder.locations;
         policies = builder.policies;
+        enrichers = builder.enrichers;
     }
 
     @Override
@@ -98,6 +108,11 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     public PolicyMemento getPolicyMemento(String id) {
         return policies.get(id);
     }
+    
+    @Override
+    public EnricherMemento getEnricherMemento(String id) {
+        return enrichers.get(id);
+    }
 
     @Override
     public Collection<String> getApplicationIds() {
@@ -120,6 +135,11 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     }
     
     @Override
+    public Collection<String> getEnricherIds() {
+        return Collections.unmodifiableSet(enrichers.keySet());
+    }
+    
+    @Override
     public Collection<String> getTopLevelLocationIds() {
         return Collections.unmodifiableList(topLevelLocationIds);
     }
@@ -137,4 +157,9 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     public Map<String, PolicyMemento> getPolicyMementos() {
         return Collections.unmodifiableMap(policies);
     }
+
+    @Override
+    public Map<String, EnricherMemento> getEnricherMementos() {
+        return Collections.unmodifiableMap(enrichers);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
index fdfc1e0..e517f15 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
@@ -21,6 +21,7 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
         protected final Map<String, String> entityIdToType = Maps.newLinkedHashMap();
         protected final Map<String, String> locationIdToType = Maps.newLinkedHashMap();
         protected final Map<String, String> policyIdToType = Maps.newLinkedHashMap();
+        protected final Map<String, String> enricherIdToType = Maps.newLinkedHashMap();
         
         public Builder brooklynVersion(String val) {
             brooklynVersion = val; return this;
@@ -43,6 +44,12 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
         public Builder policies(Map<String, String> vals) {
             policyIdToType.putAll(vals); return this;
         }
+        public Builder enricher(String id, String type) {
+            enricherIdToType.put(id, type); return this;
+        }
+        public Builder enrichers(Map<String, String> vals) {
+            enricherIdToType.putAll(vals); return this;
+        }
         public BrooklynMementoManifest build() {
             return new BrooklynMementoManifestImpl(this);
         }
@@ -51,11 +58,13 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
     private Map<String, String> entityIdToType;
     private Map<String, String> locationIdToType;
     private Map<String, String> policyIdToType;
+    private Map<String, String> enricherIdToType;
     
     private BrooklynMementoManifestImpl(Builder builder) {
         entityIdToType = builder.entityIdToType;
         locationIdToType = builder.locationIdToType;
         policyIdToType = builder.policyIdToType;
+        enricherIdToType = builder.enricherIdToType;
     }
 
     @Override
@@ -72,4 +81,9 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
     public Map<String, String> getPolicyIdToType() {
         return Collections.unmodifiableMap(policyIdToType);
     }
+
+    @Override
+    public Map<String, String> getEnricherIdToType() {
+        return Collections.unmodifiableMap(enricherIdToType);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
index 00ad013..1ba1cd1 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
@@ -6,6 +6,7 @@ import brooklyn.entity.rebind.dto.MutableBrooklynMemento;
 import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.mementos.BrooklynMementoPersister;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
@@ -36,6 +37,9 @@ public abstract class AbstractBrooklynMementoPersister implements BrooklynMement
         for (PolicyMemento entity : memento.getPolicyMementos().values()) {
             builder.policy(entity.getId(), entity.getType());
         }
+        for (EnricherMemento entity : memento.getEnricherMementos().values()) {
+            builder.enricher(entity.getId(), entity.getType());
+        }
         return builder.build();
     }
     
@@ -54,8 +58,10 @@ public abstract class AbstractBrooklynMementoPersister implements BrooklynMement
         memento.removeEntities(delta.removedEntityIds());
         memento.removeLocations(delta.removedLocationIds());
         memento.removePolicies(delta.removedPolicyIds());
+        memento.removeEnrichers(delta.removedEnricherIds());
         memento.updateEntityMementos(delta.entities());
         memento.updateLocationMementos(delta.locations());
         memento.updatePolicyMementos(delta.policies());
+        memento.updateEnricherMementos(delta.enrichers());
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
index 19b88d6..fe55213 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
@@ -16,6 +16,8 @@ import brooklyn.entity.proxying.EntityProxy;
 import brooklyn.location.Location;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.mementos.BrooklynMemento;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.os.Os;
 import brooklyn.util.time.Duration;
@@ -85,6 +87,16 @@ public class BrooklynMementoPersisterInMemory extends AbstractBrooklynMementoPer
                         if (type != null) types.add(type);
                         return (Location) newDummy(types);
                     }
+                    @Override public Policy lookupPolicy(Class<?> type, String id) {
+                        List<Class<?>> types = MutableList.<Class<?>>of(Policy.class);
+                        if (type != null) types.add(type);
+                        return (Policy) newDummy(types);
+                    }
+                    @Override public Enricher lookupEnricher(Class<?> type, String id) {
+                        List<Class<?>> types = MutableList.<Class<?>>of(Enricher.class);
+                        if (type != null) types.add(type);
+                        return (Enricher) newDummy(types);
+                    }
                     private Object newDummy(List<Class<?>> types) {
                         return java.lang.reflect.Proxy.newProxyInstance(
                             classLoader,

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
index a39bbfd..2b5f012 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
@@ -19,6 +19,7 @@ import brooklyn.entity.rebind.dto.BrooklynMementoManifestImpl;
 import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.mementos.BrooklynMementoPersister;
+import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
@@ -44,10 +45,12 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
     private final File entitiesDir;
     private final File locationsDir;
     private final File policiesDir;
+    private final File enrichersDir;
 
     private final ConcurrentMap<String, MementoFileWriter<EntityMemento>> entityWriters = new ConcurrentHashMap<String, MementoFileWriter<EntityMemento>>();
     private final ConcurrentMap<String, MementoFileWriter<LocationMemento>> locationWriters = new ConcurrentHashMap<String, MementoFileWriter<LocationMemento>>();
     private final ConcurrentMap<String, MementoFileWriter<PolicyMemento>> policyWriters = new ConcurrentHashMap<String, MementoFileWriter<PolicyMemento>>();
+    private final ConcurrentMap<String, MementoFileWriter<EnricherMemento>> enricherWriters = new ConcurrentHashMap<String, MementoFileWriter<EnricherMemento>>();
     
     private final MementoSerializer<Object> serializer;
 
@@ -77,6 +80,10 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         policiesDir = new File(dir, "policies");
         policiesDir.mkdir();
         checkDirIsAccessible(policiesDir);
+        
+        enrichersDir = new File(dir, "enrichers");
+        enrichersDir.mkdir();
+        checkDirIsAccessible(enrichersDir);
 
         File planeDir = new File(dir, "plane");
         planeDir.mkdir();
@@ -114,9 +121,10 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         File[] entityFiles = entitiesDir.listFiles(fileFilter);
         File[] locationFiles = locationsDir.listFiles(fileFilter);
         File[] policyFiles = policiesDir.listFiles(fileFilter);
+        File[] enricherFiles = enrichersDir.listFiles(fileFilter);
 
-        LOG.info("Loading memento manifest from {}; {} entities, {} locations, {} policies", 
-                new Object[] {dir, entityFiles.length, locationFiles.length, policyFiles.length});
+        LOG.info("Loading memento manifest from {}; {} entities, {} locations, {} policies, {} policies", 
+                new Object[] {dir, entityFiles.length, locationFiles.length, policyFiles.length, enricherFiles.length});
         
         BrooklynMementoManifestImpl.Builder builder = BrooklynMementoManifestImpl.builder();
         
@@ -139,6 +147,12 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
                 String type = (String) XmlUtil.xpath(contents, "/policy/type");
                 builder.policy(id, type);
             }
+            for (File file : enricherFiles) {
+                String contents = readFile(file);
+                String id = (String) XmlUtil.xpath(contents, "/enricher/id");
+                String type = (String) XmlUtil.xpath(contents, "/enricher/type");
+                builder.enricher(id, type);
+            }
             
             if (LOG.isDebugEnabled()) LOG.debug("Loaded memento manifest; took {}", Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS))); 
             return builder.build();
@@ -164,9 +178,10 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         File[] entityFiles = entitiesDir.listFiles(fileFilter);
         File[] locationFiles = locationsDir.listFiles(fileFilter);
         File[] policyFiles = policiesDir.listFiles(fileFilter);
+        File[] enricherFiles = enrichersDir.listFiles(fileFilter);
 
-        LOG.info("Loading memento from {}; {} entities, {} locations, {} policies", 
-                new Object[] {dir, entityFiles.length, locationFiles.length, policyFiles.length});
+        LOG.info("Loading memento from {}; {} entities, {} locations, {} policies and {} enrichers", 
+                new Object[] {dir, entityFiles.length, locationFiles.length, policyFiles.length}, enricherFiles.length);
         
         BrooklynMementoImpl.Builder builder = BrooklynMementoImpl.builder();
         
@@ -199,6 +214,14 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
                     builder.policy(memento);
                 }
             }
+            for (File file : enricherFiles) {
+                EnricherMemento memento = (EnricherMemento) serializer.fromString(readFile(file));
+                if (memento == null) {
+                    LOG.warn("No enricher-memento deserialized from file "+file+"; ignoring and continuing");
+                } else {
+                    builder.enricher(memento);
+                }
+            }
             
             if (LOG.isDebugEnabled()) LOG.debug("Loaded memento; took {}", Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS))); 
             return builder.build();
@@ -225,6 +248,9 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         for (PolicyMemento m : newMemento.getPolicyMementos().values()) {
             persist(m);
         }
+        for (EnricherMemento m : newMemento.getEnricherMementos().values()) {
+            persist(m);
+        }
     }
     
     @Override
@@ -233,10 +259,10 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
             if (LOG.isDebugEnabled()) LOG.debug("Ignoring checkpointed delta of memento, because not running");
             return;
         }
-        if (LOG.isTraceEnabled()) LOG.trace("Checkpointed delta of memento; updating {} entities, {} locations and {} policies; " +
-        		"removing {} entities, {} locations and {} policies", 
-                new Object[] {delta.entities(), delta.locations(), delta.policies(),
-                delta.removedEntityIds(), delta.removedLocationIds(), delta.removedPolicyIds()});
+        if (LOG.isTraceEnabled()) LOG.trace("Checkpointed delta of memento; updating {} entities, {} locations, {} policies and {} enrichers; " +
+        		"removing {} entities, {} locations {} policies and {} enrichers", 
+                new Object[] {delta.entities(), delta.locations(), delta.policies(), delta.enrichers(),
+                delta.removedEntityIds(), delta.removedLocationIds(), delta.removedPolicyIds(), delta.removedEnricherIds()});
         
         for (EntityMemento entity : delta.entities()) {
             persist(entity);
@@ -247,6 +273,9 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         for (PolicyMemento policy : delta.policies()) {
             persist(policy);
         }
+        for (EnricherMemento enricher : delta.enrichers()) {
+            persist(enricher);
+        }
         for (String id : delta.removedEntityIds()) {
             deleteEntity(id);
         }
@@ -256,6 +285,9 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         for (String id : delta.removedPolicyIds()) {
             deletePolicy(id);
         }
+        for (String id : delta.removedEnricherIds()) {
+            deleteEnricher(id);
+        }
     }
 
     @VisibleForTesting
@@ -279,6 +311,9 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         for (MementoFileWriter<?> writer : policyWriters.values()) {
             writer.waitForWriteCompleted(timeout);
         }
+        for (MementoFileWriter<?> writer : enricherWriters.values()) {
+            writer.waitForWriteCompleted(timeout);
+        }
     }
 
     // TODO Promote somewhere sensible; share code with BrooklynLauncher.checkPersistenceDirAccessible
@@ -322,6 +357,15 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         }
         writer.write(policy);
     }
+    
+    private void persist(EnricherMemento enricher) {
+        MementoFileWriter<EnricherMemento> writer = enricherWriters.get(enricher.getId());
+        if (writer == null) {
+            enricherWriters.putIfAbsent(enricher.getId(), new MementoFileWriter<EnricherMemento>(getFileFor(enricher), executor, serializer));
+            writer = enricherWriters.get(enricher.getId());
+        }
+        writer.write(enricher);
+    }
 
     private void deleteEntity(String id) {
         MementoFileWriter<EntityMemento> writer = entityWriters.get(id);
@@ -343,6 +387,13 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
             writer.delete();
         }
     }
+    
+    private void deleteEnricher(String id) {
+        MementoFileWriter<EnricherMemento> writer = enricherWriters.get(id);
+        if (writer != null) {
+            writer.delete();
+        }
+    }
 
     private File getFileFor(EntityMemento entity) {
         return new File(entitiesDir, entity.getId());
@@ -355,4 +406,8 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
     private File getFileFor(PolicyMemento policy) {
         return new File(policiesDir, policy.getId());
     }
+    
+    private File getFileFor(EnricherMemento enricher) {
+        return new File(enrichersDir, enricher.getId());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java b/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
index 8b44234..02da444 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
@@ -15,8 +15,10 @@ import brooklyn.entity.basic.BasicParameterType;
 import brooklyn.entity.effector.EffectorAndBody;
 import brooklyn.entity.effector.EffectorTasks.EffectorBodyTaskFactory;
 import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
+import brooklyn.entity.rebind.dto.BasicEnricherMemento;
 import brooklyn.entity.rebind.dto.BasicEntityMemento;
 import brooklyn.entity.rebind.dto.BasicLocationMemento;
+import brooklyn.entity.rebind.dto.BasicPolicyMemento;
 import brooklyn.entity.rebind.dto.MutableBrooklynMemento;
 import brooklyn.entity.trait.Identifiable;
 import brooklyn.event.basic.BasicAttributeSensor;
@@ -24,6 +26,8 @@ import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.location.Location;
 import brooklyn.management.Task;
 import brooklyn.mementos.BrooklynMementoPersister.LookupContext;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.xstream.XmlSerializer;
 
@@ -57,6 +61,8 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
         
         xstream.alias("entity", BasicEntityMemento.class);
         xstream.alias("location", BasicLocationMemento.class);
+        xstream.alias("policy", BasicPolicyMemento.class);
+        xstream.alias("enricher", BasicEnricherMemento.class);
         xstream.alias("configKey", BasicConfigKey.class);
         xstream.alias("attributeSensor", BasicAttributeSensor.class);
         
@@ -67,11 +73,14 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
         
         xstream.alias("entityRef", Entity.class);
         xstream.alias("locationRef", Location.class);
+        xstream.alias("policyRef", Policy.class);
+        xstream.alias("enricherRef", Enricher.class);
 
         xstream.registerConverter(new LocationConverter());
+        xstream.registerConverter(new PolicyConverter());
+        xstream.registerConverter(new EnricherConverter());
         xstream.registerConverter(new EntityConverter());
         xstream.registerConverter(new TaskConverter(xstream.getMapper()));
-        // TODO policies/enrichers serialization/deserialization?!
     }
     
     // Warning: this is called in the super-class constuctor, so before this constructor!
@@ -187,6 +196,26 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
             return lookupContext.lookupLocation(type, id);
         }
     }
+
+    public class PolicyConverter extends IdentifiableConverter<Policy> {
+        PolicyConverter() {
+            super(Policy.class);
+        }
+        @Override
+        protected Policy lookup(Class<?> type, String id) {
+            return lookupContext.lookupPolicy(type, id);
+        }
+    }
+
+    public class EnricherConverter extends IdentifiableConverter<Enricher> {
+        EnricherConverter() {
+            super(Enricher.class);
+        }
+        @Override
+        protected Enricher lookup(Class<?> type, String id) {
+            return lookupContext.lookupEnricher(type, id);
+        }
+    }
     
     public class EntityConverter extends IdentifiableConverter<Entity> {
         EntityConverter() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/management/internal/EntityChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/EntityChangeListener.java b/core/src/main/java/brooklyn/management/internal/EntityChangeListener.java
index 197b5ae..36a6324 100644
--- a/core/src/main/java/brooklyn/management/internal/EntityChangeListener.java
+++ b/core/src/main/java/brooklyn/management/internal/EntityChangeListener.java
@@ -30,7 +30,7 @@ public interface EntityChangeListener {
 
     void onChildrenChanged();
 
-    void onPoliciesChanged();
+    void onPoliciesChanged(); // TODO
 
     void onEffectorStarting(Effector<?> effector);
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java b/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
index c9b974b..6d65648 100644
--- a/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
+++ b/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
@@ -344,7 +344,9 @@ public class EntityManagementSupport {
         }
         @Override
         public void onAttributeChanged(AttributeSensor<?> attribute) {
+            // if important persist, otherwiise ignore
             getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
+            // getManagementContext().getRebindManager().getAttributeChangeListener().onChanged(entity, attribute);
         }
         @Override
         public void onConfigChanged(ConfigKey<?> key) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/80532a5b/core/src/test/java/brooklyn/entity/rebind/persister/XmlMementoSerializerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/persister/XmlMementoSerializerTest.java b/core/src/test/java/brooklyn/entity/rebind/persister/XmlMementoSerializerTest.java
index 02e06fb..47d525b 100644
--- a/core/src/test/java/brooklyn/entity/rebind/persister/XmlMementoSerializerTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/persister/XmlMementoSerializerTest.java
@@ -22,6 +22,8 @@ import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.management.ManagementContext;
 import brooklyn.mementos.BrooklynMementoPersister.LookupContext;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
@@ -43,76 +45,76 @@ public class XmlMementoSerializerTest {
     public void setUp() throws Exception {
         serializer = new XmlMementoSerializer<Object>(XmlMementoSerializerTest.class.getClassLoader());
     }
-    
+
     @Test
     public void testMutableSet() throws Exception {
         Set<?> obj = MutableSet.of("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testLinkedHashSet() throws Exception {
         Set<String> obj = new LinkedHashSet<String>();
         obj.add("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testImmutableSet() throws Exception {
         Set<String> obj = ImmutableSet.of("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testMutableList() throws Exception {
         List<?> obj = MutableList.of("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testLinkedList() throws Exception {
         List<String> obj = new LinkedList<String>();
         obj.add("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testImmutableList() throws Exception {
         List<String> obj = ImmutableList.of("123");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testMutableMap() throws Exception {
         Map<?,?> obj = MutableMap.of("mykey", "myval");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testLinkedHashMap() throws Exception {
         Map<String,String> obj = new LinkedHashMap<String,String>();
         obj.put("mykey", "myval");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testImmutableMap() throws Exception {
         Map<?,?> obj = ImmutableMap.of("mykey", "myval");
         assertSerializeAndDeserialize(obj);
     }
-    
+
     @Test
     public void testEntity() throws Exception {
         final TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of()));
+            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of(), ImmutableMap.<String,Policy>of(), ImmutableMap.<String,Enricher>of()));
             assertSerializeAndDeserialize(app);
         } finally {
             Entities.destroyAll(managementContext);
         }
     }
-    
+
     @Test
     public void testLocation() throws Exception {
         TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
@@ -120,41 +122,41 @@ public class XmlMementoSerializerTest {
         try {
             @SuppressWarnings("deprecation")
             final Location loc = managementContext.getLocationManager().createLocation(LocationSpec.create(brooklyn.location.basic.SimulatedLocation.class));
-            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.<String,Entity>of(), ImmutableMap.of(loc.getId(), loc)));
+            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.<String,Entity>of(), ImmutableMap.of(loc.getId(), loc), ImmutableMap.<String,Policy>of(), ImmutableMap.<String,Enricher>of()));
             assertSerializeAndDeserialize(loc);
         } finally {
             Entities.destroyAll(managementContext);
         }
     }
-    
+
     @Test
     public void testFieldReffingEntity() throws Exception {
         final TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
         ReffingEntity reffer = new ReffingEntity(app);
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of()));
+            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of(), ImmutableMap.<String,Policy>of(), ImmutableMap.<String,Enricher>of()));
             ReffingEntity reffer2 = assertSerializeAndDeserialize(reffer);
             assertEquals(reffer2.entity, app);
         } finally {
             Entities.destroyAll(managementContext);
         }
     }
-    
+
     @Test
     public void testUntypedFieldReffingEntity() throws Exception {
         final TestApplication app = ApplicationBuilder.newManagedApp(TestApplication.class);
         ReffingEntity reffer = new ReffingEntity((Object)app);
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of()));
+            serializer.setLookupContext(new LookupContextImpl(ImmutableMap.of(app.getId(), app), ImmutableMap.<String,Location>of(), ImmutableMap.<String,Policy>of(), ImmutableMap.<String,Enricher>of()));
             ReffingEntity reffer2 = assertSerializeAndDeserialize(reffer);
             assertEquals(reffer2.obj, app);
         } finally {
             Entities.destroyAll(managementContext);
         }
     }
-    
+
     public static class ReffingEntity {
         public Entity entity;
         public Object obj;
@@ -173,7 +175,7 @@ public class XmlMementoSerializerTest {
             return Objects.hashCode(entity, obj);
         }
     }
-    
+
     @SuppressWarnings("unchecked")
     private <T> T assertSerializeAndDeserialize(T obj) throws Exception {
         String serializedForm = serializer.toString(obj);
@@ -182,14 +184,19 @@ public class XmlMementoSerializerTest {
         assertEquals(deserialized, obj, "serializedForm="+serializedForm);
         return (T) deserialized;
     }
-    
+
     static class LookupContextImpl implements LookupContext {
         private final Map<String, ? extends Entity> entities;
         private final Map<String, ? extends Location> locations;
-        
-        LookupContextImpl(Map<String,? extends Entity> entities, Map<String,? extends Location> locations) {
+        private final Map<String, ? extends Policy> policies;
+        private final Map<String, ? extends Enricher> enrichers;
+
+        LookupContextImpl(Map<String,? extends Entity> entities, Map<String,? extends Location> locations,
+                Map<String,? extends Policy> policies, Map<String,? extends Enricher> enrichers) {
             this.entities = entities;
             this.locations = locations;
+            this.policies = policies;
+            this.enrichers = enrichers;
         }
         @Override public Entity lookupEntity(Class<?> type, String id) {
             if (entities.containsKey(id)) {
@@ -199,7 +206,7 @@ public class XmlMementoSerializerTest {
                 }
                 return result;
             }
-            throw new NoSuchElementException("no entity with id "+id+"; contenders are "+locations.keySet()); 
+            throw new NoSuchElementException("no entity with id "+id+"; contenders are "+entities.keySet());
         }
         @Override public Location lookupLocation(Class<?> type, String id) {
             if (locations.containsKey(id)) {
@@ -209,7 +216,27 @@ public class XmlMementoSerializerTest {
                 }
                 return result;
             }
-            throw new NoSuchElementException("no location with id "+id+"; contenders are "+locations.keySet()); 
+            throw new NoSuchElementException("no location with id "+id+"; contenders are "+locations.keySet());
+        }
+        @Override public Policy lookupPolicy(Class<?> type, String id) {
+            if (policies.containsKey(id)) {
+                Policy result = policies.get(id);
+                if (type != null && !type.isInstance(result)) {
+                    throw new IllegalStateException("Policy with id "+id+" does not match type "+type+"; got "+result);
+                }
+                return result;
+            }
+            throw new NoSuchElementException("no policy with id "+id+"; contenders are "+policies.keySet());
+        }
+        @Override public Enricher lookupEnricher(Class<?> type, String id) {
+            if (enrichers.containsKey(id)) {
+                Enricher result = enrichers.get(id);
+                if (type != null && !type.isInstance(result)) {
+                    throw new IllegalStateException("Enricher with id "+id+" does not match type "+type+"; got "+result);
+                }
+                return result;
+            }
+            throw new NoSuchElementException("no enricher with id "+id+"; contenders are "+enrichers.keySet());
         }
     };
 }


Mime
View raw message