You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/08/07 23:55:39 UTC

[5/9] git commit: Add persisted getTags to BrooklynObject

Add persisted getTags to BrooklynObject

- no longer just Entity
- deprecate tag methods on Entity (getTags/addTags/etc), and now have
  getTagSupport() so that the Entity interface doesn’t get as cluttered.
- adds requestPersist() to AbstractBrooklynObject


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

Branch: refs/heads/master
Commit: fed8ee6f078d79d2a9e9e9ef3e239bf861db7dd4
Parents: d9594b3
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 21:29:34 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 6 23:17:46 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/basic/BrooklynObject.java     | 28 ++++++++
 api/src/main/java/brooklyn/entity/Entity.java   | 29 ++++++---
 .../java/brooklyn/mementos/EntityMemento.java   |  3 -
 .../main/java/brooklyn/mementos/Memento.java    |  3 +
 .../brooklyn/basic/AbstractBrooklynObject.java  | 47 ++++++++++++++
 .../brooklyn/basic/BrooklynDynamicType.java     | 10 +--
 .../enricher/basic/AbstractEnricher.java        |  7 +-
 .../brooklyn/entity/basic/AbstractEntity.java   | 24 ++-----
 .../entity/basic/EntityInitializers.java        |  2 +-
 .../rebind/BasicEnricherRebindSupport.java      | 11 +++-
 .../entity/rebind/BasicEntityRebindSupport.java |  2 +-
 .../rebind/BasicLocationRebindSupport.java      |  7 ++
 .../entity/rebind/BasicPolicyRebindSupport.java | 10 ++-
 .../entity/rebind/dto/AbstractMemento.java      | 11 +++-
 .../entity/rebind/dto/BasicEntityMemento.java   |  7 --
 .../entity/rebind/dto/MementosGenerators.java   | 67 ++++++++++----------
 .../location/basic/AbstractLocation.java        |  8 +++
 .../policy/basic/AbstractEntityAdjunct.java     | 17 ++---
 .../brooklyn/policy/basic/AbstractPolicy.java   |  8 +++
 .../brooklyn/entity/basic/EntitiesTest.java     | 18 +++---
 .../entity/rebind/RebindEnricherTest.java       | 14 ++++
 .../entity/rebind/RebindEntityTest.java         | 14 ++--
 .../entity/rebind/RebindLocationTest.java       | 17 ++++-
 .../entity/rebind/RebindPolicyTest.java         | 25 ++++++--
 .../brooklyn/rest/resources/EntityResource.java | 14 ++--
 .../rest/resources/EntityResourceTest.java      | 11 +---
 26 files changed, 280 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/api/src/main/java/brooklyn/basic/BrooklynObject.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/BrooklynObject.java b/api/src/main/java/brooklyn/basic/BrooklynObject.java
index 9e22f96..44cd489 100644
--- a/api/src/main/java/brooklyn/basic/BrooklynObject.java
+++ b/api/src/main/java/brooklyn/basic/BrooklynObject.java
@@ -18,8 +18,14 @@
  */
 package brooklyn.basic;
 
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
 import brooklyn.entity.trait.Identifiable;
 
+import com.google.common.collect.ImmutableMap;
+
 /**
  * Super-type of entity, location, policy and enricher.
  */
@@ -28,4 +34,26 @@ public interface BrooklynObject extends Identifiable {
      * A display name; recommended to be a concise single-line description.
      */
     String getDisplayName();
+    
+    /** 
+     * Tags are arbitrary objects which can be attached to an entity for subsequent reference.
+     * They must not be null (as {@link ImmutableMap} may be used under the covers; also there is little point!);
+     * and they should be amenable to our persistence (on-disk serialization) and our JSON serialization in the REST API.
+     */
+    TagSupport getTagSupport();
+    
+    public static interface TagSupport {
+        /**
+         * @return An immutable copy of the set of tags on this entity. 
+         * Note {@link #containsTag(Object)} will be more efficient,
+         * and {@link #addTag(Object)} and {@link #removeTag(Object)} will not work on the returned set.
+         */
+        Set<Object> getTags();
+        
+        boolean containsTag(@Nonnull Object tag);
+        
+        boolean addTag(@Nonnull Object tag);
+        
+        boolean removeTag(@Nonnull Object tag);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/api/src/main/java/brooklyn/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/Entity.java b/api/src/main/java/brooklyn/entity/Entity.java
index c792067..88a10fa 100644
--- a/api/src/main/java/brooklyn/entity/Entity.java
+++ b/api/src/main/java/brooklyn/entity/Entity.java
@@ -38,8 +38,6 @@ import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.util.guava.Maybe;
 
-import com.google.common.collect.ImmutableMap;
-
 /**
  * The basic interface for a Brooklyn entity.
  * <p>
@@ -246,16 +244,27 @@ public interface Entity extends BrooklynObject {
     boolean removeEnricher(Enricher enricher);
     
     /** 
-     * Tags are arbitrary objects which can be attached to an entity for subsequent reference.
-     * They must not be null (as {@link ImmutableMap} may be used under the covers; also there is little point!);
-     * and they should be amenable to our persistence (on-disk serialization) and our JSON serialization in the REST API.
-     * 
-     * @return An immutable copy of the set of tags on this entity. 
-     * Note {@link #containsTag(Object)} will be more efficient,
-     * and {@link #addTag(Object)} and {@link #removeTag(Object)} will not work. */
+     * @since 0.7
+     * @deprecated since 0.7; see {@link #getTagSupport()}
+     */
+    @Deprecated
     Set<Object> getTags();
+    /** 
+     * @since 0.7
+     * @deprecated since 0.7; see {@link #getTagSupport()}
+     */
+    @Deprecated
     boolean addTag(@Nonnull Object tag);
+    /** 
+     * @since 0.7
+     * @deprecated since 0.7; see {@link #getTagSupport()}
+     */
+    @Deprecated
     boolean removeTag(@Nonnull Object tag);
+    /** 
+     * @since 0.7
+     * @deprecated since 0.7; see {@link #getTagSupport()}
+     */
+    @Deprecated
     boolean containsTag(@Nonnull Object tag);
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/api/src/main/java/brooklyn/mementos/EntityMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/EntityMemento.java b/api/src/main/java/brooklyn/mementos/EntityMemento.java
index 6f0ef78..c0547d4 100644
--- a/api/src/main/java/brooklyn/mementos/EntityMemento.java
+++ b/api/src/main/java/brooklyn/mementos/EntityMemento.java
@@ -72,7 +72,4 @@ public interface EntityMemento extends Memento, TreeNode {
      * The ids of the enrichers of this entity.
      */
     public Collection<String> getEnrichers();
-
-    public Collection<Object> getTags();
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/api/src/main/java/brooklyn/mementos/Memento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/Memento.java b/api/src/main/java/brooklyn/mementos/Memento.java
index a83bde8..be8b629 100644
--- a/api/src/main/java/brooklyn/mementos/Memento.java
+++ b/api/src/main/java/brooklyn/mementos/Memento.java
@@ -19,6 +19,7 @@
 package brooklyn.mementos;
 
 import java.io.Serializable;
+import java.util.Collection;
 import java.util.Map;
 
 import brooklyn.entity.rebind.RebindSupport;
@@ -69,4 +70,6 @@ public interface Memento extends Serializable {
      * previously calling {@code EntityTypes.getDefinedSensors(getType())}. 
      */
     public Class<?> getTypeClass();
+
+    public Collection<Object> getTags();
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
index b64db51..7cc1ffd 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -18,16 +18,63 @@
  */
 package brooklyn.basic;
 
+import java.util.Set;
+
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
 public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
     @SetFromFlag(value="id")
     private String id = Identifiers.makeRandomId(8);
     
+    private final Set<Object> tags = Sets.newLinkedHashSet();
+
+    protected abstract void requestPersist();
+
     @Override
     public String getId() {
         return id;
     }
+    
+    public TagSupport getTagSupport() {
+        return new TagSupport() {
+            @Override
+            public Set<Object> getTags() {
+                synchronized (tags) {
+                    return ImmutableSet.copyOf(tags);
+                }
+            }
+    
+            @Override
+            public boolean containsTag(Object tag) {
+                synchronized (tags) {
+                    return tags.contains(tag);
+                }
+            }
+            
+            @Override
+            public boolean addTag(Object tag) {
+                boolean result;
+                synchronized (tags) {
+                    result = tags.add(tag);
+                }
+                requestPersist();
+                return result;
+            }    
+    
+            @Override
+            public boolean removeTag(Object tag) {
+                boolean result;
+                synchronized (tags) {
+                    result = tags.remove(tag);
+                }
+                requestPersist();
+                return result;
+            }    
+        };
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
index 637841e..0ae7400 100644
--- a/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
@@ -79,16 +79,12 @@ public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT ex
     protected BrooklynDynamicType(Class<? extends T> clazz, AbstractT instance) {
         this.brooklynClass = checkNotNull(clazz, "brooklyn class");
         this.instance = instance;
-        // NB: official name is usu injected later, e.g. from AbstractEntity.setManagementContext
-        setName((clazz.getCanonicalName() == null) ? clazz.getName() : clazz.getCanonicalName());
-        
-        String id = instance==null ? clazz.getName() : instance.getId();
+        // NB: official name is usually injected later, e.g. from AbstractEntity.setManagementContext
+        this.name = (clazz.getCanonicalName() == null) ? clazz.getName() : clazz.getCanonicalName();
         
         buildConfigKeys(clazz, null, configKeys);
         if (LOG.isTraceEnabled())
-            LOG.trace("Entity {} config keys: {}", id, Joiner.on(", ").join(configKeys.keySet()));
-
-        refreshSnapshot();
+            LOG.trace("Entity {} config keys: {}", (instance==null ? clazz.getName() : instance.getId()), Joiner.on(", ").join(configKeys.keySet()));
     }
     
     protected abstract BrooklynTypeSnapshot newSnapshot();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/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 68120d9..e029ab2 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -62,7 +62,12 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
 
     @Override
     protected void onChanged() {
-        // TODO Could add EnricherChangeListener, similar to EntityChangeListener; should we do that?
+        requestPersist();
+    }
+    
+    @Override
+    protected void requestPersist() {
+        // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
         if (getManagementContext() != null) {
             getManagementContext().getRebindManager().getChangeListener().onChanged(this);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 3b8baec..e2c84fa 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -89,7 +89,6 @@ import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -173,7 +172,6 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     Map<String,Object> presentationAttributes = Maps.newLinkedHashMap();
     Collection<AbstractPolicy> policies = Lists.newCopyOnWriteArrayList();
     Collection<AbstractEnricher> enrichers = Lists.newCopyOnWriteArrayList();
-    Set<Object> tags = Sets.newLinkedHashSet();
 
     // FIXME we do not currently support changing parents, but to implement a cluster that can shrink we need to support at least
     // orphaning (i.e. removing ownership). This flag notes if the entity has previously had a parent, and if an attempt is made to
@@ -1329,36 +1327,22 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
 
     @Override
     public Set<Object> getTags() {
-        synchronized (tags) {
-            return ImmutableSet.copyOf(tags);
-        }
+        return getTagSupport().getTags();
     }
 
     @Override
     public boolean addTag(Object tag) {
-        boolean result;
-        synchronized (tags) {
-            result = tags.add(tag);
-        }
-        getManagementSupport().getEntityChangeListener().onTagsChanged();
-        return result;
+        return getTagSupport().addTag(tag);
     }    
 
     @Override
     public boolean removeTag(Object tag) {
-        boolean result;
-        synchronized (tags) {
-            result = tags.remove(tag);
-        }
-        getManagementSupport().getEntityChangeListener().onTagsChanged();
-        return result;
+        return getTagSupport().removeTag(tag);
     }    
 
     @Override
     public boolean containsTag(Object tag) {
-        synchronized (tags) {
-            return tags.contains(tag);
-        }
+        return getTagSupport().containsTag(tag);
     }    
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/basic/EntityInitializers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityInitializers.java b/core/src/main/java/brooklyn/entity/basic/EntityInitializers.java
index 3571b5a..a2f4186 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityInitializers.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityInitializers.java
@@ -36,7 +36,7 @@ public class EntityInitializers {
         @Override
         public void apply(EntityLocal entity) {
             for (Object tag: tags)
-                entity.addTag(tag);
+                entity.getTagSupport().addTag(tag);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/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 0fc1584..167d684 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
@@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.rebind.dto.MementosGenerators;
 import brooklyn.mementos.EnricherMemento;
+import brooklyn.mementos.Memento;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
 
@@ -39,7 +40,7 @@ public class BasicEnricherRebindSupport implements RebindSupport<EnricherMemento
     
     @Override
     public EnricherMemento getMemento() {
-        EnricherMemento memento = MementosGenerators.newEnricherMementoBuilder(enricher).build();
+        EnricherMemento memento = MementosGenerators.newEnricherMemento(enricher);
         if (LOG.isTraceEnabled()) LOG.trace("Creating memento for enricher: {}", memento.toVerboseString());
         return memento;
     }
@@ -57,11 +58,17 @@ public class BasicEnricherRebindSupport implements RebindSupport<EnricherMemento
         ConfigBag configBag = ConfigBag.newInstance(memento.getConfig());
         FlagUtils.setFieldsFromFlags(enricher, configBag);
         FlagUtils.setAllConfigKeys(enricher, configBag, false);
-        
+        addTags(rebindContext, memento);
         doReconstruct(rebindContext, memento);
         ((AbstractEnricher)enricher).rebind();
     }
 
+    protected void addTags(RebindContext rebindContext, Memento memento) {
+        for (Object tag : memento.getTags()) {
+            enricher.getTagSupport().addTag(tag);
+        }
+    }
+    
     @Override
     public void addPolicies(RebindContext rebindContext, EnricherMemento Memento) {
         throw new UnsupportedOperationException();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/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 62cff7b..bdb87e2 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -175,7 +175,7 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
     
     protected void addTags(RebindContext rebindContext, EntityMemento memento) {
         for (Object tag : memento.getTags()) {
-            entity.addTag(tag);
+            entity.getTagSupport().addTag(tag);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
index 7e930ef..fd5610c 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
@@ -104,12 +104,19 @@ public class BasicLocationRebindSupport implements RebindSupport<LocationMemento
         
         setParent(rebindContext, memento);
         addChildren(rebindContext, memento);
+        addTags(rebindContext, memento);
         location.init(); // TODO deprecated calling init; will be deleted
         location.rebind();
         
         doReconstruct(rebindContext, memento);
     }
 
+    protected void addTags(RebindContext rebindContext, LocationMemento memento) {
+        for (Object tag : memento.getTags()) {
+            location.getTagSupport().addTag(tag);
+        }
+    }
+
     @Override
     public void addPolicies(RebindContext rebindContext, LocationMemento Memento) {
         throw new UnsupportedOperationException();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
index cac7996..228b5ba 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
@@ -22,6 +22,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.rebind.dto.MementosGenerators;
+import brooklyn.mementos.Memento;
 import brooklyn.mementos.PolicyMemento;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.config.ConfigBag;
@@ -39,7 +40,7 @@ public class BasicPolicyRebindSupport implements RebindSupport<PolicyMemento> {
     
     @Override
     public PolicyMemento getMemento() {
-        PolicyMemento memento = MementosGenerators.newPolicyMementoBuilder(policy).build();
+        PolicyMemento memento = MementosGenerators.newPolicyMemento(policy);
         if (LOG.isTraceEnabled()) LOG.trace("Creating memento for policy: {}", memento.toVerboseString());
         return memento;
     }
@@ -57,11 +58,18 @@ public class BasicPolicyRebindSupport implements RebindSupport<PolicyMemento> {
         ConfigBag configBag = ConfigBag.newInstance(memento.getConfig());
         FlagUtils.setFieldsFromFlags(policy, configBag);
         FlagUtils.setAllConfigKeys(policy, configBag, false);
+        addTags(rebindContext, memento);
         
         doReconstruct(rebindContext, memento);
         ((AbstractPolicy)policy).rebind();
     }
 
+    protected void addTags(RebindContext rebindContext, Memento memento) {
+        for (Object tag : memento.getTags()) {
+            policy.getTagSupport().addTag(tag);
+        }
+    }
+    
     @Override
     public void addPolicies(RebindContext rebindContext, PolicyMemento Memento) {
         throw new UnsupportedOperationException();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/rebind/dto/AbstractMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/AbstractMemento.java b/core/src/main/java/brooklyn/entity/rebind/dto/AbstractMemento.java
index 90aad94..67e35da 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/AbstractMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/AbstractMemento.java
@@ -30,6 +30,7 @@ import brooklyn.mementos.Memento;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 public abstract class AbstractMemento implements Memento, Serializable {
@@ -43,7 +44,8 @@ public abstract class AbstractMemento implements Memento, Serializable {
         protected Class<?> typeClass;
         protected String displayName;
         protected Map<String, Object> fields = Maps.newLinkedHashMap();
-        
+        protected List<Object> tags = Lists.newArrayList();
+
         @SuppressWarnings("unchecked")
         protected B self() {
             return (B) this;
@@ -55,6 +57,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
             typeClass = other.getTypeClass();
             displayName = other.getDisplayName();
             fields.putAll(other.getCustomFields());
+            tags.addAll(other.getTags());
             return self();
         }
         public B brooklynVersion(String val) {
@@ -85,6 +88,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
     private String type;
     private String id;
     private String displayName;
+    private List<Object> tags;
 
     private transient Class<?> typeClass;
 
@@ -100,6 +104,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
         typeClass = builder.typeClass;
         displayName = builder.displayName;
         setCustomFields(builder.fields);
+        tags = toPersistedList(builder.tags);
     }
 
     // "fields" is not included as a field here, so that it is serialized after selected subclass fields
@@ -136,6 +141,10 @@ public abstract class AbstractMemento implements Memento, Serializable {
         return displayName;
     }
 
+    public List<Object> getTags() {
+        return fromPersistedList(tags);
+    }
+    
     @Deprecated
     @Override
     public Object getCustomField(String name) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java b/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
index 680b1bf..30eb653 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
@@ -70,7 +70,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         protected List<String> enrichers = Lists.newArrayList();
         protected List<String> members = Lists.newArrayList();
         protected List<Effector<?>> effectors = Lists.newArrayList();
-        protected List<Object> tags = Lists.newArrayList();
         
         public Builder from(EntityMemento other) {
             super.from((TreeNode)other);
@@ -104,7 +103,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
     private Map<String, Object> attributes;
     private List<String> policies;
     private List<String> enrichers;
-    private List<Object> tags;
     
     // TODO can we move some of these to entity type, or remove/re-insert those which are final statics?
     private Map<String, ConfigKey<?>> configKeys;
@@ -133,7 +131,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         policies = toPersistedList(builder.policies);
         enrichers = toPersistedList(builder.enrichers);
         members = toPersistedList(builder.members);
-        tags = toPersistedList(builder.tags);
         
         effectors = toPersistedList(builder.effectors);
         
@@ -278,10 +275,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         return fromPersistedList(members);
     }
     
-    public List<Object> getTags() {
-        return fromPersistedList(tags);
-    }
-    
     @Override
     public List<String> getLocations() {
         return fromPersistedList(locations);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
index 66d9aab..79600da 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Modifier;
 import java.util.Map;
 import java.util.Set;
 
+import brooklyn.basic.BrooklynObject;
 import brooklyn.basic.BrooklynTypes;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
@@ -60,7 +61,10 @@ public class MementosGenerators {
     
     /**
      * Walks the contents of a ManagementContext, to create a corresponding memento.
+     * 
+     * @deprecated since 0.7.0; will be moved to test code; generate each entity/location memento separately
      */
+    @Deprecated
     public static BrooklynMemento newBrooklynMemento(ManagementContext managementContext) {
         BrooklynMementoImpl.Builder builder = BrooklynMementoImpl.builder();
                 
@@ -97,16 +101,17 @@ public class MementosGenerators {
     public static EntityMemento newEntityMemento(Entity entity) {
         return newEntityMementoBuilder(entity).build();
     }
-    
+
+    /**
+     * @deprecated since 0.7.0; use {@link #newEntityMemento(Enricher)} instead
+     */
+    @Deprecated
     public static BasicEntityMemento.Builder newEntityMementoBuilder(Entity entity) {
-        EntityDynamicType definedType = BrooklynTypes.getDefinedEntityType(entity.getClass());
         BasicEntityMemento.Builder builder = BasicEntityMemento.builder();
+        populateBrooklynObjectMementoBuilder(entity, builder);
+        
+        EntityDynamicType definedType = BrooklynTypes.getDefinedEntityType(entity.getClass());
                 
-        builder.id = entity.getId();
-        builder.displayName = entity.getDisplayName();
-        builder.type = entity.getClass().getName();
-        builder.typeClass = entity.getClass();
-
         // TODO the dynamic attributeKeys and configKeys are computed in the BasicEntityMemento
         // whereas effectors are computed here -- should be consistent! 
         // (probably best to compute attrKeys and configKeys here)
@@ -157,10 +162,6 @@ public class MementosGenerators {
             builder.enrichers.add(enricher.getId()); 
         }
         
-        for (Object tag : entity.getTags()) {
-            builder.tags.add(tag); 
-        }
-        
         Entity parentEntity = entity.getParent();
         builder.parent = (parentEntity != null) ? parentEntity.getId() : null;
 
@@ -195,8 +196,13 @@ public class MementosGenerators {
         return newLocationMementoBuilder(location).build();
     }
     
+    /**
+     * @deprecated since 0.7.0; use {@link #newLocationMemento(Enricher)} instead
+     */
+    @Deprecated
     public static BasicLocationMemento.Builder newLocationMementoBuilder(Location location) {
         BasicLocationMemento.Builder builder = BasicLocationMemento.builder();
+        populateBrooklynObjectMementoBuilder(location, builder);
 
         Set<String> nonPersistableFlagNames = MutableMap.<String,Object>builder()
                 .putAll(FlagUtils.getFieldsWithFlagsWithModifiers(location, Modifier.TRANSIENT))
@@ -211,10 +217,6 @@ public class MementosGenerators {
                 .build();
         ConfigBag persistableConfig = new ConfigBag().copy( ((AbstractLocation)location).getLocalConfigBag() ).removeAll(nonPersistableFlagNames);
 
-        builder.type = location.getClass().getName();
-        builder.typeClass = location.getClass();
-        builder.id = location.getId();
-        builder.displayName = location.getDisplayName();
         builder.copyConfig(persistableConfig);
         builder.locationConfig.putAll(persistableFlags);
 
@@ -242,16 +244,8 @@ public class MementosGenerators {
      * Given a policy, extracts its state for serialization.
      */
     public static PolicyMemento newPolicyMemento(Policy policy) {
-        return newPolicyMementoBuilder(policy).build();
-    }
-    
-    public static BasicPolicyMemento.Builder newPolicyMementoBuilder(Policy policy) {
         BasicPolicyMemento.Builder builder = BasicPolicyMemento.builder();
-        
-        builder.type = policy.getClass().getName();
-        builder.typeClass = policy.getClass();
-        builder.id = policy.getId();
-        builder.displayName = policy.getDisplayName();
+        populateBrooklynObjectMementoBuilder(policy, builder);
 
         // TODO persist config keys as well? Or only support those defined on policy class;
         // current code will lose the ConfigKey type on rebind for anything not defined on class.
@@ -271,7 +265,7 @@ public class MementosGenerators {
                 .build();
         builder.config.putAll(persistableFlags);
 
-        return builder;
+        return builder.build();
     }
     
     public static Function<Policy, PolicyMemento> policyMementoFunction() {
@@ -288,17 +282,9 @@ public class MementosGenerators {
      * Given an enricher, extracts its state for serialization.
      */
     public static EnricherMemento newEnricherMemento(Enricher enricher) {
-        return newEnricherMementoBuilder(enricher).build();
-    }
-    
-    public static BasicEnricherMemento.Builder newEnricherMementoBuilder(Enricher enricher) {
         BasicEnricherMemento.Builder builder = BasicEnricherMemento.builder();
+        populateBrooklynObjectMementoBuilder(enricher, builder);
         
-        builder.type = enricher.getClass().getName();
-        builder.typeClass = enricher.getClass();
-        builder.id = enricher.getId();
-        builder.displayName = enricher.getDisplayName();
-
         // TODO persist config keys as well? Or only support those defined on policy class;
         // current code will lose the ConfigKey type on rebind for anything not defined on class.
         // Whereas entities support that.
@@ -317,9 +303,20 @@ public class MementosGenerators {
                 .build();
         builder.config.putAll(persistableFlags);
 
-        return builder;
+        return builder.build();
     }
     
+    private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance, AbstractMemento.Builder<?> builder) {
+        builder.id = instance.getId();
+        builder.displayName = instance.getDisplayName();
+        builder.type = instance.getClass().getName();
+        builder.typeClass = instance.getClass();
+        
+        for (Object tag : instance.getTagSupport().getTags()) {
+            builder.tags.add(tag); 
+        }
+    }
+
     protected static Object configValueToPersistable(Object value) {
         // TODO Swapping an attributeWhenReady task for the actual value, if completed.
         // Long-term, want to just handle task-persistence properly.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
index 651a46b..9c0317e 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -565,6 +565,14 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     }
 
     @Override
+    public void requestPersist() {
+        // TODO Could add LocationChangeListener, similar to EntityChangeListener; should we do that?
+        if (getManagementContext() != null) {
+            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+        }
+    }
+
+    @Override
     public RebindSupport<LocationMemento> getRebindSupport() {
         return new BasicLocationRebindSupport(this);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index 9ca0e91..39524f8 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -69,6 +69,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
     private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
 
     private volatile ManagementContext managementContext;
+
     protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
 
     private boolean _legacyConstruction;
@@ -179,6 +180,14 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         return _legacyConstruction;
     }
 
+    public void setManagementContext(ManagementContext managementContext) {
+        this.managementContext = managementContext;
+    }
+    
+    protected ManagementContext getManagementContext() {
+        return managementContext;
+    }
+
     /**
      * 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.
@@ -188,14 +197,6 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         return _legacyNoConstructionInit;
     }
     
-    public void setManagementContext(ManagementContext managementContext) {
-        this.managementContext = managementContext;
-    }
-    
-    protected ManagementContext getManagementContext() {
-        return managementContext;
-    }
-
     /**
      * Called by framework (in new-style policies where PolicySpec was used) after configuring etc,
      * but before a reference to this policy is shared.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
index 1da196e..52fa5b9 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
@@ -101,6 +101,14 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
     }
     
     @Override
+    protected void requestPersist() {
+        // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
+        if (getManagementContext() != null) {
+            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+        }
+    }
+
+    @Override
     public RebindSupport<PolicyMemento> getRebindSupport() {
         return new BasicPolicyRebindSupport(this);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
index 8acdf72..999c168 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
@@ -109,20 +109,20 @@ public class EntitiesTest extends BrooklynAppUnitTestSupport {
         entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
             .addInitializer(EntityInitializers.addingTags("foo")));
         
-        entity.addTag(app);
+        entity.getTagSupport().addTag(app);
         
-        Assert.assertTrue(entity.containsTag("foo"));
-        Assert.assertFalse(entity.containsTag("bar"));
+        Assert.assertTrue(entity.getTagSupport().containsTag("foo"));
+        Assert.assertFalse(entity.getTagSupport().containsTag("bar"));
         
-        Assert.assertEquals(entity.getTags(), MutableSet.of(app, "foo"));
+        Assert.assertEquals(entity.getTagSupport().getTags(), MutableSet.of(app, "foo"));
         
-        entity.removeTag("foo");
-        Assert.assertFalse(entity.containsTag("foo"));
+        entity.getTagSupport().removeTag("foo");
+        Assert.assertFalse(entity.getTagSupport().containsTag("foo"));
         
-        Assert.assertTrue(entity.containsTag(entity.getParent()));
-        Assert.assertFalse(entity.containsTag(entity));
+        Assert.assertTrue(entity.getTagSupport().containsTag(entity.getParent()));
+        Assert.assertFalse(entity.getTagSupport().containsTag(entity));
         
-        Assert.assertEquals(entity.getTags(), MutableSet.of(app));
+        Assert.assertEquals(entity.getTagSupport().getTags(), MutableSet.of(app));
     }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
index a2bdbb7..d8273ca 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@ -47,6 +47,7 @@ import brooklyn.location.LocationSpec;
 import brooklyn.location.basic.SimulatedLocation;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
+import brooklyn.test.Asserts;
 import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
@@ -57,6 +58,7 @@ import brooklyn.util.text.StringFunctions;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
 public class RebindEnricherTest extends RebindTestFixtureWithApp {
@@ -200,6 +202,18 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
         assertFalse(newEnricher.isRebinding());
     }
     
+    @Test
+    public void testPolicyTags() throws Exception {
+        Enricher origEnricher = origApp.addEnricher(EnricherSpec.create(MyEnricher.class));
+        origEnricher.getTagSupport().addTag("foo");
+        origEnricher.getTagSupport().addTag(origApp);
+
+        newApp = rebind();
+        Enricher newEnricher = Iterables.getOnlyElement(newApp.getEnrichers());
+
+        Asserts.assertEqualsIgnoringOrder(newEnricher.getTagSupport().getTags(), ImmutableSet.of("foo", newApp));
+    }
+
     public static class EnricherChecksIsRebinding extends AbstractEnricher {
         boolean isRebindingValWhenRebinding;
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
index 1292dea..1886619 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
@@ -277,17 +277,17 @@ public class RebindEntityTest extends RebindTestFixtureWithApp {
     @Test
     public void testEntityTags() throws Exception {
         MyEntity origE = origApp.createAndManageChild(EntitySpec.create(MyEntity.class));
-        origE.addTag("foo");
-        origE.addTag(origApp);
+        origE.getTagSupport().addTag("foo");
+        origE.getTagSupport().addTag(origApp);
 
         newApp = rebind(false);
         MyEntity newE = Iterables.getOnlyElement( Entities.descendants(newApp, MyEntity.class) );
 
-        assertTrue(newE.containsTag("foo"), "tags are "+newE.getTags());
-        assertFalse(newE.containsTag("bar"));
-        assertTrue(newE.containsTag(newE.getParent()));
-        assertTrue(newE.containsTag(origApp));
-        assertEquals(newE.getTags(), MutableSet.of("foo", newE.getParent()));
+        assertTrue(newE.getTagSupport().containsTag("foo"), "tags are "+newE.getTagSupport().getTags());
+        assertFalse(newE.getTagSupport().containsTag("bar"));
+        assertTrue(newE.getTagSupport().containsTag(newE.getParent()));
+        assertTrue(newE.getTagSupport().containsTag(origApp));
+        assertEquals(newE.getTagSupport().getTags(), MutableSet.of("foo", newE.getParent()));
     }
 
     public static class ReffingEntity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
index 32342ca..d47a987 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
@@ -40,6 +40,7 @@ import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.basic.AbstractLocation;
 import brooklyn.mementos.LocationMemento;
+import brooklyn.test.Asserts;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
@@ -47,6 +48,7 @@ import brooklyn.util.flags.SetFromFlag;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
 public class RebindLocationTest extends RebindTestFixtureWithApp {
@@ -236,7 +238,7 @@ public class RebindLocationTest extends RebindTestFixtureWithApp {
         MyLocation origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class));
         origApp.start(ImmutableList.of(origLoc));
 
-        newApp = (TestApplication) rebind();
+        newApp = rebind();
         MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
 
         assertNull(newLoc.getAllConfigBag().getStringKey("id"));
@@ -254,6 +256,19 @@ public class RebindLocationTest extends RebindTestFixtureWithApp {
         assertFalse(newLoc.isRebinding());
     }
     
+    @Test
+    public void testLocationTags() throws Exception {
+        Location origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class));
+        origLoc.getTagSupport().addTag("foo");
+        origLoc.getTagSupport().addTag(origApp);
+        origApp.start(ImmutableList.of(origLoc));
+
+        newApp = rebind();
+        Location newLoc = (Location) newManagementContext.getLocationManager().getLocation(origLoc.getId());
+
+        Asserts.assertEqualsIgnoringOrder(newLoc.getTagSupport().getTags(), ImmutableSet.of("foo", newApp));
+    }
+
     public static class LocationChecksIsRebinding extends AbstractLocation {
         boolean isRebindingValWhenRebinding;
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index 35acb2e..90d700b 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@ -40,14 +40,17 @@ import brooklyn.location.Location;
 import brooklyn.location.basic.Locations;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.policy.EnricherSpec;
+import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.policy.basic.AbstractPolicy;
+import brooklyn.test.Asserts;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
 public class RebindPolicyTest extends RebindTestFixtureWithApp {
@@ -90,7 +93,7 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
         assertTrue(origPolicy.initCalled);
         assertFalse(origPolicy.rebindCalled);
         
-        TestApplication newApp = rebind();
+        newApp = rebind();
         MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
         
         assertEquals(newPolicy.myfield, "myFieldVal");
@@ -107,7 +110,7 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
                 .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();
+        newApp = rebind();
         MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
         
         assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
@@ -156,7 +159,7 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
     public void testReboundConfigDoesNotContainId() throws Exception {
         MyPolicy policy = origApp.addPolicy(PolicySpec.create(MyPolicy.class));
         
-        newApp = (TestApplication) rebind();
+        newApp = rebind();
         MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
 
         assertNull(newPolicy.getConfig(ConfigKeys.newStringConfigKey("id")));
@@ -169,7 +172,7 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
                 .configure(MyPolicyReconfigurable.MY_CONFIG, "oldval"));
         policy.setConfig(MyPolicyReconfigurable.MY_CONFIG, "newval");
         
-        newApp = (TestApplication) rebind();
+        newApp = rebind();
         MyPolicyReconfigurable newPolicy = (MyPolicyReconfigurable) Iterables.getOnlyElement(newApp.getPolicies());
 
         assertEquals(newPolicy.getConfig(MyPolicyReconfigurable.MY_CONFIG), "newval");
@@ -179,13 +182,25 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
     public void testIsRebinding() throws Exception {
         origApp.addPolicy(PolicySpec.create(PolicyChecksIsRebinding.class));
 
-        newApp = (TestApplication) rebind();
+        newApp = rebind();
         PolicyChecksIsRebinding newPolicy = (PolicyChecksIsRebinding) Iterables.getOnlyElement(newApp.getPolicies());
 
         assertTrue(newPolicy.isRebindingValWhenRebinding());
         assertFalse(newPolicy.isRebinding());
     }
     
+    @Test
+    public void testPolicyTags() throws Exception {
+        Policy origPolicy = origApp.addPolicy(PolicySpec.create(MyPolicy.class));
+        origPolicy.getTagSupport().addTag("foo");
+        origPolicy.getTagSupport().addTag(origApp);
+
+        newApp = rebind();
+        Policy newPolicy = Iterables.getOnlyElement(newApp.getPolicies());
+
+        Asserts.assertEqualsIgnoringOrder(newPolicy.getTagSupport().getTags(), ImmutableSet.of("foo", newApp));
+    }
+
     // Previously, policy+enricher was added to entity as part of entity.reconstitute, so other entities might not
     // have been initialised and the relationships not set. If a policy immediately looked at entity's children or
     // at another entity, then it might find those entities' state uninitialised.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
index 05b1908..d4d3962 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
@@ -18,8 +18,8 @@
  */
 package brooklyn.rest.resources;
 
-import static javax.ws.rs.core.Response.Status.ACCEPTED;
 import static javax.ws.rs.core.Response.status;
+import static javax.ws.rs.core.Response.Status.ACCEPTED;
 
 import java.net.URI;
 import java.util.LinkedList;
@@ -31,11 +31,6 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
-import com.google.common.collect.Collections2;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Lists;
-import com.google.common.io.Files;
-
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityLocal;
@@ -55,6 +50,11 @@ import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
 public class EntityResource extends AbstractBrooklynRestResource implements EntityApi {
 
   @Override
@@ -104,7 +104,7 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti
   @Override
   public List<Object> listTags(String applicationId, String entityId) {
       Entity entity = brooklyn().getEntity(applicationId, entityId);
-      return MutableList.copyOf(entity.getTags());
+      return MutableList.copyOf(entity.getTagSupport().getTags());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fed8ee6f/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
index 9c56e81..bedf61b 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
@@ -24,16 +24,11 @@ import javax.annotation.Nullable;
 import javax.ws.rs.core.MediaType;
 
 import org.testng.Assert;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import brooklyn.config.render.RendererHints;
-import brooklyn.config.render.TestRendererHints;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.event.AttributeSensor;
-import brooklyn.rest.api.SensorApi;
 import brooklyn.rest.domain.ApplicationSpec;
 import brooklyn.rest.domain.EntitySpec;
 import brooklyn.rest.testing.BrooklynRestResourceTest;
@@ -79,7 +74,7 @@ public class EntityResourceTest extends BrooklynRestResourceTest {
 
     @Test
     public void testTagsSanity() throws Exception {
-        entity.addTag("foo");
+        entity.getTagSupport().addTag("foo");
         
         ClientResponse response = client().resource(entityEndpoint + "/tags")
                 .accept(MediaType.APPLICATION_JSON)
@@ -93,8 +88,8 @@ public class EntityResourceTest extends BrooklynRestResourceTest {
     // TODO any entity or complex object should be cleaned up as part of WebResourceUtils call
     @Test(groups="WIP")
     public void testTagsDoNotSerializeTooMuch() throws Exception {
-        entity.addTag("foo");
-        entity.addTag(entity.getParent());
+        entity.getTagSupport().addTag("foo");
+        entity.getTagSupport().addTag(entity.getParent());
 
         ClientResponse response = client().resource(entityEndpoint + "/tags")
                 .accept(MediaType.APPLICATION_JSON)