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:35 UTC

[1/9] git commit: Adds BrooklynType super-class

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 4891355f7 -> d4a6328eb


Adds BrooklynType super-class

- use PolicyDynamicType and EnricherDynamicType, deleting previous
  classes.
- adds BrooklynTypes, deprecating old EntityTypes


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

Branch: refs/heads/master
Commit: d9594b36c1861d58fbb03ed9e2787234294c5dc4
Parents: 371a351
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 16:21:17 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 6 22:10:35 2014 +0100

----------------------------------------------------------------------
 .../main/java/brooklyn/basic/BrooklynType.java  |  54 ++++
 .../main/java/brooklyn/entity/EntityType.java   |  24 +-
 .../main/java/brooklyn/policy/EnricherType.java |  24 +-
 .../main/java/brooklyn/policy/PolicyType.java   |  22 +-
 .../brooklyn/basic/BrooklynDynamicType.java     | 287 +++++++++++++++++++
 .../brooklyn/basic/BrooklynTypeSnapshot.java    | 100 +++++++
 .../main/java/brooklyn/basic/BrooklynTypes.java | 119 ++++++++
 .../enricher/basic/AbstractEnricher.java        |  12 +-
 .../enricher/basic/EnricherDynamicType.java     |  39 +++
 .../enricher/basic/EnricherTypeSnapshot.java    |  39 +++
 .../brooklyn/entity/basic/AbstractEntity.java   |   2 -
 .../entity/basic/EntityDynamicType.java         | 252 ++--------------
 .../entity/basic/EntityTypeSnapshot.java        |  58 +---
 .../java/brooklyn/entity/basic/EntityTypes.java |  86 +-----
 .../entity/rebind/dto/BasicEntityMemento.java   |   6 +-
 .../entity/rebind/dto/MementosGenerators.java   |   4 +-
 .../brooklyn/policy/basic/AbstractPolicy.java   |  14 +-
 .../brooklyn/policy/basic/EnricherTypeImpl.java |  75 -----
 .../policy/basic/PolicyDynamicType.java         |  39 +++
 .../brooklyn/policy/basic/PolicyTypeImpl.java   |  75 -----
 .../policy/basic/PolicyTypeSnapshot.java        |  39 +++
 .../rest/transform/CatalogTransformer.java      |   4 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   4 +-
 23 files changed, 782 insertions(+), 596 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/api/src/main/java/brooklyn/basic/BrooklynType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/BrooklynType.java b/api/src/main/java/brooklyn/basic/BrooklynType.java
new file mode 100644
index 0000000..fe1efe2
--- /dev/null
+++ b/api/src/main/java/brooklyn/basic/BrooklynType.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.basic;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import brooklyn.config.ConfigKey;
+
+/**
+ * Gives type information for a {@link BrooklynObject}. It is an immutable snapshot.
+ * 
+ * It reflects a given brooklyn object at the time the snapshot was created: if anything
+ * were added or removed on-the-fly then those changes will be included in subsequent
+ * snapshots. Therefore instances of a given class could have different {@link BrooklynType}s.
+ */
+public interface BrooklynType extends Serializable {
+
+    /**
+     * The type name of this entity (normally the fully qualified class name).
+     */
+    String getName();
+    
+    /**
+     * The simple type name of this entity (normally the unqualified class name).
+     */
+    String getSimpleName();
+
+    /**
+     * ConfigKeys available on this entity.
+     */
+    Set<ConfigKey<?>> getConfigKeys();
+    
+    /**
+     * The ConfigKey with the given name, or null if not found.
+     */
+    ConfigKey<?> getConfigKey(String name);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/api/src/main/java/brooklyn/entity/EntityType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/EntityType.java b/api/src/main/java/brooklyn/entity/EntityType.java
index 78d1d77..de8bdfe 100644
--- a/api/src/main/java/brooklyn/entity/EntityType.java
+++ b/api/src/main/java/brooklyn/entity/EntityType.java
@@ -18,10 +18,10 @@
  */
 package brooklyn.entity;
 
-import java.io.Serializable;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
+import brooklyn.basic.BrooklynType;
 import brooklyn.config.ConfigKey;
 import brooklyn.event.Sensor;
 import brooklyn.util.guava.Maybe;
@@ -34,24 +34,9 @@ import brooklyn.util.guava.Maybe;
  * snapshots. Therefore instances of a given class of entity could have different 
  * EntityTypes.
  */
-public interface EntityType extends Serializable {
+public interface EntityType extends BrooklynType {
 
     /**
-     * The type name of this entity (normally the fully qualified class name).
-     */
-    String getName();
-    
-    /**
-     * The simple type name of this entity (normally the unqualified class name).
-     */
-    String getSimpleName();
-
-    /**
-     * ConfigKeys available on this entity.
-     */
-    Set<ConfigKey<?>> getConfigKeys();
-    
-    /**
      * Sensors available on this entity.
      */
     Set<Sensor<?>> getSensors();
@@ -77,11 +62,6 @@ public interface EntityType extends Serializable {
     Effector<?> getEffector(String name, Class<?>... parameterTypes);
 
     /**
-     * The ConfigKey with the given name, or null if not found.
-     */
-    ConfigKey<?> getConfigKey(String name);
-    
-    /**
      * The Sensor with the given name, or null if not found.
      */
     Sensor<?> getSensor(String name);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/api/src/main/java/brooklyn/policy/EnricherType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/EnricherType.java b/api/src/main/java/brooklyn/policy/EnricherType.java
index 35a1301..dc59423 100644
--- a/api/src/main/java/brooklyn/policy/EnricherType.java
+++ b/api/src/main/java/brooklyn/policy/EnricherType.java
@@ -18,10 +18,7 @@
  */
 package brooklyn.policy;
 
-import java.io.Serializable;
-import java.util.Set;
-
-import brooklyn.config.ConfigKey;
+import brooklyn.basic.BrooklynType;
 
 import com.google.common.annotations.Beta;
 
@@ -35,22 +32,5 @@ import com.google.common.annotations.Beta;
  * @since 0.6
  */
 @Beta
-public interface EnricherType extends Serializable {
-
-    // TODO Consider merging this with PolicyType? Have a common super-type? It also has overlap with EntityType.
-    
-    /**
-     * The type name of this policy (normally the fully qualified class name).
-     */
-    String getName();
-    
-    /**
-     * ConfigKeys available on this policy.
-     */
-    Set<ConfigKey<?>> getConfigKeys();
-    
-    /**
-     * The ConfigKey with the given name, or null if not found.
-     */
-    ConfigKey<?> getConfigKey(String name);
+public interface EnricherType extends BrooklynType {
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/api/src/main/java/brooklyn/policy/PolicyType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/PolicyType.java b/api/src/main/java/brooklyn/policy/PolicyType.java
index 207d727..707b4aa 100644
--- a/api/src/main/java/brooklyn/policy/PolicyType.java
+++ b/api/src/main/java/brooklyn/policy/PolicyType.java
@@ -18,10 +18,7 @@
  */
 package brooklyn.policy;
 
-import java.io.Serializable;
-import java.util.Set;
-
-import brooklyn.config.ConfigKey;
+import brooklyn.basic.BrooklynType;
 
 import com.google.common.annotations.Beta;
 
@@ -35,20 +32,5 @@ import com.google.common.annotations.Beta;
  * @since 0.5
  */
 @Beta
-public interface PolicyType extends Serializable {
-
-    /**
-     * The type name of this policy (normally the fully qualified class name).
-     */
-    String getName();
-    
-    /**
-     * ConfigKeys available on this policy.
-     */
-    Set<ConfigKey<?>> getConfigKeys();
-    
-    /**
-     * The ConfigKey with the given name, or null if not found.
-     */
-    ConfigKey<?> getConfigKey(String name);
+public interface PolicyType extends BrooklynType {
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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
new file mode 100644
index 0000000..637841e
--- /dev/null
+++ b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.basic;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
+import brooklyn.util.flags.FlagUtils;
+import brooklyn.util.javalang.Reflections;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Lists;
+
+/**
+ * This is the actual type of a brooklyn object instance at runtime,
+ * which can change from the static {@link BrooklynType}, and can change over time;
+ * for this reason it does *not* implement BrooklynType, but 
+ * callers can call {@link #getSnapshot()} to get a snapshot such instance.  
+ */
+public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT extends AbstractBrooklynObject> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BrooklynDynamicType.class);
+
+    protected final Class<? extends T> brooklynClass;
+    protected final AbstractT instance;
+    protected volatile String name;
+    
+    /** 
+     * Map of config keys (and their fields) on this instance, by name.
+     */
+    protected final Map<String,FieldAndValue<ConfigKey<?>>> configKeys = new ConcurrentHashMap<String, FieldAndValue<ConfigKey<?>>>();
+
+    private volatile BrooklynTypeSnapshot snapshot;
+    private final AtomicBoolean snapshotValid = new AtomicBoolean(false);
+
+    public BrooklynDynamicType(AbstractT instance) {
+        this((Class<? extends T>) instance.getClass(), instance);
+    }
+    public BrooklynDynamicType(Class<? extends T> clazz) {
+        this(clazz, null);
+    }
+    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();
+        
+        buildConfigKeys(clazz, null, configKeys);
+        if (LOG.isTraceEnabled())
+            LOG.trace("Entity {} config keys: {}", id, Joiner.on(", ").join(configKeys.keySet()));
+
+        refreshSnapshot();
+    }
+    
+    protected abstract BrooklynTypeSnapshot newSnapshot();
+
+    protected void invalidateSnapshot() {
+        snapshotValid.set(false);
+    }
+
+    public void setName(String name) {
+        if (Strings.isBlank(name)) {
+            throw new IllegalArgumentException("Invalid name "+(name == null ? "null" : "'"+name+"'")+"; name must be non-empty and not just white space");
+        }
+        this.name = name;
+        invalidateSnapshot();
+    }
+    
+    public synchronized BrooklynType getSnapshot() {
+        return refreshSnapshot();
+    }
+    
+    public Class<? extends T> getBrooklynClass() {
+        return brooklynClass;
+    }
+    
+    // --------------------------------------------------
+    
+    /**
+     * ConfigKeys available on this entity.
+     */
+    public Map<String,ConfigKey<?>> getConfigKeys() {
+        return Collections.unmodifiableMap(value(configKeys));
+    }
+
+    /**
+     * ConfigKeys available on this entity.
+     */
+    public ConfigKey<?> getConfigKey(String keyName) { 
+        return value(configKeys.get(keyName)); 
+    }
+
+    /** field where a config key is defined, for use getting annotations. note annotations are not inherited. */
+    public Field getConfigKeyField(String keyName) { 
+        return field(configKeys.get(keyName)); 
+    }
+
+    protected BrooklynTypeSnapshot refreshSnapshot() {
+        if (snapshotValid.compareAndSet(false, true)) {
+            snapshot = newSnapshot();
+        }
+        return snapshot;
+    }
+
+    /**
+     * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged).
+     * Prefers keys which overwrite other keys, and prefers keys which are lower in the hierarchy;
+     * logs warnings if there are two conflicting keys which don't have an overwriting relationship.
+     */
+    protected static void buildConfigKeys(Class<? extends BrooklynObject> clazz, AbstractBrooklynObject optionalInstance, 
+            Map<String, FieldAndValue<ConfigKey<?>>> configKeys) {
+        ListMultimap<String,FieldAndValue<ConfigKey<?>>> configKeysAll = 
+                ArrayListMultimap.<String, FieldAndValue<ConfigKey<?>>>create();
+        
+        for (Field f : FlagUtils.getAllFields(clazz)) {
+            boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType());
+            if (!isConfigKey) {
+                if (!HasConfigKey.class.isAssignableFrom(f.getType())) {
+                    // neither ConfigKey nor HasConfigKey
+                    continue;
+                }
+            }
+            if (!Modifier.isStatic(f.getModifiers())) {
+                // require it to be static or we have an instance
+                LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalInstance!=null ? optionalInstance : clazz));
+                if (optionalInstance==null) continue;
+            }
+            try {
+                ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) f.get(optionalInstance) : 
+                    ((HasConfigKey<?>)f.get(optionalInstance)).getConfigKey();
+                
+                if (k==null) {
+                    LOG.warn("no value defined for config key field (skipping): "+f);
+                } else {
+                    configKeysAll.put(k.getName(), new FieldAndValue<ConfigKey<?>>(f, k));
+                }
+                
+            } catch (IllegalAccessException e) {
+                LOG.warn("cannot access config key (skipping): "+f);
+            }
+        }
+        LinkedHashSet<String> keys = new LinkedHashSet<String>(configKeysAll.keys());
+        for (String kn: keys) {
+            List<FieldAndValue<ConfigKey<?>>> kk = Lists.newArrayList(configKeysAll.get(kn));
+            if (kk.size()>1) {
+                // remove anything which extends another value in the list
+                for (FieldAndValue<ConfigKey<?>> k: kk) {
+                    ConfigKey<?> key = value(k);
+                    if (key instanceof BasicConfigKeyOverwriting) {                            
+                        ConfigKey<?> parent = ((BasicConfigKeyOverwriting<?>)key).getParentKey();
+                        // find and remove the parent from consideration
+                        for (FieldAndValue<ConfigKey<?>> k2: kk) {
+                            if (value(k2) == parent)
+                                configKeysAll.remove(kn, k2);
+                        }
+                    }
+                }
+                kk = Lists.newArrayList(configKeysAll.get(kn));
+            }
+            // multiple keys, not overwriting; if their values are the same then we don't mind
+            FieldAndValue<ConfigKey<?>> best = null;
+            for (FieldAndValue<ConfigKey<?>> k: kk) {
+                if (best==null) {
+                    best=k;
+                } else {
+                    Field lower = Reflections.inferSubbestField(k.field, best.field);
+                    ConfigKey<? extends Object> lowerV = lower==null ? null : lower.equals(k.field) ? k.value : best.value;
+                    if (best.value == k.value) {
+                        // same value doesn't matter which we take (but take lower if there is one)
+                        if (LOG.isTraceEnabled()) 
+                            LOG.trace("multiple definitions for config key {} on {}; same value {}; " +
+                                    "from {} and {}, preferring {}", 
+                                    new Object[] {
+                                    best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                    best.value.getDefaultValue(),
+                                    k.field, best.field, lower});
+                        best = new FieldAndValue<ConfigKey<?>>(lower!=null ? lower : best.field, best.value);
+                    } else if (lower!=null) {
+                        // different value, but one clearly lower (in type hierarchy)
+                        if (LOG.isTraceEnabled()) 
+                            LOG.trace("multiple definitions for config key {} on {}; " +
+                                    "from {} and {}, preferring lower {}, value {}", 
+                                    new Object[] {
+                                    best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                    k.field, best.field, lower,
+                                    lowerV.getDefaultValue() });
+                        best = new FieldAndValue<ConfigKey<?>>(lower, lowerV);
+                    } else {
+                        // different value, neither one lower than another in hierarchy
+                        LOG.warn("multiple ambiguous definitions for config key {} on {}; " +
+                                "from {} and {}, values {} and {}; " +
+                                "keeping latter (arbitrarily)", 
+                                new Object[] {
+                                best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                k.field, best.field, 
+                                k.value.getDefaultValue(), best.value.getDefaultValue() });
+                        // (no change)
+                    }
+                }
+            }
+            if (best==null) {
+                // shouldn't happen
+                LOG.error("Error - no matching config key from "+kk+" in class "+clazz+", even though had config key name "+kn);
+                continue;
+            } else {
+                configKeys.put(best.value.getName(), best);
+            }
+        }
+    }
+    
+    protected static class FieldAndValue<V> {
+        public final Field field;
+        public final V value;
+        public FieldAndValue(Field field, V value) {
+            this.field = field;
+            this.value = value;
+        }
+        @Override
+        public String toString() {
+            return Objects.toStringHelper(this).add("field", field).add("value", value).toString();
+        }
+    }
+    
+    protected static <V> V value(FieldAndValue<V> fv) {
+        if (fv==null) return null;
+        return fv.value;
+    }
+    
+    protected static Field field(FieldAndValue<?> fv) {
+        if (fv==null) return null;
+        return fv.field;
+    }
+
+    @SuppressWarnings("unused")
+    protected static <V> Collection<V> value(Collection<FieldAndValue<V>> fvs) {
+        List<V> result = new ArrayList<V>();
+        for (FieldAndValue<V> fv: fvs) result.add(value(fv));
+        return result;
+    }
+
+    protected static <K,V> Map<K,V> value(Map<K,FieldAndValue<V>> fvs) {
+        Map<K,V> result = new LinkedHashMap<K,V>();
+        for (K key: fvs.keySet())
+            result.put(key, value(fvs.get(key)));
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/basic/BrooklynTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynTypeSnapshot.java b/core/src/main/java/brooklyn/basic/BrooklynTypeSnapshot.java
new file mode 100644
index 0000000..61e31a0
--- /dev/null
+++ b/core/src/main/java/brooklyn/basic/BrooklynTypeSnapshot.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.basic;
+
+import java.util.Map;
+import java.util.Set;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class BrooklynTypeSnapshot implements BrooklynType {
+    private static final long serialVersionUID = 4670930188951106009L;
+    
+    private final String name;
+    private transient volatile String simpleName;
+    private final Map<String, ConfigKey<?>> configKeys;
+    private final Set<ConfigKey<?>> configKeysSet;
+
+    protected BrooklynTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
+        this.name = name;
+        this.configKeys = ImmutableMap.copyOf(configKeys);
+        this.configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+    
+    private String toSimpleName(String name) {
+        String simpleName = name.substring(name.lastIndexOf(".")+1);
+        if (Strings.isBlank(simpleName)) simpleName = name.trim();
+        return Strings.makeValidFilename(simpleName);
+    }
+
+    @Override
+    public String getSimpleName() {
+        String sn = simpleName;
+        if (sn==null) {
+            sn = toSimpleName(getName());
+            simpleName = sn;
+        }
+        return sn;
+    }
+    
+    @Override
+    public Set<ConfigKey<?>> getConfigKeys() {
+        return configKeysSet;
+    }
+    
+    @Override
+    public ConfigKey<?> getConfigKey(String name) {
+        return configKeys.get(name);
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name, configKeys);
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (!(obj instanceof BrooklynTypeSnapshot)) return false;
+        BrooklynTypeSnapshot o = (BrooklynTypeSnapshot) obj;
+        
+        return Objects.equal(name, o.name) && Objects.equal(configKeys, o.configKeys);
+    }
+    
+    @Override
+    public String toString() {
+        return toStringHelper().toString();
+    }
+    
+    protected ToStringHelper toStringHelper() {
+        return Objects.toStringHelper(name)
+                .add("configKeys", configKeys);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/basic/BrooklynTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynTypes.java b/core/src/main/java/brooklyn/basic/BrooklynTypes.java
new file mode 100644
index 0000000..c2052c7
--- /dev/null
+++ b/core/src/main/java/brooklyn/basic/BrooklynTypes.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.basic;
+
+import java.util.Map;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityDynamicType;
+import brooklyn.event.Sensor;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.collect.Maps;
+
+public class BrooklynTypes {
+
+    private static class ImmutableEntityType extends EntityDynamicType {
+        public ImmutableEntityType(Class<? extends Entity> clazz) {
+            super(clazz);
+        }
+        @Override
+        public void setName(String name) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void addSensor(Sensor<?> newSensor) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void addSensorIfAbsent(Sensor<?> newSensor) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public Sensor<?> addSensorIfAbsentWithoutPublishing(Sensor<?> newSensor) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void addSensors(Iterable<? extends Sensor<?>> newSensors) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public boolean removeSensor(Sensor<?> sensor) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public Sensor<?> removeSensor(String sensorName) {
+            throw new UnsupportedOperationException();
+        }
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private static final Map<Class,BrooklynDynamicType<?,?>> cache = Maps.newConcurrentMap();
+    
+    public static EntityDynamicType getDefinedEntityType(Class<? extends Entity> entityClass) {
+        return (EntityDynamicType) BrooklynTypes.getDefinedBrooklynType(entityClass);
+    }
+
+    private static BrooklynDynamicType<?,?> getDefinedBrooklynType(Class<? extends BrooklynObject> brooklynClass) {
+        BrooklynDynamicType<?,?> t = cache.get(brooklynClass);
+        if (t!=null) return t;
+        return loadDefinedBrooklynType(brooklynClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static synchronized BrooklynDynamicType<?,?> loadDefinedBrooklynType(Class<? extends BrooklynObject> brooklynClass) {
+        BrooklynDynamicType<?,?> type = cache.get(brooklynClass);
+        if (type != null) return type;
+        
+        if (Entity.class.isAssignableFrom(brooklynClass)) {
+            type = new ImmutableEntityType((Class<? extends Entity>)brooklynClass);
+        } else {
+            throw new IllegalStateException("Invalid brooklyn type "+brooklynClass);
+        }
+        cache.put(brooklynClass, type);
+        return type;
+    }
+
+    public static Map<String, ConfigKey<?>> getDefinedConfigKeys(Class<? extends BrooklynObject> brooklynClass) {
+        return getDefinedBrooklynType(brooklynClass).getConfigKeys();
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static Map<String, ConfigKey<?>> getDefinedConfigKeys(String brooklynTypeName) {
+        try {
+            return getDefinedConfigKeys((Class<? extends BrooklynObject>) Class.forName(brooklynTypeName));
+        } catch (ClassNotFoundException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    public static Map<String, Sensor<?>> getDefinedSensors(Class<? extends Entity> entityClass) {
+        return getDefinedEntityType(entityClass).getSensors();
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static Map<String, Sensor<?>> getDefinedSensors(String entityTypeName) {
+        try {
+            return getDefinedSensors((Class<? extends Entity>) Class.forName(entityTypeName));
+        } catch (ClassNotFoundException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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 6368866..68120d9 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -26,7 +26,6 @@ import brooklyn.mementos.EnricherMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherType;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
-import brooklyn.policy.basic.EnricherTypeImpl;
 
 import com.google.common.collect.Maps;
 
@@ -35,15 +34,16 @@ import com.google.common.collect.Maps;
 */
 public abstract class AbstractEnricher extends AbstractEntityAdjunct implements Enricher {
 
-    private final EnricherType enricherType;
-    
+    private final EnricherDynamicType enricherType;
+
     public AbstractEnricher() {
         this(Maps.newLinkedHashMap());
     }
     
-    public AbstractEnricher(Map flags) {
+    public AbstractEnricher(Map<?,?> flags) {
         super(flags);
-        enricherType = new EnricherTypeImpl(getAdjunctType());
+        
+        enricherType = new EnricherDynamicType(this);
         
         if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
             init();
@@ -57,7 +57,7 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
     
     @Override
     public EnricherType getEnricherType() {
-        return enricherType;
+        return enricherType.getSnapshot();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/enricher/basic/EnricherDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/EnricherDynamicType.java b/core/src/main/java/brooklyn/enricher/basic/EnricherDynamicType.java
new file mode 100644
index 0000000..9217c3d
--- /dev/null
+++ b/core/src/main/java/brooklyn/enricher/basic/EnricherDynamicType.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.enricher.basic;
+
+import brooklyn.basic.BrooklynDynamicType;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.EnricherType;
+
+public class EnricherDynamicType extends BrooklynDynamicType<Enricher, AbstractEnricher> {
+
+    public EnricherDynamicType(AbstractEnricher enricher) {
+        super(enricher);
+    }
+    
+    public EnricherType getSnapshot() {
+        return (EnricherType) super.getSnapshot();
+    }
+
+    @Override
+    protected EnricherTypeSnapshot newSnapshot() {
+        return new EnricherTypeSnapshot(name, value(configKeys));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/enricher/basic/EnricherTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/EnricherTypeSnapshot.java b/core/src/main/java/brooklyn/enricher/basic/EnricherTypeSnapshot.java
new file mode 100644
index 0000000..86e1f26
--- /dev/null
+++ b/core/src/main/java/brooklyn/enricher/basic/EnricherTypeSnapshot.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.enricher.basic;
+
+import java.util.Map;
+
+import brooklyn.basic.BrooklynTypeSnapshot;
+import brooklyn.config.ConfigKey;
+import brooklyn.policy.EnricherType;
+
+public class EnricherTypeSnapshot extends BrooklynTypeSnapshot implements EnricherType {
+    private static final long serialVersionUID = 4670930188951106009L;
+    
+    EnricherTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
+        super(name, configKeys);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        return (obj instanceof EnricherTypeSnapshot) && super.equals(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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 9ebb62f..3b8baec 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -34,7 +34,6 @@ import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.enricher.basic.Aggregator;
 import brooklyn.entity.Application;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -71,7 +70,6 @@ import brooklyn.management.internal.SubscriptionTracker;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
-import brooklyn.policy.EntityAdjunct;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.policy.basic.AbstractEntityAdjunct;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/entity/basic/EntityDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityDynamicType.java b/core/src/main/java/brooklyn/entity/basic/EntityDynamicType.java
index 468e538..14500d3 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityDynamicType.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityDynamicType.java
@@ -21,21 +21,15 @@ package brooklyn.entity.basic;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.config.ConfigKey;
+import brooklyn.basic.BrooklynDynamicType;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -47,18 +41,11 @@ import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
 import brooklyn.entity.effector.EffectorWithBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.event.Sensor;
-import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
 import com.google.common.base.Throwables;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 /** This is the actual type of an entity instance at runtime,
@@ -66,14 +53,10 @@ import com.google.common.collect.Maps;
  * for this reason it does *not* implement EntityType, but 
  * callers can call {@link #getSnapshot()} to get a snapshot such instance  
  */
-public class EntityDynamicType {
+public class EntityDynamicType extends BrooklynDynamicType<Entity, AbstractEntity> {
 
     private static final Logger LOG = LoggerFactory.getLogger(EntityDynamicType.class);
 
-    private final Class<? extends Entity> entityClass;
-    private final AbstractEntity entity;
-    private volatile String name;
-    
     /** 
      * Effectors on this entity, by name.
      */
@@ -85,14 +68,6 @@ public class EntityDynamicType {
      */
     private final ConcurrentMap<String,Sensor<?>> sensors = new ConcurrentHashMap<String, Sensor<?>>();
 
-    /** 
-     * Map of config keys (and their fields) on this entity, by name.
-     */
-    private final Map<String,FieldAndValue<ConfigKey<?>>> configKeys = new ConcurrentHashMap<String, FieldAndValue<ConfigKey<?>>>();
-
-    private volatile EntityTypeSnapshot snapshot;
-    private final AtomicBoolean snapshotValid = new AtomicBoolean(false);
-
     public EntityDynamicType(AbstractEntity entity) {
         this(entity.getClass(), entity);
     }
@@ -100,11 +75,7 @@ public class EntityDynamicType {
         this(clazz, null);
     }
     private EntityDynamicType(Class<? extends Entity> clazz, AbstractEntity entity) {
-        this.entityClass = clazz;
-        this.entity = entity;
-        // NB: official name is usu injected later, from AbstractEntity.setManagementContext
-        setName((clazz.getCanonicalName() == null) ? clazz.getName() : clazz.getCanonicalName());
-        
+        super(clazz, entity);
         String id = entity==null ? clazz.getName() : entity.getId();
         
         effectors.putAll(findEffectors(clazz, null));
@@ -115,29 +86,21 @@ public class EntityDynamicType {
         if (LOG.isTraceEnabled())
             LOG.trace("Entity {} sensors: {}", id, Joiner.on(", ").join(sensors.keySet()));
         
-        buildConfigKeys(clazz, null, configKeys);
-        if (LOG.isTraceEnabled())
-            LOG.trace("Entity {} config keys: {}", id, Joiner.on(", ").join(configKeys.keySet()));
-
         refreshSnapshot();
     }
     
-    public void setName(String name) {
-        if (Strings.isBlank(name)) {
-            throw new IllegalArgumentException("Invalid name "+(name == null ? "null" : "'"+name+"'")+"; name must be non-empty and not just white space");
-        }
-        this.name = name;
-        snapshotValid.set(false);
-    }
-    
-    public synchronized EntityType getSnapshot() {
-        return refreshSnapshot();
-    }
-    
+    /**
+     * @deprecated since 0.7; unused code; instead use {@link #getBrooklynClass()}
+     */
+    @Deprecated
     public Class<? extends Entity> getEntityClass() {
-        return entityClass;
+        return super.getBrooklynClass();
     }
     
+    public EntityType getSnapshot() {
+        return (EntityType) super.getSnapshot();
+    }
+
     // --------------------------------------------------
     
     /**
@@ -160,11 +123,11 @@ public class EntityDynamicType {
     @Beta
     public void addEffector(Effector<?> newEffector) {
         Effector<?> oldEffector = effectors.put(newEffector.getName(), newEffector);
-        snapshotValid.set(false);
+        invalidateSnapshot();
         if (oldEffector!=null)
-            entity.emit(AbstractEntity.EFFECTOR_CHANGED, newEffector.getName());
+            instance.emit(AbstractEntity.EFFECTOR_CHANGED, newEffector.getName());
         else
-            entity.emit(AbstractEntity.EFFECTOR_ADDED, newEffector.getName());
+            instance.emit(AbstractEntity.EFFECTOR_ADDED, newEffector.getName());
     }
 
     /** Adds an effector with an explicit body */
@@ -199,8 +162,8 @@ public class EntityDynamicType {
      */
     public void addSensor(Sensor<?> newSensor) {
         sensors.put(newSensor.getName(), newSensor);
-        snapshotValid.set(false);
-        entity.emit(AbstractEntity.SENSOR_ADDED, newSensor);
+        invalidateSnapshot();
+        instance.emit(AbstractEntity.SENSOR_ADDED, newSensor);
     }
     
     /**
@@ -215,14 +178,14 @@ public class EntityDynamicType {
     public void addSensorIfAbsent(Sensor<?> newSensor) {
         Sensor<?> prev = addSensorIfAbsentWithoutPublishing(newSensor);
         if (prev == null) {
-            entity.emit(AbstractEntity.SENSOR_ADDED, newSensor);
+            instance.emit(AbstractEntity.SENSOR_ADDED, newSensor);
         }
     }
     
     public Sensor<?> addSensorIfAbsentWithoutPublishing(Sensor<?> newSensor) {
         Sensor<?> prev = sensors.putIfAbsent(newSensor.getName(), newSensor);
         if (prev == null) {
-            snapshotValid.set(false);
+            invalidateSnapshot();
         }
         return prev;
     }
@@ -233,8 +196,8 @@ public class EntityDynamicType {
     public Sensor<?> removeSensor(String sensorName) {
         Sensor<?> result = sensors.remove(sensorName);
         if (result != null) {
-            snapshotValid.set(false);
-            entity.emit(AbstractEntity.SENSOR_REMOVED, result);
+            invalidateSnapshot();
+            instance.emit(AbstractEntity.SENSOR_REMOVED, result);
         }
         return result;
     }
@@ -248,32 +211,9 @@ public class EntityDynamicType {
     
     // --------------------------------------------------
     
-    // --------------------------------------------------
-    
-    /**
-     * ConfigKeys available on this entity.
-     */
-    public Map<String,ConfigKey<?>> getConfigKeys() {
-        return Collections.unmodifiableMap(value(configKeys));
-    }
-
-    /**
-     * ConfigKeys available on this entity.
-     */
-    public ConfigKey<?> getConfigKey(String keyName) { 
-        return value(configKeys.get(keyName)); 
-    }
-
-    /** field where a config key is defined, for use getting annotations. note annotations are not inherited. */
-    public Field getConfigKeyField(String keyName) { 
-        return field(configKeys.get(keyName)); 
-    }
-
-    private EntityTypeSnapshot refreshSnapshot() {
-        if (snapshotValid.compareAndSet(false, true)) {
-            snapshot = new EntityTypeSnapshot(name, value(configKeys), sensors, effectors.values());
-        }
-        return snapshot;
+    @Override
+    protected EntityTypeSnapshot newSnapshot() {
+        return new EntityTypeSnapshot(name, value(configKeys), sensors, effectors.values());
     }
     
     /**
@@ -375,148 +315,4 @@ public class EntityDynamicType {
             throw Throwables.propagate(e);
         }
     }
-    
-    /**
-     * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged).
-     * Prefers keys which overwrite other keys, and prefers keys which are lower in the hierarchy;
-     * logs warnings if there are two conflicting keys which don't have an overwriting relationship.
-     */
-    protected static void buildConfigKeys(Class<? extends Entity> clazz, AbstractEntity optionalEntity, 
-            Map<String, FieldAndValue<ConfigKey<?>>> configKeys) {
-        ListMultimap<String,FieldAndValue<ConfigKey<?>>> configKeysAll = 
-                ArrayListMultimap.<String, FieldAndValue<ConfigKey<?>>>create();
-        
-        for (Field f : FlagUtils.getAllFields(clazz)) {
-            boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType());
-            if (!isConfigKey) {
-                if (!HasConfigKey.class.isAssignableFrom(f.getType())) {
-                    // neither ConfigKey nor HasConfigKey
-                    continue;
-                }
-            }
-            if (!Modifier.isStatic(f.getModifiers())) {
-                // require it to be static or we have an instance
-                LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalEntity!=null ? optionalEntity : clazz));
-                if (optionalEntity==null) continue;
-            }
-            try {
-                ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) f.get(optionalEntity) : 
-                    ((HasConfigKey<?>)f.get(optionalEntity)).getConfigKey();
-                
-                if (k==null) {
-                    LOG.warn("no value defined for config key field (skipping): "+f);
-                } else {
-                    configKeysAll.put(k.getName(), new FieldAndValue<ConfigKey<?>>(f, k));
-                }
-                
-            } catch (IllegalAccessException e) {
-                LOG.warn("cannot access config key (skipping): "+f);
-            }
-        }
-        LinkedHashSet<String> keys = new LinkedHashSet<String>(configKeysAll.keys());
-        for (String kn: keys) {
-            List<FieldAndValue<ConfigKey<?>>> kk = Lists.newArrayList(configKeysAll.get(kn));
-            if (kk.size()>1) {
-                // remove anything which extends another value in the list
-                for (FieldAndValue<ConfigKey<?>> k: kk) {
-                    ConfigKey<?> key = value(k);
-                    if (key instanceof BasicConfigKeyOverwriting) {                            
-                        ConfigKey<?> parent = ((BasicConfigKeyOverwriting<?>)key).getParentKey();
-                        // find and remove the parent from consideration
-                        for (FieldAndValue<ConfigKey<?>> k2: kk) {
-                            if (value(k2) == parent)
-                                configKeysAll.remove(kn, k2);
-                        }
-                    }
-                }
-                kk = Lists.newArrayList(configKeysAll.get(kn));
-            }
-            // multiple keys, not overwriting; if their values are the same then we don't mind
-            FieldAndValue<ConfigKey<?>> best = null;
-            for (FieldAndValue<ConfigKey<?>> k: kk) {
-                if (best==null) {
-                    best=k;
-                } else {
-                    Field lower = Reflections.inferSubbestField(k.field, best.field);
-                    ConfigKey<? extends Object> lowerV = lower==null ? null : lower.equals(k.field) ? k.value : best.value;
-                    if (best.value == k.value) {
-                        // same value doesn't matter which we take (but take lower if there is one)
-                        if (LOG.isTraceEnabled()) 
-                            LOG.trace("multiple definitions for config key {} on {}; same value {}; " +
-                                    "from {} and {}, preferring {}", 
-                                    new Object[] {
-                                    best.value.getName(), optionalEntity!=null ? optionalEntity : clazz,
-                                    best.value.getDefaultValue(),
-                                    k.field, best.field, lower});
-                        best = new FieldAndValue<ConfigKey<?>>(lower!=null ? lower : best.field, best.value);
-                    } else if (lower!=null) {
-                        // different value, but one clearly lower (in type hierarchy)
-                        if (LOG.isTraceEnabled()) 
-                            LOG.trace("multiple definitions for config key {} on {}; " +
-                                    "from {} and {}, preferring lower {}, value {}", 
-                                    new Object[] {
-                                    best.value.getName(), optionalEntity!=null ? optionalEntity : clazz,
-                                    k.field, best.field, lower,
-                                    lowerV.getDefaultValue() });
-                        best = new FieldAndValue<ConfigKey<?>>(lower, lowerV);
-                    } else {
-                        // different value, neither one lower than another in hierarchy
-                        LOG.warn("multiple ambiguous definitions for config key {} on {}; " +
-                                "from {} and {}, values {} and {}; " +
-                                "keeping latter (arbitrarily)", 
-                                new Object[] {
-                                best.value.getName(), optionalEntity!=null ? optionalEntity : clazz,
-                                k.field, best.field, 
-                                k.value.getDefaultValue(), best.value.getDefaultValue() });
-                        // (no change)
-                    }
-                }
-            }
-            if (best==null) {
-                // shouldn't happen
-                LOG.error("Error - no matching config key from "+kk+" in class "+clazz+", even though had config key name "+kn);
-                continue;
-            } else {
-                configKeys.put(best.value.getName(), best);
-            }
-        }
-    }
-    
-    private static class FieldAndValue<V> {
-        public final Field field;
-        public final V value;
-        public FieldAndValue(Field field, V value) {
-            this.field = field;
-            this.value = value;
-        }
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this).add("field", field).add("value", value).toString();
-        }
-    }
-    
-    private static <V> V value(FieldAndValue<V> fv) {
-        if (fv==null) return null;
-        return fv.value;
-    }
-    
-    private static Field field(FieldAndValue<?> fv) {
-        if (fv==null) return null;
-        return fv.field;
-    }
-
-    @SuppressWarnings("unused")
-    private static <V> Collection<V> value(Collection<FieldAndValue<V>> fvs) {
-        List<V> result = new ArrayList<V>();
-        for (FieldAndValue<V> fv: fvs) result.add(value(fv));
-        return result;
-    }
-
-    private static <K,V> Map<K,V> value(Map<K,FieldAndValue<V>> fvs) {
-        Map<K,V> result = new LinkedHashMap<K,V>();
-        for (K key: fvs.keySet())
-            result.put(key, value(fvs.get(key)));
-        return result;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/entity/basic/EntityTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityTypeSnapshot.java b/core/src/main/java/brooklyn/entity/basic/EntityTypeSnapshot.java
index d0832f2..2395d66 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityTypeSnapshot.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityTypeSnapshot.java
@@ -24,66 +24,35 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
+import brooklyn.basic.BrooklynTypeSnapshot;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Effector;
 import brooklyn.entity.EntityType;
 import brooklyn.entity.ParameterType;
 import brooklyn.event.Sensor;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.text.Strings;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
-public class EntityTypeSnapshot implements EntityType {
+public class EntityTypeSnapshot extends BrooklynTypeSnapshot implements EntityType {
     private static final long serialVersionUID = 4670930188951106009L;
     
-    private final String name;
-    private transient volatile String simpleName;
-    private final Map<String, ConfigKey<?>> configKeys;
     private final Map<String, Sensor<?>> sensors;
     private final Set<Effector<?>> effectors;
-    private final Set<ConfigKey<?>> configKeysSet;
     private final Set<Sensor<?>> sensorsSet;
 
     EntityTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys, Map<String, Sensor<?>> sensors, Collection<Effector<?>> effectors) {
-        this.name = name;
-        this.configKeys = ImmutableMap.copyOf(configKeys);
+        super(name, configKeys);
         this.sensors = ImmutableMap.copyOf(sensors);
         this.effectors = ImmutableSet.copyOf(effectors);
-        this.configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
         this.sensorsSet = ImmutableSet.copyOf(this.sensors.values());
     }
 
     @Override
-    public String getName() {
-        return name;
-    }
-    
-    private String toSimpleName(String name) {
-        String simpleName = name.substring(name.lastIndexOf(".")+1);
-        if (Strings.isBlank(simpleName)) simpleName = name.trim();
-        return Strings.makeValidFilename(simpleName);
-    }
-
-    @Override
-    public String getSimpleName() {
-        String sn = simpleName;
-        if (sn==null) {
-            sn = toSimpleName(getName());
-            simpleName = sn;
-        }
-        return sn;
-    }
-    
-    @Override
-    public Set<ConfigKey<?>> getConfigKeys() {
-        return configKeysSet;
-    }
-    
-    @Override
     public Set<Sensor<?>> getSensors() {
         return sensorsSet;
     }
@@ -124,12 +93,6 @@ public class EntityTypeSnapshot implements EntityType {
         throw new NoSuchElementException("No matching effector "+name+"("+Joiner.on(", ").join(parameterTypes)+") on entity "+getName());
     }
 
-    
-    @Override
-    public ConfigKey<?> getConfigKey(String name) {
-        return configKeys.get(name);
-    }
-    
     @Override
     public Sensor<?> getSensor(String name) {
         return sensors.get(name);
@@ -142,7 +105,7 @@ public class EntityTypeSnapshot implements EntityType {
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(name, configKeys, sensors, effectors);
+        return Objects.hashCode(super.hashCode(), sensors, effectors);
     }
     
     @Override
@@ -151,16 +114,13 @@ public class EntityTypeSnapshot implements EntityType {
         if (!(obj instanceof EntityTypeSnapshot)) return false;
         EntityTypeSnapshot o = (EntityTypeSnapshot) obj;
         
-        return Objects.equal(name, o.name) && Objects.equal(configKeys, o.configKeys) &&
-                Objects.equal(sensors, o.sensors) && Objects.equal(effectors, o.effectors);
+        return super.equals(obj) && Objects.equal(sensors, o.sensors) && Objects.equal(effectors, o.effectors);
     }
     
     @Override
-    public String toString() {
-        return Objects.toStringHelper(name)
-                .add("configKeys", configKeys)
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper()
                 .add("sensors", sensors)
-                .add("effectors", effectors)
-                .toString();
+                .add("effectors", effectors);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/entity/basic/EntityTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityTypes.java b/core/src/main/java/brooklyn/entity/basic/EntityTypes.java
index 6fc047a..9970538 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityTypes.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityTypes.java
@@ -18,85 +18,11 @@
  */
 package brooklyn.entity.basic;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import brooklyn.basic.BrooklynTypes;
 
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.event.Sensor;
-import brooklyn.util.exceptions.Exceptions;
-
-public class EntityTypes {
-
-    private static class ImmutableEntityType extends EntityDynamicType {
-        public ImmutableEntityType(Class<? extends Entity> clazz) {
-            super(clazz);
-        }
-        @Override
-        public void addSensor(Sensor<?> newSensor) {
-            throw new UnsupportedOperationException();
-        }
-        @Override
-        public void addSensorIfAbsent(Sensor<?> newSensor) {
-            throw new UnsupportedOperationException();
-        }
-        @Override
-        public Sensor<?> addSensorIfAbsentWithoutPublishing(Sensor<?> newSensor) {
-            throw new UnsupportedOperationException();
-        }
-        @Override
-        public void addSensors(Iterable<? extends Sensor<?>> newSensors) {
-            throw new UnsupportedOperationException();
-        }
-        @Override
-        public boolean removeSensor(Sensor<?> sensor) {
-            throw new UnsupportedOperationException();
-        }
-        @Override
-        public Sensor<?> removeSensor(String sensorName) {
-            throw new UnsupportedOperationException();
-        }
-    }
-    
-    @SuppressWarnings("rawtypes")
-    private static final Map<Class,ImmutableEntityType> cache = new LinkedHashMap<Class,ImmutableEntityType>();
-    
-    public static EntityDynamicType getDefinedEntityType(Class<? extends Entity> entityClass) {
-        ImmutableEntityType t = cache.get(entityClass);
-        if (t!=null) return t;
-        return loadDefinedEntityType(entityClass);
-    }
-
-    private static synchronized EntityDynamicType loadDefinedEntityType(Class<? extends Entity> entityClass) {
-        ImmutableEntityType type = cache.get(entityClass);
-        if (type!=null) return type;
-        type = new ImmutableEntityType(entityClass);
-        cache.put(entityClass, type);
-        return type;
-    }
-
-    public static Map<String, ConfigKey<?>> getDefinedConfigKeys(Class<? extends Entity> entityClass) {
-        return getDefinedEntityType(entityClass).getConfigKeys();
-    }
-    @SuppressWarnings("unchecked")
-    public static Map<String, ConfigKey<?>> getDefinedConfigKeys(String entityTypeName) {
-        try {
-            return getDefinedConfigKeys((Class<? extends Entity>) Class.forName(entityTypeName));
-        } catch (ClassNotFoundException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    public static Map<String, Sensor<?>> getDefinedSensors(Class<? extends Entity> entityClass) {
-        return getDefinedEntityType(entityClass).getSensors();
-    }
-    @SuppressWarnings("unchecked")
-    public static Map<String, Sensor<?>> getDefinedSensors(String entityTypeName) {
-        try {
-            return getDefinedSensors((Class<? extends Entity>) Class.forName(entityTypeName));
-        } catch (ClassNotFoundException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
+/**
+ * @deprecated since 0.7.0; use {@link BrooklynTypes}
+ */
+@Deprecated
+public class EntityTypes extends BrooklynTypes {
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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 c2f3104..680b1bf 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
@@ -26,12 +26,12 @@ import java.util.Map;
 import org.codehaus.jackson.annotate.JsonAutoDetect;
 import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
 
+import brooklyn.basic.BrooklynTypes;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityTypes;
 import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -176,7 +176,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         if (staticConfigKeys==null) {
             @SuppressWarnings("unchecked")
             Class<? extends Entity> clazz = (Class<? extends Entity>) getTypeClass();
-            staticConfigKeys = (clazz == null) ? EntityTypes.getDefinedConfigKeys(getType()) : EntityTypes.getDefinedConfigKeys(clazz);
+            staticConfigKeys = (clazz == null) ? BrooklynTypes.getDefinedConfigKeys(getType()) : BrooklynTypes.getDefinedConfigKeys(clazz);
         }
         return staticConfigKeys;
     }
@@ -193,7 +193,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
         if (staticSensorKeys==null) {
             @SuppressWarnings("unchecked")
             Class<? extends Entity> clazz = (Class<? extends Entity>) getTypeClass();
-            staticSensorKeys = (clazz == null) ? EntityTypes.getDefinedSensors(getType()) : EntityTypes.getDefinedSensors(clazz);
+            staticSensorKeys = (clazz == null) ? BrooklynTypes.getDefinedSensors(getType()) : BrooklynTypes.getDefinedSensors(clazz);
         }
         return staticSensorKeys;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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 be1f27d..66d9aab 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.BrooklynTypes;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Application;
@@ -31,7 +32,6 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
 import brooklyn.entity.basic.EntityDynamicType;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.EntityTypes;
 import brooklyn.entity.rebind.TreeUtils;
 import brooklyn.event.AttributeSensor;
 import brooklyn.location.Location;
@@ -99,7 +99,7 @@ public class MementosGenerators {
     }
     
     public static BasicEntityMemento.Builder newEntityMementoBuilder(Entity entity) {
-        EntityDynamicType definedType = EntityTypes.getDefinedEntityType(entity.getClass());
+        EntityDynamicType definedType = BrooklynTypes.getDefinedEntityType(entity.getClass());
         BasicEntityMemento.Builder builder = BasicEntityMemento.builder();
                 
         builder.id = entity.getId();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/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 70fa44b..1da196e 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
@@ -44,19 +44,17 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
     protected String policyStatus;
     protected AtomicBoolean suspended = new AtomicBoolean(false);
 
-    /**
-     * The config values of this entity. Updating this map should be done
-     * via getConfig/setConfig.
-     */
-    private final PolicyType policyType;
+    private final PolicyDynamicType policyType;
     
     public AbstractPolicy() {
         this(Collections.emptyMap());
     }
     
-    public AbstractPolicy(Map flags) {
+    public AbstractPolicy(Map<?,?> flags) {
         super(flags);
-        policyType = new PolicyTypeImpl(getAdjunctType());
+        
+        // TODO Don't let `this` reference escape during construction
+        policyType = new PolicyDynamicType(this);
         
         if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
             init();
@@ -65,7 +63,7 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
 
     @Override
     public PolicyType getPolicyType() {
-        return policyType;
+        return policyType.getSnapshot();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/policy/basic/EnricherTypeImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/EnricherTypeImpl.java b/core/src/main/java/brooklyn/policy/basic/EnricherTypeImpl.java
deleted file mode 100644
index f09d800..0000000
--- a/core/src/main/java/brooklyn/policy/basic/EnricherTypeImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.policy.basic;
-
-import java.util.Set;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.policy.EnricherType;
-
-import com.google.common.base.Objects;
-
-/**
- * This is the actual type of an enricher instance.
- */
-public class EnricherTypeImpl implements EnricherType {
-    private static final long serialVersionUID = 668629178669109738L;
-    
-    private final AdjunctType delegate;
-
-    public EnricherTypeImpl(AdjunctType delegate) {
-        this.delegate = delegate;
-    }
-
-    @Override
-    public String getName() {
-        return delegate.getName();
-    }
-    
-    @Override
-    public Set<ConfigKey<?>> getConfigKeys() {
-        return delegate.getConfigKeys();
-    }
-    
-    @Override
-    public ConfigKey<?> getConfigKey(String name) {
-        return delegate.getConfigKey(name);
-    }
-    
-    @Override
-    public int hashCode() {
-        return delegate.hashCode();
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!(obj instanceof EnricherType)) return false;
-        EnricherType o = (EnricherType) obj;
-        
-        return Objects.equal(getName(), o.getName()) && Objects.equal(getConfigKeys(), o.getConfigKeys());
-    }
-    
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(getName())
-                .add("configKeys", getConfigKeys())
-                .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java b/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
new file mode 100644
index 0000000..6c99240
--- /dev/null
+++ b/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.policy.basic;
+
+import brooklyn.basic.BrooklynDynamicType;
+import brooklyn.policy.Policy;
+import brooklyn.policy.PolicyType;
+
+public class PolicyDynamicType extends BrooklynDynamicType<Policy, AbstractPolicy> {
+
+    public PolicyDynamicType(AbstractPolicy policy) {
+        super(policy);
+    }
+    
+    public PolicyType getSnapshot() {
+        return (PolicyType) super.getSnapshot();
+    }
+
+    @Override
+    protected PolicyTypeSnapshot newSnapshot() {
+        return new PolicyTypeSnapshot(name, value(configKeys));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/policy/basic/PolicyTypeImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/PolicyTypeImpl.java b/core/src/main/java/brooklyn/policy/basic/PolicyTypeImpl.java
deleted file mode 100644
index eddb5d5..0000000
--- a/core/src/main/java/brooklyn/policy/basic/PolicyTypeImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.policy.basic;
-
-import java.util.Set;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.policy.PolicyType;
-
-import com.google.common.base.Objects;
-
-/**
- * This is the actual type of a policy instance at runtime.
- */
-public class PolicyTypeImpl implements PolicyType {
-    private static final long serialVersionUID = -7370390838599315481L;
-    
-    private final AdjunctType delegate;
-
-    public PolicyTypeImpl(AdjunctType delegate) {
-        this.delegate = delegate;
-    }
-
-    @Override
-    public String getName() {
-        return delegate.getName();
-    }
-    
-    @Override
-    public Set<ConfigKey<?>> getConfigKeys() {
-        return delegate.getConfigKeys();
-    }
-    
-    @Override
-    public ConfigKey<?> getConfigKey(String name) {
-        return delegate.getConfigKey(name);
-    }
-    
-    @Override
-    public int hashCode() {
-        return delegate.hashCode();
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!(obj instanceof PolicyType)) return false;
-        PolicyType o = (PolicyType) obj;
-        
-        return Objects.equal(getName(), o.getName()) && Objects.equal(getConfigKeys(), o.getConfigKeys());
-    }
-    
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(getName())
-                .add("configKeys", getConfigKeys())
-                .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java b/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java
new file mode 100644
index 0000000..ed36adb
--- /dev/null
+++ b/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.policy.basic;
+
+import java.util.Map;
+
+import brooklyn.basic.BrooklynTypeSnapshot;
+import brooklyn.config.ConfigKey;
+import brooklyn.policy.PolicyType;
+
+public class PolicyTypeSnapshot extends BrooklynTypeSnapshot implements PolicyType {
+    private static final long serialVersionUID = 4670930188951106009L;
+    
+    PolicyTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
+        super(name, configKeys);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        return (obj instanceof PolicyTypeSnapshot) && super.equals(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
index a69f94d..33dc4d9 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
@@ -24,13 +24,13 @@ import java.util.Set;
 
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.BrooklynTypes;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
 import brooklyn.entity.EntityType;
 import brooklyn.entity.basic.EntityDynamicType;
-import brooklyn.entity.basic.EntityTypes;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.Sensor;
 import brooklyn.policy.Policy;
@@ -56,7 +56,7 @@ public class CatalogTransformer {
     
     public static CatalogEntitySummary catalogEntitySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Entity,EntitySpec<?>> item) {
         EntitySpec<?> spec = b.getCatalog().createSpec(item);
-        EntityDynamicType typeMap = EntityTypes.getDefinedEntityType(spec.getType());
+        EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
         EntityType type = typeMap.getSnapshot();
 
         Set<EntityConfigSummary> config = Sets.newTreeSet(SummaryComparators.nameComparator());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d9594b36/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java b/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
index b2dba14..7075fa5 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -38,6 +38,7 @@ import javax.ws.rs.core.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.BrooklynTypes;
 import brooklyn.catalog.BrooklynCatalog;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.config.ConfigKey;
@@ -50,7 +51,6 @@ import brooklyn.entity.basic.BasicApplication;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
-import brooklyn.entity.basic.EntityTypes;
 import brooklyn.entity.trait.Startable;
 import brooklyn.location.Location;
 import brooklyn.location.LocationRegistry;
@@ -393,7 +393,7 @@ public class BrooklynRestResourceUtils {
     private Map<?,?> convertFlagsToKeys(Class<? extends Entity> javaType, Map<?, ?> config) {
         if (config==null || config.isEmpty() || javaType==null) return config;
         
-        Map<String, ConfigKey<?>> configKeys = EntityTypes.getDefinedConfigKeys(javaType);
+        Map<String, ConfigKey<?>> configKeys = BrooklynTypes.getDefinedConfigKeys(javaType);
         Map<Object,Object> result = new LinkedHashMap<Object,Object>();
         for (Map.Entry<?,?> entry: config.entrySet()) {
             log.debug("Setting key {} to {} for REST creation of {}", new Object[] { entry.getKey(), entry.getValue(), javaType});


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

Posted by he...@apache.org.
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)


[3/9] git commit: Push managementContext up to AbstractBrooklynObject

Posted by he...@apache.org.
Push managementContext up 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/5c5ed962
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/5c5ed962
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/5c5ed962

Branch: refs/heads/master
Commit: 5c5ed962397958c763b2b0fbc2146f713a286d27
Parents: fed8ee6
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 21:38:48 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 6 23:17:46 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/basic/AbstractBrooklynObject.java  | 12 ++++++++
 .../brooklyn/entity/basic/AbstractEntity.java   |  1 +
 .../location/basic/AbstractLocation.java        | 29 ++++++++------------
 .../policy/basic/AbstractEntityAdjunct.java     | 10 -------
 4 files changed, 24 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5c5ed962/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 7cc1ffd..e11e4b9 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -20,6 +20,8 @@ package brooklyn.basic;
 
 import java.util.Set;
 
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
@@ -33,8 +35,18 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
     
     private final Set<Object> tags = Sets.newLinkedHashSet();
 
+    private volatile ManagementContext managementContext;
+
     protected abstract void requestPersist();
 
+    public void setManagementContext(ManagementContextInternal managementContext) {
+        this.managementContext = managementContext;
+    }
+    
+    public ManagementContext getManagementContext() {
+        return managementContext;
+    }
+
     @Override
     public String getId() {
         return id;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5c5ed962/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 e2c84fa..8cf279c 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -409,6 +409,7 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     }
 
     public void setManagementContext(ManagementContextInternal managementContext) {
+        super.setManagementContext(managementContext);
         getManagementSupport().setManagementContext(managementContext);
         entityType.setName(getEntityTypeName());
         if (displayNameAutoGenerated) displayName.set(getEntityType().getSimpleName()+":"+Strings.maxlen(getId(), 4));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5c5ed962/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 9c0317e..f6657c8 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -49,7 +49,6 @@ import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.geo.HasHostGeoInfo;
 import brooklyn.location.geo.HostGeoInfo;
-import brooklyn.management.ManagementContext;
 import brooklyn.management.internal.LocalLocationManager;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.mementos.LocationMemento;
@@ -101,7 +100,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
 
     private ConfigBag configBag = new ConfigBag();
 
-    private volatile ManagementContext managementContext;
     private volatile boolean managed;
 
     private boolean _legacyConstruction;
@@ -169,14 +167,14 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     }
 
     protected void assertNotYetManaged() {
-        if (!inConstruction && (managementContext != null && managementContext.getLocationManager().isManaged(this))) {
+        if (!inConstruction && Locations.isManaged(this)) {
             LOG.warn("Configuration being made to {} after deployment; may not be supported in future versions", this);
         }
         //throw new IllegalStateException("Cannot set configuration "+key+" on active location "+this)
     }
 
     public void setManagementContext(ManagementContextInternal managementContext) {
-        this.managementContext = managementContext;
+        super.setManagementContext(managementContext);
         if (displayNameAutoGenerated && getId() != null) name.set(getClass().getSimpleName()+":"+getId().substring(0, Math.min(getId().length(),4)));
 
         Location oldParent = parent.get();
@@ -214,11 +212,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
     }
 
-    @Override
-    public ManagementContext getManagementContext() {
-        return managementContext;
-    }
-    
     /**
      * Will set fields from flags. The unused configuration can be found via the 
      * {@linkplain ConfigBag#getUnusedConfig()}.
@@ -320,7 +313,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     }
     
     public boolean isManaged() {
-        return managementContext != null && managed;
+        return getManagementContext() != null && managed;
     }
 
     public void onManagementStarted() {
@@ -330,8 +323,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     
     public void onManagementStopped() {
         this.managed = false;
-        if (managementContext.isRunning()) {
-            BrooklynStorage storage = ((ManagementContextInternal)managementContext).getStorage();
+        if (getManagementContext().isRunning()) {
+            BrooklynStorage storage = ((ManagementContextInternal)getManagementContext()).getStorage();
             storage.remove(getId()+"-parent");
             storage.remove(getId()+"-children");
             storage.remove(getId()+"-creationTime");
@@ -482,7 +475,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     }
 
     protected <T extends Location> T addChild(LocationSpec<T> spec) {
-        T child = managementContext.getLocationManager().createLocation(spec);
+        T child = getManagementContext().getLocationManager().createLocation(spec);
         addChild(child);
         return child;
     }
@@ -508,10 +501,10 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
         
         if (isManaged()) {
-            Locations.manage(child, managementContext);
-        } else if (managementContext != null) {
-            if (((LocalLocationManager)managementContext.getLocationManager()).getLocationEvenIfPreManaged(child.getId()) == null) {
-                ((ManagementContextInternal)managementContext).prePreManage(child);
+            Locations.manage(child, getManagementContext());
+        } else if (getManagementContext() != null) {
+            if (((LocalLocationManager)getManagementContext().getLocationManager()).getLocationEvenIfPreManaged(child.getId()) == null) {
+                ((ManagementContextInternal)getManagementContext()).prePreManage(child);
             }
         }
 
@@ -531,7 +524,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
             child.setParent(null);
             
             if (isManaged()) {
-                managementContext.getLocationManager().unmanage(child);
+                getManagementContext().getLocationManager().unmanage(child);
             }
         }
         return removed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5c5ed962/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 39524f8..fed1fd2 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -68,8 +68,6 @@ import com.google.common.collect.Maps;
 public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable {
     private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
 
-    private volatile ManagementContext managementContext;
-
     protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
 
     private boolean _legacyConstruction;
@@ -180,14 +178,6 @@ 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.


[8/9] git commit: Move isRebinding up to AbstractBrooklynObject

Posted by he...@apache.org.
Move isRebinding up 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/79b49a9c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/79b49a9c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/79b49a9c

Branch: refs/heads/master
Commit: 79b49a9cc0d9dd4d026b7e8690baa2cd77f9e6c1
Parents: 6cb55b5
Author: Aled Sage <al...@gmail.com>
Authored: Thu Aug 7 13:42:18 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 7 13:43:33 2014 +0100

----------------------------------------------------------------------
 core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java   | 5 +++++
 core/src/main/java/brooklyn/entity/basic/AbstractEntity.java    | 4 ----
 .../src/main/java/brooklyn/location/basic/AbstractLocation.java | 5 -----
 .../main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java  | 4 ----
 4 files changed, 5 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/79b49a9c/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 8396ec7..b15e73d 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -26,6 +26,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.proxying.InternalFactory;
+import brooklyn.entity.rebind.RebindManagerImpl;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.config.ConfigBag;
@@ -138,6 +139,10 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
         return managementContext;
     }
 
+    protected boolean isRebinding() {
+        return RebindManagerImpl.RebindTracker.isRebinding();
+    }
+    
     protected void requestPersist() {
         // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
         if (getManagementContext() != null) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/79b49a9c/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 729a2ff..ad2043c 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -355,10 +355,6 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
                 (o instanceof Entity && Objects.equal(getId(), ((Entity)o).getId()));
     }
     
-    protected boolean isRebinding() {
-        return RebindManagerImpl.RebindTracker.isRebinding();
-    }
-    
     public void setProxy(Entity proxy) {
         if (selfProxy != null) throw new IllegalStateException("Proxy is already set; cannot reset proxy for "+toString());
         selfProxy = checkNotNull(proxy, "proxy");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/79b49a9c/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 734b1c8..c4b4ee0 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -37,7 +37,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.basic.EntityDynamicType;
 import brooklyn.entity.rebind.BasicLocationRebindSupport;
-import brooklyn.entity.rebind.RebindManagerImpl;
 import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.entity.trait.Configurable;
 import brooklyn.event.basic.BasicConfigKey;
@@ -263,10 +262,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
     }
     
-    protected boolean isRebinding() {
-        return RebindManagerImpl.RebindTracker.isRebinding();
-    }
-    
     public boolean isManaged() {
         return getManagementContext() != null && managed;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/79b49a9c/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 a8cf150..7f0e08f 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -162,10 +162,6 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         return _legacyNoConstructionInit;
     }
 
-    protected boolean isRebinding() {
-        return RebindManagerImpl.RebindTracker.isRebinding();
-    }
-    
     public <T> T getConfig(ConfigKey<T> key) {
         return configsInternal.getConfig(key);
     }


[6/9] git commit: Adds AbstractBrooklynObjectRebindSupport

Posted by he...@apache.org.
Adds AbstractBrooklynObjectRebindSupport

- removes duplication from Basic*RebindSupport, for them all
  extending AbstractBrooklynObjectRebindSupport
- adds MementosGenerator.newMemento(BrooklynObject)
- moves init+rebind method declarations into 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/0ab0c392
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/0ab0c392
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/0ab0c392

Branch: refs/heads/master
Commit: 0ab0c3926fe356106d0519aae822a2e0bd7a16e3
Parents: 2a0d03a
Author: Aled Sage <al...@gmail.com>
Authored: Thu Aug 7 11:41:37 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 7 11:41:37 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/basic/AbstractBrooklynObject.java  | 31 +++++++
 .../brooklyn/entity/basic/AbstractEntity.java   | 28 -------
 .../AbstractBrooklynObjectRebindSupport.java    | 88 ++++++++++++++++++++
 .../rebind/BasicEnricherRebindSupport.java      | 48 ++---------
 .../entity/rebind/BasicEntityRebindSupport.java | 64 ++++++--------
 .../rebind/BasicLocationRebindSupport.java      | 47 +++--------
 .../entity/rebind/BasicPolicyRebindSupport.java | 49 ++---------
 .../entity/rebind/dto/MementosGenerators.java   | 22 ++++-
 .../location/basic/AbstractLocation.java        | 33 ++------
 .../policy/basic/AbstractEntityAdjunct.java     |  9 --
 10 files changed, 189 insertions(+), 230 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 8764bf0..5ddefd0 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -37,6 +37,37 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
     private volatile ManagementContext managementContext;
 
+    public abstract void setDisplayName(String newName);
+
+    /**
+     * Called by framework (in new-style instances where spec was used) after configuring etc,
+     * but before a reference to this instance is shared.
+     * 
+     * To preserve backwards compatibility for if the instance is constructed directly, one
+     * can call the code below, but that means it will be called after references to this 
+     * policy have been shared with other entities.
+     * <pre>
+     * {@code
+     * if (isLegacyConstruction()) {
+     *     init();
+     * }
+     * }
+     * </pre>
+     */
+    public void init() {
+        // no-op
+    }
+    
+    /**
+     * Called by framework on rebind (in new-style instances),
+     * after configuring but before the instance is managed (or is attached to an entity, depending on its type), 
+     * and before a reference to this policy is shared.
+     * Note that {@link #init()} will not be called on rebind.
+     */
+    public void rebind() {
+        // no-op
+    }
+    
     public void setManagementContext(ManagementContextInternal managementContext) {
         this.managementContext = managementContext;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 8cf279c..0f1a184 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -518,34 +518,6 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     }
     
     /**
-     * Called by framework (in new-style entities) after configuring, setting parent, etc,
-     * but before a reference to this entity is shared with other entities.
-     * 
-     * To preserve backwards compatibility for if the entity is constructed directly, one
-     * can add to the start method the code below, but that means it will be called after
-     * references to this entity have been shared with other entities.
-     * <pre>
-     * {@code
-     * if (isLegacyConstruction()) {
-     *     init();
-     * }
-     * }
-     * </pre>
-     */
-    public void init() {
-        // no-op
-    }
-    
-    /**
-     * Called by framework (in new-style entities where EntitySpec was used) on rebind, 
-     * after configuring but before the entity is managed.
-     * Note that {@link #init()} will not be called on rebind.
-     */
-    public void rebind() {
-        // no-op
-    }
-    
-    /**
      * Adds this as a child of the given entity; registers with application if necessary.
      */
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
new file mode 100644
index 0000000..4549dd2
--- /dev/null
+++ b/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.rebind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.basic.AbstractBrooklynObject;
+import brooklyn.entity.rebind.dto.MementosGenerators;
+import brooklyn.mementos.Memento;
+
+public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> implements RebindSupport<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractBrooklynObjectRebindSupport.class);
+    
+    private final AbstractBrooklynObject instance;
+    
+    public AbstractBrooklynObjectRebindSupport(AbstractBrooklynObject instance) {
+        this.instance = instance;
+    }
+    
+    @Override
+    @SuppressWarnings("unchecked")
+    public T getMemento() {
+        T memento = (T) MementosGenerators.newMemento(instance);
+        if (LOG.isTraceEnabled()) LOG.trace("Created memento: {}", memento.toVerboseString());
+        return memento;
+    }
+
+    @Override
+    public void reconstruct(RebindContext rebindContext, T memento) {
+        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing: {}", memento.toVerboseString());
+
+        instance.setDisplayName(memento.getDisplayName());
+        addConfig(rebindContext, memento);
+        addTags(rebindContext, memento);
+        addCustoms(rebindContext, memento);
+        
+        doReconstruct(rebindContext, memento);
+        instance.rebind();
+    }
+
+    protected abstract void addConfig(RebindContext rebindContext, T memento);
+
+    protected abstract void addCustoms(RebindContext rebindContext, T memento);
+    
+    protected void addTags(RebindContext rebindContext, T memento) {
+        for (Object tag : memento.getTags()) {
+            instance.getTagSupport().addTag(tag);
+        }
+    }
+
+    @Override
+    public void addPolicies(RebindContext rebindContext, T Memento) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addEnrichers(RebindContext rebindContext, T Memento) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * For overriding, to give custom reconstruct behaviour.
+     * 
+     * @deprecated since 0.7.0; should never need to override the RebindSupport types
+     */
+    @Deprecated
+    protected void doReconstruct(RebindContext rebindContext, T memento) {
+        // default is no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 167d684..65f093d 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
@@ -18,39 +18,22 @@
  */
 package brooklyn.entity.rebind;
 
-import org.slf4j.Logger;
-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;
 
-public class BasicEnricherRebindSupport implements RebindSupport<EnricherMemento> {
+public class BasicEnricherRebindSupport extends AbstractBrooklynObjectRebindSupport<EnricherMemento> {
 
-    private static final Logger LOG = LoggerFactory.getLogger(BasicEnricherRebindSupport.class);
-    
     private final AbstractEnricher enricher;
     
     public BasicEnricherRebindSupport(AbstractEnricher enricher) {
+        super(enricher);
         this.enricher = enricher;
     }
     
     @Override
-    public EnricherMemento getMemento() {
-        EnricherMemento memento = MementosGenerators.newEnricherMemento(enricher);
-        if (LOG.isTraceEnabled()) LOG.trace("Creating memento for enricher: {}", memento.toVerboseString());
-        return memento;
-    }
-
-    @Override
-    public void reconstruct(RebindContext rebindContext, EnricherMemento memento) {
-        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing enricher: {}", memento.toVerboseString());
-
-        enricher.setDisplayName(memento.getDisplayName());
-        
+    protected void addConfig(RebindContext rebindContext, EnricherMemento memento) {
         // TODO entity does config-lookup differently; the memento contains the config keys.
         // BasicEntityMemento.postDeserialize uses the injectTypeClass to call EntityTypes.getDefinedConfigKeys(clazz)
         // 
@@ -58,31 +41,10 @@ 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();
-    }
-
-    @Override
-    public void addEnrichers(RebindContext rebindContext, EnricherMemento Memento) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * For overriding, to give custom reconsruct behaviour.
-     */
-    protected void doReconstruct(RebindContext rebindContext, EnricherMemento memento) {
-        // default is no-op
+    protected void addCustoms(RebindContext rebindContext, EnricherMemento memento) {
+        // no-op
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 bdb87e2..a6e1341 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -43,16 +43,18 @@ import brooklyn.policy.basic.AbstractPolicy;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 
-public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
+public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSupport<EntityMemento> {
 
     private static final Logger LOG = LoggerFactory.getLogger(BasicEntityRebindSupport.class);
     
     private final EntityLocal entity;
     
-    public BasicEntityRebindSupport(EntityLocal entity) {
+    public BasicEntityRebindSupport(AbstractEntity entity) {
+        super(entity);
         this.entity = checkNotNull(entity, "entity");
     }
     
+    // Can rely on super-type once the deprecated getMementoWithProperties is deleted
     @Override
     public EntityMemento getMemento() {
         return getMementoWithProperties(Collections.<String,Object>emptyMap());
@@ -68,31 +70,13 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
         return memento;
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void reconstruct(RebindContext rebindContext, EntityMemento memento) {
-        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());
-        
-        for (Effector<?> eff: memento.getEffectors())
+    @SuppressWarnings("unchecked")
+    protected void addCustoms(RebindContext rebindContext, EntityMemento memento) {
+        for (Effector<?> eff: memento.getEffectors()) {
             ((EntityInternal)entity).getMutableEntityType().addEffector(eff);
-
-        for (Map.Entry<ConfigKey<?>, Object> entry : memento.getConfig().entrySet()) {
-            try {
-                ConfigKey<?> key = entry.getKey();
-                Object value = entry.getValue();
-                Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName());
-                entity.setConfig((ConfigKey<Object>)key, value);
-            } catch (ClassNotFoundException e) {
-                throw Throwables.propagate(e);
-            }
         }
-        
-        ((EntityInternal)entity).getConfigMap().addToLocalBag(memento.getConfigUnmatched());
-        ((EntityInternal)entity).refreshInheritedConfig();
-        
+    
         for (Map.Entry<AttributeSensor<?>, Object> entry : memento.getAttributes().entrySet()) {
             try {
                 AttributeSensor<?> key = entry.getKey();
@@ -107,11 +91,24 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
         setParent(rebindContext, memento);
         addChildren(rebindContext, memento);
         addMembers(rebindContext, memento);
-        addTags(rebindContext, memento);
         addLocations(rebindContext, memento);
+    }
 
-        doReconstruct(rebindContext, memento);
-        ((AbstractEntity)entity).rebind();
+    @Override
+    protected void addConfig(RebindContext rebindContext, EntityMemento memento) {
+        for (Map.Entry<ConfigKey<?>, Object> entry : memento.getConfig().entrySet()) {
+            try {
+                ConfigKey<?> key = entry.getKey();
+                Object value = entry.getValue();
+                Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName());
+                entity.setConfig((ConfigKey<Object>)key, value);
+            } catch (ClassNotFoundException e) {
+                throw Throwables.propagate(e);
+            }
+        }
+        
+        ((EntityInternal)entity).getConfigMap().addToLocalBag(memento.getConfigUnmatched());
+        ((EntityInternal)entity).refreshInheritedConfig();
     }
     
     @Override
@@ -148,13 +145,6 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
         }
     }
     
-    /**
-     * For overriding, to reconstruct other fields.
-     */
-    protected void doReconstruct(RebindContext rebindContext, EntityMemento memento) {
-        // default is no-op
-    }
-    
     protected void addMembers(RebindContext rebindContext, EntityMemento memento) {
         if (memento.getMembers().size() > 0) {
             if (entity instanceof Group) {
@@ -173,12 +163,6 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento> {
         }
     }
     
-    protected void addTags(RebindContext rebindContext, EntityMemento memento) {
-        for (Object tag : memento.getTags()) {
-            entity.getTagSupport().addTag(tag);
-        }
-    }
-    
     protected void addChildren(RebindContext rebindContext, EntityMemento memento) {
         for (String childId : memento.getChildren()) {
             Entity child = rebindContext.getEntity(childId);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 fd5610c..50b4147 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
@@ -36,16 +36,18 @@ import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.collect.Sets;
 
-public class BasicLocationRebindSupport implements RebindSupport<LocationMemento> {
+public class BasicLocationRebindSupport extends AbstractBrooklynObjectRebindSupport<LocationMemento> {
 
     private static final Logger LOG = LoggerFactory.getLogger(BasicLocationRebindSupport.class);
     
     private final AbstractLocation location;
     
     public BasicLocationRebindSupport(AbstractLocation location) {
+        super(location);
         this.location = location;
     }
     
+    // Can rely on super-type once the deprecated getMementoWithProperties is deleted
     @Override
     public LocationMemento getMemento() {
         return getMementoWithProperties(Collections.<String,Object>emptyMap());
@@ -62,14 +64,11 @@ public class BasicLocationRebindSupport implements RebindSupport<LocationMemento
     }
 
     @Override
-    public void reconstruct(RebindContext rebindContext, LocationMemento memento) {
-    	if (LOG.isTraceEnabled()) LOG.trace("Reconstructing location: {}", memento.toVerboseString());
-
-    	// FIXME Treat config like we do for entities; this code will disappear when locations become entities.
-    	
-    	// Note that the flags have been set in the constructor
+    protected void addConfig(RebindContext rebindContext, LocationMemento memento) {
+        // FIXME Treat config like we do for entities; this code will disappear when locations become entities.
+        
+        // Note that the flags have been set in the constructor
         // FIXME Relies on location.getLocalConfigBag being mutable (to modify the location's own config)
-        location.setName(memento.getDisplayName());
         
         location.getLocalConfigBag().putAll(memento.getLocationConfig()).markAll(
                 Sets.difference(memento.getLocationConfig().keySet(), memento.getLocationConfigUnused())).
@@ -101,30 +100,13 @@ public class BasicLocationRebindSupport implements RebindSupport<LocationMemento
                 // FIXME How to do findFieldForFlag without throwing exception if it's not there?
             }
         }
-        
+    }
+    
+    @Override
+    protected void addCustoms(RebindContext rebindContext, LocationMemento memento) {
         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();
-    }
-
-    @Override
-    public void addEnrichers(RebindContext rebindContext, LocationMemento Memento) {
-        throw new UnsupportedOperationException();
     }
 
     protected void addChildren(RebindContext rebindContext, LocationMemento memento) {
@@ -146,11 +128,4 @@ public class BasicLocationRebindSupport implements RebindSupport<LocationMemento
         	LOG.warn("Ignoring parent {} of location {}({}), as cannot be found", new Object[] {memento.getParent(), memento.getType(), memento.getId()});
         }
     }
-    
-    /**
-     * For overriding, to give custom reconsruct behaviour.
-     */
-    protected void doReconstruct(RebindContext rebindContext, LocationMemento memento) {
-        // default is no-op
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 228b5ba..838023e 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
@@ -18,39 +18,22 @@
  */
 package brooklyn.entity.rebind;
 
-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;
 import brooklyn.util.flags.FlagUtils;
 
-public class BasicPolicyRebindSupport implements RebindSupport<PolicyMemento> {
+public class BasicPolicyRebindSupport extends AbstractBrooklynObjectRebindSupport<PolicyMemento> {
 
-    private static final Logger LOG = LoggerFactory.getLogger(BasicPolicyRebindSupport.class);
-    
     private final AbstractPolicy policy;
     
     public BasicPolicyRebindSupport(AbstractPolicy policy) {
+        super(policy);
         this.policy = policy;
     }
     
     @Override
-    public PolicyMemento getMemento() {
-        PolicyMemento memento = MementosGenerators.newPolicyMemento(policy);
-        if (LOG.isTraceEnabled()) LOG.trace("Creating memento for policy: {}", memento.toVerboseString());
-        return memento;
-    }
-
-    @Override
-    public void reconstruct(RebindContext rebindContext, PolicyMemento memento) {
-        if (LOG.isTraceEnabled()) LOG.trace("Reconstructing policy: {}", memento.toVerboseString());
-
-        policy.setDisplayName(memento.getDisplayName());
-
+    protected void addConfig(RebindContext rebindContext, PolicyMemento memento) {
         // TODO entity does config-lookup differently; the memento contains the config keys.
         // BasicEntityMemento.postDeserialize uses the injectTypeClass to call EntityTypes.getDefinedConfigKeys(clazz)
         // 
@@ -58,32 +41,10 @@ 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();
-    }
-
-    @Override
-    public void addEnrichers(RebindContext rebindContext, PolicyMemento Memento) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * For overriding, to give custom reconsruct behaviour.
-     */
-    protected void doReconstruct(RebindContext rebindContext, PolicyMemento memento) {
-        // default is no-op
+    protected void addCustoms(RebindContext rebindContext, PolicyMemento memento) {
+        // no-op
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 79600da..3289665 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
@@ -44,6 +44,7 @@ import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
+import brooklyn.mementos.Memento;
 import brooklyn.mementos.PolicyMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
@@ -60,6 +61,23 @@ public class MementosGenerators {
     private MementosGenerators() {}
     
     /**
+     * Inspects a brooklyn object to create a corresponding memento.
+     */
+    public static Memento newMemento(BrooklynObject instance) {
+        if (instance instanceof Entity) {
+            return newEntityMemento((Entity)instance);
+        } else if (instance instanceof Location) {
+            return newLocationMemento((Location)instance);
+        } else if (instance instanceof Policy) {
+            return newPolicyMemento((Policy)instance);
+        } else if (instance instanceof Enricher) {
+            return newEnricherMemento((Enricher)instance);
+        } else {
+            throw new IllegalArgumentException("Unexpected brooklyn type: "+(instance == null ? "null" : instance.getClass())+" ("+instance+")");
+        }
+    }
+
+    /**
      * 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
@@ -103,7 +121,7 @@ public class MementosGenerators {
     }
 
     /**
-     * @deprecated since 0.7.0; use {@link #newEntityMemento(Enricher)} instead
+     * @deprecated since 0.7.0; use {@link #newMemento(BrooklynObject)} instead
      */
     @Deprecated
     public static BasicEntityMemento.Builder newEntityMementoBuilder(Entity entity) {
@@ -197,7 +215,7 @@ public class MementosGenerators {
     }
     
     /**
-     * @deprecated since 0.7.0; use {@link #newLocationMemento(Enricher)} instead
+     * @deprecated since 0.7.0; use {@link #newMemento(BrooklynObject)} instead
      */
     @Deprecated
     public static BasicLocationMemento.Builder newLocationMementoBuilder(Location location) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 9937e47..8aea917 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -281,33 +281,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
     }
     
-    /**
-     * Called by framework (in new-style locations) after configuring, setting parent, etc,
-     * but before a reference to this location is shared with other locations.
-     * 
-     * To preserve backwards compatibility for if the location is constructed directly, one
-     * can call the code below, but that means it will be called after references to this 
-     * location have been shared with other entities.
-     * <pre>
-     * {@code
-     * if (isLegacyConstruction()) {
-     *     init();
-     * }
-     * }
-     * </pre>
-     */
-    public void init() {
-        // no-op
-    }
-
-    /**
-     * Called by framework (in new-style locations) on rebind, after configuring, setting parent, etc.
-     * Note that a future change to Brooklyn is that {@link #init()} will not be called when rebinding.
-     */
-    public void rebind() {
-        // no-op
-    }
-
     protected boolean isRebinding() {
         return RebindManagerImpl.RebindTracker.isRebinding();
     }
@@ -438,7 +411,11 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         return configBag.put(key, value);
     }
 
-    /** @since 0.6.0 (?) - use getDisplayName */
+    /**
+     * @since 0.6.0 (?) - use getDisplayName
+     * @deprecated since 0.7.0; use {@link #getDisplayName()}
+     */
+    @Deprecated
     public void setName(String newName) {
         setDisplayName(newName);
         displayNameAutoGenerated = false;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0ab0c392/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 fed1fd2..a1e2449 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -206,15 +206,6 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         // no-op
     }
     
-    /**
-     * Called by framework (in new-style policies/enrichers where PolicySpec/EnricherSpec was used) on rebind, 
-     * after configuring but before {@link #setEntity(EntityLocal)} and before a reference to this policy is shared.
-     * Note that {@link #init()} will not be called on rebind.
-     */
-    public void rebind() {
-        // no-op
-    }
-    
     protected boolean isRebinding() {
         return RebindManagerImpl.RebindTracker.isRebinding();
     }


[2/9] git commit: ChangeListener: use BrooklynObject

Posted by he...@apache.org.
ChangeListener: use BrooklynObject

- instead of having separate methods for Entity, Location, etc,
  just have one for BrooklynObject.
- move requestPersist() impl up 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/bf0b3e7d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/bf0b3e7d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/bf0b3e7d

Branch: refs/heads/master
Commit: bf0b3e7db3457cc5cc5e407c718555740d5719f3
Parents: 5c5ed96
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 22:00:47 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 6 23:17:46 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/rebind/ChangeListener.java  |  44 +----
 .../brooklyn/basic/AbstractBrooklynObject.java  |   9 +-
 .../enricher/basic/AbstractEnricher.java        |   8 -
 .../rebind/ImmediateDeltaChangeListener.java    | 179 +++++++------------
 .../rebind/PeriodicDeltaChangeListener.java     | 153 ++++++----------
 .../entity/rebind/RebindManagerImpl.java        | 100 ++---------
 .../location/basic/AbstractLocation.java        |   8 -
 .../brooklyn/policy/basic/AbstractPolicy.java   |   8 -
 8 files changed, 147 insertions(+), 362 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 582c7e0..02d4ad2 100644
--- a/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
+++ b/api/src/main/java/brooklyn/entity/rebind/ChangeListener.java
@@ -18,10 +18,7 @@
  */
 package brooklyn.entity.rebind;
 
-import brooklyn.entity.Entity;
-import brooklyn.location.Location;
-import brooklyn.policy.Enricher;
-import brooklyn.policy.Policy;
+import brooklyn.basic.BrooklynObject;
 
 /**
  * Listener to be notified of changes within brooklyn, so that the new state
@@ -34,41 +31,14 @@ import brooklyn.policy.Policy;
 public interface ChangeListener {
 
     public static final ChangeListener NOOP = new ChangeListener() {
-        @Override public void onManaged(Entity entity) {}
-        @Override public void onUnmanaged(Entity entity) {}
-        @Override public void onChanged(Entity entity) {}
-        @Override public void onManaged(Location location) {}
-        @Override public void onUnmanaged(Location location) {}
-        @Override public void onChanged(Location location) {}
-        @Override public void onManaged(Policy policy) {}
-        @Override public void onUnmanaged(Policy policy) {}
-        @Override public void onChanged(Policy policy) {}
-        @Override public void onManaged(Enricher enricher) {}
-        @Override public void onUnmanaged(Enricher enricher) {}
-        @Override public void onChanged(Enricher enricher) {}
+        @Override public void onChanged(BrooklynObject instance) {}
+        @Override public void onManaged(BrooklynObject instance) {}
+        @Override public void onUnmanaged(BrooklynObject instance) {}
     };
-    
-    void onManaged(Entity entity);
-    
-    void onUnmanaged(Entity entity);
-    
-    void onChanged(Entity entity);
-    
-    void onManaged(Location location);
-
-    void onUnmanaged(Location location);
 
-    void onChanged(Location location);
+    void onManaged(BrooklynObject instance);
     
-    void onManaged(Policy policy);
-
-    void onUnmanaged(Policy policy);
-
-    void onChanged(Policy policy);
+    void onUnmanaged(BrooklynObject instance);
     
-    void onManaged(Enricher enricher);
-
-    void onUnmanaged(Enricher enricher);
-
-    void onChanged(Enricher enricher);
+    void onChanged(BrooklynObject instance);
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 e11e4b9..8764bf0 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -37,8 +37,6 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
     private volatile ManagementContext managementContext;
 
-    protected abstract void requestPersist();
-
     public void setManagementContext(ManagementContextInternal managementContext) {
         this.managementContext = managementContext;
     }
@@ -47,6 +45,13 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
         return managementContext;
     }
 
+    protected void requestPersist() {
+        // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
+        if (getManagementContext() != null) {
+            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+        }
+    }
+    
     @Override
     public String getId() {
         return id;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 e029ab2..8503663 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -64,12 +64,4 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
     protected void onChanged() {
         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/bf0b3e7d/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 06c8519..67a8c96 100644
--- a/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
@@ -21,12 +21,17 @@ package brooklyn.entity.rebind;
 import java.util.Collection;
 import java.util.Map;
 
+import brooklyn.basic.BrooklynObject;
+import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.entity.Entity;
-import brooklyn.entity.basic.EntityInternal;
 import brooklyn.location.Location;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.mementos.BrooklynMementoPersister;
+import brooklyn.mementos.EnricherMemento;
+import brooklyn.mementos.EntityMemento;
 import brooklyn.mementos.LocationMemento;
+import brooklyn.mementos.Memento;
+import brooklyn.mementos.PolicyMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 
@@ -55,133 +60,87 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
     }
     
     @Override
-    public void onManaged(Entity entity) {
-        onChanged(entity);
+    public void onManaged(BrooklynObject instance) {
+        onChanged(instance);
     }
 
     @Override
-    public void onManaged(Location location) {
-        onChanged(location);
-    }
-    
-    @Override
-    public void onManaged(Policy policy) {
-        onChanged(policy);
-    }
-    
-    @Override
-    public void onManaged(Enricher enricher) {
-        onChanged(enricher);
-    }
-    
-    @Override
-    public void onChanged(Entity entity) {
+    public void onUnmanaged(BrooklynObject instance) {
         if (running && persister != null) {
             PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.entities.add(((EntityInternal)entity).getRebindSupport().getMemento());
-
-            // FIXME How to let the policy/location tell us about changes?
-            // Don't do this every time!
-            Map<String, LocationMemento> locations = Maps.newLinkedHashMap();
-            for (Location location : entity.getLocations()) {
-                if (!locations.containsKey(location.getId())) {
-                    Collection<Location> locsInHierachy = TreeUtils.findLocationsInHierarchy(location);
-
-                    /*
-                     * Need to guarantee "happens before", with any thread that has written 
-                     * fields of these locations. In particular, saw failures where SshMachineLocation
-                     * had null address field. Our hypothesis is that the location had its fields set,
-                     * and then set its parent (which goes through a synchronized in AbstractLocation.addChild),
-                     * but that this memento-generating code did not go through any synchronization or volatiles.
-                     */
-                    synchronized (new Object()) {}
-                    
-                    for (Location locInHierarchy : locsInHierachy) {
-                        locations.put(locInHierarchy.getId(), ((LocationInternal)locInHierarchy).getRebindSupport().getMemento());
-                    }
-                }
+            if (instance instanceof Entity) {
+                delta.removedEntityIds.add(instance.getId());
+            } else if (instance instanceof Location) {
+                delta.removedLocationIds.add(instance.getId());
+            } else if (instance instanceof Policy) {
+                delta.removedPolicyIds.add(instance.getId());
+            } else if (instance instanceof Enricher) {
+                delta.removedEnricherIds.add(instance.getId());
+            } else {
+                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
             }
-            delta.locations = locations.values();
-
-            // FIXME Not including policies, because lots of places regiser anonymous inner class policies
-            // (e.g. AbstractController registering a AbstractMembershipTrackingPolicy)
-            // Also, the entity constructor often re-creates the policy.
-            // Also see MementosGenerator.newEntityMementoBuilder()
-//            List<PolicyMemento> policies = Lists.newArrayList();
-//            for (Policy policy : entity.getPolicies()) {
-//                policies.add(policy.getRebindSupport().getMemento());
-//            }
-//            delta.policies = policies;
-
-            /*
-             * Make the writes to the mementos visible to other threads.
-             */
-            synchronized (new Object()) {}
-
-            persister.delta(delta, exceptionHandler);
-        }
-    }
-    
-    @Override
-    public void onUnmanaged(Entity entity) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.removedEntityIds.add(entity.getId());
             persister.delta(delta, exceptionHandler);
         }
     }
 
     @Override
-    public void onUnmanaged(Location location) {
+    public void onChanged(BrooklynObject instance) {
         if (running && persister != null) {
             PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.removedLocationIds.add(location.getId());
+            Memento memento = ((BrooklynObjectInternal)instance).getRebindSupport().getMemento();
+            if (instance instanceof Entity) {
+                delta.entities.add((EntityMemento) memento);
+                addEntityAdjuncts((Entity)instance, delta);
+            } else if (instance instanceof Location) {
+                delta.locations.add((LocationMemento) memento);
+            } else if (instance instanceof Policy) {
+                delta.policies.add((PolicyMemento) memento);
+            } else if (instance instanceof Enricher) {
+                delta.enrichers.add((EnricherMemento) memento);
+            } else {
+                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
+            }
             persister.delta(delta, exceptionHandler);
         }
     }
-
-    @Override
-    public void onUnmanaged(Policy policy) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.removedPolicyIds.add(policy.getId());
-            persister.delta(delta, exceptionHandler);
+    
+    private void addEntityAdjuncts(Entity entity, PersisterDeltaImpl delta) {
+        // FIXME How to let the policy/location tell us about changes?
+        // Don't do this every time!
+        Map<String, LocationMemento> locations = Maps.newLinkedHashMap();
+        for (Location location : entity.getLocations()) {
+            if (!locations.containsKey(location.getId())) {
+                Collection<Location> locsInHierachy = TreeUtils.findLocationsInHierarchy(location);
+
+                /*
+                 * Need to guarantee "happens before", with any thread that has written 
+                 * fields of these locations. In particular, saw failures where SshMachineLocation
+                 * had null address field. Our hypothesis is that the location had its fields set,
+                 * and then set its parent (which goes through a synchronized in AbstractLocation.addChild),
+                 * but that this memento-generating code did not go through any synchronization or volatiles.
+                 */
+                synchronized (new Object()) {}
+                
+                for (Location locInHierarchy : locsInHierachy) {
+                    locations.put(locInHierarchy.getId(), ((LocationInternal)locInHierarchy).getRebindSupport().getMemento());
+                }
+            }
         }
-    }
+        delta.locations = locations.values();
 
-    @Override
-    public void onUnmanaged(Enricher enricher) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.removedEnricherIds.add(enricher.getId());
-            persister.delta(delta, exceptionHandler);
-        }
-    }
+        // FIXME Not including policies, because lots of places regiser anonymous inner class policies
+        // (e.g. AbstractController registering a AbstractMembershipTrackingPolicy)
+        // Also, the entity constructor often re-creates the policy.
+        // Also see MementosGenerator.newEntityMementoBuilder()
+//            List<PolicyMemento> policies = Lists.newArrayList();
+//            for (Policy policy : entity.getPolicies()) {
+//                policies.add(policy.getRebindSupport().getMemento());
+//            }
+//            delta.policies = policies;
 
-    @Override
-    public void onChanged(Location location) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.locations.add(((LocationInternal)location).getRebindSupport().getMemento());
-            persister.delta(delta, exceptionHandler);
-        }
-    }
-    
-    @Override
-    public void onChanged(Policy policy) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.policies.add(policy.getRebindSupport().getMemento());
-            persister.delta(delta, exceptionHandler);
-        }
-    }
-    
-    @Override
-    public void onChanged(Enricher enricher) {
-        if (running && persister != null) {
-            PersisterDeltaImpl delta = new PersisterDeltaImpl();
-            delta.enrichers.add(enricher.getRebindSupport().getMemento());
-            persister.delta(delta, exceptionHandler);
-        }
+        /*
+         * Make the writes to the mementos visible to other threads.
+         */
+        synchronized (new Object()) {}
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 955ba2e..7613c2a 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.BrooklynObject;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.internal.BrooklynFeatureEnablement;
@@ -280,120 +281,74 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
     }
     
     @Override
-    public synchronized void onManaged(Entity entity) {
-        if (LOG.isTraceEnabled()) LOG.trace("onManaged: {}", entity);
-        onChanged(entity);
+    public synchronized void onManaged(BrooklynObject instance) {
+        if (LOG.isTraceEnabled()) LOG.trace("onManaged: {}", instance);
+        onChanged(instance);
     }
 
     @Override
-    public synchronized void onManaged(Location location) {
-        if (LOG.isTraceEnabled()) LOG.trace("onManaged: {}", location);
-        onChanged(location);
-    }
-    
-    @Override
-    public synchronized void onManaged(Policy policy) {
-        if (LOG.isTraceEnabled()) LOG.trace("onManaged: {}", policy);
-        onChanged(policy);
-    }
-    
-    @Override
-    public synchronized void onManaged(Enricher enricher) {
-        if (LOG.isTraceEnabled()) LOG.trace("onManaged: {}", enricher);
-        onChanged(enricher);
-    }
-    
-    @Override
-    public synchronized void onChanged(Entity entity) {
-        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", entity);
+    public synchronized void onUnmanaged(BrooklynObject instance) {
+        if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", instance);
         if (!isStopped()) {
-            deltaCollector.entities.add(entity);
-
-            // FIXME How to let the policy/location tell us about changes? Don't do this every time!
-            for (Location location : entity.getLocations()) {
-                deltaCollector.locations.addAll(TreeUtils.findLocationsInHierarchy(location));
-            }
-
-            if (persistPoliciesEnabled) {
+            if (instance instanceof Entity) {
+                Entity entity = (Entity) instance;
+                deltaCollector.removedEntityIds.add(entity.getId());
+                deltaCollector.entities.remove(entity);
+                
                 for (Policy policy : entity.getPolicies()) {
-                    deltaCollector.policies.add(policy);
+                    deltaCollector.removedPolicyIds.add(policy.getId());
+                    deltaCollector.policies.remove(policy);
                 }
-            }
-
-            if (persistEnrichersEnabled) {
                 for (Enricher enricher : entity.getEnrichers()) {
-                    deltaCollector.enrichers.add(enricher);
+                    deltaCollector.removedEnricherIds.add(enricher.getId());
+                    deltaCollector.enrichers.remove(enricher);
                 }
+            } else if (instance instanceof Location) {
+                deltaCollector.removedLocationIds.add(instance.getId());
+                deltaCollector.locations.remove(instance);
+            } else if (instance instanceof Policy) {
+                deltaCollector.removedPolicyIds.add(instance.getId());
+                deltaCollector.policies.remove(instance);
+            } else if (instance instanceof Enricher) {
+                deltaCollector.removedEnricherIds.add(instance.getId());
+                deltaCollector.enrichers.remove(instance);
+            } else {
+                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
             }
         }
     }
-    
-    @Override
-    public synchronized void onUnmanaged(Entity entity) {
-        if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", entity);
-        if (!isStopped()) {
-            deltaCollector.removedEntityIds.add(entity.getId());
-            deltaCollector.entities.remove(entity);
-            
-            for (Policy policy : entity.getPolicies()) {
-                deltaCollector.removedPolicyIds.add(policy.getId());
-                deltaCollector.policies.remove(policy);
-            }
-            for (Enricher enricher : entity.getEnrichers()) {
-                deltaCollector.removedEnricherIds.add(enricher.getId());
-                deltaCollector.enrichers.remove(enricher);
-            }
-        }
-    }
-
-    @Override
-    public synchronized void onUnmanaged(Location location) {
-        if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", location);
-        if (!isStopped()) {
-            deltaCollector.removedLocationIds.add(location.getId());
-            deltaCollector.locations.remove(location);
-        }
-    }
 
     @Override
-    public synchronized void onUnmanaged(Policy policy) {
-        if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", policy);
+    public synchronized void onChanged(BrooklynObject instance) {
+        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", instance);
         if (!isStopped()) {
-            deltaCollector.removedPolicyIds.add(policy.getId());
-            deltaCollector.policies.remove(policy);
-        }
-    }
-
-    @Override
-    public synchronized void onUnmanaged(Enricher enricher) {
-        if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", enricher);
-        if (!isStopped()) {
-            deltaCollector.removedEnricherIds.add(enricher.getId());
-            deltaCollector.enrichers.remove(enricher);
-        }
-    }
+            if (instance instanceof Entity) {
+                Entity entity = (Entity) instance;
+                deltaCollector.entities.add(entity);
 
-    @Override
-    public synchronized void onChanged(Location location) {
-        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", location);
-        if (!isStopped()) {
-            deltaCollector.locations.add(location);
-        }
-    }
-    
-    @Override
-    public synchronized void onChanged(Policy policy) {
-        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", policy);
-        if (!isStopped()) {
-            deltaCollector.policies.add(policy);
-        }
-    }
-    
-    @Override
-    public synchronized void onChanged(Enricher enricher) {
-        if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", enricher);
-        if (!isStopped()) {
-            deltaCollector.enrichers.add(enricher);
+                // FIXME How to let the policy/location tell us about changes? Don't do this every time!
+                for (Location location : entity.getLocations()) {
+                    deltaCollector.locations.addAll(TreeUtils.findLocationsInHierarchy(location));
+                }
+                if (persistPoliciesEnabled) {
+                    for (Policy policy : entity.getPolicies()) {
+                        deltaCollector.policies.add(policy);
+                    }
+                }
+                if (persistEnrichersEnabled) {
+                    for (Enricher enricher : entity.getEnrichers()) {
+                        deltaCollector.enrichers.add(enricher);
+                    }
+                }
+            } else if (instance instanceof Location) {
+                deltaCollector.locations.add((Location) instance);
+            } else if (instance instanceof Policy) {
+                deltaCollector.policies.add((Policy) instance);
+            } else if (instance instanceof Enricher) {
+                deltaCollector.enrichers.add((Enricher) instance);
+            } else {
+                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 2bd121c..4e8ffc8 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -30,6 +30,7 @@ import java.util.concurrent.TimeoutException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.BrooklynObject;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Application;
@@ -747,110 +748,29 @@ public class RebindManagerImpl implements RebindManager {
         }
         
         @Override
-        public void onManaged(Entity entity) {
+        public void onManaged(BrooklynObject instance) {
             try {
-                delegate.onManaged(entity);
+                delegate.onManaged(instance);
             } catch (Throwable t) {
-                LOG.error("Error persisting mememento onManaged("+entity+"); continuing.", t);
+                LOG.error("Error persisting mememento onManaged("+instance+"); continuing.", t);
             }
         }
 
         @Override
-        public void onManaged(Location location) {
+        public void onChanged(BrooklynObject instance) {
             try {
-                delegate.onManaged(location);
+                delegate.onChanged(instance);
             } catch (Throwable t) {
-                LOG.error("Error persisting mememento onManaged("+location+"); continuing.", t);
+                LOG.error("Error persisting mememento onChanged("+instance+"); continuing.", t);
             }
         }
         
         @Override
-        public void onManaged(Policy policy) {
+        public void onUnmanaged(BrooklynObject instance) {
             try {
-                delegate.onManaged(policy);
+                delegate.onUnmanaged(instance);
             } catch (Throwable t) {
-                LOG.error("Error persisting mememento onManaged("+policy+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onManaged(Enricher enricher) {
-            try {
-                delegate.onManaged(enricher);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onManaged("+enricher+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onChanged(Entity entity) {
-            try {
-                delegate.onChanged(entity);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onChanged("+entity+"); continuing.", t);
-            }
-        }
-        
-        @Override
-        public void onUnmanaged(Entity entity) {
-            try {
-                delegate.onUnmanaged(entity);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onUnmanaged("+entity+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onUnmanaged(Location location) {
-            try {
-                delegate.onUnmanaged(location);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onUnmanaged("+location+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onUnmanaged(Policy policy) {
-            try {
-                delegate.onUnmanaged(policy);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onUnmanaged("+policy+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onUnmanaged(Enricher enricher) {
-            try {
-                delegate.onUnmanaged(enricher);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onUnmanaged("+enricher+"); continuing.", t);
-            }
-        }
-
-        @Override
-        public void onChanged(Location location) {
-            try {
-                delegate.onChanged(location);
-            } catch (Throwable t) {
-                LOG.error("Error persisting mememento onChanged("+location+"); continuing.", t);
-            }
-        }
-        
-        @Override
-        public void onChanged(Policy policy) {
-            try {
-                delegate.onChanged(policy);
-            } catch (Throwable t) {
-                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);
+                LOG.error("Error persisting mememento onUnmanaged("+instance+"); continuing.", t);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf0b3e7d/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 f6657c8..9937e47 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -558,14 +558,6 @@ 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/bf0b3e7d/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 52fa5b9..1da196e 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
@@ -101,14 +101,6 @@ 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);
     }


[7/9] git commit: Move construction mess into AbstractBrooklynObject

Posted by he...@apache.org.
Move construction mess into AbstractBrooklynObject

- delete duplication from AbstractEntity, AbstractLocation, etc


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

Branch: refs/heads/master
Commit: 6cb55b500449c6d6dee033509d50e9a20cc16d1e
Parents: 0ab0c39
Author: Aled Sage <al...@gmail.com>
Authored: Thu Aug 7 13:24:16 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 7 13:43:33 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/basic/AbstractBrooklynObject.java  |  62 ++++++++++
 .../brooklyn/entity/basic/AbstractEntity.java   | 124 +++++++++----------
 .../location/basic/AbstractLocation.java        |  48 ++-----
 .../AggregatingMachineProvisioningLocation.java |   4 +-
 .../FixedListMachineProvisioningLocation.java   |   4 +-
 .../LocalhostMachineProvisioningLocation.java   |  10 +-
 .../location/basic/SshMachineLocation.java      |   3 +-
 .../policy/basic/AbstractEntityAdjunct.java     |  80 +++---------
 .../location/jclouds/JcloudsLocation.java       |   4 +-
 9 files changed, 167 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/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 5ddefd0..8396ec7 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -18,18 +18,30 @@
  */
 package brooklyn.basic;
 
+import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
+    private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynObject.class);
+
+    private boolean _legacyConstruction;
+
     @SetFromFlag(value="id")
     private String id = Identifiers.makeRandomId(8);
     
@@ -39,6 +51,56 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
     public abstract void setDisplayName(String newName);
 
+    public AbstractBrooklynObject() {
+        this(Maps.newLinkedHashMap());
+    }
+    
+    public AbstractBrooklynObject(Map<?,?> properties) {
+        _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
+        
+        if (!_legacyConstruction && properties!=null && !properties.isEmpty()) {
+            log.warn("Forcing use of deprecated old-style location construction for "+getClass().getName()+" because properties were specified ("+properties+"); instead use specs (e.g. LocationSpec, EntitySpec, etc)");
+            if (log.isDebugEnabled())
+                log.debug("Source of use of old-style construction", new Throwable("Source of use of old-style construction"));
+            _legacyConstruction = true;
+        }
+        
+        // rely on sub-class to call configure(properties), because otherwise its fields will not have been initialised
+    }
+
+    /**
+     * See {@link #configure(Map)}
+     * 
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+     */ 
+    @Deprecated
+    protected AbstractBrooklynObject configure() {
+        return configure(Collections.emptyMap());
+    }
+    
+    /**
+     * Will set fields from flags, and put the remaining ones into the 'leftovers' map.
+     * For some types, you can find unused config via {@link ConfigBag#getUnusedConfig()}.
+     * <p>
+     * To be overridden by AbstractEntity, AbstractLoation, AbstractPolicy, AbstractEnricher, etc.
+     * <p>
+     * But should not be overridden by specific entity types. If you do, the entity may break in
+     * subsequent releases. Also note that if you require fields to be initialized you must do that 
+     * in this method. You must *not* rely on field initializers because they may not run until *after* 
+     * this method (this method is invoked by the constructor in this class, so initializers
+     * in subclasses will not have run when this overridden method is invoked.)
+     * 
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+     */ 
+    @Deprecated
+    protected AbstractBrooklynObject configure(Map flags) {
+        return this;
+    }
+    
+    protected boolean isLegacyConstruction() {
+        return _legacyConstruction;
+    }
+
     /**
      * Called by framework (in new-style instances where spec was used) after configuring etc,
      * but before a reference to this instance is shared.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/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 0f1a184..729a2ff 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -40,7 +40,6 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.EntityType;
 import brooklyn.entity.Group;
 import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.entity.rebind.BasicEntityRebindSupport;
 import brooklyn.entity.rebind.RebindManagerImpl;
 import brooklyn.entity.rebind.RebindSupport;
@@ -80,6 +79,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
+import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.DeferredSupplier;
 import brooklyn.util.text.Strings;
@@ -212,8 +212,6 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
 
     protected transient SubscriptionTracker _subscriptionTracker;
 
-    private final boolean _legacyConstruction;
-    
     public AbstractEntity() {
         this(Maps.newLinkedHashMap(), null);
     }
@@ -240,8 +238,25 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
      */
     @Deprecated
     public AbstractEntity(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
+        super(checkConstructorFlags(flags, parent));
+
+        // TODO Don't let `this` reference escape during construction
+        entityType = new EntityDynamicType(this);
+        
+        if (isLegacyConstruction()) {
+            AbstractBrooklynObject checkWeGetThis = configure(flags);
+            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
+
+            boolean deferConstructionChecks = (flags.containsKey("deferConstructionChecks") && TypeCoercions.coerce(flags.get("deferConstructionChecks"), Boolean.class));
+            if (!deferConstructionChecks) {
+                FlagUtils.checkRequiredFields(this);
+            }
+        }
+    }
+    
+    private static Map<?,?> checkConstructorFlags(Map flags, Entity parent) {
         if (flags==null) {
-            throw new IllegalArgumentException("Flags passed to entity "+this+" must not be null (try no-arguments or empty map)");
+            throw new IllegalArgumentException("Flags passed to entity must not be null (try no-arguments or empty map)");
         }
         if (flags.get("parent") != null && parent != null && flags.get("parent") != parent) {
             throw new IllegalArgumentException("Multiple parents supplied, "+flags.get("parent")+" and "+parent);
@@ -256,77 +271,18 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
             flags.put("parent", parent);
         }
         if (flags.get("owner") != null) {
-            LOG.warn("Use of deprecated \"flags.owner\" instead of \"flags.parent\" for entity {}", this);
+            LOG.warn("Use of deprecated \"flags.owner\" instead of \"flags.parent\" for entity");
             flags.put("parent", flags.get("owner"));
             flags.remove("owner");
         }
-
-        // TODO Don't let `this` reference escape during construction
-        entityType = new EntityDynamicType(this);
-        
-        _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
-        
-        if (_legacyConstruction) {
-            LOG.warn("Deprecated use of old-style entity construction for "+getClass().getName()+"; instead use EntityManager().createEntity(spec)");
-            AbstractEntity checkWeGetThis = configure(flags);
-            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead";
-        }
-        
-        inConstruction = false;
+        return flags;
     }
 
-    @Override
-    public int hashCode() {
-        return getId().hashCode();
-    }
-    
-    @Override
-    public boolean equals(Object o) {
-        return (o == this || o == selfProxy) || 
-                (o instanceof Entity && Objects.equal(getId(), ((Entity)o).getId()));
-    }
-    
-    protected boolean isLegacyConstruction() {
-        return _legacyConstruction;
-    }
-    
-    protected boolean isRebinding() {
-        return RebindManagerImpl.RebindTracker.isRebinding();
-    }
-    
-    public void setProxy(Entity proxy) {
-        if (selfProxy != null) throw new IllegalStateException("Proxy is already set; cannot reset proxy for "+toString());
-        selfProxy = checkNotNull(proxy, "proxy");
-    }
-    
-    public Entity getProxy() {
-        return selfProxy;
-    }
-    
     /**
-     * Returns the proxy, or if not available (because using legacy code) then returns the real entity.
-     * This method will be deleted in a future release; it will be kept while deprecated legacy code
-     * still exists that creates entities without setting the proxy.
-     */
-    @Beta
-    public Entity getProxyIfAvailable() {
-        return getProxy()!=null ? getProxy() : this;
-    }
-    
-    /** sets fields from flags; can be overridden if needed, subclasses should
-     * set custom fields before _invoking_ this super
-     * (and they nearly always should invoke the super)
-     * <p>
-     * note that it is usually preferred to use the SetFromFlag annotation on relevant fields
-     * so they get set automatically by this method and overriding it is unnecessary
-     *
-     * @return this entity, for fluent style initialization
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
      */
-    public AbstractEntity configure() {
-        return configure(Maps.newLinkedHashMap());
-    }
-    
     @Override
+    @Deprecated
     public AbstractEntity configure(Map flags) {
         if (!inConstruction && getManagementSupport().isDeployed()) {
             LOG.warn("bulk/flag configuration being made to {} after deployment: may not be supported in future versions ({})", 
@@ -387,6 +343,40 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
 
         return this;
     }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        return (o == this || o == selfProxy) || 
+                (o instanceof Entity && Objects.equal(getId(), ((Entity)o).getId()));
+    }
+    
+    protected boolean isRebinding() {
+        return RebindManagerImpl.RebindTracker.isRebinding();
+    }
+    
+    public void setProxy(Entity proxy) {
+        if (selfProxy != null) throw new IllegalStateException("Proxy is already set; cannot reset proxy for "+toString());
+        selfProxy = checkNotNull(proxy, "proxy");
+    }
+    
+    public Entity getProxy() {
+        return selfProxy;
+    }
+    
+    /**
+     * Returns the proxy, or if not available (because using legacy code) then returns the real entity.
+     * This method will be deleted in a future release; it will be kept while deprecated legacy code
+     * still exists that creates entities without setting the proxy.
+     */
+    @Beta
+    public Entity getProxyIfAvailable() {
+        return getProxy()!=null ? getProxy() : this;
+    }
     
     /**
      * Sets a config key value, and returns this Entity instance for use in fluent-API style coding.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/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 8aea917..734b1c8 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -36,7 +36,6 @@ import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.basic.EntityDynamicType;
-import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.entity.rebind.BasicLocationRebindSupport;
 import brooklyn.entity.rebind.RebindManagerImpl;
 import brooklyn.entity.rebind.RebindSupport;
@@ -83,7 +82,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
 
     public static final ConfigKey<Location> PARENT_LOCATION = new BasicConfigKey<Location>(Location.class, "parentLocation");
     
-    private final AtomicBoolean configured = new AtomicBoolean(false);
+    private final AtomicBoolean configured = new AtomicBoolean();
     
     private Reference<Long> creationTimeUtc = new BasicReference<Long>(System.currentTimeMillis());
     
@@ -102,8 +101,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
 
     private volatile boolean managed;
 
-    private boolean _legacyConstruction;
-
     private boolean inConstruction;
 
     private final Map<Class<?>, Object> extensions = Maps.newConcurrentMap();
@@ -137,12 +134,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
      * </ul>
      */
     public AbstractLocation(Map properties) {
+        super(properties);
         inConstruction = true;
-        _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
-        if (!_legacyConstruction && properties!=null && !properties.isEmpty()) {
-            LOG.warn("Forcing use of deprecated old-style location construction for "+getClass().getName()+" because properties were specified ("+properties+")");
-            _legacyConstruction = true;
-        }
         
         // When one calls getConfig(key), we want to use the default value specified on *this* location
         // if it overrides the default config. The easiest way to look up all our config keys is to 
@@ -150,13 +143,10 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         // entities). See {@link #getConfig(ConfigKey)}
         entityType = new EntityDynamicType((Class)getClass());
         
-        if (_legacyConstruction) {
-            LOG.warn("Deprecated use of old-style location construction for "+getClass().getName()+"; instead use LocationManager().createLocation(spec)");
-            if (LOG.isDebugEnabled())
-                LOG.debug("Source of use of old-style location construction", new Throwable("Source of use of old-style location construction"));
-            
-            configure(properties);
-            
+        if (isLegacyConstruction()) {
+            AbstractBrooklynObject checkWeGetThis = configure(properties);
+            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
+
             boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
             if (!deferConstructionChecks) {
                 FlagUtils.checkRequiredFields(this);
@@ -213,21 +203,11 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     }
 
     /**
-     * Will set fields from flags. The unused configuration can be found via the 
-     * {@linkplain ConfigBag#getUnusedConfig()}.
-     * This can be overridden for custom initialization but note the following. 
-     * <p>
-     * For new-style locations (i.e. not calling constructor directly, this will
-     * be invoked automatically by brooklyn-core post-construction).
-     * <p>
-     * For legacy location use, this will be invoked by the constructor in this class.
-     * Therefore if over-riding you must *not* rely on field initializers because they 
-     * may not run until *after* this method (this method is invoked by the constructor 
-     * in this class, so initializers in subclasses will not have run when this overridden 
-     * method is invoked.) If you require fields to be initialized you must do that in 
-     * this method with a guard (as in FixedListMachineProvisioningLocation).
-     */ 
-    public void configure(Map properties) {
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+     */
+    @Override
+    @Deprecated
+    public AbstractLocation configure(Map properties) {
         assertNotYetManaged();
         
         boolean firstTime = !configured.getAndSet(true);
@@ -269,6 +249,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
             }
             configBag.put(LocationConfigKeys.ISO_3166, codes);
         }
+        
+        return this;
     }
 
     // TODO ensure no callers rely on 'remove' semantics, and don't remove;
@@ -307,10 +289,6 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
     }
     
-    protected boolean isLegacyConstruction() {
-        return _legacyConstruction;
-    }
-    
     @Override
     public String getDisplayName() {
         return name.get();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/core/src/main/java/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
index d50aa7b..dbb52c5 100644
--- a/core/src/main/java/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
@@ -78,13 +78,13 @@ public class AggregatingMachineProvisioningLocation<T extends MachineLocation> e
     }
 
     @Override
-    public void configure(Map properties) {
+    public AbstractLocation configure(Map properties) {
         if (lock == null) {
             lock = new Object();
             provisioners = Lists.<MachineProvisioningLocation<T>>newArrayList();
             inUse = Maps.<T, MachineProvisioningLocation<T>>newLinkedHashMap();
         }
-        super.configure(properties);
+        return super.configure(properties);
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
index 595ab8a..263e307 100644
--- a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
@@ -121,11 +121,11 @@ implements MachineProvisioningLocation<T>, Closeable {
     }
 
     @Override
-    public void configure(Map properties) {
+    public AbstractLocation configure(Map properties) {
         if (machines == null) machines = Sets.newLinkedHashSet();
         if (inUse == null) inUse = Sets.newLinkedHashSet();
         if (pendingRemoval == null) pendingRemoval = Sets.newLinkedHashSet();
-        super.configure(properties);
+        return super.configure(properties);
     }
     
     public FixedListMachineProvisioningLocation<T> newSubLocation(Map<?,?> newFlags) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
index 1562f9f..64a9345 100644
--- a/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
@@ -118,7 +118,7 @@ public class LocalhostMachineProvisioningLocation extends FixedListMachineProvis
         return LocationSpec.create(LocalhostMachineProvisioningLocation.class);
     }
     
-    public void configure(Map flags) {
+    public LocalhostMachineProvisioningLocation configure(Map flags) {
         super.configure(flags);
         
         if (!truth(getDisplayName())) { setDisplayName("localhost"); }
@@ -142,6 +142,8 @@ public class LocalhostMachineProvisioningLocation extends FixedListMachineProvis
         if (getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR)==null && (getManagementContext()==null || getManagementContext().getConfig().getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR)==null)) {
             setConfig(BrooklynConfigKeys.ONBOX_BASE_DIR, "/tmp/brooklyn-"+Os.user());
         }
+        
+        return this;
     }
     
     public static InetAddress getLocalhostInetAddress() {
@@ -253,11 +255,13 @@ public class LocalhostMachineProvisioningLocation extends FixedListMachineProvis
         public LocalhostMachine(Map properties) {
             super(MutableMap.builder().putAll(properties).put("mutexSupport", mutexSupport).build());
         }
+        
         public boolean obtainSpecificPort(int portNumber) {
             if (!isSudoAllowed() && portNumber <= 1024)
                 return false;
             return LocalhostMachineProvisioningLocation.obtainSpecificPort(getAddress(), portNumber);
         }
+        
         public int obtainPort(PortRange range) {
             int r = LocalhostMachineProvisioningLocation.obtainPort(getAddress(), range);
             synchronized (portsObtained) {
@@ -266,6 +270,7 @@ public class LocalhostMachineProvisioningLocation extends FixedListMachineProvis
             LOG.debug("localhost.obtainPort("+range+"), returning "+r);
             return r;
         }
+        
         @Override
         public void releasePort(int portNumber) {
             synchronized (portsObtained) {
@@ -280,10 +285,11 @@ public class LocalhostMachineProvisioningLocation extends FixedListMachineProvis
         }
         
         @Override
-        public void configure(Map properties) {
+        public LocalhostMachine configure(Map properties) {
             if (address==null || !properties.containsKey("address"))
                 address = Networking.getLocalHost();
             super.configure(properties);
+            return this;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
index 47376d5..a88218e 100644
--- a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
@@ -309,7 +309,7 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
     }
 
     @Override
-    public void configure(Map properties) {
+    public SshMachineLocation configure(Map properties) {
         super.configure(properties);
 
         // TODO Note that check for addresss!=null is done automatically in super-constructor, in FlagUtils.checkRequiredFields
@@ -325,6 +325,7 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
                 setDisplayName((truth(user) ? user+"@" : "") + address.getHostName());
             }
         }
+        return this;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/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 a1e2449..a8cf150 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -39,14 +39,12 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
-import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.entity.rebind.RebindManagerImpl;
 import brooklyn.entity.trait.Configurable;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEventListener;
 import brooklyn.management.ExecutionContext;
-import brooklyn.management.ManagementContext;
 import brooklyn.management.SubscriptionContext;
 import brooklyn.management.SubscriptionHandle;
 import brooklyn.management.internal.SubscriptionTracker;
@@ -68,14 +66,9 @@ import com.google.common.collect.Maps;
 public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable {
     private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
 
-    protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
-
-    private boolean _legacyConstruction;
     private boolean _legacyNoConstructionInit;
-    
-    // TODO not sure if we need this -- never read
-    @SuppressWarnings("unused")
-    private boolean inConstruction;
+
+    protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
 
     protected transient ExecutionContext execution;
 
@@ -101,43 +94,28 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         this(Collections.emptyMap());
     }
     
-    public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map flags) {
-        inConstruction = true;
-        _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
-        _legacyNoConstructionInit = (flags != null) && Boolean.TRUE.equals(flags.get("noConstructionInit"));
-        
-        if (!_legacyConstruction && flags!=null && !flags.isEmpty()) {
-            log.debug("Using direct construction for "+getClass().getName()+" because properties were specified ("+flags+")");
-            _legacyConstruction = true;
-        }
+    public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map properties) {
+        super(properties);
+        _legacyNoConstructionInit = (properties != null) && Boolean.TRUE.equals(properties.get("noConstructionInit"));
         
-        if (_legacyConstruction) {
-            log.debug("Using direct construction for "+getClass().getName()+"; calling configure(Map) immediately");
-            
-            configure(flags);
-            
-            boolean deferConstructionChecks = (flags.containsKey("deferConstructionChecks") && TypeCoercions.coerce(flags.get("deferConstructionChecks"), Boolean.class));
+        if (isLegacyConstruction()) {
+            AbstractBrooklynObject checkWeGetThis = configure(properties);
+            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
+
+            boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
             if (!deferConstructionChecks) {
                 FlagUtils.checkRequiredFields(this);
             }
         }
-        
-        inConstruction = false;
     }
 
-    /** will set fields from flags, and put the remaining ones into the 'leftovers' map.
-     * can be subclassed for custom initialization but note the following. 
-     * <p>
-     * if you require fields to be initialized you must do that in this method. You must
-     * *not* rely on field initializers because they may not run until *after* this method
-     * (this method is invoked by the constructor in this class, so initializers
-     * in subclasses will not have run when this overridden method is invoked.) */ 
-    protected void configure() {
-        configure(Collections.emptyMap());
-    }
-    
+    /**
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+     */
+    @Override
+    @Deprecated
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public void configure(Map flags) {
+    public AbstractEntityAdjunct configure(Map flags) {
         // TODO only set on first time through
         boolean isFirstTime = true;
         
@@ -172,12 +150,9 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
             Preconditions.checkArgument(flags.get("displayName") instanceof CharSequence, "'displayName' property should be a string");
             setDisplayName(flags.remove("displayName").toString());
         }
+        return this;
     }
     
-    protected boolean isLegacyConstruction() {
-        return _legacyConstruction;
-    }
-
     /**
      * Used for legacy-style policies/enrichers on rebind, to indicate that init() should not be called.
      * Will likely be deleted in a future release; should not be called apart from by framework code.
@@ -186,26 +161,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
     protected boolean isLegacyNoConstructionInit() {
         return _legacyNoConstructionInit;
     }
-    
-    /**
-     * Called by framework (in new-style policies where PolicySpec was used) after configuring etc,
-     * but before a reference to this policy is shared.
-     * 
-     * To preserve backwards compatibility for if the policy is constructed directly, one
-     * can call the code below, but that means it will be called after references to this 
-     * policy have been shared with other entities.
-     * <pre>
-     * {@code
-     * if (isLegacyConstruction()) {
-     *     init();
-     * }
-     * }
-     * </pre>
-     */
-    public void init() {
-        // no-op
-    }
-    
+
     protected boolean isRebinding() {
         return RebindManagerImpl.RebindTracker.isRebinding();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cb55b50/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index 0290dc5..380e351 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -93,6 +93,7 @@ import brooklyn.location.MachineManagementMixins.MachineMetadata;
 import brooklyn.location.MachineManagementMixins.RichMachineProvisioningLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.location.access.PortForwardManager;
+import brooklyn.location.basic.AbstractLocation;
 import brooklyn.location.basic.BasicMachineMetadata;
 import brooklyn.location.basic.LocationConfigKeys;
 import brooklyn.location.basic.LocationConfigUtils;
@@ -206,7 +207,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
     }
 
     @Override
-    public void configure(Map properties) {
+    public JcloudsLocation configure(Map properties) {
         super.configure(properties);
         
         if (getLocalConfigBag().containsKey("providerLocationId")) {
@@ -231,6 +232,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             }
             setConfig(MACHINE_CREATION_SEMAPHORE, new Semaphore(maxConcurrent, true));
         }
+        return this;
     }
     
     @Override


[9/9] git commit: This closes #110

Posted by he...@apache.org.
This closes #110

Merge remote-tracking branch 'apache-gh/pr/110'

Conflicts:
	api/src/main/java/brooklyn/basic/BrooklynObject.java
	core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
	core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
	core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
	core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
	core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
	core/src/main/java/brooklyn/location/basic/AbstractLocation.java
	core/src/test/java/brooklyn/entity/basic/EntitiesTest.java

Conflicts mainly new tags methods from #109, resolved and confirmed tests pass.
Also added LocationType and related classes.


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

Branch: refs/heads/master
Commit: d4a6328ebf2fdab2306d84261bfd412ec1dc04e7
Parents: 4891355 79b49a9
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Aug 7 17:54:08 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Aug 7 17:55:14 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/basic/BrooklynObject.java     |  30 +-
 .../main/java/brooklyn/basic/BrooklynType.java  |  54 ++++
 api/src/main/java/brooklyn/entity/Entity.java   |  29 +-
 .../main/java/brooklyn/entity/EntityType.java   |  24 +-
 .../brooklyn/entity/rebind/ChangeListener.java  |  44 +--
 .../java/brooklyn/location/LocationType.java    |  32 +++
 .../java/brooklyn/mementos/EntityMemento.java   |   3 -
 .../main/java/brooklyn/mementos/Memento.java    |   3 +
 .../main/java/brooklyn/policy/EnricherType.java |  24 +-
 .../java/brooklyn/policy/EntityAdjunct.java     |  11 -
 .../main/java/brooklyn/policy/PolicyType.java   |  22 +-
 .../brooklyn/basic/AbstractBrooklynObject.java  | 198 ++++++++++---
 .../brooklyn/basic/BrooklynDynamicType.java     | 283 +++++++++++++++++++
 .../brooklyn/basic/BrooklynTypeSnapshot.java    | 100 +++++++
 .../main/java/brooklyn/basic/BrooklynTypes.java | 119 ++++++++
 .../enricher/basic/AbstractEnricher.java        |  15 +-
 .../enricher/basic/EnricherDynamicType.java     |  39 +++
 .../enricher/basic/EnricherTypeSnapshot.java    |  39 +++
 .../brooklyn/entity/basic/AbstractEntity.java   | 169 +++++------
 .../entity/basic/EntityDynamicType.java         | 252 ++---------------
 .../entity/basic/EntityInitializers.java        |   2 +-
 .../entity/basic/EntityTypeSnapshot.java        |  58 +---
 .../java/brooklyn/entity/basic/EntityTypes.java |  86 +-----
 .../proxying/BasicEntityTypeRegistry.java       |   2 -
 .../entity/proxying/InternalEntityFactory.java  |   2 +-
 .../proxying/InternalLocationFactory.java       |  11 +-
 .../entity/proxying/InternalPolicyFactory.java  |  19 +-
 .../AbstractBrooklynObjectRebindSupport.java    |  88 ++++++
 .../rebind/BasicEnricherRebindSupport.java      |  43 +--
 .../entity/rebind/BasicEntityRebindSupport.java |  64 ++---
 .../rebind/BasicLocationRebindSupport.java      |  40 +--
 .../entity/rebind/BasicPolicyRebindSupport.java |  41 +--
 .../rebind/ImmediateDeltaChangeListener.java    | 179 +++++-------
 .../rebind/PeriodicDeltaChangeListener.java     | 153 ++++------
 .../entity/rebind/RebindManagerImpl.java        | 104 +------
 .../entity/rebind/dto/AbstractMemento.java      |  11 +-
 .../entity/rebind/dto/BasicEntityMemento.java   |  13 +-
 .../entity/rebind/dto/MementosGenerators.java   |  87 +++---
 .../location/basic/AbstractLocation.java        | 137 +++------
 .../AggregatingMachineProvisioningLocation.java |   4 +-
 .../FixedListMachineProvisioningLocation.java   |   4 +-
 .../LocalhostMachineProvisioningLocation.java   |  10 +-
 .../location/basic/LocationDynamicType.java     |  39 +++
 .../location/basic/LocationTypeSnapshot.java    |  40 +++
 .../location/basic/SshMachineLocation.java      |   3 +-
 .../policy/basic/AbstractEntityAdjunct.java     | 111 ++------
 .../brooklyn/policy/basic/AbstractPolicy.java   |  12 +-
 .../brooklyn/policy/basic/EnricherTypeImpl.java |  75 -----
 .../policy/basic/PolicyDynamicType.java         |  39 +++
 .../brooklyn/policy/basic/PolicyTypeImpl.java   |  75 -----
 .../policy/basic/PolicyTypeSnapshot.java        |  39 +++
 .../enricher/basic/BasicEnricherTest.java       |   2 +-
 .../brooklyn/entity/basic/EntitiesTest.java     |  22 +-
 .../entity/rebind/RebindEnricherTest.java       |  16 +-
 .../entity/rebind/RebindEntityTest.java         |  14 +-
 .../entity/rebind/RebindLocationTest.java       |  17 +-
 .../entity/rebind/RebindPolicyTest.java         |  27 +-
 .../location/basic/AbstractLocationTest.java    |   3 +-
 .../brooklyn/policy/basic/BasicPolicyTest.java  |   2 +-
 .../location/jclouds/JcloudsLocation.java       |   4 +-
 .../brooklyn/rest/resources/EntityResource.java |  14 +-
 .../rest/transform/CatalogTransformer.java      |   4 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   4 +-
 .../rest/resources/EntityResourceTest.java      |  11 +-
 64 files changed, 1687 insertions(+), 1534 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/api/src/main/java/brooklyn/basic/BrooklynObject.java
----------------------------------------------------------------------
diff --cc api/src/main/java/brooklyn/basic/BrooklynObject.java
index dd26528,44cd489..88b50c2
--- a/api/src/main/java/brooklyn/basic/BrooklynObject.java
+++ b/api/src/main/java/brooklyn/basic/BrooklynObject.java
@@@ -34,12 -35,25 +36,28 @@@ public interface BrooklynObject extend
       */
      String getDisplayName();
      
-     /**
-      * A set of tags associated to this adjunct.
+     /** 
+      * 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.
       */
-     @Nonnull Set<Object> getTags();
- 
-     /** whether the given object is contained as a tag */
-     boolean containsTag(Object tag);
+     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();
++        @Nonnull Set<Object> getTags();
+         
+         boolean containsTag(@Nonnull Object tag);
+         
+         boolean addTag(@Nonnull Object tag);
+         
++        boolean addTags(@Nonnull Iterable<?> tags);
++        
+         boolean removeTag(@Nonnull Object tag);
+     }
++
  }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/api/src/main/java/brooklyn/entity/Entity.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/api/src/main/java/brooklyn/location/LocationType.java
----------------------------------------------------------------------
diff --cc api/src/main/java/brooklyn/location/LocationType.java
index 0000000,0000000..7bdb179
new file mode 100644
--- /dev/null
+++ b/api/src/main/java/brooklyn/location/LocationType.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied.  See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++package brooklyn.location;
++
++import brooklyn.basic.BrooklynType;
++
++import com.google.common.annotations.Beta;
++
++/**
++ * Gives type information for a {@link Location}. It is immutable.
++ 
++ * @since 0.7.0
++ */
++@Beta
++public interface LocationType extends BrooklynType {
++}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/api/src/main/java/brooklyn/policy/EntityAdjunct.java
----------------------------------------------------------------------
diff --cc api/src/main/java/brooklyn/policy/EntityAdjunct.java
index 97acc08,fa05a2a..ed42605
--- a/api/src/main/java/brooklyn/policy/EntityAdjunct.java
+++ b/api/src/main/java/brooklyn/policy/EntityAdjunct.java
@@@ -18,11 -18,6 +18,8 @@@
   */
  package brooklyn.policy;
  
- import java.util.Set;
- 
- import javax.annotation.Nonnull;
 +import javax.annotation.Nullable;
 +
  import brooklyn.basic.BrooklynObject;
  
  /**
@@@ -48,25 -43,7 +45,17 @@@ public interface EntityAdjunct extends 
      boolean isDestroyed();
      
      /**
 -     * Whether the adjunct is available
 +     * Whether the adjunct is available/active
       */
      boolean isRunning();
 +    
 +    /**
 +     * An optional tag used to identify adjuncts with a specific purpose, typically created by the caller.
 +     * This is used to prevent multiple instances with the same purpose from being created,
 +     * and to access and customize adjuncts so created.
 +     * <p>
 +     * This will be included in the call to {@link #getTags()}.
 +     */
 +    @Nullable String getUniqueTag();
-     
-     /**
-      * A set of tags associated to this adjunct.
-      * <p>
-      * This will include {@link #getUniqueTag()} if that is set.
-      */
-     @Override
-     @Nonnull Set<Object> getTags();
 +
  }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
index e977fec,b15e73d..d06eb2f
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@@ -24,7 -34,7 +34,8 @@@ import brooklyn.util.flags.SetFromFlag
  import brooklyn.util.text.Identifiers;
  
  import com.google.common.collect.ImmutableSet;
 +import com.google.common.collect.Iterables;
+ import com.google.common.collect.Maps;
  import com.google.common.collect.Sets;
  
  public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
@@@ -32,55 -46,150 +47,166 @@@
      @SetFromFlag(value="id")
      private String id = Identifiers.makeRandomId(8);
      
 +    /** subclasses should synchronize on this for all access */
 +    @SetFromFlag(value="tags")
-     protected Set<Object> tags = Sets.newLinkedHashSet();
+     private final Set<Object> tags = Sets.newLinkedHashSet();
+ 
+     private volatile ManagementContext managementContext;
+ 
+     public abstract void setDisplayName(String newName);
+ 
+     public AbstractBrooklynObject() {
+         this(Maps.newLinkedHashMap());
+     }
+     
+     public AbstractBrooklynObject(Map<?,?> properties) {
+         _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
+         
+         if (!_legacyConstruction && properties!=null && !properties.isEmpty()) {
+             log.warn("Forcing use of deprecated old-style location construction for "+getClass().getName()+" because properties were specified ("+properties+"); instead use specs (e.g. LocationSpec, EntitySpec, etc)");
+             if (log.isDebugEnabled())
+                 log.debug("Source of use of old-style construction", new Throwable("Source of use of old-style construction"));
+             _legacyConstruction = true;
+         }
+         
+         // rely on sub-class to call configure(properties), because otherwise its fields will not have been initialised
+     }
+ 
+     /**
+      * See {@link #configure(Map)}
+      * 
+      * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+      */ 
+     @Deprecated
+     protected AbstractBrooklynObject configure() {
+         return configure(Collections.emptyMap());
+     }
+     
+     /**
+      * Will set fields from flags, and put the remaining ones into the 'leftovers' map.
+      * For some types, you can find unused config via {@link ConfigBag#getUnusedConfig()}.
+      * <p>
+      * To be overridden by AbstractEntity, AbstractLoation, AbstractPolicy, AbstractEnricher, etc.
+      * <p>
+      * But should not be overridden by specific entity types. If you do, the entity may break in
+      * subsequent releases. Also note that if you require fields to be initialized you must do that 
+      * in this method. You must *not* rely on field initializers because they may not run until *after* 
+      * this method (this method is invoked by the constructor in this class, so initializers
+      * in subclasses will not have run when this overridden method is invoked.)
+      * 
+      * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+      */ 
+     @Deprecated
 -    protected AbstractBrooklynObject configure(Map flags) {
 -        return this;
 -    }
++    protected abstract AbstractBrooklynObject configure(Map<?,?> flags);
+     
+     protected boolean isLegacyConstruction() {
+         return _legacyConstruction;
+     }
+ 
+     /**
+      * Called by framework (in new-style instances where spec was used) after configuring etc,
+      * but before a reference to this instance is shared.
+      * 
+      * To preserve backwards compatibility for if the instance is constructed directly, one
+      * can call the code below, but that means it will be called after references to this 
+      * policy have been shared with other entities.
+      * <pre>
+      * {@code
+      * if (isLegacyConstruction()) {
+      *     init();
+      * }
+      * }
+      * </pre>
+      */
+     public void init() {
+         // no-op
+     }
+     
+     /**
+      * Called by framework on rebind (in new-style instances),
+      * after configuring but before the instance is managed (or is attached to an entity, depending on its type), 
+      * and before a reference to this policy is shared.
+      * Note that {@link #init()} will not be called on rebind.
+      */
+     public void rebind() {
+         // no-op
+     }
+     
+     public void setManagementContext(ManagementContextInternal managementContext) {
+         this.managementContext = managementContext;
+     }
+     
+     public ManagementContext getManagementContext() {
+         return managementContext;
+     }
+ 
+     protected boolean isRebinding() {
+         return RebindManagerImpl.RebindTracker.isRebinding();
+     }
+     
+     protected void requestPersist() {
 -        // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
+         if (getManagementContext() != null) {
+             getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+         }
+     }
      
      @Override
      public String getId() {
          return id;
      }
      
-     @Override
-     public Set<Object> getTags() {
-         synchronized (tags) {
-             return ImmutableSet.copyOf(tags);
-         }
++    protected void onTagsChanged() {
++        requestPersist();
++    }
++    
+     public TagSupport getTagSupport() {
 -        return new TagSupport() {
 -            @Override
 -            public Set<Object> getTags() {
 -                synchronized (tags) {
 -                    return ImmutableSet.copyOf(tags);
 -                }
++        return new BasicTagSupport();
 +    }
 +
-     public boolean addTag(Object tag) {
-         boolean result;
-         synchronized (tags) {
-             result = tags.add(tag);
++    protected class BasicTagSupport implements TagSupport {
++        @Override
++        public Set<Object> getTags() {
++            synchronized (tags) {
++                return ImmutableSet.copyOf(tags);
+             }
 -    
 -            @Override
 -            public boolean containsTag(Object tag) {
 -                synchronized (tags) {
 -                    return tags.contains(tag);
 -                }
 +        }
-         onTagsChanged();
-         return result;
-     }    
- 
-     public boolean addTags(Iterable<Object> tags) {
-         boolean result;
-         synchronized (tags) {
-             result = Iterables.addAll(this.tags, tags);
-         }
-         onTagsChanged();
-         return result;
-     }    
- 
-     public boolean removeTag(Object tag) {
-         boolean result;
-         synchronized (tags) {
-             result = tags.remove(tag);
-         }
-         onTagsChanged();
-         return result;
-     }    
 +
-     public boolean containsTag(Object tag) {
-         synchronized (tags) {
-             return tags.contains(tag);
++        @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;
 -            }    
 -        };
 +        }
-     }    
++        
++        @Override
++        public boolean addTag(Object tag) {
++            boolean result;
++            synchronized (tags) {
++                result = tags.add(tag);
++            }
++            onTagsChanged();
++            return result;
++        }    
 +
-     protected abstract void onTagsChanged();
++        @Override
++        public boolean addTags(Iterable<?> newTags) {
++            boolean result;
++            synchronized (tags) {
++                result = Iterables.addAll(tags, newTags);
++            }
++            onTagsChanged();
++            return result;
++        }    
++
++        @Override
++        public boolean removeTag(Object tag) {
++            boolean result;
++            synchronized (tags) {
++                result = tags.remove(tag);
++            }
++            onTagsChanged();
++            return result;
++        }    
+     }
 +    
  }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
index 0000000,0ae7400..011c499
mode 000000,100644..100644
--- a/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
@@@ -1,0 -1,283 +1,283 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package brooklyn.basic;
+ 
+ import static com.google.common.base.Preconditions.checkNotNull;
+ 
+ import java.lang.reflect.Field;
+ import java.lang.reflect.Modifier;
+ import java.util.ArrayList;
+ import java.util.Collection;
+ import java.util.Collections;
+ import java.util.LinkedHashMap;
+ import java.util.LinkedHashSet;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.concurrent.ConcurrentHashMap;
+ import java.util.concurrent.atomic.AtomicBoolean;
+ 
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+ import brooklyn.config.ConfigKey;
+ import brooklyn.config.ConfigKey.HasConfigKey;
+ import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
+ import brooklyn.util.flags.FlagUtils;
+ import brooklyn.util.javalang.Reflections;
+ import brooklyn.util.text.Strings;
+ 
+ import com.google.common.base.Joiner;
+ import com.google.common.base.Objects;
+ import com.google.common.collect.ArrayListMultimap;
+ import com.google.common.collect.ListMultimap;
+ import com.google.common.collect.Lists;
+ 
+ /**
+  * This is the actual type of a brooklyn object instance at runtime,
+  * which can change from the static {@link BrooklynType}, and can change over time;
+  * for this reason it does *not* implement BrooklynType, but 
+  * callers can call {@link #getSnapshot()} to get a snapshot such instance.  
+  */
+ public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT extends AbstractBrooklynObject> {
+ 
+     private static final Logger LOG = LoggerFactory.getLogger(BrooklynDynamicType.class);
+ 
+     protected final Class<? extends T> brooklynClass;
+     protected final AbstractT instance;
+     protected volatile String name;
+     
+     /** 
+      * Map of config keys (and their fields) on this instance, by name.
+      */
+     protected final Map<String,FieldAndValue<ConfigKey<?>>> configKeys = new ConcurrentHashMap<String, FieldAndValue<ConfigKey<?>>>();
+ 
+     private volatile BrooklynTypeSnapshot snapshot;
+     private final AtomicBoolean snapshotValid = new AtomicBoolean(false);
+ 
++    @SuppressWarnings("unchecked")
+     public BrooklynDynamicType(AbstractT instance) {
+         this((Class<? extends T>) instance.getClass(), instance);
+     }
+     public BrooklynDynamicType(Class<? extends T> clazz) {
+         this(clazz, null);
+     }
+     protected BrooklynDynamicType(Class<? extends T> clazz, AbstractT instance) {
+         this.brooklynClass = checkNotNull(clazz, "brooklyn class");
+         this.instance = instance;
+         // 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: {}", (instance==null ? clazz.getName() : instance.getId()), Joiner.on(", ").join(configKeys.keySet()));
+     }
+     
+     protected abstract BrooklynTypeSnapshot newSnapshot();
+ 
+     protected void invalidateSnapshot() {
+         snapshotValid.set(false);
+     }
+ 
+     public void setName(String name) {
+         if (Strings.isBlank(name)) {
+             throw new IllegalArgumentException("Invalid name "+(name == null ? "null" : "'"+name+"'")+"; name must be non-empty and not just white space");
+         }
+         this.name = name;
+         invalidateSnapshot();
+     }
+     
+     public synchronized BrooklynType getSnapshot() {
+         return refreshSnapshot();
+     }
+     
+     public Class<? extends T> getBrooklynClass() {
+         return brooklynClass;
+     }
+     
+     // --------------------------------------------------
+     
+     /**
+      * ConfigKeys available on this entity.
+      */
+     public Map<String,ConfigKey<?>> getConfigKeys() {
+         return Collections.unmodifiableMap(value(configKeys));
+     }
+ 
+     /**
+      * ConfigKeys available on this entity.
+      */
+     public ConfigKey<?> getConfigKey(String keyName) { 
+         return value(configKeys.get(keyName)); 
+     }
+ 
+     /** field where a config key is defined, for use getting annotations. note annotations are not inherited. */
+     public Field getConfigKeyField(String keyName) { 
+         return field(configKeys.get(keyName)); 
+     }
+ 
+     protected BrooklynTypeSnapshot refreshSnapshot() {
+         if (snapshotValid.compareAndSet(false, true)) {
+             snapshot = newSnapshot();
+         }
+         return snapshot;
+     }
+ 
+     /**
+      * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged).
+      * Prefers keys which overwrite other keys, and prefers keys which are lower in the hierarchy;
+      * logs warnings if there are two conflicting keys which don't have an overwriting relationship.
+      */
+     protected static void buildConfigKeys(Class<? extends BrooklynObject> clazz, AbstractBrooklynObject optionalInstance, 
+             Map<String, FieldAndValue<ConfigKey<?>>> configKeys) {
+         ListMultimap<String,FieldAndValue<ConfigKey<?>>> configKeysAll = 
+                 ArrayListMultimap.<String, FieldAndValue<ConfigKey<?>>>create();
+         
+         for (Field f : FlagUtils.getAllFields(clazz)) {
+             boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType());
+             if (!isConfigKey) {
+                 if (!HasConfigKey.class.isAssignableFrom(f.getType())) {
+                     // neither ConfigKey nor HasConfigKey
+                     continue;
+                 }
+             }
+             if (!Modifier.isStatic(f.getModifiers())) {
+                 // require it to be static or we have an instance
+                 LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalInstance!=null ? optionalInstance : clazz));
+                 if (optionalInstance==null) continue;
+             }
+             try {
+                 ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) f.get(optionalInstance) : 
+                     ((HasConfigKey<?>)f.get(optionalInstance)).getConfigKey();
+                 
+                 if (k==null) {
+                     LOG.warn("no value defined for config key field (skipping): "+f);
+                 } else {
+                     configKeysAll.put(k.getName(), new FieldAndValue<ConfigKey<?>>(f, k));
+                 }
+                 
+             } catch (IllegalAccessException e) {
+                 LOG.warn("cannot access config key (skipping): "+f);
+             }
+         }
+         LinkedHashSet<String> keys = new LinkedHashSet<String>(configKeysAll.keys());
+         for (String kn: keys) {
+             List<FieldAndValue<ConfigKey<?>>> kk = Lists.newArrayList(configKeysAll.get(kn));
+             if (kk.size()>1) {
+                 // remove anything which extends another value in the list
+                 for (FieldAndValue<ConfigKey<?>> k: kk) {
+                     ConfigKey<?> key = value(k);
+                     if (key instanceof BasicConfigKeyOverwriting) {                            
+                         ConfigKey<?> parent = ((BasicConfigKeyOverwriting<?>)key).getParentKey();
+                         // find and remove the parent from consideration
+                         for (FieldAndValue<ConfigKey<?>> k2: kk) {
+                             if (value(k2) == parent)
+                                 configKeysAll.remove(kn, k2);
+                         }
+                     }
+                 }
+                 kk = Lists.newArrayList(configKeysAll.get(kn));
+             }
+             // multiple keys, not overwriting; if their values are the same then we don't mind
+             FieldAndValue<ConfigKey<?>> best = null;
+             for (FieldAndValue<ConfigKey<?>> k: kk) {
+                 if (best==null) {
+                     best=k;
+                 } else {
+                     Field lower = Reflections.inferSubbestField(k.field, best.field);
+                     ConfigKey<? extends Object> lowerV = lower==null ? null : lower.equals(k.field) ? k.value : best.value;
+                     if (best.value == k.value) {
+                         // same value doesn't matter which we take (but take lower if there is one)
+                         if (LOG.isTraceEnabled()) 
+                             LOG.trace("multiple definitions for config key {} on {}; same value {}; " +
+                                     "from {} and {}, preferring {}", 
+                                     new Object[] {
+                                     best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                     best.value.getDefaultValue(),
+                                     k.field, best.field, lower});
+                         best = new FieldAndValue<ConfigKey<?>>(lower!=null ? lower : best.field, best.value);
+                     } else if (lower!=null) {
+                         // different value, but one clearly lower (in type hierarchy)
+                         if (LOG.isTraceEnabled()) 
+                             LOG.trace("multiple definitions for config key {} on {}; " +
+                                     "from {} and {}, preferring lower {}, value {}", 
+                                     new Object[] {
+                                     best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                     k.field, best.field, lower,
+                                     lowerV.getDefaultValue() });
+                         best = new FieldAndValue<ConfigKey<?>>(lower, lowerV);
+                     } else {
+                         // different value, neither one lower than another in hierarchy
+                         LOG.warn("multiple ambiguous definitions for config key {} on {}; " +
+                                 "from {} and {}, values {} and {}; " +
+                                 "keeping latter (arbitrarily)", 
+                                 new Object[] {
+                                 best.value.getName(), optionalInstance!=null ? optionalInstance : clazz,
+                                 k.field, best.field, 
+                                 k.value.getDefaultValue(), best.value.getDefaultValue() });
+                         // (no change)
+                     }
+                 }
+             }
+             if (best==null) {
+                 // shouldn't happen
+                 LOG.error("Error - no matching config key from "+kk+" in class "+clazz+", even though had config key name "+kn);
+                 continue;
+             } else {
+                 configKeys.put(best.value.getName(), best);
+             }
+         }
+     }
+     
+     protected static class FieldAndValue<V> {
+         public final Field field;
+         public final V value;
+         public FieldAndValue(Field field, V value) {
+             this.field = field;
+             this.value = value;
+         }
+         @Override
+         public String toString() {
+             return Objects.toStringHelper(this).add("field", field).add("value", value).toString();
+         }
+     }
+     
+     protected static <V> V value(FieldAndValue<V> fv) {
+         if (fv==null) return null;
+         return fv.value;
+     }
+     
+     protected static Field field(FieldAndValue<?> fv) {
+         if (fv==null) return null;
+         return fv.field;
+     }
+ 
 -    @SuppressWarnings("unused")
+     protected static <V> Collection<V> value(Collection<FieldAndValue<V>> fvs) {
+         List<V> result = new ArrayList<V>();
+         for (FieldAndValue<V> fv: fvs) result.add(value(fv));
+         return result;
+     }
+ 
+     protected static <K,V> Map<K,V> value(Map<K,FieldAndValue<V>> fvs) {
+         Map<K,V> result = new LinkedHashMap<K,V>();
+         for (K key: fvs.keySet())
+             result.put(key, value(fvs.get(key)));
+         return result;
+     }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index df6a370,8503663..9cba5b9
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@@ -62,10 -62,6 +62,7 @@@ public abstract class AbstractEnricher 
  
      @Override
      protected void onChanged() {
-         // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
-         if (getManagementContext() != null) {
-             getManagementContext().getRebindManager().getChangeListener().onChanged(this);
-         }
+         requestPersist();
      }
 +    
  }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 68846aa,ad2043c..97d7b4e
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@@ -1349,9 -1285,24 +1308,29 @@@ public abstract class AbstractEntity ex
      }
  
      @Override
 +    protected void onTagsChanged() {
++        super.onTagsChanged();
 +        getManagementSupport().getEntityChangeListener().onTagsChanged();
 +    }
++
+     public Set<Object> getTags() {
+         return getTagSupport().getTags();
+     }
+ 
+     @Override
+     public boolean addTag(Object tag) {
+         return getTagSupport().addTag(tag);
+     }    
+ 
+     @Override
+     public boolean removeTag(Object tag) {
+         return getTagSupport().removeTag(tag);
+     }    
+ 
+     @Override
+     public boolean containsTag(Object tag) {
+         return getTagSupport().containsTag(tag);
+     }    
      
      @Override
      protected void finalize() throws Throwable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
index 9cc05c3,b5d7c0a..78fa574
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@@ -231,7 -230,6 +231,7 @@@ public class InternalEntityFactory exte
              if (spec.getDisplayName()!=null)
                  ((AbstractEntity)entity).setDisplayName(spec.getDisplayName());
              
-             ((AbstractEntity)entity).addTags(spec.getTags());
++            entity.getTagSupport().addTags(spec.getTags());
              ((AbstractEntity)entity).configure(MutableMap.copyOf(spec.getFlags()));
              
              for (Map.Entry<ConfigKey<?>, Object> entry : spec.getConfig().entrySet()) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
index 6a7b599,b989392..934acce
--- a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
@@@ -95,11 -102,9 +102,11 @@@ public class InternalLocationFactory ex
              managementContext.prePreManage(loc);
  
              if (spec.getDisplayName()!=null)
 -                ((AbstractLocation)loc).setName(spec.getDisplayName());
 +                ((AbstractLocation)loc).setDisplayName(spec.getDisplayName());
 +            
-             ((AbstractLocation)loc).addTags(spec.getTags());
++            loc.getTagSupport().addTags(spec.getTags());
              
-             if (isNewStyleLocation(clazz)) {
+             if (isNewStyle(clazz)) {
                  ((AbstractLocation)loc).setManagementContext(managementContext);
                  ((AbstractLocation)loc).configure(ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig());
              }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
index 76dd312,d52d368..9a84c3b
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@@ -94,9 -105,7 +105,9 @@@ public class InternalPolicyFactory exte
              if (spec.getDisplayName()!=null)
                  ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName());
              
-             ((AbstractPolicy)pol).addTags(spec.getTags());
++            pol.getTagSupport().addTags(spec.getTags());
 +            
-             if (isNewStylePolicy(clazz)) {
+             if (isNewStyle(clazz)) {
                  ((AbstractPolicy)pol).setManagementContext(managementContext);
                  Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
                  ((AbstractPolicy)pol).configure(MutableMap.copyOf(config)); // TODO AbstractPolicy.configure modifies the map
@@@ -131,9 -140,7 +142,9 @@@
              if (spec.getDisplayName()!=null)
                  ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName());
              
-             ((AbstractEnricher)enricher).addTags(spec.getTags());
++            enricher.getTagSupport().addTags(spec.getTags());
 +            
-             if (isNewStyleEnricher(clazz)) {
+             if (isNewStyle(clazz)) {
                  ((AbstractEnricher)enricher).setManagementContext(managementContext);
                  Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
                  ((AbstractEnricher)enricher).configure(MutableMap.copyOf(config)); // TODO AbstractEnricher.configure modifies the map

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/location/basic/AbstractLocation.java
index 84259ff,c4b4ee0..4d76849
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@@ -35,10 -35,8 +35,7 @@@ import org.slf4j.LoggerFactory
  import brooklyn.basic.AbstractBrooklynObject;
  import brooklyn.config.ConfigKey;
  import brooklyn.config.ConfigKey.HasConfigKey;
--import brooklyn.entity.basic.EntityDynamicType;
- import brooklyn.entity.proxying.InternalFactory;
  import brooklyn.entity.rebind.BasicLocationRebindSupport;
- import brooklyn.entity.rebind.RebindManagerImpl;
  import brooklyn.entity.rebind.RebindSupport;
  import brooklyn.entity.trait.Configurable;
  import brooklyn.event.basic.BasicConfigKey;
@@@ -113,7 -104,7 +106,7 @@@ public abstract class AbstractLocation 
  
      private final Map<Class<?>, Object> extensions = Maps.newConcurrentMap();
      
--    private final EntityDynamicType entityType;
++    private final LocationDynamicType locationType;
      
      /**
       * Construct a new instance of an AbstractLocation.
@@@ -141,28 -132,20 +134,18 @@@
       * <li>abbreviatedName
       * </ul>
       */
-     @SuppressWarnings({ "rawtypes", "unchecked" })
 -    public AbstractLocation(Map properties) {
 +    public AbstractLocation(Map<?,?> properties) {
+         super(properties);
          inConstruction = true;
-         _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
-         if (!_legacyConstruction && properties!=null && !properties.isEmpty()) {
-             LOG.warn("Forcing use of deprecated old-style location construction for "+getClass().getName()+" because properties were specified ("+properties+")");
-             _legacyConstruction = true;
-         }
          
          // When one calls getConfig(key), we want to use the default value specified on *this* location
--        // if it overrides the default config. The easiest way to look up all our config keys is to 
--        // reuse the code for Entity (and this will become identical when locations become first-class
--        // entities). See {@link #getConfig(ConfigKey)}
--        entityType = new EntityDynamicType((Class)getClass());
++        // if it overrides the default config, by using the type object 
++        locationType = new LocationDynamicType(this);
          
-         if (_legacyConstruction) {
-             LOG.warn("Deprecated use of old-style location construction for "+getClass().getName()+"; instead use LocationManager().createLocation(spec)");
-             if (LOG.isDebugEnabled())
-                 LOG.debug("Source of use of old-style location construction", new Throwable("Source of use of old-style location construction"));
-             
-             configure(properties);
-             
+         if (isLegacyConstruction()) {
+             AbstractBrooklynObject checkWeGetThis = configure(properties);
+             assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
+ 
              boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
              if (!deferConstructionChecks) {
                  FlagUtils.checkRequiredFields(this);
@@@ -218,28 -201,12 +201,14 @@@
          }
      }
  
-     @Override
-     public ManagementContext getManagementContext() {
-         return managementContext;
-     }
-     
      /**
-      * Will set fields from flags. The unused configuration can be found via the 
-      * {@linkplain ConfigBag#getUnusedConfig()}.
-      * This can be overridden for custom initialization but note the following. 
-      * <p>
-      * For new-style locations (i.e. not calling constructor directly, this will
-      * be invoked automatically by brooklyn-core post-construction).
-      * <p>
-      * For legacy location use, this will be invoked by the constructor in this class.
-      * Therefore if over-riding you must *not* rely on field initializers because they 
-      * may not run until *after* this method (this method is invoked by the constructor 
-      * in this class, so initializers in subclasses will not have run when this overridden 
-      * method is invoked.) If you require fields to be initialized you must do that in 
-      * this method with a guard (as in FixedListMachineProvisioningLocation).
 -     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
++     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly;
++     * see overridden method for more info
       */
 +    @SuppressWarnings("serial")
-     public void configure(Map<?,?> properties) {
+     @Override
+     @Deprecated
 -    public AbstractLocation configure(Map properties) {
++    public AbstractLocation configure(Map<?,?> properties) {
          assertNotYetManaged();
          
          boolean firstTime = !configured.getAndSet(true);
@@@ -406,8 -338,7 +342,8 @@@
          
          // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key
          // TODO when locations become entities, the duplication of this compared to EntityConfigMap.getConfig will disappear.
 -        ConfigKey<T> ownKey = (ConfigKey<T>) elvis(entityType.getConfigKey(key.getName()), key);
 +        @SuppressWarnings("unchecked")
-         ConfigKey<T> ownKey = (ConfigKey<T>) elvis(entityType.getConfigKey(key.getName()), key);
++        ConfigKey<T> ownKey = (ConfigKey<T>) elvis(locationType.getConfigKey(key.getName()), key);
  
          return ownKey.getDefaultValue();
      }
@@@ -450,11 -381,19 +386,20 @@@
      
      @Override
      public <T> T setConfig(ConfigKey<T> key, T value) {
 -        return configBag.put(key, value);
 +        T result = configBag.put(key, value);
 +        onChanged();
 +        return result;
      }
  
+     /**
+      * @since 0.6.0 (?) - use getDisplayName
+      * @deprecated since 0.7.0; use {@link #getDisplayName()}
+      */
+     @Deprecated
+     public void setName(String newName) {
+         setDisplayName(newName);
 -        displayNameAutoGenerated = false;
+     }
+ 
      public void setDisplayName(String newName) {
          name.set(newName);
          displayNameAutoGenerated = false;
@@@ -514,13 -451,10 +459,12 @@@
          }
          
          if (isManaged()) {
-             if (!managementContext.getLocationManager().isManaged(child)) {
-                 // this deprecated call should be replaced with an internal interface call?
-                 managementContext.getLocationManager().manage(child);
 -            Locations.manage(child, getManagementContext());
++            if (!getManagementContext().getLocationManager().isManaged(child)) {
++                Locations.manage(child, getManagementContext());
 +            }
-         } else if (managementContext != null) {
-             if (((LocalLocationManager)managementContext.getLocationManager()).getLocationEvenIfPreManaged(child.getId()) == null) {
-                 ((ManagementContextInternal)managementContext).prePreManage(child);
+         } else if (getManagementContext() != null) {
+             if (((LocalLocationManager)getManagementContext().getLocationManager()).getLocationEvenIfPreManaged(child.getId()) == null) {
+                 ((ManagementContextInternal)getManagementContext()).prePreManage(child);
              }
          }
  
@@@ -542,25 -474,12 +486,20 @@@
              child.setParent(null);
              
              if (isManaged()) {
-                 managementContext.getLocationManager().unmanage(child);
+                 getManagementContext().getLocationManager().unmanage(child);
              }
          }
 +        onChanged();
          return removed;
      }
  
-     @Override
-     protected void onTagsChanged() {
-         onChanged();
-     }
- 
 +    protected void onChanged() {
 +        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
 +        if (getManagementContext() != null) {
 +            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
 +        }
 +    }
 +
      /** Default String representation is simplified name of class, together with selected fields. */
      @Override
      public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/location/basic/LocationDynamicType.java
index 0000000,0000000..cc0b304
new file mode 100644
--- /dev/null
+++ b/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java
@@@ -1,0 -1,0 +1,39 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied.  See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++package brooklyn.location.basic;
++
++import brooklyn.basic.BrooklynDynamicType;
++import brooklyn.location.Location;
++import brooklyn.location.LocationType;
++
++public class LocationDynamicType extends BrooklynDynamicType<Location, AbstractLocation> {
++
++    public LocationDynamicType(AbstractLocation location) {
++        super(location);
++    }
++    
++    public LocationType getSnapshot() {
++        return (LocationType) super.getSnapshot();
++    }
++
++    @Override
++    protected LocationTypeSnapshot newSnapshot() {
++        return new LocationTypeSnapshot(name, value(configKeys));
++    }
++}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/location/basic/LocationTypeSnapshot.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/location/basic/LocationTypeSnapshot.java
index 0000000,0000000..9a96e98
new file mode 100644
--- /dev/null
+++ b/core/src/main/java/brooklyn/location/basic/LocationTypeSnapshot.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied.  See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++package brooklyn.location.basic;
++
++import java.util.Map;
++
++import brooklyn.basic.BrooklynTypeSnapshot;
++import brooklyn.config.ConfigKey;
++import brooklyn.policy.EnricherType;
++
++public class LocationTypeSnapshot extends BrooklynTypeSnapshot implements EnricherType {
++    
++    private static final long serialVersionUID = 9150132836104748237L;
++
++    LocationTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
++        super(name, configKeys);
++    }
++
++    @Override
++    public boolean equals(Object obj) {
++        if (this == obj) return true;
++        return (obj instanceof LocationTypeSnapshot) && super.equals(obj);
++    }
++}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index a53d9a5,7f0e08f..36d8505
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@@ -40,8 -39,7 +39,6 @@@ import brooklyn.entity.Entity
  import brooklyn.entity.Group;
  import brooklyn.entity.basic.EntityInternal;
  import brooklyn.entity.basic.EntityLocal;
- import brooklyn.entity.proxying.InternalFactory;
--import brooklyn.entity.rebind.RebindManagerImpl;
  import brooklyn.entity.trait.Configurable;
  import brooklyn.event.AttributeSensor;
  import brooklyn.event.Sensor;
@@@ -407,25 -331,11 +338,17 @@@ public abstract class AbstractEntityAdj
      public boolean isRunning() {
          return !isDestroyed();
      }
 +
 +    @Override
 +    public String getUniqueTag() {
 +        return uniqueTag;
 +    }
      
      @Override
-     public Set<Object> getTags() {
-         if (getUniqueTag()==null) return super.getTags();
-         synchronized (tags) {
-             return ImmutableSet.builder().addAll(tags).add(getUniqueTag()).build();
-         }
-     }
-     
-     @Override
      public String toString() {
 -        return Objects.toStringHelper(getClass())
 +        return Objects.toStringHelper(getClass()).omitNullValues()
                  .add("name", name)
 +                .add("uniqueTag", uniqueTag)
                  .add("running", isRunning())
                  .add("id", getId())
                  .toString();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
index b62b9c9,0000000..1252e36
mode 100644,000000..100644
--- a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
+++ b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
@@@ -1,100 -1,0 +1,100 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package brooklyn.enricher.basic;
 +
 +import static org.testng.Assert.assertEquals;
 +
 +import java.util.Map;
 +
 +import org.testng.annotations.Test;
 +
 +import brooklyn.config.ConfigKey;
 +import brooklyn.entity.BrooklynAppUnitTestSupport;
 +import brooklyn.event.basic.BasicConfigKey;
 +import brooklyn.policy.EnricherSpec;
 +import brooklyn.util.collections.MutableSet;
 +import brooklyn.util.flags.SetFromFlag;
 +
 +/**
 + * Test that enricher can be created and accessed, by construction and by spec
 + */
 +public class BasicEnricherTest extends BrooklynAppUnitTestSupport {
 +    
 +    // TODO These tests are a copy of BasicPolicyTest, which is a code smell.
 +    // However, the src/main/java code does not contain as much duplication.
 +    
 +    public static class MyEnricher extends AbstractEnricher {
 +        @SetFromFlag("intKey")
 +        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
 +        
 +        @SetFromFlag("strKey")
 +        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
 +        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
 +        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
 +        
 +        MyEnricher(Map<?,?> flags) {
 +            super(flags);
 +        }
 +        
 +        public MyEnricher() {
 +            super();
 +        }
 +    }
 +    
 +    @Test
 +    public void testAddInstance() throws Exception {
 +        MyEnricher enricher = new MyEnricher();
 +        enricher.setDisplayName("Bob");
 +        enricher.setConfig(MyEnricher.STR_KEY, "aval");
 +        enricher.setConfig(MyEnricher.INT_KEY, 2);
 +        app.addEnricher(enricher);
 +        
 +        assertEquals(enricher.getDisplayName(), "Bob");
 +        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
 +        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
 +    }
 +    
 +    @Test
 +    public void testAddSpec() throws Exception {
 +        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class)
 +            .displayName("Bob")
 +            .configure(MyEnricher.STR_KEY, "aval").configure(MyEnricher.INT_KEY, 2));
 +        
 +        assertEquals(enricher.getDisplayName(), "Bob");
 +        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
 +        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
 +    }
 +        
 +    @Test
 +    public void testTagsFromSpec() throws Exception {
 +        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
 +
-         assertEquals(enricher.getTags(), MutableSet.of("x", 99));
++        assertEquals(enricher.getTagSupport().getTags(), MutableSet.of("x", 99));
 +        assertEquals(enricher.getUniqueTag(), "x");
 +    }
 +
 +    @Test
 +    public void testSameUniqueTagEnricherNotAddedTwice() throws Exception {
 +        MyEnricher enricher1 = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
 +        MyEnricher enricher2 = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(94).uniqueTag("x"));
 +        assertEquals(enricher2, enricher1);
 +        assertEquals(app.getEnrichers().size(), 1);
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
index e9b3399,999c168..415efa5
--- a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
@@@ -107,26 -107,22 +107,26 @@@ public class EntitiesTest extends Brook
      @Test
      public void testCreateGetContainsAndRemoveTags() throws Exception {
          entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
 +            .tag(2)
              .addInitializer(EntityInitializers.addingTags("foo")));
          
-         entity.addTag(app);
+         entity.getTagSupport().addTag(app);
          
-         Assert.assertTrue(entity.containsTag(app));
-         Assert.assertTrue(entity.containsTag("foo"));
-         Assert.assertTrue(entity.containsTag(2));
-         Assert.assertFalse(entity.containsTag("bar"));
++        Assert.assertTrue(entity.getTagSupport().containsTag(app));
+         Assert.assertTrue(entity.getTagSupport().containsTag("foo"));
++        Assert.assertTrue(entity.getTagSupport().containsTag(2));
+         Assert.assertFalse(entity.getTagSupport().containsTag("bar"));
          
-         Assert.assertEquals(entity.getTags(), MutableSet.of(app, "foo", 2));
 -        Assert.assertEquals(entity.getTagSupport().getTags(), MutableSet.of(app, "foo"));
++        Assert.assertEquals(entity.getTagSupport().getTags(), MutableSet.of(app, "foo", 2));
          
-         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));
          
 +        entity.removeTag(2);
-         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/d4a6328e/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
index d23e2d2,d8273ca..27e5edc
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@@ -177,11 -174,7 +179,11 @@@ public class RebindEnricherTest extend
          newApp = (TestApplication) rebind();
          MyEnricher newEnricher = (MyEnricher) Iterables.getOnlyElement(newApp.getEnrichers());
          
 -        assertEquals(newEnricher.getName(), "My Enricher");
 +        assertEquals(newEnricher.getDisplayName(), "My Enricher");
 +        
 +        assertEquals(newEnricher.getUniqueTag(), "tagU");
-         assertEquals(newEnricher.getTags(), MutableSet.of("tagU", "tag1", "tag2"));
++        assertEquals(newEnricher.getTagSupport().getTags(), MutableSet.of("tagU", "tag1", "tag2"));
 +        
          assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
          assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
          assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index bc4e845,90d700b..e0314c3
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@@ -111,14 -110,9 +114,14 @@@ public class RebindPolicyTest extends R
                  .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.getDisplayName(), "My Policy");
 +        
 +        assertEquals(newPolicy.getUniqueTag(), "tagU");
-         assertEquals(newPolicy.getTags(), MutableSet.of("tagU", "tag1", "tag2"));
++        assertEquals(newPolicy.getTagSupport().getTags(), MutableSet.of("tagU", "tag1", "tag2"));
 +        
          assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
          assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
          assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
index 97fb633,4993486..d005098
--- a/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
+++ b/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
@@@ -76,6 -75,6 +76,7 @@@ public class AbstractLocationTest 
      private ConcreteLocation createConcrete(Map<String,?> flags) {
          return createConcrete(null, flags);
      }
++    @SuppressWarnings("deprecation")
      private ConcreteLocation createConcrete(String id, Map<String,?> flags) {
          return mgmt.getLocationManager().createLocation( LocationSpec.create(ConcreteLocation.class).id(id).configure(flags) );
      }
@@@ -173,11 -172,5 +174,11 @@@
          ConcreteLocation loc = createConcrete();
          assertEquals(loc.myfield, "mydefault");
      }
 -    
 +
 +    @Test
 +    public void testLocationTags() throws Exception {
 +        LocationInternal loc = mgmt.getLocationManager().createLocation(LocationSpec.create(ConcreteLocation.class).tag("x"));
-         assertEquals(loc.getTags(), MutableSet.of("x"));
++        assertEquals(loc.getTagSupport().getTags(), MutableSet.of("x"));
 +    }
 +
  }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4a6328e/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
index 1072bc8,0000000..2488aee
mode 100644,000000..100644
--- a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
+++ b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
@@@ -1,89 -1,0 +1,89 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package brooklyn.policy.basic;
 +
 +import static org.testng.Assert.assertEquals;
 +
 +import java.util.Map;
 +
 +import org.testng.annotations.Test;
 +
 +import brooklyn.config.ConfigKey;
 +import brooklyn.entity.BrooklynAppUnitTestSupport;
 +import brooklyn.event.basic.BasicConfigKey;
 +import brooklyn.policy.PolicySpec;
 +import brooklyn.util.collections.MutableSet;
 +import brooklyn.util.flags.SetFromFlag;
 +
 +/**
 + * Test that policy can be created and accessed, by construction and by spec
 + */
 +public class BasicPolicyTest extends BrooklynAppUnitTestSupport {
 +    
 +    public static class MyPolicy extends AbstractPolicy {
 +        @SetFromFlag("intKey")
 +        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
 +        
 +        @SetFromFlag("strKey")
 +        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
 +        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
 +        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
 +        
 +        MyPolicy(Map<?,?> flags) {
 +            super(flags);
 +        }
 +        
 +        public MyPolicy() {
 +            super();
 +        }
 +    }
 +    
 +    @Test
 +    public void testAddInstance() throws Exception {
 +        MyPolicy policy = new MyPolicy();
 +        policy.setDisplayName("Bob");
 +        policy.setConfig(MyPolicy.STR_KEY, "aval");
 +        policy.setConfig(MyPolicy.INT_KEY, 2);
 +        app.addPolicy(policy);
 +        
 +        assertEquals(policy.getDisplayName(), "Bob");
 +        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
 +        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
 +    }
 +    
 +    @Test
 +    public void testAddSpec() throws Exception {
 +        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class)
 +            .displayName("Bob")
 +            .configure(MyPolicy.STR_KEY, "aval").configure(MyPolicy.INT_KEY, 2));
 +        
 +        assertEquals(policy.getDisplayName(), "Bob");
 +        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
 +        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
 +    }
 +        
 +    @Test
 +    public void testTagsFromSpec() throws Exception {
 +        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class).tag(99).uniqueTag("x"));
 +
-         assertEquals(policy.getTags(), MutableSet.of("x", 99));
++        assertEquals(policy.getTagSupport().getTags(), MutableSet.of("x", 99));
 +        assertEquals(policy.getUniqueTag(), "x");
 +    }
 +
 +}


[4/9] git commit: Tidy Internal*Factory

Posted by he...@apache.org.
Tidy Internal*Factory

- deprecates isNewStyleEnricher etc, in preference for general
  InternalFactory.isNewStyle


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

Branch: refs/heads/master
Commit: 2a0d03a9fe05fdaf384f67b4323916a31b30408a
Parents: bf0b3e7
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 22:39:42 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 6 23:17:46 2014 +0100

----------------------------------------------------------------------
 .../entity/proxying/BasicEntityTypeRegistry.java     |  2 --
 .../entity/proxying/InternalLocationFactory.java     |  9 ++++++++-
 .../entity/proxying/InternalPolicyFactory.java       | 15 +++++++++++++--
 .../brooklyn/entity/rebind/RebindManagerImpl.java    |  4 ++--
 4 files changed, 23 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a0d03a9/core/src/main/java/brooklyn/entity/proxying/BasicEntityTypeRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/BasicEntityTypeRegistry.java b/core/src/main/java/brooklyn/entity/proxying/BasicEntityTypeRegistry.java
index aeb4365..09f0cfb 100644
--- a/core/src/main/java/brooklyn/entity/proxying/BasicEntityTypeRegistry.java
+++ b/core/src/main/java/brooklyn/entity/proxying/BasicEntityTypeRegistry.java
@@ -30,9 +30,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.Entity;
-import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.javalang.Reflections;
 
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a0d03a9/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
index 804b5d5..b989392 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
@@ -51,7 +51,10 @@ public class InternalLocationFactory extends InternalFactory {
      * 
      * @param managementContext
      * @param clazz
+     * 
+     * @deprecated since 0.7.0; use {@link InternalFactory#isNewStyle(Class)}
      */
+    @Deprecated
     public static boolean isNewStyleLocation(ManagementContext managementContext, Class<?> clazz) {
         try {
             return isNewStyleLocation(clazz);
@@ -60,6 +63,10 @@ public class InternalLocationFactory extends InternalFactory {
         }
     }
     
+    /**
+     * @deprecated since 0.7.0; use {@link InternalFactory#isNewStyle(Class)}
+     */
+    @Deprecated
     public static boolean isNewStyleLocation(Class<?> clazz) {
         if (!Location.class.isAssignableFrom(clazz)) {
             throw new IllegalArgumentException("Class "+clazz+" is not an location");
@@ -97,7 +104,7 @@ public class InternalLocationFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractLocation)loc).setName(spec.getDisplayName());
             
-            if (isNewStyleLocation(clazz)) {
+            if (isNewStyle(clazz)) {
                 ((AbstractLocation)loc).setManagementContext(managementContext);
                 ((AbstractLocation)loc).configure(ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig());
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a0d03a9/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
index ebf13dd..d52d368 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@ -51,7 +51,10 @@ public class InternalPolicyFactory extends InternalFactory {
      * 
      * @param managementContext
      * @param clazz
+     * 
+     * @deprecated since 0.7.0; use {@link InternalFactory#isNewStyle(Class)}
      */
+    @Deprecated
     public static boolean isNewStylePolicy(ManagementContext managementContext, Class<?> clazz) {
         try {
             return isNewStylePolicy(clazz);
@@ -60,6 +63,10 @@ public class InternalPolicyFactory extends InternalFactory {
         }
     }
     
+    /**
+     * @deprecated since 0.7.0; use {@link InternalFactory#isNewStyle(Class)}
+     */
+    @Deprecated
     public static boolean isNewStylePolicy(Class<?> clazz) {
         if (!Policy.class.isAssignableFrom(clazz)) {
             throw new IllegalArgumentException("Class "+clazz+" is not a policy");
@@ -68,6 +75,10 @@ public class InternalPolicyFactory extends InternalFactory {
         return InternalFactory.isNewStyle(clazz);
     }
     
+    /**
+     * @deprecated since 0.7.0; use {@link InternalFactory#isNewStyle(Class)}
+     */
+    @Deprecated
     public static boolean isNewStyleEnricher(Class<?> clazz) {
         if (!Enricher.class.isAssignableFrom(clazz)) {
             throw new IllegalArgumentException("Class "+clazz+" is not an enricher");
@@ -94,7 +105,7 @@ public class InternalPolicyFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName());
             
-            if (isNewStylePolicy(clazz)) {
+            if (isNewStyle(clazz)) {
                 ((AbstractPolicy)pol).setManagementContext(managementContext);
                 Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
                 ((AbstractPolicy)pol).configure(MutableMap.copyOf(config)); // TODO AbstractPolicy.configure modifies the map
@@ -129,7 +140,7 @@ public class InternalPolicyFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName());
             
-            if (isNewStyleEnricher(clazz)) {
+            if (isNewStyle(clazz)) {
                 ((AbstractEnricher)enricher).setManagementContext(managementContext);
                 Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
                 ((AbstractEnricher)enricher).configure(MutableMap.copyOf(config)); // TODO AbstractEnricher.configure modifies the map

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a0d03a9/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 4e8ffc8..5094e78 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -645,7 +645,7 @@ public class RebindManagerImpl implements RebindManager {
         String policyType = checkNotNull(memento.getType(), "policy type of %s must not be null in memento", id);
         Class<? extends Policy> policyClazz = (Class<? extends Policy>) reflections.loadClass(policyType);
 
-        if (InternalPolicyFactory.isNewStylePolicy(policyClazz)) {
+        if (InternalFactory.isNewStyle(policyClazz)) {
             InternalPolicyFactory policyFactory = managementContext.getPolicyFactory();
             Policy policy = policyFactory.constructPolicy(policyClazz);
             FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", id), policy);
@@ -677,7 +677,7 @@ public class RebindManagerImpl implements RebindManager {
         String enricherType = checkNotNull(memento.getType(), "enricher type of %s must not be null in memento", id);
         Class<? extends Enricher> enricherClazz = (Class<? extends Enricher>) reflections.loadClass(enricherType);
 
-        if (InternalPolicyFactory.isNewStyleEnricher(enricherClazz)) {
+        if (InternalFactory.isNewStyle(enricherClazz)) {
             InternalPolicyFactory policyFactory = managementContext.getPolicyFactory();
             Enricher enricher = policyFactory.constructEnricher(enricherClazz);
             FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", id), enricher);