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 2015/11/17 23:51:22 UTC

[07/14] incubator-brooklyn git commit: Working CampTypePlanTransformer

Working CampTypePlanTransformer


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

Branch: refs/heads/master
Commit: 904c45e961f5e6b596e6c7238ebf86ee7a6ce7bc
Parents: 817e9bd
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Nov 4 10:47:22 2015 -0500
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Nov 10 17:13:02 2015 +0000

----------------------------------------------------------------------
 .../apache/brooklyn/api/entity/EntitySpec.java  |   2 -
 .../internal/AbstractBrooklynObjectSpec.java    |  16 ++
 .../brooklyn/api/typereg/RegisteredType.java    |  20 +-
 .../api/typereg/RegisteredTypeConstraint.java   |   5 +
 .../core/catalog/internal/CatalogUtils.java     |  17 +-
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   2 +-
 .../entity/DelegatingEntitySpecResolver.java    |   2 +-
 .../core/typereg/BasicBrooklynTypeRegistry.java |   8 +-
 .../core/typereg/BasicRegisteredType.java       |  27 +-
 .../JavaClassNameTypePlanTransformer.java       |  90 +++++++
 .../core/typereg/JavaTypePlanTransformer.java   | 112 --------
 .../core/typereg/RegisteredTypeConstraints.java |  59 +++-
 .../core/typereg/RegisteredTypePredicates.java  |  32 ++-
 .../brooklyn/core/typereg/RegisteredTypes.java  | 143 +++++++++-
 ...lyn.core.typereg.BrooklynTypePlanTransformer |  19 ++
 .../brooklyn/core/sensor/StaticSensorTest.java  |   8 +-
 .../core/test/entity/TestEntityImpl.java        |   1 -
 .../typereg/JavaTypePlanTransformerTest.java    |   6 +-
 .../api/AssemblyTemplateSpecInstantiator.java   |   6 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |  17 +-
 .../brooklyn/spi/creation/CampCatalogUtils.java |  54 +---
 .../spi/creation/CampInternalUtils.java         | 247 +++++++++++++++++
 .../brooklyn/spi/creation/CampResolver.java     | 142 ++++++++++
 .../spi/creation/CampToSpecTransformer.java     |  15 +-
 .../spi/creation/CampTypePlanTransformer.java   |  90 +++++++
 .../camp/brooklyn/spi/creation/CampUtils.java   | 267 -------------------
 .../service/UrlServiceSpecResolver.java         |  19 +-
 ...lyn.core.typereg.BrooklynTypePlanTransformer |  19 ++
 .../camp/brooklyn/AbstractYamlTest.java         |  42 ++-
 .../camp/brooklyn/EntitiesYamlTest.java         |   2 +
 .../camp/brooklyn/ReferencedYamlTest.java       |   1 +
 .../CatalogOsgiVersionMoreEntityTest.java       |  18 +-
 .../catalog/CatalogYamlLocationTest.java        |   3 +-
 .../test/lite/TestAppAssemblyInstantiator.java  |  10 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   2 +-
 .../exceptions/PropagatedRuntimeException.java  |   6 +
 36 files changed, 995 insertions(+), 534 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
index a38e52e..500952d 100644
--- a/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
@@ -337,8 +337,6 @@ public class EntitySpec<T extends Entity> extends AbstractBrooklynObjectSpec<T,E
         return this;
     }
     
-    /** strings inserted as flags, config keys inserted as config keys; 
-     * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */
     public EntitySpec<T> configure(Map<?,?> val) {
         checkMutable();
         for (Map.Entry<?, ?> entry: val.entrySet()) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
index 6ba5a3c..de2954d 100644
--- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
+++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
@@ -23,8 +23,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.api.mgmt.EntityManager;
+import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.exceptions.Exceptions;
@@ -34,6 +37,15 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
+/** Defines a spec for creating a {@link BrooklynObject}.
+ * <p>
+ * In addition to the contract defined by the code,
+ * subclasses should provide a public static <code>create(Class)</code>
+ * method to create an instance of the spec for the target type indicated by the argument. 
+ * <p>
+ * The spec is then passed to type-specific methods,
+ * e.g. {@link EntityManager#createEntity(org.apache.brooklyn.api.entity.EntitySpec)}
+ * to create a managed instance of the target type. */
 public abstract class AbstractBrooklynObjectSpec<T,SpecT extends AbstractBrooklynObjectSpec<T,SpecT>> implements Serializable {
 
     private static final long serialVersionUID = 3010955277740333030L;
@@ -160,5 +172,9 @@ public abstract class AbstractBrooklynObjectSpec<T,SpecT extends AbstractBrookly
     public int hashCode() {
         return Objects.hashCode(getCatalogItemId(), getDisplayName(), getType(), getTags());
     }
+
+    /** strings inserted as flags, config keys inserted as config keys; 
+     * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */
+    public abstract SpecT configure(Map<?,?> val);
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java
index a1fc5cf..ed84179 100644
--- a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java
@@ -19,11 +19,13 @@
 package org.apache.brooklyn.api.typereg;
 
 import java.util.Collection;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 
@@ -44,22 +46,24 @@ public interface RegisteredType extends Identifiable {
     String getDescription();
     String getIconUrl();
 
-    /** @return the java type or a supertype thereof that this registered type represents.
+    /** @return all declared supertypes or super-interfaces of this registered type,
+     * consisting of a collection of {@link Class} or {@link RegisteredType}
      * <p>
-     * For beans, this is the type that the {@link BrooklynTypeRegistry} will create. 
-     * For specs, this is what the spec that will be created points at 
-     * (e.g. the concrete {@link Entity}, not the {@link EntitySpec});
+     * This should normally include at least one {@link Class} object:
+     * For beans, this should include the java type that the {@link BrooklynTypeRegistry} will create. 
+     * For specs, this should refer to the {@link BrooklynObject} type that the created spec will point at 
+     * (e.g. the concrete {@link Entity}, not the {@link EntitySpec}).
      * <p>
-     * In some cases this may return an interface or a super-type of what will actually be created, 
+     * This may not necessarily return the most specific java class or classes;
      * such as if the concrete type is private and callers should know only about a particular public interface,
      * or if precise type details are unavailable and all that is known at creation is some higher level interface/supertype
      * (e.g. this may return {@link Entity} even though the spec points at a specific subclass,
      * for instance because the YAML has not yet been parsed or OSGi bundles downloaded).
      * <p>
-     * If nothing is known, this will return null, and the item will not participate in type filtering.
+     * This may include other registered types such as marker interfaces.
      */
     @Beta
-    @Nullable Class<?> getJavaType();
+    @Nullable Set<Object> getSuperTypes();
 
     /**
      * @return True if the item has been deprecated (i.e. its use is discouraged)
@@ -84,5 +88,5 @@ public interface RegisteredType extends Identifiable {
         /** data for the implementation; may be more specific */
         Object getPlanData();
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java
index 851d88a..8bcff38 100644
--- a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java
@@ -42,4 +42,9 @@ public interface RegisteredTypeConstraint {
      * if we have already attempted to resolve a given type,
      * the instantiator can avoid recursive cycles */
     @Nonnull public Set<String> getEncounteredTypes();
+    
+    /** A special loader to use, if available.
+     * For internal use only; implementations should be a BrooklynClassLoadingContext */
+    @Nullable public Object getLoader();
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
index db4b72a..2955895 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
@@ -69,7 +69,11 @@ public class CatalogUtils {
     }
     
     public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item) {
-        return newClassLoadingContext(mgmt, item.getId(), item.getLibraries());
+        return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), null);
+    }
+    
+    public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item, BrooklynClassLoadingContext loader) {
+        return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), loader);
     }
     
     public static BrooklynClassLoadingContext getClassLoadingContext(Entity entity) {
@@ -85,16 +89,23 @@ public class CatalogUtils {
     }
 
     public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries) {
+        return newClassLoadingContext(mgmt, catalogItemId, libraries, null);
+    }
+    
+    public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries, BrooklynClassLoadingContext loader) {
         BrooklynClassLoadingContextSequential result = new BrooklynClassLoadingContextSequential(mgmt);
 
         if (libraries!=null && !libraries.isEmpty()) {
             result.add(new OsgiBrooklynClassLoadingContext(mgmt, catalogItemId, libraries));
         }
 
-        BrooklynClassLoadingContext loader = BrooklynLoaderTracker.getLoader();
-        if (loader != null) {
+        if (loader !=null) {
             result.add(loader);
         }
+        BrooklynClassLoadingContext threadLocalLoader = BrooklynLoaderTracker.getLoader();
+        if (threadLocalLoader != null) {
+            result.add(threadLocalLoader);
+        }
 
         result.addSecondary(JavaBrooklynClassLoadingContext.create(mgmt));
         return result;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
index 5614b97..7aef313 100644
--- a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
+++ b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
@@ -111,7 +111,7 @@ public class PlanToSpecFactory {
                     (Strings.isNonBlank(e.getMessage()) ? " ("+e.getMessage()+")" : ""));
             } catch (Throwable e) {
                 Exceptions.propagateIfFatal(e);
-                otherProblemsFromTransformers.add(new PropagatedRuntimeException("Transformer for "+t.getShortDescription()+" gave an error creating this plan: "+
+                otherProblemsFromTransformers.add(new PropagatedRuntimeException("Transformer for "+t.getShortDescription()+" gave an error creating this plan: ",
                     Exceptions.collapseText(e), e));
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java
index 2ccc468..415f209 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java
@@ -105,7 +105,7 @@ public class DelegatingEntitySpecResolver extends AbstractEntitySpecResolver {
                         resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
                     }
                 } catch (Exception e) {
-                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
+                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: ",
                             Exceptions.collapseText(e), e));
                 }
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
index 08b6103..0ca8bc7 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
@@ -112,7 +112,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
                 // TODO implement using java if permitted
             }
         }
-        constraint = RegisteredTypeConstraints.extendedWithSpecSuperType(constraint, specSuperType);
+        constraint = RegisteredTypeConstraints.withSpecSuperType(constraint, specSuperType);
 
         Maybe<Object> result = TypePlanTransformers.transform(mgmt, type, constraint);
         if (result.isPresent()) return (SpecT) result.get();
@@ -120,6 +120,10 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
         // fallback: look up in (legacy) catalog
         // TODO remove once all transformers are available in the new style
         CatalogItem item = (CatalogItem) mgmt.getCatalog().getCatalogItem(type.getSymbolicName(), type.getVersion());
+        if (item==null) {
+            // if not in catalog (because loading new one?) then throw original
+            result.get();
+        }
         try {
             return (SpecT) BasicBrooklynCatalog.internalCreateSpecWithTransformers(mgmt, item, constraint.getEncounteredTypes());
         } catch (Exception e) {
@@ -127,7 +131,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
             // for now, combine this failure with the original
             try {
                 result.get();
-                // won't come here
+                // above will throw -- so won't come here
                 throw new IllegalStateException("should have failed getting type resolution for "+type);
             } catch (Exception e0) {
                 // prefer older exception, until the new transformer is the primary pathway

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
index ac0b266..54b04a3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
@@ -20,19 +20,27 @@ package org.apache.brooklyn.core.typereg;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 
+import com.google.common.collect.ImmutableSet;
+
+/** Instances are usually created by methods in {@link RegisteredTypes}. */
 public class BasicRegisteredType implements RegisteredType {
 
     final String symbolicName;
     final String version;
     final RegisteredTypeKind kind;
     
-    List<OsgiBundleWithUrl> bundles;
+    Set<Object> superTypes = MutableSet.of();
+    List<OsgiBundleWithUrl> bundles = MutableList.of();
     String displayName;
     String description;
     String iconUrl;
@@ -41,14 +49,12 @@ public class BasicRegisteredType implements RegisteredType {
     
     TypeImplementationPlan implementationPlan;
 
-    // TODO ensure this is re-populated on rebind?  or remove?
-    transient Class<?> javaType;
+    private transient ConfigBag cache = new ConfigBag();
     
-    public BasicRegisteredType(RegisteredTypeKind kind, String symbolicName, String version, Class<?> javaType, TypeImplementationPlan implementationPlan) {
+    BasicRegisteredType(RegisteredTypeKind kind, String symbolicName, String version, TypeImplementationPlan implementationPlan) {
         this.kind = kind;
         this.symbolicName = symbolicName;
         this.version = version;
-        this.javaType = javaType;
         this.implementationPlan = implementationPlan;
     }
 
@@ -74,7 +80,7 @@ public class BasicRegisteredType implements RegisteredType {
     
     @Override
     public Collection<OsgiBundleWithUrl> getLibraries() {
-        return bundles;
+        return ImmutableSet.copyOf(bundles);
     }
 
     @Override
@@ -103,8 +109,12 @@ public class BasicRegisteredType implements RegisteredType {
     }
     
     @Override
-    public Class<?> getJavaType() {
-        return javaType;
+    public Set<Object> getSuperTypes() {
+        return ImmutableSet.copyOf(superTypes);
+    }
+
+    public ConfigBag getCache() {
+        return cache;
     }
     
     @Override
@@ -117,6 +127,7 @@ public class BasicRegisteredType implements RegisteredType {
         return JavaClassNames.simpleClassName(this)+"["+getId()+
             (isDisabled() ? ";DISABLED" : "")+
             (isDeprecated() ? ";deprecated" : "")+
+            (getPlan()!=null ? ";"+getPlan().getPlanFormat() : "")+
             "]";
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java
new file mode 100644
index 0000000..a84c9f5
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java
@@ -0,0 +1,90 @@
+/*
+ * 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 org.apache.brooklyn.core.typereg;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.util.text.Identifiers;
+
+/**
+ * Instantiates classes from a registered type which simply
+ * defines the java class name and OSGi bundles to use.
+ * <p>
+ * This is used where a {@link RegisteredType} is defined simply with the name of a java class
+ * e.g. with a no-arg constructor -- no YAML etc just the name of the class.
+ */
+public class JavaClassNameTypePlanTransformer extends AbstractTypePlanTransformer {
+    
+    public static final String FORMAT = "java-type-name";
+
+    public static class JavaTypeNameImplementation extends AbstractCustomImplementationPlan<String> {
+        public JavaTypeNameImplementation(String javaType) { super(FORMAT, javaType); }
+    }
+
+    public JavaClassNameTypePlanTransformer() {
+        super(FORMAT, "Java type name", "Expects a java type name in a format suitable for use with ClassLoader.loadClass");
+    }
+
+    @Override
+    protected double scoreForNullFormat(Object planData, RegisteredType type, RegisteredTypeConstraint context) {
+        if (type.getPlan().getPlanData() instanceof String && 
+                ((String)type.getPlan().getPlanData()).matches(Identifiers.JAVA_BINARY_REGEX)) {
+            return 0.1;
+        }
+        return 0;
+    }
+    
+    @Override
+    protected double scoreForNonmatchingNonnullFormat(String planFormat, Object planData, RegisteredType type, RegisteredTypeConstraint context) {
+        return 0;
+    }
+
+    @SuppressWarnings({ "unchecked" })
+    @Override
+    protected AbstractBrooklynObjectSpec<?,?> createSpec(RegisteredType type, RegisteredTypeConstraint context) throws Exception {
+        return RegisteredTypes.newSpecInstance(mgmt, (Class<? extends BrooklynObject>) getType(type, context));
+    }
+
+    @Override
+    protected Object createBean(RegisteredType type, RegisteredTypeConstraint context) throws Exception {
+        return getType(type, context).newInstance();
+    }
+
+    private Class<?> getType(RegisteredType type, RegisteredTypeConstraint context) throws Exception {
+        return RegisteredTypes.loadActualJavaType((String)type.getPlan().getPlanData(), mgmt, type, context);
+    }
+    
+    
+    // not supported as a catalog format (yet? should we?)
+    
+    @Override
+    public double scoreForTypeDefinition(String formatCode, Object catalogData) {
+        return 0;
+    }
+
+    @Override
+    public List<RegisteredType> createFromTypeDefinition(String formatCode, Object catalogData) {
+        throw new UnsupportedTypePlanException("this transformer does not support YAML catalog additions");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java
deleted file mode 100644
index febf52a..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java
+++ /dev/null
@@ -1,112 +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 org.apache.brooklyn.core.typereg;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
-import org.apache.brooklyn.api.typereg.RegisteredType;
-import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.util.text.Identifiers;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Instantiates classes from a registered type which simply
- * defines the java class name and OSGi bundles to use.
- * <p>
- * This is used where a {@link RegisteredType} is defined simply with the name of a java class
- * e.g. with a no-arg constructor -- no YAML etc just the name of the class.
- */
-public class JavaTypePlanTransformer extends AbstractTypePlanTransformer {
-    
-    private static final Logger log = LoggerFactory.getLogger(JavaTypePlanTransformer.class);
-    public static final String FORMAT = "java-type-name";
-
-    public static class JavaTypeNameImplementation extends AbstractCustomImplementationPlan<String> {
-        private transient Class<?> cachedType;
-        public JavaTypeNameImplementation(String javaType) {
-            super(FORMAT, javaType);
-        }
-        public Class<?> getCachedType() {
-            return cachedType;
-        }
-    }
-
-    public JavaTypePlanTransformer() {
-        super(FORMAT, "Java type name", "Expects a java type name in a format suitable for use with ClassLoader.loadClass");
-    }
-
-    @Override
-    protected double scoreForNullFormat(Object planData, RegisteredType type, RegisteredTypeConstraint context) {
-        if (type.getPlan().getPlanData() instanceof String && 
-                ((String)type.getPlan().getPlanData()).matches(Identifiers.JAVA_BINARY_REGEX)) {
-            return 0.1;
-        }
-        return 0;
-    }
-    
-    @Override
-    protected double scoreForNonmatchingNonnullFormat(String planFormat, Object planData, RegisteredType type, RegisteredTypeConstraint context) {
-        return 0;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Override
-    protected AbstractBrooklynObjectSpec<?,?> createSpec(RegisteredType type, RegisteredTypeConstraint context) throws Exception {
-        Class targetType = getType(type, context);
-        Class specType = RegisteredTypeConstraints.spec((Class)targetType).getJavaSuperType();
-        AbstractBrooklynObjectSpec result = (AbstractBrooklynObjectSpec) specType.getConstructor(Class.class).newInstance(targetType);
-        return result;
-    }
-
-    @Override
-    protected Object createBean(RegisteredType type, RegisteredTypeConstraint context) throws Exception {
-        return getType(type, context).newInstance();
-    }
-
-    private Class<?> getType(RegisteredType type, RegisteredTypeConstraint context) {
-        if (type.getPlan() instanceof JavaTypeNameImplementation) {
-            Class<?> cachedType = ((JavaTypeNameImplementation)type.getPlan()).getCachedType();
-            if (cachedType==null) {
-                log.debug("Storing cached type "+cachedType+" for "+type);
-                cachedType = loadType(type, context);
-            }
-            return cachedType;
-        }
-        return loadType(type, context);
-    }
-    private Class<?> loadType(RegisteredType type, RegisteredTypeConstraint context) {
-        return CatalogUtils.newClassLoadingContext(mgmt, type).loadClass( ((String)type.getPlan().getPlanData()) );
-    }
-
-    
-    // TODO not supported as a catalog format (yet)
-    @Override
-    public double scoreForTypeDefinition(String formatCode, Object catalogData) {
-        return 0;
-    }
-
-    @Override
-    public List<RegisteredType> createFromTypeDefinition(String formatCode, Object catalogData) {
-        throw new UnsupportedTypePlanException("this transformer does not support YAML catalog additions");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java
index c880b7e..5b4c0cf 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java
@@ -31,7 +31,9 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,6 +48,7 @@ public class RegisteredTypeConstraints {
         @Nullable private RegisteredTypeKind kind;
         @Nullable private Class<?> javaSuperType;
         @Nonnull private Set<String> encounteredTypes = ImmutableSet.of();
+        @Nullable BrooklynClassLoadingContext loader;
         
         private BasicRegisteredTypeConstraint() {}
         
@@ -55,6 +58,7 @@ public class RegisteredTypeConstraints {
             this.kind = source.getKind();
             this.javaSuperType = source.getJavaSuperType();
             this.encounteredTypes = source.getEncounteredTypes();
+            this.loader = (BrooklynClassLoadingContext) source.getLoader();
         }
 
         @Override
@@ -75,8 +79,13 @@ public class RegisteredTypeConstraints {
         }
         
         @Override
+        public BrooklynClassLoadingContext getLoader() {
+            return loader;
+        }
+        
+        @Override
         public String toString() {
-            return super.toString()+"["+kind+","+javaSuperType+","+encounteredTypes+"]";
+            return JavaClassNames.cleanSimpleClassName(this)+"["+kind+","+javaSuperType+","+encounteredTypes+"]";
         }
     }
 
@@ -97,7 +106,11 @@ public class RegisteredTypeConstraints {
         result.encounteredTypes = encounteredTypes.asUnmodifiable();
         return result;
     }
-    
+
+    public static RegisteredTypeConstraint alreadyVisited(Set<String> encounteredTypeSymbolicNames, BrooklynClassLoadingContext loader) {
+        return withLoader(alreadyVisited(encounteredTypeSymbolicNames), loader);
+    }
+
     private static RegisteredTypeConstraint of(RegisteredTypeKind kind, Class<? extends BrooklynObject> javaSuperType) {
         BasicRegisteredTypeConstraint result = new BasicRegisteredTypeConstraint();
         result.kind = kind;
@@ -109,7 +122,7 @@ public class RegisteredTypeConstraints {
         return of(RegisteredTypeKind.SPEC, javaSuperType);
     }
 
-    public static <T extends AbstractBrooklynObjectSpec<?,?>> RegisteredTypeConstraint extendedWithSpecSuperType(@Nullable RegisteredTypeConstraint source, @Nullable Class<T> specSuperType) {
+    public static <T extends AbstractBrooklynObjectSpec<?,?>> RegisteredTypeConstraint withSpecSuperType(@Nullable RegisteredTypeConstraint source, @Nullable Class<T> specSuperType) {
         Class<?> superType = lookupTargetTypeForSpec(specSuperType);
         BasicRegisteredTypeConstraint constraint = new BasicRegisteredTypeConstraint(source);
         if (source==null) source = constraint;
@@ -131,8 +144,9 @@ public class RegisteredTypeConstraints {
         return source;
     }
     
-    /** given a spec, returns the class of the item it targets, for instance {@link EntitySpec} for {@link Entity} */
-    private static <T extends AbstractBrooklynObjectSpec<?,?>> Class<? extends BrooklynObject> lookupTargetTypeForSpec(Class<T> specSuperType) {
+    /** given a spec, returns the class of the item it targets, for instance returns {@link Entity} given {@link EntitySpec};
+     * see also {@link #lookupSpecTypeForTarget(Class)} */
+    static <T extends AbstractBrooklynObjectSpec<?,?>> Class<? extends BrooklynObject> lookupTargetTypeForSpec(Class<T> specSuperType) {
         if (specSuperType==null) return BrooklynObject.class;
         BrooklynObjectType best = null;
 
@@ -154,4 +168,39 @@ public class RegisteredTypeConstraints {
         return best.getInterfaceType();
     }
 
+    /** given a {@link BrooklynObject}, returns the spec class which would generate it, for instance returns {@link EntitySpec} given {@link Entity},
+     * or null if not known */
+    static <BO extends BrooklynObject> Class<? extends AbstractBrooklynObjectSpec<?,?>> lookupSpecTypeForTarget(Class<BO> targetSuperType) {
+        if (targetSuperType==null) return null;
+        BrooklynObjectType best = null;
+
+        for (BrooklynObjectType t: BrooklynObjectType.values()) {
+            if (t.getSpecType()==null) continue;
+            if (!t.getInterfaceType().isAssignableFrom(targetSuperType)) continue;
+            // on equality, exit immediately
+            if (t.getInterfaceType().equals(targetSuperType)) return t.getSpecType();
+            // else pick which is best
+            if (best==null) { best = t; continue; }
+            // if t is more specific, it is better (handles case when e.g. a Policy is a subclass of Entity)
+            if (best.getSpecType().isAssignableFrom(t.getSpecType())) { best = t; continue; }
+        }
+        if (best==null) {
+            log.warn("Unexpected target supertype ("+targetSuperType+"); unable to infer spec type");
+            return null;
+        }
+        // the spec is more specific, but we're not familiar with it here; return the best
+        return best.getSpecType();
+    }
+
+    public static RegisteredTypeConstraint loader(BrooklynClassLoadingContext loader) {
+        BasicRegisteredTypeConstraint result = new BasicRegisteredTypeConstraint();
+        result.loader = loader;
+        return result;
+    }
+    
+    public static RegisteredTypeConstraint withLoader(RegisteredTypeConstraint constraint, BrooklynClassLoadingContext loader) {
+        ((BasicRegisteredTypeConstraint)constraint).loader = loader;
+        return constraint;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
index 3560e47..2e7c038 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
@@ -109,36 +109,46 @@ public class RegisteredTypePredicates {
         }
     }
 
-    public static <T> Predicate<RegisteredType> javaType(final Predicate<Class<T>> filter) {
-        return new JavaTypeMatches(filter);
+    public static <T> Predicate<RegisteredType> anySuperType(final Predicate<Class<T>> filter) {
+        return new AnySuperTypeMatches(filter);
     }
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static Predicate<RegisteredType> javaTypeAssignableFrom(final Class<?> filter) {
-        return javaType((Predicate)Predicates.assignableFrom(filter));
+    public static Predicate<RegisteredType> assignableFrom(final Class<?> filter) {
+        return anySuperType((Predicate)Predicates.assignableFrom(filter));
     }
     
-    private static class JavaTypeMatches implements Predicate<RegisteredType> {
+    private static class AnySuperTypeMatches implements Predicate<RegisteredType> {
         private final Predicate<Class<?>> filter;
         
         @SuppressWarnings({ "rawtypes", "unchecked" })
-        private <T> JavaTypeMatches(Predicate filter) {
+        private <T> AnySuperTypeMatches(Predicate filter) {
             this.filter = filter;
         }
         @Override
         public boolean apply(@Nullable RegisteredType item) {
             if (item==null) return false;
-            return (item != null) && filter.apply(item.getJavaType());
+            for (Object o: item.getSuperTypes()) {
+                if (o instanceof Class) {
+                    if (filter.apply((Class<?>)o)) return true;
+                }
+            }
+            for (Object o: item.getSuperTypes()) {
+                if (o instanceof RegisteredType) {
+                    if (apply((RegisteredType)o)) return true;
+                }
+            }
+            return false;
         }
     }
 
-    public static final Predicate<RegisteredType> IS_APPLICATION = javaTypeAssignableFrom(Application.class);
+    public static final Predicate<RegisteredType> IS_APPLICATION = assignableFrom(Application.class);
     // TODO do we need this?  introduced already deprecated in 0.9.0 so can be removed, or enabled
     @Deprecated
     public static final Predicate<RegisteredType> IS_TEMPLATE = IS_APPLICATION;
     
-    public static final Predicate<RegisteredType> IS_ENTITY = javaTypeAssignableFrom(Entity.class);
-    public static final Predicate<RegisteredType> IS_LOCATION = javaTypeAssignableFrom(Location.class);
-    public static final Predicate<RegisteredType> IS_POLICY = javaTypeAssignableFrom(Policy.class);
+    public static final Predicate<RegisteredType> IS_ENTITY = assignableFrom(Entity.class);
+    public static final Predicate<RegisteredType> IS_LOCATION = assignableFrom(Location.class);
+    public static final Predicate<RegisteredType> IS_POLICY = assignableFrom(Policy.class);
 
     public static Predicate<RegisteredType> entitledToSee(final ManagementContext mgmt) {
         return new EntitledToSee(mgmt);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
index 7e35084..0ebbdcd 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
@@ -18,19 +18,50 @@
  */
 package org.apache.brooklyn.core.typereg;
 
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
 import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
-import org.apache.brooklyn.core.typereg.JavaTypePlanTransformer.JavaTypeNameImplementation;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer.JavaTypeNameImplementation;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.yaml.Yamls;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
 
+/**
+ * Utility and preferred creation mechanisms for working with {@link RegisteredType} instances.
+ * <p>
+ * Use {@link #bean(String, String, TypeImplementationPlan, Class)} and {@link #spec(String, String, TypeImplementationPlan, Class)}
+ * to create {@link RegisteredType} instances.
+ * <p>
+ * See {@link #isSubTypeOf(RegisteredType, Class)} or {@link #isSubTypeOf(RegisteredType, RegisteredType)} to 
+ * inspect the type hierarchy.
+ */
 public class RegisteredTypes {
 
+    @SuppressWarnings("serial")
+    static ConfigKey<Class<?>> ACTUAL_JAVA_TYPE = ConfigKeys.newConfigKey(new TypeToken<Class<?>>() {}, "java.type.actual",
+        "The actual Java type which will be instantiated (bean) or pointed at (spec)");
+
     /** @deprecated since it was introduced in 0.9.0; for backwards compatibility only, may be removed at any point */
     @Deprecated
     static final Function<CatalogItem<?,?>,RegisteredType> CI_TO_RT = new Function<CatalogItem<?,?>, RegisteredType>() {
@@ -53,7 +84,7 @@ public class RegisteredTypes {
             throw new IllegalStateException("Unsupported catalog item "+item+" when trying to create RegisteredType");
         }
         
-        BasicRegisteredType type = (BasicRegisteredType) spec(item.getSymbolicName(), item.getVersion(), item.getCatalogItemJavaType(), impl);
+        BasicRegisteredType type = (BasicRegisteredType) spec(item.getSymbolicName(), item.getVersion(), impl, item.getCatalogItemJavaType());
         type.bundles = item.getLibraries()==null ? ImmutableList.<OsgiBundleWithUrl>of() : ImmutableList.<OsgiBundleWithUrl>copyOf(item.getLibraries());
         type.displayName = item.getDisplayName();
         type.description = item.getDescription();
@@ -66,13 +97,49 @@ public class RegisteredTypes {
         // maybe: tags ?
         return type;
     }
-    
-    public static RegisteredType bean(String symbolicName, String version, Class<?> javaType, TypeImplementationPlan plan) {
-        return new BasicRegisteredType(RegisteredTypeKind.BEAN, symbolicName, version, javaType, plan);
+
+    /** Preferred mechanism for defining a bean {@link RegisteredType} */
+    public static RegisteredType bean(String symbolicName, String version, TypeImplementationPlan plan, @Nullable Class<?> superType) {
+        return addSuperType(new BasicRegisteredType(RegisteredTypeKind.BEAN, symbolicName, version, plan), superType);
     }
     
-    public static RegisteredType spec(String symbolicName, String version, Class<?> javaType, TypeImplementationPlan plan) {
-        return new BasicRegisteredType(RegisteredTypeKind.SPEC, symbolicName, version, javaType, plan);
+    public static RegisteredType spec(String symbolicName, String version, TypeImplementationPlan plan, @Nullable Class<?> superType) {
+        return addSuperType(new BasicRegisteredType(RegisteredTypeKind.SPEC, symbolicName, version, plan), superType);
+    }
+
+    /** returns the {@link Class} object corresponding to the given java type name,
+     * using the cache on the type and the loader defined on the type
+     * @param mgmt */
+    @Beta
+    // TODO should this be on the AbstractTypePlanTransformer ?
+    public static Class<?> loadActualJavaType(String javaTypeName, ManagementContext mgmt, RegisteredType type, RegisteredTypeConstraint constraint) throws Exception {
+        Class<?> result = ((BasicRegisteredType)type).getCache().get(ACTUAL_JAVA_TYPE);
+        if (result!=null) return result;
+        
+        result = CatalogUtils.newClassLoadingContext(mgmt, type).loadClass( javaTypeName );
+        Preconditions.checkNotNull(result, "Could not load class "+javaTypeName+"; returned null (should have thrown a different exception!)");
+        
+        ((BasicRegisteredType)type).getCache().put(ACTUAL_JAVA_TYPE, result);
+        return result;
+    }
+
+    @Beta
+    public static RegisteredType addSuperType(RegisteredType type, @Nullable Class<?> superType) {
+        if (superType!=null) {
+            ((BasicRegisteredType)type).superTypes.add(superType);
+        }
+        return type;
+    }
+
+    @Beta
+    public static RegisteredType addSuperType(RegisteredType type, @Nullable RegisteredType superType) {
+        if (superType!=null) {
+            if (isSubTypeOf(superType, type)) {
+                throw new IllegalStateException(superType+" declares "+type+" as a supertype; cannot set "+superType+" as a supertype of "+type);
+            }
+            ((BasicRegisteredType)type).superTypes.add(superType);
+        }
+        return type;
     }
 
     /** returns the implementation data for a spec if it is a string (e.g. plan yaml or java class name); else false */
@@ -84,4 +151,66 @@ public class RegisteredTypes {
         return (String)data;
     }
 
+    /** returns an implementation of the spec class corresponding to the given target type;
+     * for use in {@link BrooklynTypePlanTransformer#create(RegisteredType, RegisteredTypeConstraint)} 
+     * implementations when dealing with a spec; returns null if none found
+     * @param mgmt */
+    @Beta
+    public static AbstractBrooklynObjectSpec<?,?> newSpecInstance(ManagementContext mgmt, Class<? extends BrooklynObject> targetType) throws Exception {
+        Class<? extends AbstractBrooklynObjectSpec<?, ?>> specType = RegisteredTypeConstraints.lookupSpecTypeForTarget(targetType);
+        if (specType==null) return null;
+        Method createMethod = specType.getMethod("create", Class.class);
+        return (AbstractBrooklynObjectSpec<?, ?>) createMethod.invoke(null, targetType);
+    }
+
+    /** Returns a wrapped map, if the object is YAML which parses as a map; 
+     * otherwise returns absent capable of throwing an error with more details */
+    @SuppressWarnings("unchecked")
+    public static Maybe<Map<Object,Object>> getAsYamlMap(Object planData) {
+        if (!(planData instanceof String)) return Maybe.absent("not a string");
+        Iterable<Object> result;
+        try {
+            result = Yamls.parseAll((String)planData);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            return Maybe.absent(e);
+        }
+        Iterator<Object> ri = result.iterator();
+        if (!ri.hasNext()) return Maybe.absent("YAML has no elements in it");
+        Object r1 = ri.next();
+        if (!ri.hasNext()) return Maybe.absent("YAML has multiple elements in it");
+        if (r1 instanceof Map) return Maybe.of((Map<Object,Object>)r1);
+        return Maybe.absent("YAML does not contain a map");
+    }
+
+    /** 
+     * Queries recursively the supertypes of {@link RegisteredType} to see whether it 
+     * declares a supertype compatible with the given {@link Class} */
+    public static boolean isSubTypeOf(RegisteredType type, Class<?> superType) {
+        for (Object st: type.getSuperTypes()) {
+            if (st instanceof Class) {
+                if (superType.isAssignableFrom((Class<?>)st)) return true;
+            }
+        }
+        for (Object st: type.getSuperTypes()) {
+            if (st instanceof RegisteredType) {
+                if (isSubTypeOf((RegisteredType)st, superType)) return true;
+            }
+        }
+        return false;
+    }
+
+    /** 
+     * Queries recursively the supertypes of {@link RegisteredType} to see whether it 
+     * declares a supertype compatible with the given {@link Class} */
+    public static boolean isSubTypeOf(RegisteredType type, RegisteredType superType) {
+        if (type.equals(superType)) return true;
+        for (Object st: type.getSuperTypes()) {
+            if (st instanceof RegisteredType) {
+                if (isSubTypeOf((RegisteredType)st, superType)) return true;
+            }
+        }
+        return false;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer
----------------------------------------------------------------------
diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer
new file mode 100644
index 0000000..48c4a9d
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
index 1e6efb1..a574aeb 100644
--- a/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
@@ -19,11 +19,9 @@
 package org.apache.brooklyn.core.sensor;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.sensor.StaticSensor;
+import org.apache.brooklyn.core.entity.EntityAsserts;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.testng.annotations.Test;
 
@@ -39,7 +37,7 @@ public class StaticSensorTest extends BrooklynAppUnitTestSupport {
                         StaticSensor.SENSOR_TYPE, String.class.getName(),
                         StaticSensor.STATIC_VALUE, "myval")))));
         
-        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval");
+        EntityAsserts.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval");
     }
     
     @Test
@@ -50,6 +48,6 @@ public class StaticSensorTest extends BrooklynAppUnitTestSupport {
                         StaticSensor.SENSOR_TYPE, Integer.class.getName(),
                         StaticSensor.STATIC_VALUE, "1")))));
         
-        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1);
+        EntityAsserts.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java
index 6c3b913..77d4672 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java
@@ -157,7 +157,6 @@ public class TestEntityImpl extends AbstractEntity implements TestEntity {
     public <T extends Entity> T createAndManageChild(EntitySpec<T> spec) {
         if (!getManagementSupport().isDeployed()) throw new IllegalStateException("Entity "+this+" not managed");
         T child = createChild(spec);
-        getEntityManager().manage(child);
         return child;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java
index c4d8038..def79d8 100644
--- a/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java
@@ -37,16 +37,16 @@ public class JavaTypePlanTransformerTest extends BrooklynMgmtUnitTestSupport {
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        type = newNoArgRegisteredType(JavaTypePlanTransformer.FORMAT);
+        type = newNoArgRegisteredType(JavaClassNameTypePlanTransformer.FORMAT);
         transformer = newTransformer();
     }
     
     protected RegisteredType newNoArgRegisteredType(String format) {
-        return RegisteredTypes.bean("no-arg", "1.0", null, new BasicTypeImplementationPlan(format, NoArg.class.getName()));
+        return RegisteredTypes.bean("no-arg", "1.0", new BasicTypeImplementationPlan(format, NoArg.class.getName()), null);
     }
     
     protected BrooklynTypePlanTransformer newTransformer() {
-        BrooklynTypePlanTransformer xf = new JavaTypePlanTransformer();
+        BrooklynTypePlanTransformer xf = new JavaClassNameTypePlanTransformer();
         xf.injectManagementContext(mgmt);
         return xf;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java
index 1dfc351..8fb7164 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java
@@ -30,12 +30,16 @@ import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 
 public interface AssemblyTemplateSpecInstantiator extends AssemblyTemplateInstantiator {
 
+    @Deprecated /** @deprecaed since 0.9.0 include encountered types */
+    EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader);
+    
     /**
      * Gets the single item returned by {@link #createServiceSpecs}
      * and wraps it in an Application if needed, applying top-level
      * attributes and locations to the root entity.
      */
-    EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader);
+    EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes);
+    
     /** Returns specs for each item in the services list */
     List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
index a400758..5070777 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
@@ -35,12 +35,12 @@ import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult;
 import org.apache.brooklyn.core.mgmt.HasBrooklynManagementContext;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 
 public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpecInstantiator {
 
@@ -59,7 +59,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
     private Application create(AssemblyTemplate template, CampPlatform platform) {
         ManagementContext mgmt = getManagementContext(platform);
         BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt);
-        EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader);
+        EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader, MutableSet.<String>of());
         Application instance = mgmt.getEntityManager().createEntity(spec);
         log.info("CAMP created '{}'", instance);
         return instance;
@@ -78,15 +78,24 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
             AssemblyTemplate template,
             CampPlatform platform,
             BrooklynClassLoadingContext loader) {
+        return createApplicationSpec(template, platform, loader, MutableSet.<String>of());
+    }
+    
+    @Override
+    public EntitySpec<? extends Application> createApplicationSpec(
+            AssemblyTemplate template,
+            CampPlatform platform,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredTypeSymbolicNames) {
         log.debug("CAMP creating application instance for {} ({})", template.getId(), template);
 
         // AssemblyTemplates created via PDP, _specifying_ then entities to put in
 
-        EntitySpec<? extends Application> app = CampUtils.createWrapperApp(template, loader);
+        EntitySpec<? extends Application> app = CampInternalUtils.createWrapperApp(template, loader);
         app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE);
 
         // first build the children into an empty shell app
-        List<EntitySpec<?>> childSpecs = createServiceSpecs(template, platform, loader, Sets.<String>newLinkedHashSet());
+        List<EntitySpec<?>> childSpecs = createServiceSpecs(template, platform, loader, encounteredTypeSymbolicNames);
         for (EntitySpec<?> childSpec : childSpecs) {
             app.child(childSpec);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java
index d4c5142..32f7c0e 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java
@@ -24,61 +24,17 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.camp.CampPlatform;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
 
+@Deprecated /** @deprecated since 0.9.0 use RegisteredType and CampResolver */
 public class CampCatalogUtils {
 
     public static AbstractBrooklynObjectSpec<?, ?> createSpec(ManagementContext mgmt, CatalogItem<?, ?> item, Set<String> parentEncounteredTypes) {
-        // preferred way is to parse the yaml, to resolve references late;
-        // the parsing on load is to populate some fields, but it is optional.
-        // TODO messy for location and policy that we need brooklyn.{locations,policies} root of the yaml, but it works;
-        // see related comment when the yaml is set, in addAbstractCatalogItems
-        // (not sure if anywhere else relies on that syntax; if not, it should be easy to fix!)
-        BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item);
-        Preconditions.checkNotNull(item.getCatalogItemType(), "catalog item type for "+item.getPlanYaml());
-
-        Set<String> encounteredTypes;
-        // symbolicName could be null if coming from the catalog parser where it tries to load before knowing the id
-        if (item.getSymbolicName() != null) {
-            encounteredTypes = ImmutableSet.<String>builder()
-                    .addAll(parentEncounteredTypes)
-                    .add(item.getSymbolicName())
-                    .build();
-        } else {
-            encounteredTypes = parentEncounteredTypes;
-        }
-
-        AbstractBrooklynObjectSpec<?, ?> spec;
-        switch (item.getCatalogItemType()) {
-            case TEMPLATE:
-            case ENTITY:
-                spec = CampUtils.createRootServiceSpec(item.getPlanYaml(), loader, encounteredTypes);
-                break;
-            case LOCATION: 
-                spec = CampUtils.createLocationSpec(item.getPlanYaml(), loader, encounteredTypes);
-                break;
-            case POLICY: 
-                spec = CampUtils.createPolicySpec(item.getPlanYaml(), loader, encounteredTypes);
-                break;
-            default:
-                throw new IllegalStateException("Unknown CI Type "+item.getCatalogItemType()+" for "+item.getPlanYaml());
-        }
-
-        ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId());
-
-        if (Strings.isBlank( ((AbstractBrooklynObjectSpec<?, ?>)spec).getDisplayName() ))
-            ((AbstractBrooklynObjectSpec<?, ?>)spec).displayName(item.getDisplayName());
-
-        return spec;
+        return CampResolver.createSpecFromFull(mgmt, RegisteredTypes.of(item), parentEncounteredTypes, null);
     }
-
+    
     public static CampPlatform getCampPlatform(ManagementContext mgmt) {
-        return CampUtils.getCampPlatform(mgmt);
+        return CampInternalUtils.getCampPlatform(mgmt);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
new file mode 100644
index 0000000..abd32c6
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
@@ -0,0 +1,247 @@
+/*
+ * 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 org.apache.brooklyn.camp.brooklyn.spi.creation;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.objs.SpecParameter;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.camp.CampPlatform;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
+import org.apache.brooklyn.camp.spi.AssemblyTemplate;
+import org.apache.brooklyn.camp.spi.AssemblyTemplate.Builder;
+import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
+import org.apache.brooklyn.camp.spi.pdp.DeploymentPlan;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.objs.BasicSpecParameter;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
+import org.apache.brooklyn.entity.stock.BasicApplicationImpl;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.brooklyn.util.yaml.Yamls;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/** package-private; as {@link RegisteredType} becomes standard hopefully we can remove this */
+class CampInternalUtils {
+
+    static EntitySpec<? extends Application> createWrapperApp(AssemblyTemplate template, BrooklynClassLoadingContext loader) {
+        BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance(
+            loader, buildWrapperAppTemplate(template));
+        EntitySpec<Application> wrapperSpec = resolver.resolveSpec(ImmutableSet.<String>of());
+        resetSpecIfTemplateHasNoExplicitParameters(template, wrapperSpec);
+        // caller always sets WRAPPER_APP config; should we do it here?
+        return wrapperSpec;
+    }
+
+    static void resetSpecIfTemplateHasNoExplicitParameters(AssemblyTemplate template, EntitySpec<? extends Application> wrapperSpec) {
+        if (!template.getCustomAttributes().containsKey(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS)) {
+            // Clear out default parameters (coming from the wrapper app's class) so they don't overwrite the entity's params on unwrap.
+            wrapperSpec.parameters(ImmutableList.<SpecParameter<?>>of());
+        }
+    }
+
+    private static AssemblyTemplate buildWrapperAppTemplate(AssemblyTemplate template) {
+        Builder<? extends AssemblyTemplate> builder = AssemblyTemplate.builder();
+        builder.type("brooklyn:" + BasicApplicationImpl.class.getName());
+        builder.id(template.getId());
+        builder.name(template.getName());
+        builder.sourceCode(template.getSourceCode());
+        for (Entry<String, Object> entry : template.getCustomAttributes().entrySet()) {
+            builder.customAttribute(entry.getKey(), entry.getValue());
+        }
+        builder.instantiator(template.getInstantiator());
+        AssemblyTemplate wrapTemplate = builder.build();
+        return wrapTemplate;
+    }
+
+    static AssemblyTemplateInstantiator getInstantiator(AssemblyTemplate at) {
+        try {
+            return at.getInstantiator().newInstance();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    static AssemblyTemplate registerDeploymentPlan(String plan, BrooklynClassLoadingContext loader, CampPlatform camp) {
+        BrooklynLoaderTracker.setLoader(loader);
+        try {
+            return camp.pdp().registerDeploymentPlan(new StringReader(plan));
+        } finally {
+            BrooklynLoaderTracker.unsetLoader(loader);
+        }
+    }
+
+    static PolicySpec<?> createPolicySpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes) {
+        DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan);
+
+        //Would ideally re-use the PolicySpecResolver
+        //but it is CAMP specific and there is no easy way to get hold of it.
+        Object policies = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.POLICIES_KEY), "policy config");
+        if (!(policies instanceof Iterable<?>)) {
+            throw new IllegalStateException("The value of " + BasicBrooklynCatalog.POLICIES_KEY + " must be an Iterable.");
+        }
+
+        Object policy = Iterables.getOnlyElement((Iterable<?>)policies);
+
+        return createPolicySpec(loader, policy, encounteredCatalogTypes);
+    }
+
+    @SuppressWarnings("unchecked")
+    static PolicySpec<?> createPolicySpec(BrooklynClassLoadingContext loader, Object policy, Set<String> encounteredCatalogTypes) {
+        Map<String, Object> itemMap;
+        if (policy instanceof String) {
+            itemMap = ImmutableMap.<String, Object>of("type", policy);
+        } else if (policy instanceof Map) {
+            itemMap = (Map<String, Object>) policy;
+        } else {
+            throw new IllegalStateException("Policy expected to be string or map. Unsupported object type " + policy.getClass().getName() + " (" + policy.toString() + ")");
+        }
+
+        String versionedId = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "policy_type", "policyType", "type"), "policy type");
+        PolicySpec<? extends Policy> spec = resolvePolicySpec(versionedId, loader, encounteredCatalogTypes);
+        Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_CONFIG);
+        if (brooklynConfig != null) {
+            spec.configure(brooklynConfig);
+        }
+        List<?> parameters = (List<?>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS);
+        initParameters(parameters, spec, loader);
+        return spec;
+    }
+
+    static LocationSpec<?> createLocationSpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan);
+        Object locations = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.LOCATIONS_KEY), "location config");
+        if (!(locations instanceof Iterable<?>)) {
+            throw new IllegalStateException("The value of " + BasicBrooklynCatalog.LOCATIONS_KEY + " must be an Iterable.");
+        }
+
+        Object location = Iterables.getOnlyElement((Iterable<?>)locations);
+        return createLocationSpec(loader, location);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static LocationSpec<?> createLocationSpec(BrooklynClassLoadingContext loader, Object location) {
+        Map<String, Object> itemMap;
+        if (location instanceof String) {
+            itemMap = ImmutableMap.<String, Object>of("type", location);
+        } else if (location instanceof Map) {
+            itemMap = (Map<String, Object>) location;
+        } else {
+            throw new IllegalStateException("Location expected to be string or map. Unsupported object type " + location.getClass().getName() + " (" + location.toString() + ")");
+        }
+
+        String type = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "location_type", "locationType", "type"), "location type");
+        Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config");
+        LocationSpec<?> locationSpec = resolveLocationSpec(type, brooklynConfig, loader);
+        List<?> explicitParams = (List<?>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS);
+        initParameters(explicitParams, locationSpec, loader);
+        return locationSpec;
+    }
+
+    private static void initParameters(List<?> explicitParams, AbstractBrooklynObjectSpec<?, ?> spec, BrooklynClassLoadingContext loader) {
+        if (explicitParams != null) {
+            spec.parameters(BasicSpecParameter.fromConfigList(explicitParams, loader));
+        } else {
+            spec.parameters(BasicSpecParameter.fromSpec(loader.getManagementContext(), spec));
+        }
+    }
+
+    public static DeploymentPlan makePlanFromYaml(ManagementContext mgmt, String yaml) {
+        CampPlatform camp = getCampPlatform(mgmt);
+        return camp.pdp().parseDeploymentPlan(Streams.newReaderWithContents(yaml));
+    }
+
+    public static CampPlatform getCampPlatform(ManagementContext mgmt) {
+        CampPlatform result = mgmt.getConfig().getConfig(BrooklynCampConstants.CAMP_PLATFORM);
+        if (result!=null) {
+            return result;
+        } else {
+            throw new IllegalStateException("No CAMP Platform is registered with this Brooklyn management context.");
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static PolicySpec<? extends Policy> resolvePolicySpec(
+            String versionedId,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredCatalogTypes) {
+        
+        PolicySpec<? extends Policy> spec;
+        RegisteredType item = loader.getManagementContext().getTypeRegistry().get(versionedId);
+        if (item != null && !encounteredCatalogTypes.contains(item.getSymbolicName())) {
+            return loader.getManagementContext().getTypeRegistry().createSpec(item, null, PolicySpec.class);
+        } else {
+            // TODO-type-registry pass the loader in to the above, and allow it to load with the loader
+            spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class));
+        }
+        return spec;
+    }
+
+    private static LocationSpec<?> resolveLocationSpec(
+            String type,
+            Map<String, Object> brooklynConfig,
+            BrooklynClassLoadingContext loader) {
+        Maybe<Class<? extends Location>> javaClass = loader.tryLoadClass(type, Location.class);
+        if (javaClass.isPresent()) {
+            LocationSpec<?> spec = LocationSpec.create(javaClass.get());
+            if (brooklynConfig != null) {
+                spec.configure(brooklynConfig);
+            }
+            return spec;
+        } else {
+            Maybe<Location> loc = loader.getManagementContext().getLocationRegistry().resolve(type, false, brooklynConfig);
+            if (loc.isPresent()) {
+                // TODO extensions?
+                Map<String, Object> locConfig = ((ConfigurationSupportInternal)loc.get().config()).getBag().getAllConfig();
+                Class<? extends Location> locType = loc.get().getClass();
+                Set<Object> locTags = loc.get().tags().getTags();
+                String locDisplayName = loc.get().getDisplayName();
+                return LocationSpec.create(locType)
+                        .configure(locConfig)
+                        .displayName(locDisplayName)
+                        .tags(locTags);
+            } else {
+                throw new IllegalStateException("No class or resolver found for location type "+type);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
new file mode 100644
index 0000000..1fc6eaf
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -0,0 +1,142 @@
+/*
+ * 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 org.apache.brooklyn.camp.brooklyn.spi.creation;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.camp.CampPlatform;
+import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
+import org.apache.brooklyn.camp.spi.AssemblyTemplate;
+import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.collect.ImmutableSet;
+
+class CampResolver {
+
+    private ManagementContext mgmt;
+    private RegisteredType type;
+    private RegisteredTypeConstraint context;
+
+    /** whether to allow parsing of the 'full' syntax for applications,
+     * where items are wrapped in a "services:" block, and if the wrapper is an application,
+     * to promote it */
+    boolean allowApplicationFullSyntax = true;
+
+    /** whether to allow parsing of the legacy 'full' syntax, 
+     * where a non-application items are wrapped:
+     * <li> in a "services:" block for entities,
+     * <li> in a "brooklyn.locations" or "brooklyn.policies" block for locations and policies */
+    boolean allowLegacyFullSyntax = true;
+
+    /** whether to allow parsing of the type syntax, where an item is a map with a "type:" field,
+     * i.e. not wrapped in any "services:" or "brooklyn.{locations,policies}" block */
+    boolean allowTypeSyntax = true;
+
+    public CampResolver(ManagementContext mgmt, RegisteredType type, RegisteredTypeConstraint context) {
+        this.mgmt = mgmt;
+        this.type = type;
+        this.context = context;
+    }
+
+    public AbstractBrooklynObjectSpec<?, ?> createSpec() {
+        // TODO modern approach
+        //            AbstractBrooklynObjectSpec<?, ?> spec = RegisteredTypes.newSpecInstance(mgmt, /* 'type' key */);
+        //            spec.configure(keysAndValues);
+        return createSpecFromFull(mgmt, type, 
+            context.getEncounteredTypes(), (BrooklynClassLoadingContext) context.getLoader());
+    }
+
+    static AbstractBrooklynObjectSpec<?, ?> createSpecFromFull(ManagementContext mgmt, RegisteredType item, Set<String> parentEncounteredTypes, BrooklynClassLoadingContext loaderO) {
+        // for this method, a prefix "services" or "brooklyn.{location,policies}" is required at the root;
+        // we now prefer items to come in "{ type: .. }" format, except for application roots which
+        // should have a "services: [ ... ]" block (and which may subsequently be unwrapped)
+        BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item, loaderO);
+
+        Set<String> encounteredTypes;
+        // symbolicName could be null if coming from the catalog parser where it tries to load before knowing the id
+        if (item.getSymbolicName() != null) {
+            encounteredTypes = ImmutableSet.<String>builder()
+                .addAll(parentEncounteredTypes)
+                .add(item.getSymbolicName())
+                .build();
+        } else {
+            encounteredTypes = parentEncounteredTypes;
+        }
+
+        AbstractBrooklynObjectSpec<?, ?> spec;
+        String planYaml = RegisteredTypes.getImplementationDataStringForSpec(item);
+        if (RegisteredTypes.isSubTypeOf(item, Policy.class)) {
+            spec = CampInternalUtils.createPolicySpec(planYaml, loader, encounteredTypes);
+        } else if (RegisteredTypes.isSubTypeOf(item, Location.class)) {
+            spec = CampInternalUtils.createLocationSpec(planYaml, loader, encounteredTypes);
+        } else if (RegisteredTypes.isSubTypeOf(item, Application.class)) {
+            spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, true);
+        } else if (RegisteredTypes.isSubTypeOf(item, Entity.class)) {
+            spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, false);
+        } else {
+            // try any of them???
+            
+            throw new IllegalStateException("Cannot detect spec type from "+item.getSuperTypes()+" for "+item+"\n"+planYaml);
+        }
+
+        ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId());
+
+        if (Strings.isBlank( ((AbstractBrooklynObjectSpec<?, ?>)spec).getDisplayName() ))
+            ((AbstractBrooklynObjectSpec<?, ?>)spec).displayName(item.getDisplayName());
+
+        return spec;
+    }
+ 
+    private static EntitySpec<?> createEntitySpecFromServicesBlock(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes, boolean isApplication) {
+        CampPlatform camp = CampInternalUtils.getCampPlatform(loader.getManagementContext());
+
+        AssemblyTemplate at = CampInternalUtils.registerDeploymentPlan(plan, loader, camp);
+        AssemblyTemplateInstantiator instantiator = CampInternalUtils.getInstantiator(at);
+        if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
+            EntitySpec<? extends Application> appSpec = ((AssemblyTemplateSpecInstantiator)instantiator).createApplicationSpec(at, camp, loader, encounteredTypes);
+            CampInternalUtils.resetSpecIfTemplateHasNoExplicitParameters(at, appSpec);
+
+            if (!isApplication && EntityManagementUtils.canPromoteChildrenInWrappedApplication(appSpec) && appSpec.getChildren().size()==1) {
+                EntitySpec<?> childSpec = appSpec.getChildren().get(0);
+                EntityManagementUtils.mergeWrapperParentSpecToChildEntity(appSpec, childSpec);
+                return childSpec;
+            }
+            return appSpec;
+            
+        } else {
+            throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
+        }
+
+    }
+
+}
\ No newline at end of file