Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 7c649d73d -> 3e40b2bfd


Start to flesh out how types get created.

also move inner classes to top level


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

Branch: refs/heads/master
Commit: 817e9bd278a2bf9e13341c67e9bc130dc897f889
Parents: 2aa01c0
Author: Alex Heneveld <[email protected]>
Authored: Mon Nov 2 16:06:44 2015 +0000
Committer: Alex Heneveld <[email protected]>
Committed: Tue Nov 10 17:13:01 2015 +0000

----------------------------------------------------------------------
 .../api/typereg/BrooklynTypeRegistry.java       |   8 +-
 .../brooklyn/api/typereg/RegisteredType.java    |  31 ++-
 .../api/typereg/RegisteredTypeConstraint.java   |   2 +-
 .../core/plan/PlanNotRecognizedException.java   |   6 +
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   4 +
 .../core/plan/PlanToSpecTransformer.java        |   3 +-
 .../AbstractCustomImplementationPlan.java       |  52 +++++
 .../typereg/AbstractTypePlanTransformer.java    | 130 +++++++++++++
 .../core/typereg/BasicBrooklynTypeRegistry.java |  31 ++-
 .../core/typereg/BasicRegisteredType.java       | 122 ++++++++++++
 .../typereg/BasicTypeImplementationPlan.java    |  41 ++++
 .../typereg/BrooklynTypePlanTransformer.java    |  68 +++++++
 .../core/typereg/JavaTypePlanTransformer.java   | 112 +++++++++++
 .../core/typereg/RegisteredTypeConstraints.java |   9 +-
 .../core/typereg/RegisteredTypeKindVisitor.java |  42 ++++
 .../brooklyn/core/typereg/RegisteredTypes.java  | 192 ++-----------------
 .../core/typereg/TypePlanTransformers.java      | 160 ++++++++++++++++
 .../typereg/UnsupportedTypePlanException.java   |  37 ++++
 .../core/test/BrooklynAppLiveTestSupport.java   |  26 +--
 .../core/test/BrooklynAppUnitTestSupport.java   |  38 +---
 .../core/test/BrooklynMgmtUnitTestSupport.java  |  58 ++++++
 .../typereg/JavaTypePlanTransformerTest.java    |  90 +++++++++
 .../apache/brooklyn/util/text/Identifiers.java  |   3 +
 .../brooklyn/util/text/IdentifiersTest.java     |   6 +
 24 files changed, 1024 insertions(+), 247 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
----------------------------------------------------------------------
diff --git 
a/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java 
b/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
index 3ade1db..f98f12f 100644
--- 
a/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
+++ 
b/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
@@ -33,10 +33,10 @@ public interface BrooklynTypeRegistry {
         /** a registered type which will create an {@link 
AbstractBrooklynObjectSpec} (e.g. {@link EntitySpec}) 
          * for the type registered (e.g. the {@link Entity} instance) */
         SPEC,
-        // TODO
-//        BEAN 
-        
-        // NB: additional kinds should have the Visitor in RegisteredTypes 
updated
+        /** a registered type which will create the java type described */
+        BEAN 
+        // note: additional kinds should have the visitor in 
core/RegisteredTypeKindVisitor updated
+        // to flush out all places which want to implement support for all 
kinds 
     }
     
     Iterable<RegisteredType> getAll();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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 6ffa09c..a1fc5cf 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
@@ -20,14 +20,20 @@ package org.apache.brooklyn.api.typereg;
 
 import java.util.Collection;
 
+import javax.annotation.Nullable;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.objs.Identifiable;
+import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
+
+import com.google.common.annotations.Beta;
 
 public interface RegisteredType extends Identifiable {
     
-    @Override
-    String getId();
+    @Override String getId();
+    
+    RegisteredTypeKind getKind();
     
     String getSymbolicName();
     String getVersion();
@@ -48,9 +54,12 @@ public interface RegisteredType extends Identifiable {
      * 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). 
+     * 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.
      */
-    Class<?> getJavaType();
+    @Beta
+    @Nullable Class<?> getJavaType();
 
     /**
      * @return True if the item has been deprecated (i.e. its use is 
discouraged)
@@ -61,5 +70,19 @@ public interface RegisteredType extends Identifiable {
      * @return True if the item has been disabled (i.e. its use is forbidden, 
except for pre-existing apps)
      */
     boolean isDisabled();
+
+    /** @return implementation details, so that the framework can find a 
suitable {@link BrooklynTypePlanTransformer} 
+     * which can then use this object to instantiate this type */
+    TypeImplementationPlan getPlan();
+    
+    public interface TypeImplementationPlan {
+        /** hint which {@link BrooklynTypePlanTransformer} instance(s) can be 
used, if known;
+         * this may be null if the relevant transformer was not declared when 
created,
+         * but in general we should look to determine the kind as early as 
possible 
+         * and use that to retrieve the appropriate such transformer */
+        String getPlanFormat();
+        /** data for the implementation; may be more specific */
+        Object getPlanData();
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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 b55d546..851d88a 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
@@ -41,5 +41,5 @@ public interface RegisteredTypeConstraint {
     /** encountered types, so that during resolution, 
      * if we have already attempted to resolve a given type,
      * the instantiator can avoid recursive cycles */
-    public Set<String> getEncounteredTypes();
+    @Nonnull public Set<String> getEncounteredTypes();
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/plan/PlanNotRecognizedException.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/plan/PlanNotRecognizedException.java
 
b/core/src/main/java/org/apache/brooklyn/core/plan/PlanNotRecognizedException.java
index 4d62d4a..dd5c93d 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/plan/PlanNotRecognizedException.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/plan/PlanNotRecognizedException.java
@@ -18,8 +18,14 @@
  */
 package org.apache.brooklyn.core.plan;
 
+import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
+
+/** @deprecated since 0.9.0 use {@link UnsupportedTypePlanException} as part 
of switch to {@link BrooklynTypePlanTransformer} */
+@Deprecated 
 public class PlanNotRecognizedException extends RuntimeException {
 
+    /** {@link UnsupportedTypePlanException} */
     private static final long serialVersionUID = -5590108442839125317L;
 
     public PlanNotRecognizedException(String message, Throwable cause) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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 1b49170..5614b97 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
@@ -24,6 +24,8 @@ import java.util.Collection;
 import java.util.ServiceLoader;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
+import org.apache.brooklyn.core.typereg.TypePlanTransformers;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -36,6 +38,8 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 
+/** @deprecated since 0.9.0 use {@link TypePlanTransformers} as part of switch 
to {@link BrooklynTypePlanTransformer} */
+@Deprecated 
 public class PlanToSpecFactory {
     
     private static final Logger log = 
LoggerFactory.getLogger(PlanToSpecFactory.class);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java 
b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
index 24753aa..e88406c 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
@@ -26,13 +26,14 @@ 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.core.mgmt.ManagementContextInjectable;
+import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
 
 import com.google.common.annotations.Beta;
 
 /** Pluggable {@link ServiceLoader} interface for different plan-interpreters,
  * that is, different ways of taking an application plan and returning an 
{@link EntitySpec},
  * and a {@link CatalogItem} and returning an {@link 
AbstractBrooklynObjectSpec}.
- */
+ * @deprecated since 0.9.0 use {@link BrooklynTypePlanTransformer} */
 @Beta
 public interface PlanToSpecTransformer extends ManagementContextInjectable {
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractCustomImplementationPlan.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractCustomImplementationPlan.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractCustomImplementationPlan.java
new file mode 100644
index 0000000..d9dde39
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractCustomImplementationPlan.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
+
+/** Abstract superclass for plans to create {@link TypeImplementationPlan} 
with strong types on 
+ * {@link #getPlanData()} and ensuring the correct format (or null for no 
format) */
+public abstract class AbstractCustomImplementationPlan<T> extends 
BasicTypeImplementationPlan {
+    
+    public AbstractCustomImplementationPlan(String format, T data) {
+        super(format, data);
+    }
+    public AbstractCustomImplementationPlan(String expectedFormat, Class<T> 
expectedDataType, TypeImplementationPlan otherPlan) {
+        super(expectedFormat!=null ? expectedFormat : 
otherPlan.getPlanFormat(), otherPlan.getPlanData());
+        if (!expectedDataType.isInstance(otherPlan.getPlanData())) {
+            throw new IllegalArgumentException("Plan "+otherPlan+" does not 
have "+expectedDataType+" data so cannot cast to "+this);
+        }
+        if (expectedFormat!=null && otherPlan.getPlanFormat()!=null) {
+            if (!otherPlan.getPlanFormat().equals(expectedFormat)) {
+                throw new IllegalArgumentException("Plan "+otherPlan+" in 
wrong format "+otherPlan.getPlanFormat()+", when expecting "+expectedFormat);
+            }
+        }
+    }
+    
+    @Override
+    public String getPlanFormat() {
+        return format;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T getPlanData() {
+        return (T)super.getPlanData();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
new file mode 100644
index 0000000..ae2c610
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
@@ -0,0 +1,130 @@
+/*
+ * 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 org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Convenience supertype for {@link BrooklynTypePlanTransformer} instances.
+ */
+public abstract class AbstractTypePlanTransformer implements 
BrooklynTypePlanTransformer {
+
+    private static final Logger log = 
LoggerFactory.getLogger(AbstractTypePlanTransformer.class);
+    
+    protected ManagementContext mgmt;
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+    }
+
+    private final String format;
+    private final String formatName;
+    private final String formatDescription;
+    
+    protected AbstractTypePlanTransformer(String format, String formatName, 
String formatDescription) {
+        this.format = format;
+        this.formatName = formatName;
+        this.formatDescription = formatDescription;
+    }
+    
+    @Override
+    public String getFormatCode() {
+        return format;
+    }
+
+    @Override
+    public String getFormatName() {
+        return formatName;
+    }
+
+    @Override
+    public String getFormatDescription() {
+        return formatDescription;
+    }
+
+    @Override
+    public String toString() {
+        return getFormatCode()+":"+JavaClassNames.simpleClassName(this);
+    }
+    
+    @Override
+    public double scoreForType(RegisteredType type, RegisteredTypeConstraint 
context) {
+        if (getFormatCode().equals(type.getPlan().getPlanFormat())) return 1;
+        if (type.getPlan().getPlanFormat()==null)
+            return scoreForNullFormat(type.getPlan().getPlanData(), type, 
context);
+        else
+            return 
scoreForNonmatchingNonnullFormat(type.getPlan().getPlanFormat(), 
type.getPlan().getPlanData(), type, context);
+    }
+
+    protected abstract double scoreForNullFormat(Object planData, 
RegisteredType type, RegisteredTypeConstraint context);
+    protected abstract double scoreForNonmatchingNonnullFormat(String 
planFormat, Object planData, RegisteredType type, RegisteredTypeConstraint 
context);
+
+    /** delegates to more specific abstract create methods,
+     * and performs common validation and customisation of the items created.
+     * <p>
+     * this includes:
+     * <li> setting the {@link 
AbstractBrooklynObjectSpec#catalogItemId(String)}
+     */
+    @Override
+    public Object create(final RegisteredType type, final 
RegisteredTypeConstraint context) {
+        try {
+            return validate(new RegisteredTypeKindVisitor<Object>() {
+                @Override protected Object visitSpec(RegisteredType type) {
+                    try { 
+                        AbstractBrooklynObjectSpec<?, ?> result = 
createSpec(type, context);
+                        result.catalogItemId(type.getId());
+                        return result;
+                    } catch (Exception e) { throw Exceptions.propagate(e); }
+                }
+                @Override protected Object visitBean(RegisteredType type) {
+                    try { 
+                        return createBean(type, context);
+                    } catch (Exception e) { throw Exceptions.propagate(e); }
+                }
+                
+            }.visit(type), type, context);
+        } catch (UnsupportedTypePlanException e) {
+            // no logging
+            throw Exceptions.propagate(e);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            log.debug("Could not instantiate "+type+" (rethrowing): 
"+Exceptions.collapseText(e));
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    protected <T> T validate(T createdObject, RegisteredType type, 
RegisteredTypeConstraint context) {
+        if (createdObject==null) return null;
+        // TODO validation based on the constraint, throw 
UnsupportedTypePlanException with details if not matched
+        return createdObject;
+    }
+
+    protected abstract AbstractBrooklynObjectSpec<?,?> 
createSpec(RegisteredType type, RegisteredTypeConstraint context) throws 
Exception;
+
+    protected abstract Object createBean(RegisteredType type, 
RegisteredTypeConstraint context) throws Exception;
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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 0a9a229..08b6103 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
@@ -29,10 +29,13 @@ import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.typereg.RegisteredTypes.RegisteredSpecType;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.api.client.util.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
@@ -96,8 +99,9 @@ public class BasicBrooklynTypeRegistry implements 
BrooklynTypeRegistry {
     @SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
     @Override
     public <SpecT extends AbstractBrooklynObjectSpec<?,?>> SpecT 
createSpec(RegisteredType type, @Nullable RegisteredTypeConstraint constraint, 
Class<SpecT> specSuperType) {
-        if (!(type instanceof RegisteredSpecType)) { 
-            throw new IllegalStateException("Cannot create spec from type 
"+type);
+        Preconditions.checkNotNull(type, "type");
+        if (type.getKind()!=RegisteredTypeKind.SPEC) { 
+            throw new IllegalStateException("Cannot create spec from type 
"+type+" (kind "+type.getKind()+")");
         }
         if (constraint!=null) {
             if (constraint.getKind()!=null && 
constraint.getKind()!=RegisteredTypeKind.SPEC) {
@@ -110,11 +114,28 @@ public class BasicBrooklynTypeRegistry implements 
BrooklynTypeRegistry {
         }
         constraint = 
RegisteredTypeConstraints.extendedWithSpecSuperType(constraint, specSuperType);
 
-        // TODO look up in the actual registry
+        Maybe<Object> result = TypePlanTransformers.transform(mgmt, type, 
constraint);
+        if (result.isPresent()) return (SpecT) result.get();
         
         // 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());
-        return (SpecT) 
BasicBrooklynCatalog.internalCreateSpecWithTransformers(mgmt, item, 
constraint.getEncounteredTypes());
+        try {
+            return (SpecT) 
BasicBrooklynCatalog.internalCreateSpecWithTransformers(mgmt, item, 
constraint.getEncounteredTypes());
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // for now, combine this failure with the original
+            try {
+                result.get();
+                // 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
+                throw Exceptions.create("Unable to instantiate "+type, 
MutableList.of(e, e0));
+            }
+            // ultimately swallow the legacy failure, return the original 
failure (the call below will throw because result is absent)
+//            return (SpecT) result.get();
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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
new file mode 100644
index 0000000..ac0b266
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
@@ -0,0 +1,122 @@
+/*
+ * 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.Collection;
+import java.util.List;
+
+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.javalang.JavaClassNames;
+
+public class BasicRegisteredType implements RegisteredType {
+
+    final String symbolicName;
+    final String version;
+    final RegisteredTypeKind kind;
+    
+    List<OsgiBundleWithUrl> bundles;
+    String displayName;
+    String description;
+    String iconUrl;
+    boolean deprecated;
+    boolean disabled;
+    
+    TypeImplementationPlan implementationPlan;
+
+    // TODO ensure this is re-populated on rebind?  or remove?
+    transient Class<?> javaType;
+    
+    public BasicRegisteredType(RegisteredTypeKind kind, String symbolicName, 
String version, Class<?> javaType, TypeImplementationPlan implementationPlan) {
+        this.kind = kind;
+        this.symbolicName = symbolicName;
+        this.version = version;
+        this.javaType = javaType;
+        this.implementationPlan = implementationPlan;
+    }
+
+    @Override
+    public String getId() {
+        return symbolicName + (version!=null ? ":"+version : "");
+    }
+
+    @Override
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public RegisteredTypeKind getKind() {
+        return kind;
+    }
+    
+    @Override
+    public Collection<OsgiBundleWithUrl> getLibraries() {
+        return bundles;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String getIconUrl() {
+        return iconUrl;
+    }
+    
+    @Override
+    public boolean isDisabled() {
+        return disabled;
+    }
+    
+    @Override
+    public boolean isDeprecated() {
+        return deprecated;
+    }
+    
+    @Override
+    public Class<?> getJavaType() {
+        return javaType;
+    }
+    
+    @Override
+    public TypeImplementationPlan getPlan() {
+        return implementationPlan;
+    }
+    
+    @Override
+    public String toString() {
+        return JavaClassNames.simpleClassName(this)+"["+getId()+
+            (isDisabled() ? ";DISABLED" : "")+
+            (isDeprecated() ? ";deprecated" : "")+
+            "]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/BasicTypeImplementationPlan.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicTypeImplementationPlan.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicTypeImplementationPlan.java
new file mode 100644
index 0000000..7647323
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicTypeImplementationPlan.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
+
+public class BasicTypeImplementationPlan implements TypeImplementationPlan {
+    final String format;
+    final Object data;
+    
+    public BasicTypeImplementationPlan(String format, Object data) {
+        this.format = format;
+        this.data = data;
+    }
+    
+    @Override
+    public String getPlanFormat() {
+        return format;
+    }
+
+    @Override
+    public Object getPlanData() {
+        return data;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynTypePlanTransformer.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynTypePlanTransformer.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynTypePlanTransformer.java
new file mode 100644
index 0000000..96c9cb7
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynTypePlanTransformer.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.ServiceLoader;
+
+import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
+
+/**
+ * Interface for use by schemes which with to be able to transform plans.
+ * <p>
+ * To add a new plan transformation scheme, simply create an implementation 
and declare it
+ * as a java service (cf {@link ServiceLoader}).
+ * <p>
+ * Implementations may wish to extend {@link AbstractTypePlanTransformer} 
which simplifies the process.
+ */
+public interface BrooklynTypePlanTransformer extends 
ManagementContextInjectable {
+
+    /** @return a code to identify type implementations created specifying the 
use of this plan transformer. */
+    String getFormatCode();
+    /** @return a display name for this transformer. */
+    String getFormatName();
+    /** @return a description for this transformer */
+    String getFormatDescription();
+
+    /** @return how appropriate is this transformer for the {@link 
RegisteredType#getPlan()} of the type;
+     * 0 (or less) if not, 1 for absolutely, and in some autodetect cases a 
value between 0 and 1 indicate a ranking.
+     * <p>
+     * The framework guarantees arguments are nonnull, and that the {@link 
RegisteredType#getPlan()} is also not-null.
+     * However the format in that plan may be null. */
+    double scoreForType(RegisteredType type, RegisteredTypeConstraint context);
+    /** Creates a new instance of the indicated type, or throws if not 
supported;
+     * this method is used by the {@link BrooklynTypeRegistry} when it creates 
instances,
+     * so implementations must respect the {@link RegisteredTypeKind} 
semantics and the {@link RegisteredTypeConstraint}
+     * if they return an instance.
+     * <p>
+     * The framework guarantees this will only be invoked when {@link 
#scoreForType(RegisteredType, RegisteredTypeConstraint)} 
+     * has returned a positive value.
+     * <p>
+     * Implementations should either return null or throw {@link 
UnsupportedTypePlanException} 
+     * if the {@link RegisteredType#getPlan()} is not supported. */
+    Object create(RegisteredType type, RegisteredTypeConstraint context);
+    
+    double scoreForTypeDefinition(String formatCode, Object catalogData);
+    List<RegisteredType> createFromTypeDefinition(String formatCode, Object 
catalogData);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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
new file mode 100644
index 0000000..febf52a
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java
@@ -0,0 +1,112 @@
+/*
+ * 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/817e9bd2/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 9d59343..c880b7e 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
@@ -22,6 +22,7 @@ import groovy.xml.Entity;
 
 import java.util.Set;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
@@ -42,9 +43,9 @@ public class RegisteredTypeConstraints {
     
     /** Immutable (from caller's perspective) record of a constraint */
     public final static class BasicRegisteredTypeConstraint implements 
RegisteredTypeConstraint {
-        private RegisteredTypeKind kind;
-        private Class<?> javaSuperType;
-        private Set<String> encounteredTypes;
+        @Nullable private RegisteredTypeKind kind;
+        @Nullable private Class<?> javaSuperType;
+        @Nonnull private Set<String> encounteredTypes = ImmutableSet.of();
         
         private BasicRegisteredTypeConstraint() {}
         
@@ -108,7 +109,7 @@ public class RegisteredTypeConstraints {
         return of(RegisteredTypeKind.SPEC, javaSuperType);
     }
 
-    public static <T extends AbstractBrooklynObjectSpec<?,?>> 
RegisteredTypeConstraint extendedWithSpecSuperType(RegisteredTypeConstraint 
source, Class<T> specSuperType) {
+    public static <T extends AbstractBrooklynObjectSpec<?,?>> 
RegisteredTypeConstraint extendedWithSpecSuperType(@Nullable 
RegisteredTypeConstraint source, @Nullable Class<T> specSuperType) {
         Class<?> superType = lookupTargetTypeForSpec(specSuperType);
         BasicRegisteredTypeConstraint constraint = new 
BasicRegisteredTypeConstraint(source);
         if (source==null) source = constraint;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeKindVisitor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeKindVisitor.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeKindVisitor.java
new file mode 100644
index 0000000..530828e
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeKindVisitor.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.brooklyn.api.typereg.RegisteredType;
+
+/** Visitor adapter which can be used to ensure all kinds are supported
+ * <p>
+ * By design this class may have abstract methods added without notification,
+ * and subclasses will be responsible for providing the implementation in 
order to ensure compatibility. */
+public abstract class RegisteredTypeKindVisitor<T> {
+    
+    public T visit(RegisteredType type) {
+        if (type==null) throw new NullPointerException("Registered type must 
not be null");
+        switch (type.getKind()) {
+        case SPEC: return visitSpec(type);
+        case BEAN: return visitBean(type);
+        // others go here
+        default:
+            throw new IllegalStateException("Unexpected registered type: 
"+type.getClass());
+        }
+    }
+
+    protected abstract T visitSpec(RegisteredType type);
+    protected abstract T visitBean(RegisteredType type);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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 8cddde2..7e35084 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,15 +18,12 @@
  */
 package org.apache.brooklyn.core.typereg;
 
-import java.util.Collection;
-import java.util.List;
-
 import org.apache.brooklyn.api.catalog.CatalogItem;
 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.core.plan.PlanToSpecTransformer;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
+import 
org.apache.brooklyn.core.typereg.JavaTypePlanTransformer.JavaTypeNameImplementation;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
@@ -47,17 +44,16 @@ public class RegisteredTypes {
     @Deprecated
     public static RegisteredType of(CatalogItem<?, ?> item) {
         if (item==null) return null;
-        TypeImplementation impl = null;
+        TypeImplementationPlan impl = null;
         if (item.getPlanYaml()!=null) {
-            impl = new TypeImplementation(null, item.getPlanYaml());
+            impl = new BasicTypeImplementationPlan(null, item.getPlanYaml());
         } else if (item.getJavaType()!=null) {
-            impl = new JavaTypeImplementation(item.getJavaType());
+            impl = new JavaTypeNameImplementation(item.getJavaType());
         } else {
             throw new IllegalStateException("Unsupported catalog item "+item+" 
when trying to create RegisteredType");
         }
         
-        RegisteredSpecType type = new 
RegisteredSpecType(item.getSymbolicName(), item.getVersion(),
-            item.getCatalogItemJavaType(), impl);
+        BasicRegisteredType type = (BasicRegisteredType) 
spec(item.getSymbolicName(), item.getVersion(), item.getCatalogItemJavaType(), 
impl);
         type.bundles = item.getLibraries()==null ? 
ImmutableList.<OsgiBundleWithUrl>of() : 
ImmutableList.<OsgiBundleWithUrl>copyOf(item.getLibraries());
         type.displayName = item.getDisplayName();
         type.description = item.getDescription();
@@ -66,180 +62,26 @@ public class RegisteredTypes {
         type.deprecated = item.isDeprecated();
 
         // TODO
-        // javaType, specType, registeredTypeName ...
-        // tags ?
+        // probably not: javaType, specType, registeredTypeName ...
+        // maybe: tags ?
         return type;
     }
-
-    /** Visitor adapter which can be used to ensure all kinds are supported */
-    public static abstract class RegisteredTypeKindVisitor<T> {
-        public T visit(RegisteredType type) {
-            if (type==null) throw new NullPointerException("Registered type 
must not be null");
-            if (type instanceof RegisteredSpecType) {
-                return visitSpec((RegisteredSpecType)type);
-            }
-            // others go here
-            throw new IllegalStateException("Unexpected registered type: 
"+type.getClass());
-        }
-
-        protected abstract T visitSpec(RegisteredSpecType type);
-        
-        // TODO beans, others
-    }
-    
-    public static RegisteredTypeKind getKindOf(RegisteredType type) {
-        return new RegisteredTypeKindVisitor<RegisteredTypeKind>() {
-            @Override protected RegisteredTypeKind 
visitSpec(RegisteredSpecType type) { return RegisteredTypeKind.SPEC; }
-        }.visit(type);
-    }
-    
-    public abstract static class AbstractRegisteredType implements 
RegisteredType {
-
-        final String symbolicName;
-        final String version;
-        
-        List<OsgiBundleWithUrl> bundles;
-        String displayName;
-        String description;
-        String iconUrl;
-        boolean deprecated;
-        boolean disabled;
-
-        // TODO ensure this is re-populated on rebind
-        transient Class<?> javaType;
-        
-        public AbstractRegisteredType(String symbolicName, String version, 
Class<?> javaType) {
-            this.symbolicName = symbolicName;
-            this.version = version;
-            this.javaType = javaType;
-        }
-
-        @Override
-        public String getId() {
-            return symbolicName + (version!=null ? ":"+version : "");
-        }
-
-        @Override
-        public String getSymbolicName() {
-            return symbolicName;
-        }
-
-        @Override
-        public String getVersion() {
-            return version;
-        }
-        
-        @Override
-        public Collection<OsgiBundleWithUrl> getLibraries() {
-            return bundles;
-        }
-
-        @Override
-        public String getDisplayName() {
-            return displayName;
-        }
-
-        @Override
-        public String getDescription() {
-            return description;
-        }
-
-        @Override
-        public String getIconUrl() {
-            return iconUrl;
-        }
-        
-        @Override
-        public boolean isDisabled() {
-            return disabled;
-        }
-        
-        @Override
-        public boolean isDeprecated() {
-            return deprecated;
-        }
-        
-        @Override
-        public Class<?> getJavaType() {
-            return javaType;
-        }
-        
-        @Override
-        public String toString() {
-            return JavaClassNames.simpleClassName(this)+"["+getId()+
-                (isDisabled() ? ";DISABLED" : "")+
-                (isDeprecated() ? ";deprecated" : "")+
-                "]";
-        }
-    }
-
-    // TODO
-//    public static class RegisteredBeanType extends AbstractRegisteredType {
-//        
-//    }
     
-    public static class RegisteredSpecType extends AbstractRegisteredType {
-
-        private TypeImplementation impl;
-        
-        public RegisteredSpecType(String symbolicName, String version, 
Class<?> javaType, TypeImplementation impl) {
-            super(symbolicName, version, javaType);
-            this.impl = impl;
-        }
-
-        public TypeImplementation getImplementation() {
-            return impl;
-        }
-    }
-
-    public static class TypeImplementation {
-        final String format;
-        final Object data;
-        
-        public TypeImplementation(String kind, Object data) {
-            super();
-            this.format = kind;
-            this.data = data;
-        }
-
-        /** details of the implementation, if known;
-         * this may be null if the relevant {@link PlanToSpecTransformer} was 
not declared when created,
-         * but in general we should look to determine the kind as early as 
possible and use that
-         * to retrieve the appropriate such transformer.
-         */
-        public String getFormat() {
-            return format;
-        }
-        
-        public Object getData() {
-            return data;
-        }
+    public static RegisteredType bean(String symbolicName, String version, 
Class<?> javaType, TypeImplementationPlan plan) {
+        return new BasicRegisteredType(RegisteredTypeKind.BEAN, symbolicName, 
version, javaType, plan);
     }
     
-    public static class JavaTypeImplementation extends TypeImplementation {
-        public static final String FORMAT = "java";
-        public JavaTypeImplementation(String javaType) {
-            super(FORMAT, javaType);
-        }
-        public String getJavaType() { return (String)getData(); }
+    public static RegisteredType spec(String symbolicName, String version, 
Class<?> javaType, TypeImplementationPlan plan) {
+        return new BasicRegisteredType(RegisteredTypeKind.SPEC, symbolicName, 
version, javaType, plan);
     }
-    
-//    // TODO remove, unless we want it
-//    public static class CampYamlTypeImplementation extends 
TypeImplementation {
-//        public static final String FORMAT = "camp";
-//        public CampYamlTypeImplementation(String javaType) {
-//            super(FORMAT, javaType);
-//        }
-//        public String getCampYaml() { return (String)getData(); }
-//    }
 
     /** returns the implementation data for a spec if it is a string (e.g. 
plan yaml or java class name); else false */
     @Beta
     public static String getImplementationDataStringForSpec(RegisteredType 
item) {
-        if (!(item instanceof RegisteredSpecType)) return null;
-        Object data = ((RegisteredSpecType)item).getImplementation().getData();
-        if (data instanceof String) return (String) data;
-        return null;
+        if (item==null || item.getPlan()==null) return null;
+        Object data = item.getPlan().getPlanData();
+        if (!(data instanceof String)) return null;
+        return (String)data;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java 
b/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
new file mode 100644
index 0000000..b2b496e
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
@@ -0,0 +1,160 @@
+/*
+ * 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.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.TreeMap;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+public class TypePlanTransformers {
+
+    private static final Logger log = 
LoggerFactory.getLogger(TypePlanTransformers.class);
+
+    private static Collection<BrooklynTypePlanTransformer> getAll() {
+        return 
ImmutableList.copyOf(ServiceLoader.load(BrooklynTypePlanTransformer.class));
+    }
+
+    private static Collection<Class<? extends BrooklynTypePlanTransformer>> 
OVERRIDE;
+    @SafeVarargs
+    @VisibleForTesting
+    public synchronized static void forceAvailable(Class<? extends 
BrooklynTypePlanTransformer> ...classes) {
+        OVERRIDE = Arrays.asList(classes);
+    }
+    public synchronized static void clearForced() {
+        OVERRIDE = null;
+    }
+
+    public static Collection<BrooklynTypePlanTransformer> 
all(ManagementContext mgmt) {
+        // TODO cache these in the TypeRegistry, looking for new ones 
periodically or supplying a way to register them
+        Collection<Class<? extends BrooklynTypePlanTransformer>> override = 
OVERRIDE;
+        Collection<BrooklynTypePlanTransformer> result = new 
ArrayList<BrooklynTypePlanTransformer>();
+        if (override!=null) {
+            for (Class<? extends BrooklynTypePlanTransformer> o1: override) {
+                try {
+                    result.add(o1.newInstance());
+                } catch (Exception e) {
+                    Exceptions.propagate(e);
+                }
+            }
+        } else {
+            result.addAll(getAll());
+        }
+        for(BrooklynTypePlanTransformer t : result) {
+            t.injectManagementContext(mgmt);
+        }
+        return result;
+    }
+
+    /** returns a list of {@link BrooklynTypePlanTransformer} instances for 
this {@link ManagementContext}
+     * which may be able to handle the given plan; the list is sorted with 
highest-score transformer first */
+    @Beta
+    public static List<BrooklynTypePlanTransformer> forType(ManagementContext 
mgmt, RegisteredType type, RegisteredTypeConstraint constraint) {
+        Multimap<Double,BrooklynTypePlanTransformer> byScoreMulti = 
ArrayListMultimap.create(); 
+        Collection<BrooklynTypePlanTransformer> transformers = all(mgmt);
+        for (BrooklynTypePlanTransformer transformer : transformers) {
+            double score = transformer.scoreForType(type, constraint);
+            if (score>0) byScoreMulti.put(score, transformer);
+        }
+        Map<Double, Collection<BrooklynTypePlanTransformer>> tree = new 
TreeMap<Double, Collection<BrooklynTypePlanTransformer>>(byScoreMulti.asMap());
+        List<Collection<BrooklynTypePlanTransformer>> highestFirst = new 
ArrayList<Collection<BrooklynTypePlanTransformer>>(tree.values());
+        Collections.reverse(highestFirst);
+        return 
MutableList.copyOf(Iterables.concat(highestFirst)).asUnmodifiable();
+    }
+
+    /** transforms the given type to an instance, if possible
+     * <p>
+     * callers should generally use one of the create methods on {@link 
BrooklynTypeRegistry} rather than using this method directly. */
+    @Beta
+    public static Maybe<Object> transform(ManagementContext mgmt, 
RegisteredType type, RegisteredTypeConstraint constraint) {
+        if (type==null) return Maybe.absent("type cannot be null");
+        if (type.getPlan()==null) return Maybe.absent("type plan cannot be 
null, when instantiating "+type);
+        
+        List<BrooklynTypePlanTransformer> transformers = forType(mgmt, type, 
constraint);
+        Collection<String> transformersWhoDontSupport = new 
ArrayList<String>();
+        Collection<Exception> failuresFromTransformers = new 
ArrayList<Exception>();
+        for (BrooklynTypePlanTransformer t: transformers) {
+            try {
+                Object result = t.create(type, constraint);
+                if (result==null) {
+                    transformersWhoDontSupport.add(t.getFormatCode() + " 
(returned null)");
+                    continue;
+                }
+                return Maybe.of(result);
+            } catch (UnsupportedTypePlanException e) {
+                transformersWhoDontSupport.add(t.getFormatCode() +
+                    (Strings.isNonBlank(e.getMessage()) ? " 
("+e.getMessage()+")" : ""));
+            } catch (@SuppressWarnings("deprecation") 
org.apache.brooklyn.core.plan.PlanNotRecognizedException e) {
+                // just in case (shouldn't happen)
+                transformersWhoDontSupport.add(t.getFormatCode() +
+                    (Strings.isNonBlank(e.getMessage()) ? " 
("+e.getMessage()+")" : ""));
+            } catch (Throwable e) {
+                Exceptions.propagateIfFatal(e);
+                failuresFromTransformers.add(new 
PropagatedRuntimeException("Transformer for "+t.getFormatCode()+" gave an error 
creating this plan: "+
+                    Exceptions.collapseText(e), e));
+            }
+        }
+        
+        // failed
+        Exception result;
+        if (!failuresFromTransformers.isEmpty()) {
+            // at least one thought he could do it
+            if (log.isDebugEnabled()) {
+                log.debug("Failure transforming plan; returning summary 
failure, but for reference "
+                    + "potentially application transformers were 
"+transformers+", "
+                    + "others available are 
"+MutableList.builder().addAll(all(mgmt)).removeAll(transformers).build()+"; "
+                    + "failures: "+failuresFromTransformers);
+            }
+            result = failuresFromTransformers.size()==1 ? 
Exceptions.create(null, failuresFromTransformers) :
+                Exceptions.create("All plan transformers failed", 
failuresFromTransformers);
+        } else {
+            if (transformers.isEmpty()) {
+                result = new UnsupportedTypePlanException("Invalid plan; 
format could not be recognized, none of the available transformers 
"+all(mgmt)+" support "+type);
+            } else {
+                result = new UnsupportedTypePlanException("Invalid plan; 
potentially applicable transformers "+transformers+" do not support it, and 
other available transformers "+
+                    
MutableList.builder().addAll(all(mgmt)).removeAll(transformers).build()+" do 
not accept it");
+            }
+        }
+        return Maybe.absent(result);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/main/java/org/apache/brooklyn/core/typereg/UnsupportedTypePlanException.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/UnsupportedTypePlanException.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/UnsupportedTypePlanException.java
new file mode 100644
index 0000000..98cbd7a
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/UnsupportedTypePlanException.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public class UnsupportedTypePlanException extends RuntimeException {
+
+    private static final long serialVersionUID = -5590108442839125317L;
+
+    public UnsupportedTypePlanException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UnsupportedTypePlanException(String message) {
+        super(message);
+    }
+
+    public UnsupportedTypePlanException(Throwable cause) {
+        super(cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java
 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java
index b986fed..977b7a5 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppLiveTestSupport.java
@@ -19,15 +19,9 @@
 package org.apache.brooklyn.core.test;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
 /**
@@ -36,31 +30,17 @@ import org.testng.annotations.BeforeMethod;
  * Uses a management context that will not load {@code 
~/.brooklyn/catalog.xml} but will
  * read from the default {@code ~/.brooklyn/brooklyn.properties}.
  */
-public class BrooklynAppLiveTestSupport {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynAppLiveTestSupport.class);
+public class BrooklynAppLiveTestSupport extends BrooklynMgmtUnitTestSupport {
 
     protected TestApplication app;
-    protected ManagementContextInternal mgmt;
 
     @BeforeMethod(alwaysRun=true)
     public void setUp() throws Exception {
         if (mgmt!=null) {
-            app = ApplicationBuilder.newManagedApp(newAppSpec(), mgmt);
+            app = mgmt.getEntityManager().createEntity(newAppSpec());
         } else {
             mgmt = new 
LocalManagementContextForTests(BrooklynProperties.Factory.newDefault());
-            app = ApplicationBuilder.newManagedApp(newAppSpec(), mgmt);
-        }
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        try {
-            if (mgmt != null) Entities.destroyAll(mgmt);
-        } catch (Throwable t) {
-            LOG.error("Caught exception in tearDown method", t);
-        } finally {
-            mgmt = null;
+            app = mgmt.getEntityManager().createEntity(newAppSpec());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java
 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java
index fa96e0b..cbe39d0 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java
@@ -20,14 +20,7 @@ package org.apache.brooklyn.core.test;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
 /**
@@ -35,40 +28,25 @@ import org.testng.annotations.BeforeMethod;
  * <p>
  * Uses a light-weight management context that will not read {@code 
~/.brooklyn/brooklyn.properties}.
  */
-public class BrooklynAppUnitTestSupport {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynAppUnitTestSupport.class);
+public class BrooklynAppUnitTestSupport extends BrooklynMgmtUnitTestSupport {
 
     protected TestApplication app;
-    protected ManagementContextInternal mgmt;
-
-    protected boolean shouldSkipOnBoxBaseDirResolution() {
-        return true;
-    }
 
     @BeforeMethod(alwaysRun=true)
     public void setUp() throws Exception {
-        if (mgmt == null) {
-            mgmt = LocalManagementContextForTests.newInstance();
-        }
+        super.setUp();
         setUpApp();
     }
 
+    protected boolean shouldSkipOnBoxBaseDirResolution() {
+        return true;
+    }
+
     protected void setUpApp() {
         EntitySpec<TestApplication> appSpec = 
EntitySpec.create(TestApplication.class)
                 .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, 
shouldSkipOnBoxBaseDirResolution());
-        app = ApplicationBuilder.newManagedApp(appSpec, mgmt);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        try {
-            if (mgmt != null) Entities.destroyAll(mgmt);
-        } catch (Throwable t) {
-            LOG.error("Caught exception in tearDown method", t);
-        } finally {
-            mgmt = null;
-        }
+        
+        app = mgmt.getEntityManager().createEntity(appSpec);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/core/src/test/java/org/apache/brooklyn/core/test/BrooklynMgmtUnitTestSupport.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynMgmtUnitTestSupport.java
 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynMgmtUnitTestSupport.java
new file mode 100644
index 0000000..956ad63
--- /dev/null
+++ 
b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynMgmtUnitTestSupport.java
@@ -0,0 +1,58 @@
+/*
+ * 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.test;
+
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * To be extended by unit/integration tests.
+ * <p>
+ * Uses a light-weight management context that will not read {@code 
~/.brooklyn/brooklyn.properties}.
+ */
+public class BrooklynMgmtUnitTestSupport {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynMgmtUnitTestSupport.class);
+
+    protected ManagementContextInternal mgmt;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        if (mgmt == null) {
+            mgmt = LocalManagementContextForTests.newInstance();
+        }
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            if (mgmt != null) Entities.destroyAll(mgmt);
+        } catch (Throwable t) {
+            LOG.error("Caught exception in tearDown method", t);
+        } finally {
+            mgmt = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/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
new file mode 100644
index 0000000..c4d8038
--- /dev/null
+++ 
b/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.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 org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class JavaTypePlanTransformerTest extends BrooklynMgmtUnitTestSupport {
+
+    public static class NoArg {
+        public String name() { return "no-arg"; }
+    }
+
+    protected RegisteredType type;
+    protected BrooklynTypePlanTransformer transformer;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        type = newNoArgRegisteredType(JavaTypePlanTransformer.FORMAT);
+        transformer = newTransformer();
+    }
+    
+    protected RegisteredType newNoArgRegisteredType(String format) {
+        return RegisteredTypes.bean("no-arg", "1.0", null, new 
BasicTypeImplementationPlan(format, NoArg.class.getName()));
+    }
+    
+    protected BrooklynTypePlanTransformer newTransformer() {
+        BrooklynTypePlanTransformer xf = new JavaTypePlanTransformer();
+        xf.injectManagementContext(mgmt);
+        return xf;
+    }
+    
+    @Test
+    public void testScoreJavaType() {
+        double score = transformer.scoreForType(type, null);
+        Assert.assertEquals(score, 1, 0.00001);
+    }
+
+    @Test
+    public void testCreateJavaType() {
+        Object obj = transformer.create(type, null);
+        Assert.assertTrue(obj instanceof NoArg, "obj is "+obj);
+        Assert.assertEquals(((NoArg)obj).name(), "no-arg");
+    }
+
+    @Test
+    public void testScoreJavaTypeWithNullFormat() {
+        type = newNoArgRegisteredType(null);
+        double score = transformer.scoreForType(type, null);
+        Assert.assertEquals(score, 0.1, 0.00001);
+    }
+
+    @Test
+    public void testCreateJavaTypeWithNullFormat() {
+        type = newNoArgRegisteredType(null);
+        Object obj = transformer.create(type, null);
+        Assert.assertTrue(obj instanceof NoArg, "obj is "+obj);
+        Assert.assertEquals(((NoArg)obj).name(), "no-arg");
+    }
+
+    @Test
+    public void testScoreJavaTypeWithOtherFormat() {
+        type = newNoArgRegisteredType("crazy-format");
+        double score = transformer.scoreForType(type, null);
+        Assert.assertEquals(score, 0, 0.00001);
+        // we don't test creation; it may or may not succeed, but with score 0 
it shouldn't get invoked
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/utils/common/src/main/java/org/apache/brooklyn/util/text/Identifiers.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/text/Identifiers.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/text/Identifiers.java
index 8d3e035..b389f9c 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/Identifiers.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/Identifiers.java
@@ -26,6 +26,9 @@ public class Identifiers {
     
     public static final String JAVA_GOOD_START_CHARS = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
     public static final String JAVA_GOOD_NONSTART_CHARS = 
JAVA_GOOD_START_CHARS+"1234567890";
+    public static final String JAVA_SEGMENT_REGEX = 
"["+JAVA_GOOD_START_CHARS+"]"+"["+JAVA_GOOD_NONSTART_CHARS+"]*";
+    public static final String JAVA_PACKAGE_OR_CLASS_REGEX = 
"("+JAVA_SEGMENT_REGEX+"\\."+")*"+JAVA_SEGMENT_REGEX;
+    public static final String JAVA_BINARY_REGEX = 
JAVA_PACKAGE_OR_CLASS_REGEX+"(\\$["+JAVA_GOOD_NONSTART_CHARS+"]+)*";
     
     public static final String JAVA_GENERATED_IDENTIFIER_START_CHARS = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     public static final String JAVA_GENERATED_IDENTIFIERNONSTART_CHARS = 
JAVA_GENERATED_IDENTIFIER_START_CHARS+"1234567890";

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/817e9bd2/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java 
b/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
index 1b2068f..8f4463f 100644
--- 
a/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
+++ 
b/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
@@ -86,4 +86,10 @@ public class IdentifiersTest {
         log.info("ID's made from hash, of -1 is "+id1+" and of Long.MIN_VALUE 
is "+Identifiers.makeIdFromHash(Long.MIN_VALUE));
     }
 
+    @Test
+    public void testJavaClassRegex() {
+        Assert.assertTrue("foo".matches(Identifiers.JAVA_BINARY_REGEX));
+        
Assert.assertTrue("foo.bar.Baz$1".matches(Identifiers.JAVA_BINARY_REGEX));
+    }
+    
 }

Reply via email to