brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [1/9] git commit: Adds BrooklynType super-class
Date Thu, 07 Aug 2014 21:55:35 GMT
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 <aled.sage@gmail.com>
Authored: Wed Aug 6 16:21:17 2014 +0100
Committer: Aled Sage <aled.sage@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});


Mime
View raw message