You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2015/10/15 16:02:22 UTC

[01/16] incubator-brooklyn git commit: PlanToSpecTransformer for old-style xml catalog items

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master b0cadef73 -> d53bd189c


PlanToSpecTransformer for old-style xml catalog items

Implement a transformer for items with java type attribute, get the functionality out of the camp parser.


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

Branch: refs/heads/master
Commit: c71d7227dcda9e13c7aaca63cf9624caf48128e7
Parents: 3d415c4
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 8 17:36:15 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:08:53 2015 +0300

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  | 28 +-----
 .../internal/JavaCatalogToSpecTransformer.java  | 89 ++++++++++++++++++++
 ...che.brooklyn.core.plan.PlanToSpecTransformer | 19 +++++
 .../BrooklynComponentTemplateResolver.java      |  9 +-
 .../rest/util/BrooklynRestResourceUtils.java    |  2 +
 5 files changed, 114 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c71d7227/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index cc4cffe..9850eca 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.core.catalog.internal;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -50,7 +49,6 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.AggregateClassLoader;
 import org.apache.brooklyn.util.javalang.LoadedClassLoader;
-import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
@@ -327,30 +325,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             }
         }
 
-        // revert to legacy mechanism
-        SpecT spec = null;
-        Method method;
-        try {
-            method = Reflections.findMethod(specType, "create", Class.class);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Unsupported creation of spec type "+specType+"; it must have a public static create(Class) method", e);            
-        }
-        try {
-            if (loadedItem.getJavaType()!=null) {
-                @SuppressWarnings("unchecked")
-                SpecT specT = (SpecT) method.invoke(null, loadedItem.loadJavaClass(mgmt));
-                spec = specT;
-            }
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Error creating "+specType+" "+loadedItem.getJavaType()+": "+e, e);
-        }
-
-        if (spec==null) 
-            throw new IllegalStateException("No known mechanism to create instance of "+item);
-
-        return spec;
+        throw new IllegalStateException("No known mechanism to create instance of "+item);
     }
 
     @SuppressWarnings("unchecked")
@@ -1101,6 +1076,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             serializer = new CatalogXmlSerializer();
     }
 
+    @Override
     @Deprecated
     public CatalogItem<?,?> getCatalogItemForType(String typeName) {
         final CatalogItem<?,?> resultI;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c71d7227/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
new file mode 100644
index 0000000..9b4a83c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.catalog.internal;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+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.mgmt.ManagementContext;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.plan.PlanNotRecognizedException;
+import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
+    private static final Logger log = LoggerFactory.getLogger(JavaCatalogToSpecTransformer.class);
+
+    private ManagementContext mgmt;
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+    }
+
+    @Override
+    public String getShortDescription() {
+        return "Deprecated java-type catalog items transformer";
+    }
+
+    @Override
+    public boolean accepts(String planType) {
+        return false;
+    }
+
+    @Override
+    public EntitySpec<? extends Application> createApplicationSpec(String plan) throws PlanNotRecognizedException {
+        throw new PlanNotRecognizedException(getClass().getName() + " doesn't parse application plans.");
+    }
+
+    @Override
+    public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(
+            CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException {
+        if (item.getJavaType() != null) {
+            log.warn("Deprecated functionality (since 0.9.0). Using old-style xml catalog items with java type attribute for " + item);
+            BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item);
+            Class<?> type = loader.loadClass(item.getJavaType());
+            AbstractBrooklynObjectSpec<?,?> spec;
+            if (Entity.class.isAssignableFrom(type)) {
+                @SuppressWarnings("unchecked")
+                Class<Entity> entityType = (Class<Entity>)type;
+                spec = EntitySpec.create(entityType);
+            } else if (Policy.class.isAssignableFrom(type)) {
+                @SuppressWarnings("unchecked")
+                Class<Policy> policyType = (Class<Policy>)type;
+                spec = PolicySpec.create(policyType);
+            } else {
+                throw new IllegalStateException("Catalog item " + item + " java type " + item.getJavaType() + " is not a Brooklyn supported object.");
+            }
+            @SuppressWarnings("unchecked")
+            SpecT untypedSpc = (SpecT) spec;
+            return untypedSpc;
+        } else {
+            throw new PlanNotRecognizedException(getClass().getName() + " parses only old-style catalog items containing javaType");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c71d7227/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.plan.PlanToSpecTransformer
----------------------------------------------------------------------
diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.plan.PlanToSpecTransformer b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.plan.PlanToSpecTransformer
new file mode 100644
index 0000000..f43cda5
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.plan.PlanToSpecTransformer
@@ -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.catalog.internal.JavaCatalogToSpecTransformer

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c71d7227/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 914b5e6..f42145d 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -216,12 +216,7 @@ public class BrooklynComponentTemplateResolver {
     }
 
     private String getJavaType() {
-        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
-        if (!isJavaTypePrefix() && item != null && item.getJavaType() != null) {
-            return item.getJavaType();
-        } else {
-            return typeResolver.getBrooklynType(type);
-        }
+        return typeResolver.getBrooklynType(type);
     }
 
     public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
@@ -306,7 +301,7 @@ public class BrooklynComponentTemplateResolver {
         // Old-style catalog items (can be defined in catalog.xml only) don't have structure, only a single type, so
         // they are loaded as a simple java type, only taking the class name from the catalog item instead of the
         // type value in the YAML. Classpath entries in the item are also used (through the catalog root classloader).
-        if (isJavaTypePrefix() || item == null || item.getJavaType() != null) {
+        if (isJavaTypePrefix() || item == null) {
             return createSpecFromJavaType();
 
         // Same as above case, but this time force java type loading (either as plain class or through an old-style

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c71d7227/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
index cbdf70d..2d6802e 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -209,6 +209,8 @@ public class BrooklynRestResourceUtils {
 
     @SuppressWarnings({ "unchecked", "deprecation" })
     public Application create(ApplicationSpec spec) {
+        log.warn("Using deprecated functionality (as of 0.9.0), ApplicationSpec style (pre CAMP plans). " +
+                    "Transition to actively supported spec plans.");
         log.debug("REST creating application instance for {}", spec);
         
         if (!Entitlements.isEntitled(mgmt.getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, spec)) {


[10/16] incubator-brooklyn git commit: Get BrooklynServiceTypeResolver back in, used by Clocker

Posted by sj...@apache.org.
Get BrooklynServiceTypeResolver back in, used by Clocker


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

Branch: refs/heads/master
Commit: 1c72a209cd0067731f77e8ac72bedad324c2af7d
Parents: 09e9f1a
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 17:58:33 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:58:33 2015 +0300

----------------------------------------------------------------------
 .../service/BrooklynServiceTypeResolver.java    | 78 ++++++++++++++++++++
 1 file changed, 78 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1c72a209/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
new file mode 100644
index 0000000..edb1924
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
@@ -0,0 +1,78 @@
+/*
+ * 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.service;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
+import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
+import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code brooklyn:}
+ * to Brooklyn {@link EntitySpec} instances.
+ * 
+ * @deprecated since 0.9.0, use {@link AbstractServiceSpecResolver} instead
+ */
+@Deprecated
+public class BrooklynServiceTypeResolver implements ServiceTypeResolver {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class);
+    
+    public BrooklynServiceTypeResolver() {
+    }
+    
+    @Override
+    public String getTypePrefix() { return DEFAULT_TYPE_PREFIX; }
+
+    @Override
+    public String getBrooklynType(String serviceType) {
+        return Strings.removeFromStart(serviceType, getTypePrefix() + ":").trim();
+    }
+
+    @Nullable
+    @Override
+    public CatalogItem<Entity,EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) {
+        String type = getBrooklynType(serviceType);
+        if (type != null) {
+            return getCatalogItemImpl(resolver.getManagementContext(),  type);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) {
+    }
+
+    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItemImpl(ManagementContext mgmt, String brooklynType) {
+        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
+        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
+    }
+}


[09/16] incubator-brooklyn git commit: Remove duplicate dependency

Posted by sj...@apache.org.
Remove duplicate dependency


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

Branch: refs/heads/master
Commit: 073c203216428e1ddb87a8f9c2530c41d1239969
Parents: 4485fe5
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 15:02:50 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:11:07 2015 +0300

----------------------------------------------------------------------
 usage/camp/pom.xml | 5 -----
 1 file changed, 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/073c2032/usage/camp/pom.xml
----------------------------------------------------------------------
diff --git a/usage/camp/pom.xml b/usage/camp/pom.xml
index fb5d7ee..9173a58 100644
--- a/usage/camp/pom.xml
+++ b/usage/camp/pom.xml
@@ -36,11 +36,6 @@
     <dependencies>
         
         <dependency>
-            <groupId>org.apache.brooklyn.camp</groupId>
-            <artifactId>camp-base</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.apache.brooklyn</groupId>
             <artifactId>brooklyn-core</artifactId>
             <version>${project.version}</version>


[02/16] incubator-brooklyn git commit: CAMP parsing improvements

Posted by sj...@apache.org.
CAMP parsing improvements

Code cleanup, including:
  * fix recursive resolving check, avoiding stack overflow error
  * go through the PlanToSpecTransformer list for each nested catalog item, allowing nesting of different types of catalog items (already implemented, but now integrating it tighter with the parse workflow

Resolve catalog items tiop level, encountered types, cleanup


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

Branch: refs/heads/master
Commit: 3d415c41c3b3b0eeef3df1f4ad71cec7ddb8de40
Parents: 00615b7
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 8 13:51:49 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:08:53 2015 +0300

----------------------------------------------------------------------
 .../core/mgmt/EntityManagementUtils.java        |  10 +-
 .../core/plan/PlanToSpecTransformer.java        |   3 +-
 .../core/plan/XmlPlanToSpecTransformer.java     |   3 +-
 .../api/AssemblyTemplateSpecInstantiator.java   |  13 +-
 .../BrooklynAssemblyTemplateInstantiator.java   | 169 ++--------------
 .../BrooklynComponentTemplateResolver.java      | 194 +++++++++---------
 .../spi/creation/BrooklynEntityMatcher.java     |  15 +-
 .../brooklyn/spi/creation/CampCatalogUtils.java | 197 ++-----------------
 .../spi/creation/CampToSpecTransformer.java     |   8 +-
 .../camp/brooklyn/spi/creation/CampUtils.java   | 187 ++++++++++++++++++
 .../service/DefaultServiceTypeResolver.java     |  23 +++
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  43 ++++
 .../test/lite/TestAppAssemblyInstantiator.java  |  12 +-
 13 files changed, 426 insertions(+), 451 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index 3a46416..0dca83c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.mgmt;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Callable;
 
 import javax.annotation.Nullable;
@@ -55,6 +56,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 
@@ -96,11 +98,15 @@ public class EntityManagementUtils {
         }).get();
     }
 
-    public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item) {
+    public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, CatalogItem<T, SpecT> item) {
+        return createCatalogSpec(mgmt, item, ImmutableSet.<String>of());
+    }
+
+    public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item, final Set<String> encounteredTypes) {
         return PlanToSpecFactory.attemptWithLoaders(mgmt, new Function<PlanToSpecTransformer, SpecT>() {
             @Override
             public SpecT apply(PlanToSpecTransformer input) {
-                return input.createCatalogSpec(item);
+                return input.createCatalogSpec(item, encounteredTypes);
             }
         }).get();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/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 c6e3a4a..b9ca8ca 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
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.core.plan;
 
 import java.util.ServiceLoader;
+import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Application;
@@ -56,6 +57,6 @@ public interface PlanToSpecTransformer extends ManagementContextInjectable {
      * implementations will typically look at the {@link CatalogItem#getCatalogItemType()} first.
      * <p>
      * should throw {@link PlanNotRecognizedException} if this transformer does not know what to do with the plan. */
-    <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item) throws PlanNotRecognizedException;
+    <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException;
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java b/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
index a535932..a4c3766 100644
--- a/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
+++ b/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.core.plan;
 
 import java.io.StringReader;
+import java.util.Set;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -74,7 +75,7 @@ public class XmlPlanToSpecTransformer implements PlanToSpecTransformer {
 
     @SuppressWarnings({ "unchecked" })
     @Override
-    public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item) {
+    public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
         if (item.getPlanYaml()==null) throw new PlanNotRecognizedException("Plan is null");
         if (item.getCatalogItemType()==CatalogItemType.ENTITY) {
             return (SpecT)toEntitySpec(parseXml(item.getPlanYaml()), 1);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/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 df7227b..1dfc351 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
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn.api;
 
+import java.util.List;
 import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Application;
@@ -29,7 +30,13 @@ import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 
 public interface AssemblyTemplateSpecInstantiator extends AssemblyTemplateInstantiator {
 
-    EntitySpec<? extends Application> createSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader, boolean autoUnwrapIfAppropriate);
-    EntitySpec<?> createNestedSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes);
-    
+    /**
+     * 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);
+    /** 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/3d415c41/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 63f111a..e54e2ef 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
@@ -18,30 +18,20 @@
  */
 package org.apache.brooklyn.camp.brooklyn.spi.creation;
 
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import org.apache.brooklyn.api.catalog.CatalogItem;
 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.mgmt.ManagementContext;
 import org.apache.brooklyn.camp.CampPlatform;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
 import org.apache.brooklyn.camp.spi.Assembly;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate.Builder;
 import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 import org.apache.brooklyn.camp.spi.collection.ResolvableLink;
-import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
-import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult;
@@ -49,10 +39,7 @@ 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.entity.stock.BasicApplicationImpl;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.net.Urls;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,21 +60,28 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         return platform.assemblies().get(app.getApplicationId());
     }
 
-    public Application create(AssemblyTemplate template, CampPlatform platform) {
-        ManagementContext mgmt = getBrooklynManagementContext(platform);
+    private Application create(AssemblyTemplate template, CampPlatform platform) {
+        ManagementContext mgmt = getManagementContext(platform);
         BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt);
-        EntitySpec<? extends Application> spec = createSpec(template, platform, loader, true);
+        EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader);
         Application instance = mgmt.getEntityManager().createEntity(spec);
         log.info("CAMP placing '{}' under management", instance);
         Entities.startManagement(instance, mgmt);
         return instance;
     }
-    
-    private ManagementContext getBrooklynManagementContext(CampPlatform platform) {
-        return ((HasBrooklynManagementContext)platform).getBrooklynManagementContext();
+
+    @Override
+    public List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template,
+            CampPlatform platform, BrooklynClassLoadingContext itemLoader,
+            Set<String> encounteredCatalogTypes) {
+        return buildTemplateServicesAsSpecs(itemLoader, template, platform, encounteredCatalogTypes, true);
     }
 
-    public EntitySpec<? extends Application> createSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader, boolean autoUnwrapIfPossible) {
+    @Override
+    public EntitySpec<? extends Application> createApplicationSpec(
+            AssemblyTemplate template,
+            CampPlatform platform,
+            BrooklynClassLoadingContext loader) {
         log.debug("CAMP creating application instance for {} ({})", template.getId(), template);
 
         // AssemblyTemplates created via PDP, _specifying_ then entities to put in
@@ -98,12 +92,12 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE);
 
         // first build the children into an empty shell app
-        List<EntitySpec<?>> childSpecs = buildTemplateServicesAsSpecs(loader, template, platform, true);
+        List<EntitySpec<?>> childSpecs = createServiceSpecs(template, platform, loader, Sets.<String>newLinkedHashSet());
         for (EntitySpec<?> childSpec : childSpecs) {
             app.child(childSpec);
         }
 
-        if (autoUnwrapIfPossible && shouldUnwrap(template, app)) {
+        if (shouldUnwrap(template, app)) {
             app = EntityManagementUtils.unwrapApplication(app);
         }
 
@@ -124,149 +118,24 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         return wrapTemplate;
     }
 
-    protected boolean shouldUnwrap(AssemblyTemplate template, EntitySpec<? extends Application> app) {
+    private boolean shouldUnwrap(AssemblyTemplate template, EntitySpec<? extends Application> app) {
         if (Boolean.TRUE.equals(TypeCoercions.coerce(template.getCustomAttributes().get(NEVER_UNWRAP_APPS_PROPERTY), Boolean.class)))
             return false;
         return EntityManagementUtils.canPromoteWrappedApplication(app);
     }
 
-    private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, boolean canUseOtherTransformers) {
-        return buildTemplateServicesAsSpecsImpl(loader, template, platform, Sets.<String>newLinkedHashSet(), canUseOtherTransformers);
-    }
-
-    private List<EntitySpec<?>> buildTemplateServicesAsSpecsImpl(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
+    private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
         List<EntitySpec<?>> result = Lists.newArrayList();
 
         for (ResolvableLink<PlatformComponentTemplate> ctl: template.getPlatformComponentTemplates().links()) {
             PlatformComponentTemplate appChildComponentTemplate = ctl.resolve();
             BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, appChildComponentTemplate);
-            EntitySpec<?> spec;
-            spec = resolveCampSpec(platform, ResourceUtils.create(this), entityResolver, encounteredCatalogTypes, canUseOtherTransformers);
+            EntitySpec<?> spec = entityResolver.resolveSpec(encounteredCatalogTypes, canUseOtherTransformers);
             result.add(spec);
         }
         return result;
     }
 
-    static EntitySpec<?> resolveCampSpec(
-            CampPlatform platform,
-            ResourceUtils ru,
-            BrooklynComponentTemplateResolver entityResolver,
-            Set<String> encounteredCatalogTypes,
-            boolean canUseOtherTransformers) {
-        
-        String brooklynType = entityResolver.getServiceTypeResolver().getBrooklynType(entityResolver.getDeclaredType());
-        CatalogItem<Entity, EntitySpec<?>> item = entityResolver.getServiceTypeResolver().getCatalogItem(entityResolver, entityResolver.getDeclaredType());
-
-        if (log.isTraceEnabled()) log.trace("Building CAMP template services: type="+brooklynType+"; item="+item+"; loader="+entityResolver.getLoader()+"; encounteredCatalogTypes="+encounteredCatalogTypes);
-
-        EntitySpec<?> spec = null;
-        String protocol = Urls.getProtocol(brooklynType);
-        if (protocol != null) {
-            if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
-                spec = tryResolveYamlUrlReferenceSpec(platform, ru, brooklynType, entityResolver.getLoader(), encounteredCatalogTypes);
-                if (spec != null) {
-                    entityResolver.populateSpec(spec);
-                }
-            } else {
-                // TODO support https above
-                // TODO this will probably be logged if we refer to  chef:cookbook  or other service types which BCTR accepts;
-                // better would be to have BCTR supporting the calls above
-                log.debug("The reference " + brooklynType + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
-                        protocol + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
-                        "Will try to load it as catalog item or java type.");
-            }
-        }
-
-        if (spec == null) {
-            // load from java or yaml
-            spec = entityResolver.resolveSpec(encounteredCatalogTypes, canUseOtherTransformers);
-        }
-
-        return spec;
-    }
-
-    private static EntitySpec<?> tryResolveYamlUrlReferenceSpec(
-            CampPlatform platform,
-            ResourceUtils ru,
-            String brooklynType, BrooklynClassLoadingContext itemLoader,
-            Set<String> encounteredCatalogTypes) {
-        Reader yaml;
-        try {
-            yaml = new InputStreamReader(ru.getResourceFromUrl(brooklynType), "UTF-8");
-        } catch (Exception e) {
-            log.warn("AssemblyTemplate type " + brooklynType + " which looks like a URL can't be fetched.", e);
-            return null;
-        }
-        try {
-            return createNestedSpec(platform, encounteredCatalogTypes, yaml, itemLoader);
-        } finally {
-            try {
-                yaml.close();
-            } catch (IOException e) {
-                throw Exceptions.propagate(e);
-            }
-        }
-    }
-
-    static EntitySpec<?> resolveCatalogYamlReferenceCampSpec(
-            CampPlatform platform,
-            CatalogItem<Entity, EntitySpec<?>> item,
-            Set<String> encounteredCatalogTypes) {
-        ManagementContext mgmt = getManagementContext(platform);
-
-        String yaml = item.getPlanYaml();
-        Reader input = new StringReader(yaml);
-        BrooklynClassLoadingContext itemLoader = CatalogUtils.newClassLoadingContext(mgmt, item);
-
-        return createNestedSpec(platform, encounteredCatalogTypes, input, itemLoader);
-    }
-
-    private static EntitySpec<?> createNestedSpec(CampPlatform platform,
-            Set<String> encounteredCatalogTypes, Reader input,
-            BrooklynClassLoadingContext itemLoader) {
-
-        AssemblyTemplate at;
-        BrooklynLoaderTracker.setLoader(itemLoader);
-        try {
-            at = platform.pdp().registerDeploymentPlan(input);
-        } finally {
-            BrooklynLoaderTracker.unsetLoader(itemLoader);
-        }
-        return createNestedSpecStatic(at, platform, itemLoader, encounteredCatalogTypes);
-    }
-
-    @Override
-    public EntitySpec<?> createNestedSpec(
-            AssemblyTemplate template,
-            CampPlatform platform,
-            BrooklynClassLoadingContext itemLoader,
-            Set<String> encounteredCatalogTypes) {
-        return createNestedSpecStatic(template, platform, itemLoader, encounteredCatalogTypes);
-    }
-    
-    private static EntitySpec<?> createNestedSpecStatic(
-        AssemblyTemplate template,
-        CampPlatform platform,
-        BrooklynClassLoadingContext itemLoader,
-        Set<String> encounteredCatalogTypes) {
-        // In case we want to allow multiple top-level entities in a catalog we need to think
-        // about what it would mean to subsequently call buildChildrenEntitySpecs on the list of top-level entities!
-        try {
-            AssemblyTemplateInstantiator ati = template.getInstantiator().newInstance();
-            if (ati instanceof BrooklynAssemblyTemplateInstantiator) {
-                List<EntitySpec<?>> specs = ((BrooklynAssemblyTemplateInstantiator)ati).buildTemplateServicesAsSpecsImpl(itemLoader, template, platform, encounteredCatalogTypes, false);
-                if (specs.size() > 1) {
-                    throw new UnsupportedOperationException("Only supporting single service in catalog item currently: got "+specs);
-                }
-                return specs.get(0);
-            } else {
-                throw new IllegalStateException("Cannot create application with instantiator: " + ati);
-            }
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
     private static ManagementContext getManagementContext(CampPlatform platform) {
         return ((HasBrooklynManagementContext)platform).getBrooklynManagementContext();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 5857d61..914b5e6 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -32,12 +32,12 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 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.camp.CampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.service.BrooklynServiceTypeResolver;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DefaultServiceTypeResolver;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver;
 import org.apache.brooklyn.camp.spi.AbstractResource;
 import org.apache.brooklyn.camp.spi.ApplicationComponentTemplate;
@@ -46,15 +46,12 @@ import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 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.entity.AbstractEntity;
 import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.ResourceUtils;
@@ -62,9 +59,9 @@ import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 import org.apache.brooklyn.util.core.flags.FlagUtils.FlagConfigKeyAndValueRecord;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -91,7 +88,7 @@ public class BrooklynComponentTemplateResolver {
     private final ServiceTypeResolver typeResolver;
     private final AtomicBoolean alreadyBuilt = new AtomicBoolean(false);
 
-    public BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type, ServiceTypeResolver typeResolver) {
+    private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type, ServiceTypeResolver typeResolver) {
         this.loader = loader;
         this.mgmt = loader.getManagementContext();
         this.attrs = ConfigBag.newInstanceCopying(attrs);
@@ -101,14 +98,10 @@ public class BrooklynComponentTemplateResolver {
         this.typeResolver = typeResolver;
     }
 
-    public BrooklynClassLoadingContext getLoader() { return loader; }
     public ManagementContext getManagementContext() { return mgmt; }
     public ConfigBag getAttrs() { return attrs; }
-    public Maybe<AbstractResource> getTemplate() { return template; }
     public BrooklynYamlTypeInstantiator.Factory getYamlLoader() { return yamlLoader; }
-    public ServiceTypeResolver getServiceTypeResolver() { return typeResolver; }
     public String getDeclaredType() { return type; }
-    public Boolean isAlreadyBuilt() { return alreadyBuilt.get(); }
 
     public static class Factory {
 
@@ -119,7 +112,7 @@ public class BrooklynComponentTemplateResolver {
         }
 
         // TODO This could be extended to support multiple prefixes per resolver and a 'best-match' algorithm
-        protected static ServiceTypeResolver findService(BrooklynClassLoadingContext context, String type) {
+        private static ServiceTypeResolver findService(BrooklynClassLoadingContext context, String type) {
             if (type.indexOf(':') != -1) {
                 String prefix = Splitter.on(":").splitToList(type).get(0);
                 ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class,
@@ -149,11 +142,11 @@ public class BrooklynComponentTemplateResolver {
             ServiceTypeResolver typeResolver = computeResolverType(context, null, optionalTemplate, attrs);
             String type = getDeclaredType(null, optionalTemplate, attrs);
             if (typeResolver == null) // use default
-                typeResolver = new BrooklynServiceTypeResolver();
+                typeResolver = new DefaultServiceTypeResolver();
             return new BrooklynComponentTemplateResolver(context, attrs, optionalTemplate, type, typeResolver);
         }
 
-        public static String getDeclaredType(String knownServiceType, AbstractResource optionalTemplate, @Nullable ConfigBag attrs) {
+        private static String getDeclaredType(String knownServiceType, AbstractResource optionalTemplate, @Nullable ConfigBag attrs) {
             String type = knownServiceType;
             if (type==null && optionalTemplate!=null) {
                 type = optionalTemplate.getType();
@@ -168,31 +161,44 @@ public class BrooklynComponentTemplateResolver {
         private static String extractServiceTypeAttribute(@Nullable ConfigBag attrs) {
             return BrooklynYamlTypeInstantiator.InstantiatorFromKey.extractTypeName("service", attrs).orNull();
         }
+    }
 
-        public static boolean supportsType(BrooklynClassLoadingContext context, String serviceType) {
-            ServiceTypeResolver typeResolver = computeResolverType(context, serviceType, null, null);
-            if (typeResolver != null) return true;
-            return newInstance(context, serviceType).canResolve();
+    public boolean canResolve() {
+        if (!(typeResolver instanceof DefaultServiceTypeResolver)) {
+            return true;
         }
-    }
 
-    protected boolean canResolve() {
         CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
-        if (item == null) {
-            return loader.tryLoadClass(getJavaType(), Entity.class).isPresent();
+        if (item != null) {
+            if (item.isDisabled()) {
+                log.warn("Disallowed attempt to use disabled catalog item "+item.getId());
+                return false;
+            } else if (item.isDeprecated()) {
+                log.warn("Use of deprecated catalog item "+item.getId());
+            }
+            return true;
         }
-        
-        if (item.isDisabled()) {
-            log.warn("Disallowed attempt to use disabled catalog item "+item.getId());
-            return false;
-        } else if (item.isDeprecated()) {
-            log.warn("Use of deprecated catalog item "+item.getId());
+
+        if (tryLoadEntityClass().isPresent()) {
+            return true;
         }
+
+        String protocol = Urls.getProtocol(type);
+        if (protocol != null) {
+            if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
+                return true;
+            } else {
+                log.debug("The reference '" + type + "' looks like a URL (running the CAMP Brooklyn entity-matcher) but the protocol '" + 
+                        protocol + "' isn't white listed " + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + ". " +
+                        "Not recognized as catalog item or java item as well!");
+            }
+        }
+
         return true;
     }
 
     /** returns the entity class, if needed in contexts which scan its statics for example */
-    protected Class<? extends Entity> loadEntityClass() {
+    private Class<? extends Entity> loadEntityClass() {
         Maybe<Class<? extends Entity>> result = tryLoadEntityClass();
         if (result.isAbsent())
             throw new IllegalStateException("Could not find "+typeResolver.getBrooklynType(type), ((Maybe.Absent<?>)result).getException());
@@ -200,16 +206,16 @@ public class BrooklynComponentTemplateResolver {
     }
 
     /** tries to load the Java entity class */
-    protected Maybe<Class<? extends Entity>> tryLoadEntityClass() {
+    private Maybe<Class<? extends Entity>> tryLoadEntityClass() {
         return loader.tryLoadClass(getJavaType(), Entity.class);
     }
 
     // TODO Generalise to have other prefixes (e.g. explicit "catalog:" etc)?
-    protected boolean isJavaTypePrefix() {
+    private boolean isJavaTypePrefix() {
         return type != null && (type.toLowerCase().startsWith("java:") || type.toLowerCase().startsWith("brooklyn:java:"));
     }
 
-    protected String getJavaType() {
+    private String getJavaType() {
         CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
         if (!isJavaTypePrefix() && item != null && item.getJavaType() != null) {
             return item.getJavaType();
@@ -218,33 +224,67 @@ public class BrooklynComponentTemplateResolver {
         }
     }
 
-    /** resolves the spec, updating the loader if a catalog item is loaded */
-    @SuppressWarnings("unchecked")
-    protected <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
+    public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
         if (alreadyBuilt.getAndSet(true))
             throw new IllegalStateException("Spec can only be used once: "+this);
 
-        CatalogItem<Entity, EntitySpec<?>> item = getServiceTypeResolver().getCatalogItem(this, getDeclaredType());
-        try {
-            EntitySpec<T> spec = createSpec(item, encounteredCatalogTypes);
-            populateSpec(spec);
-            return spec;
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            
-            // maybe it requires a different transformer? TODO better would be to know this from a transformer type on the catalog item type
-            if (item!=null && canUseOtherTransformers) {
-                log.debug("Could not resolve child "+item+" as CAMP; trying other transformers: "+e);
-                // should only be called when resolving children. and encountered types should probably be empty. 
-                return (EntitySpec<T>) EntityManagementUtils.createCatalogSpec(mgmt, (CatalogItem) item);
+        String brooklynType = typeResolver.getBrooklynType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
+
+        if (log.isTraceEnabled()) log.trace("Building CAMP template services: type="+brooklynType+"; item="+item+"; loader="+loader+"; encounteredCatalogTypes="+encounteredCatalogTypes);
+
+        // TODO implement as service type
+        EntitySpec<T> spec = null;
+        String protocol = Urls.getProtocol(brooklynType);
+        if (protocol != null) {
+            if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
+                spec = tryResolveYamlUrlReferenceSpec(brooklynType, encounteredCatalogTypes);
+                if (spec != null) {
+                    populateSpec(spec);
+                }
             } else {
-                throw Exceptions.propagate(e);
+                // TODO this will probably be logged if we refer to  chef:cookbook  or other service types which BCTR accepts;
+                // better would be to have BCTR supporting the calls above
+                log.debug("The reference " + brooklynType + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
+                        protocol + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
+                        "Will try to load it as catalog item or java type.");
             }
         }
+
+        if (spec == null) {
+            // load from java or yaml
+            spec = resolveLocalSpec(encounteredCatalogTypes, canUseOtherTransformers);
+        }
+
+        return spec;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends Entity> EntitySpec<T> tryResolveYamlUrlReferenceSpec(String brooklynType, Set<String> encounteredCatalogTypes) {
+        String yaml;
+        try {
+            yaml = ResourceUtils.create(this).getResourceAsString(brooklynType);
+        } catch (Exception e) {
+            log.warn("AssemblyTemplate type " + brooklynType + " which looks like a URL can't be fetched.", e);
+            return null;
+        }
+        // Referenced specs are expected to be CAMP format as well.
+        List<EntitySpec<?>> serviceSpecs = CampUtils.createServiceSpecs(yaml, loader, encounteredCatalogTypes);
+        if (serviceSpecs.size() > 1) {
+            throw new UnsupportedOperationException("Only supporting single service in remotely referenced plans: got "+serviceSpecs);
+        }
+        return (EntitySpec<T>) serviceSpecs.get(0);
+    }
+
+    private <T extends Entity> EntitySpec<T> resolveLocalSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
+        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
+        EntitySpec<T> spec = createSpec(item, encounteredCatalogTypes);
+        populateSpec(spec);
+        return spec;
     }
 
     @SuppressWarnings({ "unchecked" })
-    protected <T extends Entity> EntitySpec<T> createSpec(CatalogItem<Entity, EntitySpec<?>> item, Set<String> encounteredCatalogTypes) {
+    private <T extends Entity,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> EntitySpec<T> createSpec(CatalogItem<Entity, EntitySpec<?>> item, Set<String> encounteredCatalogTypes) {
         if (item == null) {
             // ignore; presumably a java type or some such?
         } else if (item.isDisabled()) {
@@ -280,17 +320,12 @@ public class BrooklynComponentTemplateResolver {
         // Only case that's left is a catalog item with CAMP YAML content - try to parse it recursively
         // including its OSGi bundles in the loader classpath.
         } else {
-            // TODO if it isn't camp it will throw. better would be to know the transformers type for the item!
-
-            EntitySpec<?> spec = BrooklynAssemblyTemplateInstantiator.resolveCatalogYamlReferenceCampSpec(getCampPlatform(), item, encounteredCatalogTypes);
-            spec.catalogItemId(item.getId());
-            
-            return (EntitySpec<T>)spec;
+            return (EntitySpec<T>) EntityManagementUtils.createCatalogSpec(mgmt, (CatalogItem<T,SpecT>)item, encounteredCatalogTypes);
         }
     }
     
     @SuppressWarnings("unchecked")
-    protected <T extends Entity> EntitySpec<T> createSpecFromJavaType() {
+    private <T extends Entity> EntitySpec<T> createSpecFromJavaType() {
         Class<T> type = (Class<T>) loadEntityClass();
         
         EntitySpec<T> spec;
@@ -311,9 +346,8 @@ public class BrooklynComponentTemplateResolver {
         return spec;
     }
 
-    //called from BrooklynAssemblyTemplateInstantiator as well
     @SuppressWarnings("unchecked")
-    protected <T extends Entity> void populateSpec(EntitySpec<T> spec) {
+    private <T extends Entity> void populateSpec(EntitySpec<T> spec) {
         String name, templateId=null, planId=null;
         if (template.isPresent()) {
             name = template.get().getName();
@@ -335,7 +369,7 @@ public class BrooklynComponentTemplateResolver {
             Iterable<Map<String,?>> children = (Iterable<Map<String,?>>)childrenObj;
             for (Map<String,?> childAttrs : children) {
                 BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, childAttrs);
-                EntitySpec<? extends Entity> childSpec = BrooklynAssemblyTemplateInstantiator.resolveCampSpec(getCampPlatform(), ResourceUtils.create(this), entityResolver, encounteredCatalogTypes, true);
+                EntitySpec<? extends Entity> childSpec = entityResolver.resolveSpec(encounteredCatalogTypes, true);
                 spec.child(childSpec);
             }
         }
@@ -354,31 +388,8 @@ public class BrooklynComponentTemplateResolver {
         configureEntityConfig(spec);
     }
 
-    /** returns new *uninitialised* entity, with just a few of the pieces from the spec;
-     * initialisation occurs soon after, in {@link #initEntity(ManagementContext, Entity, EntitySpec)},
-     * inside an execution context and after entity ID's are recognised
-     */
-    protected <T extends Entity> T newEntity(EntitySpec<T> spec) {
-        Class<? extends T> entityImpl = (spec.getImplementation() != null) ? spec.getImplementation() : mgmt.getEntityManager().getEntityTypeRegistry().getImplementedBy(spec.getType());
-        InternalEntityFactory entityFactory = ((ManagementContextInternal)mgmt).getEntityFactory();
-        T entity = entityFactory.constructEntity(entityImpl, spec);
-
-        String planId = (String)spec.getConfig().get(BrooklynCampConstants.PLAN_ID);
-        if (planId != null) {
-            entity.config().set(BrooklynCampConstants.PLAN_ID, planId);
-        }
-
-        if (spec.getLocations().size() > 0) {
-            ((AbstractEntity)entity).addLocations(spec.getLocations());
-        }
-
-        if (spec.getParent() != null) entity.setParent(spec.getParent());
-
-        return entity;
-    }
-
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected void configureEntityConfig(EntitySpec<?> spec) {
+    private void configureEntityConfig(EntitySpec<?> spec) {
         // first take *recognised* flags and config keys from the top-level, and put them in the bag (of brooklyn.config)
         // attrs will contain only brooklyn.xxx properties when coming from BrooklynEntityMatcher.
         // Any top-level flags will go into "brooklyn.flags". When resolving a spec from $brooklyn:entitySpec
@@ -442,7 +453,7 @@ public class BrooklynComponentTemplateResolver {
         return allKeys;
     }
 
-    protected static class SpecialFlagsTransformer implements Function<Object, Object> {
+    private static class SpecialFlagsTransformer implements Function<Object, Object> {
         protected final ManagementContext mgmt;
         /* TODO find a way to make do without loader here?
          * it is not very nice having to serialize it; but serialization of BLCL is now relatively clean.
@@ -458,6 +469,7 @@ public class BrooklynComponentTemplateResolver {
             this.loader = loader;
             mgmt = loader.getManagementContext();
         }
+        @Override
         public Object apply(Object input) {
             if (input instanceof Map)
                 return transformSpecialFlags((Map<?, ?>)input);
@@ -501,7 +513,7 @@ public class BrooklynComponentTemplateResolver {
                 @SuppressWarnings("unchecked")
                 Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(specConfig.getSpecConfiguration());
                 specConfig.setSpecConfiguration(resolvedConfig);
-                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(null, false);
+                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveLocalSpec(null, false);
             }
             if (flag instanceof ManagementContextInjectable) {
                 log.debug("Injecting Brooklyn management context info object: {}", flag);
@@ -511,14 +523,4 @@ public class BrooklynComponentTemplateResolver {
             return flag;
         }
     }
-
-    @SuppressWarnings("unchecked")
-    protected List<Map<String, Object>> getChildren(Map<String, Object> attrs) {
-        if (attrs==null) return null;
-        return (List<Map<String, Object>>) attrs.get(BrooklynCampReservedKeys.BROOKLYN_CHILDREN);
-    }
-
-    private CampPlatform getCampPlatform() {
-        return CampCatalogUtils.getCampPlatform(mgmt);
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
index c0a2e19..96e8c4e 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
@@ -22,7 +22,6 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
 import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 import org.apache.brooklyn.camp.spi.PlatformComponentTemplate.Builder;
@@ -33,7 +32,6 @@ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -67,19 +65,8 @@ public class BrooklynEntityMatcher implements PdpMatcher {
             if (serviceType==null) throw new NullPointerException("Service must declare a type ("+service+")");
             BrooklynClassLoadingContext loader = BasicBrooklynCatalog.BrooklynLoaderTracker.getLoader();
             if (loader == null) loader = JavaBrooklynClassLoadingContext.create(mgmt);
-            if (BrooklynComponentTemplateResolver.Factory.supportsType(loader, serviceType))
+            if (BrooklynComponentTemplateResolver.Factory.newInstance(loader, serviceType).canResolve())
                 return serviceType;
-
-            String protocol = Urls.getProtocol(serviceType);
-            if (protocol != null) {
-                if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
-                    return serviceType;
-                } else {
-                    log.debug("The reference '" + serviceType + "' looks like a URL (running the CAMP Brooklyn entity-matcher) but the protocol '" + 
-                            protocol + "' isn't white listed " + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + ". " +
-                            "Not recognized as catalog item or java item as well!");
-                }
-            }
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/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 3d64897..4865241 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
@@ -18,67 +18,50 @@
  */
 package org.apache.brooklyn.camp.brooklyn.spi.creation;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 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.policy.Policy;
-import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.camp.CampPlatform;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
-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.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.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
-import org.apache.brooklyn.util.collections.MutableSet;
-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.text.Strings;
-import org.apache.brooklyn.util.yaml.Yamls;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 
 public class CampCatalogUtils {
 
-    public static AbstractBrooklynObjectSpec<?, ?> createSpec(ManagementContext mgmt, CatalogItem<?, ?> item) {
+    public static AbstractBrooklynObjectSpec<?, ?> createSpec(ManagementContext mgmt, CatalogItem<?, ?> item, Set<String> encounteredTypes) {
         // 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);
-        DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), item.getPlanYaml());
-        Preconditions.checkNotNull(item.getCatalogItemType(), "catalog item type for "+plan);
+        Preconditions.checkNotNull(item.getCatalogItemType(), "catalog item type for "+item.getPlanYaml());
+
+        // symbolicName could be null if coming from the catalog parser where it tries to load before knowing the id
+        if (item.getSymbolicName() != null) {
+            encounteredTypes.add(item.getSymbolicName());
+        }
+
         AbstractBrooklynObjectSpec<?, ?> spec;
         switch (item.getCatalogItemType()) {
             case TEMPLATE:
             case ENTITY:
-                spec = createEntitySpec(item.getSymbolicName(), plan, loader);
+                spec = createEntitySpec(item.getPlanYaml(), loader, encounteredTypes);
                 break;
             case LOCATION: 
-                spec = createLocationSpec(plan, loader);
+                spec = CampUtils.createLocationSpec(item.getPlanYaml(), loader, encounteredTypes);
                 break;
             case POLICY: 
-                spec = createPolicySpec(item.getSymbolicName(), plan, loader);
+                spec = CampUtils.createPolicySpec(item.getPlanYaml(), loader, encounteredTypes);
                 break;
             default:
-                throw new IllegalStateException("Unknown CI Type "+item.getCatalogItemType()+" for "+plan);
+                throw new IllegalStateException("Unknown CI Type "+item.getCatalogItemType()+" for "+item.getPlanYaml());
         }
 
         ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId());
@@ -88,157 +71,17 @@ public class CampCatalogUtils {
 
         return spec;
     }
-
-    private static EntitySpec<?> createEntitySpec(String symbolicName, DeploymentPlan plan, BrooklynClassLoadingContext loader) {
-        CampPlatform camp = getCampPlatform(loader.getManagementContext());
-
-        // TODO should not register new AT each time we instantiate from the same plan; use some kind of cache
-        AssemblyTemplate at;
-        BrooklynLoaderTracker.setLoader(loader);
-        try {
-            at = camp.pdp().registerDeploymentPlan(plan);
-        } finally {
-            BrooklynLoaderTracker.unsetLoader(loader);
-        }
-
-        try {
-            AssemblyTemplateInstantiator instantiator = at.getInstantiator().newInstance();
-            if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
-                return ((AssemblyTemplateSpecInstantiator)instantiator).createNestedSpec(at, camp, loader, 
-                    getInitialEncounteredSymbol(symbolicName));
-            }
-            throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
+    
+    private static EntitySpec<?> createEntitySpec(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        List<EntitySpec<?>> serviceEntitySpecs = CampUtils.createServiceSpecs(plan, loader, encounteredTypes);
+        if (serviceEntitySpecs.size() > 1) {
+            throw new UnsupportedOperationException("Only supporting single service in catalog item currently: got "+serviceEntitySpecs);
         }
+        return serviceEntitySpecs.get(0);
     }
 
-    private static MutableSet<String> getInitialEncounteredSymbol(String symbolicName) {
-        return symbolicName==null ? MutableSet.<String>of() : MutableSet.of(symbolicName);
-    }
-
-    private static PolicySpec<?> createPolicySpec(String symbolicName, DeploymentPlan plan, BrooklynClassLoadingContext loader) {
-        return createPolicySpec(plan, loader, getInitialEncounteredSymbol(symbolicName));
-    }
-
-    private static PolicySpec<?> createPolicySpec(DeploymentPlan plan, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes) {
-        //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")
-    private 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;
-        CatalogItem<?, ?> policyItem = CatalogUtils.getCatalogItemOptionalVersion(loader.getManagementContext(), versionedId);
-        if (policyItem != null && !encounteredCatalogTypes.contains(policyItem.getSymbolicName())) {
-            if (policyItem.getCatalogItemType() != CatalogItemType.POLICY) {
-                throw new IllegalStateException("Non-policy catalog item in policy context: " + policyItem);
-            }
-            //TODO re-use createSpec
-            BrooklynClassLoadingContext itemLoader = CatalogUtils.newClassLoadingContext(loader.getManagementContext(), policyItem);
-            if (policyItem.getPlanYaml() != null) {
-                DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), policyItem.getPlanYaml());
-                encounteredCatalogTypes.add(policyItem.getSymbolicName());
-                return createPolicySpec(plan, itemLoader, encounteredCatalogTypes);
-            } else if (policyItem.getJavaType() != null) {
-                spec = PolicySpec.create((Class<Policy>)itemLoader.loadClass(policyItem.getJavaType()));
-            } else {
-                throw new IllegalStateException("Invalid policy item - neither yaml nor javaType: " + policyItem);
-            }
-        } else {
-            spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class));
-        }
-        Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config");
-        if (brooklynConfig != null) {
-            spec.configure(brooklynConfig);
-        }
-        return spec;
-    }
-
-    private static LocationSpec<?> createLocationSpec(DeploymentPlan plan, BrooklynClassLoadingContext loader) {
-        // See #createPolicySpec; this impl is modeled on that.
-        // spec.catalogItemId is set by caller
-        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");
-        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);
-            }
-        }
-    }
-
-    private static DeploymentPlan makePlanFromYaml(ManagementContext mgmt, String yaml) {
-        CampPlatform camp = getCampPlatform(mgmt);
-        return camp.pdp().parseDeploymentPlan(Streams.newReaderWithContents(yaml));
-    }
-
-    /**
-     * @return the CAMP platform associated with a management context, if there is one.
-     */
     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.");
-        }
+        return CampUtils.getCampPlatform(mgmt);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
index 9b9f1ec..dd0a6f4 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.camp.brooklyn.spi.creation;
 
 import java.io.StringReader;
+import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Application;
@@ -68,7 +69,7 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
             }
             if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
                 BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt);
-                return ((AssemblyTemplateSpecInstantiator) instantiator).createSpec(at, camp, loader, true);
+                return ((AssemblyTemplateSpecInstantiator) instantiator).createApplicationSpec(at, camp, loader);
             } else {
                 // The unknown instantiator can create the app (Assembly), but not a spec.
                 // Currently, all brooklyn plans should produce the above.
@@ -94,8 +95,9 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
-    public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item) {
-        return (SpecT) CampCatalogUtils.createSpec(mgmt, (CatalogItem)item);
+    public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
+        // Not really clear what should happen to the top-level attributes, ignored until a good use case appears.
+        return (SpecT) CampCatalogUtils.createSpec(mgmt, (CatalogItem)item, encounteredTypes);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
new file mode 100644
index 0000000..4fca75c
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
@@ -0,0 +1,187 @@
+/*
+ * 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.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
+import org.apache.brooklyn.api.entity.EntitySpec;
+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.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.camp.CampPlatform;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+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.camp.spi.pdp.DeploymentPlan;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
+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.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class CampUtils {
+
+    public static List<EntitySpec<?>> createServiceSpecs(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        CampPlatform camp = getCampPlatform(loader.getManagementContext());
+
+        AssemblyTemplate at;
+        BrooklynLoaderTracker.setLoader(loader);
+        try {
+            at = camp.pdp().registerDeploymentPlan(new StringReader(plan));
+        } finally {
+            BrooklynLoaderTracker.unsetLoader(loader);
+        }
+
+        try {
+            AssemblyTemplateInstantiator instantiator = at.getInstantiator().newInstance();
+            if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
+                return ((AssemblyTemplateSpecInstantiator)instantiator).createServiceSpecs(at, camp, loader, encounteredTypes);
+            }
+            throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public 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")
+    public 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;
+        CatalogItem<?, ?> policyItem = CatalogUtils.getCatalogItemOptionalVersion(loader.getManagementContext(), versionedId);
+        if (policyItem != null && !encounteredCatalogTypes.contains(policyItem.getSymbolicName())) {
+            if (policyItem.getCatalogItemType() != CatalogItemType.POLICY) {
+                throw new IllegalStateException("Non-policy catalog item in policy context: " + policyItem);
+            }
+            spec = (PolicySpec<? extends Policy>) CampCatalogUtils.createSpec(loader.getManagementContext(), policyItem, encounteredCatalogTypes);
+        } else {
+            spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class));
+        }
+        Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config");
+        if (brooklynConfig != null) {
+            spec.configure(brooklynConfig);
+        }
+        return spec;
+    }
+
+    public 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");
+        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);
+            }
+        }
+    }
+
+    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.");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
new file mode 100644
index 0000000..fdd57d5
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
@@ -0,0 +1,23 @@
+/*
+ * 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.service;
+
+public class DefaultServiceTypeResolver extends BrooklynServiceTypeResolver {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index 7389190..f7c98c0 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -596,6 +596,49 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
     }
 
     @Test
+    public void testDeeplyNestedTypesDoesNotRecurse() throws Exception {
+        String symbolicName = "my.catalog.app.id.basic";
+        // Need to have a stand alone caller first so we can create an item to depend on it.
+        // After that replace it/insert a new version which completes the cycle
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName + ".caller",
+                "  version: " + TEST_VERSION + "pre",
+                "",
+                "services:",
+                "- type: org.apache.brooklyn.entity.stock.BasicEntity");
+
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName + ".callee",
+                "  version: " + TEST_VERSION,
+                "",
+                "services:",
+                "- type: " + symbolicName + ".caller");
+
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName + ".caller",
+                "  version: " + TEST_VERSION,
+                "",
+                "services:",
+                "- type: org.apache.brooklyn.entity.stock.BasicEntity",
+                // Being a child is important, triggers the case where
+                // we allow retrying with other transformers
+                // and thus breaking the recursive check.
+                "  brooklyn.children:",
+                "  - type: " + symbolicName + ".callee");
+
+        try {
+            createAndStartApplication(
+                    "services:",
+                    "- type: " + symbolicName + ".caller");
+        } catch (IllegalStateException e) {
+            assertTrue(e.toString().contains("recursive"), "Unexpected error message: "+e);
+        }
+    }
+
+    @Test
     public void testOsgiNotLeakingToParent() {
         addCatalogOSGiEntity(SIMPLE_ENTITY_TYPE);
         try {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d415c41/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/TestAppAssemblyInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/TestAppAssemblyInstantiator.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/TestAppAssemblyInstantiator.java
index 831805f..422998b 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/TestAppAssemblyInstantiator.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/TestAppAssemblyInstantiator.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn.test.lite;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -39,6 +40,8 @@ import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 
+import com.google.common.collect.ImmutableList;
+
 /** simple illustrative instantiator which always makes a {@link TestApplication}, populated with {@link TestEntity} children,
  * all setting {@link TestEntity#CONF_NAME} for the name in the plan and in the service specs
  * <p>
@@ -52,14 +55,14 @@ public class TestAppAssemblyInstantiator extends BasicAssemblyTemplateInstantiat
         }
         ManagementContext mgmt = ((HasBrooklynManagementContext)platform).getBrooklynManagementContext();
         
-        TestApplication app = (TestApplication) mgmt.getEntityManager().createEntity( createSpec(template, platform, null, false) );
+        TestApplication app = (TestApplication) mgmt.getEntityManager().createEntity( createApplicationSpec(template, platform, null) );
         mgmt.getEntityManager().manage(app);
 
         return new TestAppAssembly(app);
     }
 
     @Override
-    public EntitySpec<? extends Application> createSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader, boolean autoUnwrap) {
+    public EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader) {
         EntitySpec<TestApplication> app = EntitySpec.create(TestApplication.class)
             .configure(TestEntity.CONF_NAME, template.getName())
             .configure(TestEntity.CONF_MAP_THING, MutableMap.of("type", template.getType(), "desc", template.getDescription()));
@@ -84,8 +87,9 @@ public class TestAppAssemblyInstantiator extends BasicAssemblyTemplateInstantiat
     }
 
     @Override
-    public EntitySpec<?> createNestedSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes) {
-        return createSpec(template, platform, itemLoader, true);
+    public List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes) {
+        EntitySpec<?> createApplicationSpec = createApplicationSpec(template, platform, itemLoader);
+        return ImmutableList.<EntitySpec<?>>of(createApplicationSpec);
     }
 
 }


[07/16] incubator-brooklyn git commit: Move ServiceSpecResolver and its implementations to core

Posted by sj...@apache.org.
Move ServiceSpecResolver and its implementations to core

To be reused by other plan parsers.


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

Branch: refs/heads/master
Commit: 883feaea73a5d1f528796908535fcb3c708f96e0
Parents: 73d2790
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 16:06:31 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:11:07 2015 +0300

----------------------------------------------------------------------
 .../resolve/AbstractServiceSpecResolver.java    |  65 ++++++++++
 .../resolve/CatalogServiceSpecResolver.java     | 108 ++++++++++++++++
 .../resolve/DelegatingServiceSpecResolver.java  | 127 +++++++++++++++++++
 .../core/resolve/JavaServiceSpecResolver.java   |  91 +++++++++++++
 .../core/resolve/ServiceSpecResolver.java       |  55 ++++++++
 ...he.brooklyn.core.resolve.ServiceSpecResolver |  20 +++
 .../entity/resolve/ChefServiceSpecResolver.java |  42 ++++++
 .../HardcodedCatalogServiceSpecResolver.java    |  96 ++++++++++++++
 ...he.brooklyn.core.resolve.ServiceSpecResolver |  20 +++
 .../BrooklynComponentTemplateResolver.java      |  22 ++--
 .../service/AbstractServiceSpecResolver.java    |  65 ----------
 .../service/CampServiceSpecResolver.java        |  47 +++++++
 .../service/CatalogServiceSpecResolver.java     | 118 -----------------
 .../service/ChefServiceSpecResolver.java        |  41 ------
 .../service/DelegatingServiceSpecResolver.java  | 127 -------------------
 .../HardcodedCatalogServiceSpecResolver.java    |  95 --------------
 .../service/JavaServiceSpecResolver.java        |  91 -------------
 .../creation/service/ServiceSpecResolver.java   |  56 --------
 .../creation/service/ServiceTypeResolver.java   |   1 +
 .../service/ServiceTypeResolverAdaptor.java     |   2 +
 .../service/UrlServiceSpecResolver.java         |   2 +
 ...lyn.spi.creation.service.ServiceSpecResolver |  23 ----
 .../camp/brooklyn/AbstractYamlTest.java         |   8 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  15 ++-
 24 files changed, 705 insertions(+), 632 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
new file mode 100644
index 0000000..705ed0e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
@@ -0,0 +1,65 @@
+/*
+ * 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.resolve;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.text.Strings;
+
+public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver {
+    private static final String PREFIX_DELIMITER = ":";
+    protected final String name;
+    protected final String prefix;
+    protected ManagementContext mgmt;
+
+    public AbstractServiceSpecResolver(String name) {
+        this.name = name;
+        this.prefix = name + PREFIX_DELIMITER;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return type.startsWith(prefix) && canResolve(type, loader);
+    }
+
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        return true;
+    }
+
+    protected String getLocalType(String type) {
+        return Strings.removeFromStart(type, prefix);
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+    }
+
+    @Override
+    public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
new file mode 100644
index 0000000..f05355a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
@@ -0,0 +1,108 @@
+/*
+ * 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.resolve;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+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.mgmt.ManagementContext;
+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.mgmt.persist.DeserializingClassRenamesProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+
+public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class);
+
+    private static final String RESOLVER_NAME = "catalog";
+
+    public CatalogServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+        if (item != null) {
+            try {
+                //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items.
+                checkUsable(item);
+                return true;
+            } catch (IllegalStateException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> parentEncounteredTypes) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+
+        if (item == null) return null;
+        checkUsable(item);
+
+        //Take the symbolicName part of the catalog item only for recursion detection to prevent
+        //cross referencing of different versions. Not interested in non-catalog item types.
+        //Prevent catalog items self-referencing even if explicitly different version.
+        boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
+        if (nonRecursiveCall) {
+            // Make a copy of the encountered types, so that we add the item being resolved for
+            // dependency items only. Siblings must not see we are resolving this item.
+            Set<String> encounteredTypes = ImmutableSet.<String>builder()
+                    .addAll(parentEncounteredTypes)
+                    .add(item.getSymbolicName())
+                    .build();
+
+            // CatalogItem generics are just getting in the way, better get rid of them, we
+            // are casting anyway.
+            @SuppressWarnings({ "rawtypes" })
+            CatalogItem rawItem = item;
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, encounteredTypes);
+            return (EntitySpec<?>) rawSpec;
+        } else {
+            return null;
+        }
+    }
+
+    private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) {
+        if (item.isDisabled()) {
+            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        } else if (item.isDeprecated()) {
+            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        }
+    }
+
+    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) {
+        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
+        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
new file mode 100644
index 0000000..6dc7b87
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
@@ -0,0 +1,127 @@
+/*
+ * 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.resolve;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+public class DelegatingServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_PREFIX_CATALOG = "catalog:";
+
+    private static final String RESOLVER_PREFIX_JAVA = "java:";
+
+    private static final Logger log = LoggerFactory.getLogger(DelegatingServiceSpecResolver.class);
+
+    private static final String RESOLVER_NAME = "brooklyn";
+
+    private Collection<ServiceSpecResolver> resolvers;
+
+    public DelegatingServiceSpecResolver(@Nonnull List<ServiceSpecResolver> resolvers) {
+        super(RESOLVER_NAME);
+        this.resolvers = resolvers;
+    }
+
+    protected static ImmutableList<ServiceSpecResolver> getRegisteredResolvers() {
+        return ImmutableList.copyOf(ServiceLoader.load(ServiceSpecResolver.class));
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return accepts("", type, loader) ||
+                accepts(RESOLVER_PREFIX_CATALOG, type, loader) ||
+                accepts(RESOLVER_PREFIX_JAVA, type, loader);
+    }
+
+    private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) {
+        for (ServiceSpecResolver resolver : resolvers) {
+            String localType = getLocalType(type);
+            if (resolver.accepts(prefix + localType, loader)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+
+        EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes);
+    }
+
+    private EntitySpec<?> resolve(
+            Collection<ServiceSpecResolver> resolvers,
+            String localType,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredTypes) {
+        Collection<String> resolversWhoDontSupport = new ArrayList<String>();
+        Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>();
+
+        for (ServiceSpecResolver resolver : resolvers) {
+            if (resolver.accepts(localType, loader)) {
+                try {
+                    EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes);
+                    if (spec != null) {
+                        return spec;
+                    } else {
+                        resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
+                    }
+                } catch (Exception e) {
+                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
+                            Exceptions.collapseText(e), e));
+                }
+            }
+        }
+        if (!otherProblemsFromResolvers.isEmpty()) {
+            // at least one thought he could do it
+            log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers);
+            throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) :
+                Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers);
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass() + "[" + resolvers + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
new file mode 100644
index 0000000..af5ee5f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
@@ -0,0 +1,91 @@
+/*
+ * 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.resolve;
+
+import java.util.List;
+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.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Reflections;
+
+public class JavaServiceSpecResolver extends AbstractServiceSpecResolver{
+    private static final String RESOLVER_NAME = "java";
+
+    public JavaServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        Maybe<?> javaType = tryLoadJavaType(localType, loader);
+        return javaType.isPresent();
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        try {
+            return resolveInternal(localType, loader);
+        } catch (Exception e) {
+            boolean firstOccurrence = encounteredTypes.add(localType);
+            boolean recursiveButTryJava = !firstOccurrence;
+            if (recursiveButTryJava) {
+                throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) {
+        Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader);
+        if (javaTypeMaybe.isAbsent())
+            throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException());
+        Class<? extends Entity> javaType = javaTypeMaybe.get();
+
+        EntitySpec<? extends Entity> spec;
+        if (javaType.isInterface()) {
+            spec = EntitySpec.create(javaType);
+        } else {
+            // If this is a concrete class, particularly for an Application class, we want the proxy
+            // to expose all interfaces it implements.
+            Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class;
+            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType);
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz)
+                .impl((Class) javaType)
+                .additionalInterfaces(additionalInterfaceClazzes);
+            spec = rawSpec;
+        }
+        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
+
+        return spec;
+    }
+
+    private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) {
+        return loader.tryLoadClass(localType, Entity.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
new file mode 100644
index 0000000..5e30cfa
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
@@ -0,0 +1,55 @@
+/*
+ * 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.resolve;
+
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+
+/**
+ * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
+ * <p>
+ * The resolver implementation will use the rest of the local part of the service type information
+ * to create and decorate an appropriate {@link EntitySpec entity}.
+ * <p>
+ * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries
+ * to add extra service type implementations that will be picked up at runtime.
+ */
+public interface ServiceSpecResolver extends ManagementContextInjectable {
+    /**
+     * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time.
+     * For implementations: this usually matches the service type prefix, but not required.
+     */
+    String getName();
+
+    /**
+     * @return if the resolver can create a spec for the service type
+     */
+    boolean accepts(String type, BrooklynClassLoadingContext loader);
+
+    /**
+     * Create a spec for the service type
+     */
+    @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
new file mode 100644
index 0000000..df57859
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
@@ -0,0 +1,20 @@
+#
+# 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.resolve.CatalogServiceSpecResolver
+org.apache.brooklyn.core.resolve.JavaServiceSpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java
new file mode 100644
index 0000000..ea774c1
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.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.entity.resolve;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
+import org.apache.brooklyn.entity.chef.ChefConfig;
+import org.apache.brooklyn.entity.chef.ChefEntity;
+
+public class ChefServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_NAME = "chef";
+
+    public ChefServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        return EntitySpec.create(ChefEntity.class)
+                .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
new file mode 100644
index 0000000..7a073de
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
@@ -0,0 +1,96 @@
+/*
+ * 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.entity.resolve;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
+import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
+import org.apache.brooklyn.entity.java.VanillaJavaApp;
+import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Converter;
+import com.google.common.collect.ImmutableMap;
+
+public class HardcodedCatalogServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_NAME = "catalog";
+
+    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
+            .put("cluster", DynamicCluster.class.getName())
+            .put("fabric", DynamicRegionsFabric.class.getName())
+            .put("vanilla", VanillaSoftwareProcess.class.getName())
+            .put("software-process", VanillaSoftwareProcess.class.getName())
+            .put("java-app", VanillaJavaApp.class.getName())
+            .put("brooklyn-node", BrooklynNode.class.getName())
+            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
+            .build();
+
+    // Allow catalog-type or CatalogType as service type string
+    private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN);
+
+    public HardcodedCatalogServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        return specType != null;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        if (specType != null) {
+            return buildSpec(specType);
+        } else {
+            return null;
+        }
+    }
+
+    private String getImplementation(String type) {
+        String specType = CATALOG_TYPES.get(type);
+        if (specType != null) {
+            return specType;
+        } else {
+            return CATALOG_TYPES.get(FMT.convert(type));
+        }
+    }
+
+    private EntitySpec<?> buildSpec(String specType) {
+        // TODO is this hardcoded list deprecated? If so log a warning.
+        try {
+            @SuppressWarnings("unchecked")
+            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
+            return EntitySpec.create(specClass);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver b/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
new file mode 100644
index 0000000..d3471e0
--- /dev/null
+++ b/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
@@ -0,0 +1,20 @@
+#
+# 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.entity.resolve.ChefServiceSpecResolver
+org.apache.brooklyn.entity.resolve.HardcodedCatalogServiceSpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index b57d4df..9c0e9c6 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -36,8 +36,7 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DelegatingServiceSpecResolver;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.service.CampServiceSpecResolver;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolverAdaptor;
 import org.apache.brooklyn.camp.spi.AbstractResource;
@@ -51,6 +50,7 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
@@ -94,7 +94,7 @@ public class BrooklynComponentTemplateResolver {
         this.template = Maybe.fromNullable(optionalTemplate);
         this.yamlLoader = new BrooklynYamlTypeInstantiator.Factory(loader, this);
         this.type = type;
-        this.serviceSpecResolver = new DelegatingServiceSpecResolver(mgmt, getServiceTypeResolverOverrides());
+        this.serviceSpecResolver = new CampServiceSpecResolver(mgmt, getServiceTypeResolverOverrides());
     }
 
     // Deprecated because want to keep as much of the state private as possible
@@ -153,21 +153,21 @@ public class BrooklynComponentTemplateResolver {
 
         if (spec == null) {
             // Try to provide some troubleshooting details
-            String msgDetails = "";
+            final String msgDetails;
             CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, Strings.removeFromStart(type, "catalog:"));
+            String proto = Urls.getProtocol(type);
             if (item != null && encounteredCatalogTypes.contains(item.getSymbolicName())) {
                 msgDetails = "Cycle between catalog items detected, starting from " + type +
                         ". Other catalog items being resolved up the stack are " + encounteredCatalogTypes +
                         ". Tried loading it as a Java class instead but failed.";
+            } else if (proto != null) {
+                msgDetails = "The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
+                        proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
+                        "Not a catalog item or java type as well.";
             } else {
-                String proto = Urls.getProtocol(type);
-                if (proto != null) {
-                    msgDetails = "The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
-                            proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
-                            "Not a catalog item or java type as well.";
-                }
+                msgDetails = "No resolver knew how to handle it. Using resolvers: " + serviceSpecResolver;
             }
-            throw new IllegalStateException("Unable to create spec for type " + type + ". No resolver knew how to handle it. " + msgDetails);
+            throw new IllegalStateException("Unable to create spec for type " + type + ". " + msgDetails);
         }
 
         populateSpec(spec, encounteredCatalogTypes);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
deleted file mode 100644
index 3fb3c89..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
+++ /dev/null
@@ -1,65 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.text.Strings;
-
-public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver {
-    private static final String PREFIX_DELIMITER = ":";
-    protected final String name;
-    protected final String prefix;
-    protected ManagementContext mgmt;
-
-    public AbstractServiceSpecResolver(String name) {
-        this.name = name;
-        this.prefix = name + PREFIX_DELIMITER;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
-        return type.startsWith(prefix) && canResolve(type, loader);
-    }
-
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        return true;
-    }
-
-    protected String getLocalType(String type) {
-        return Strings.removeFromStart(type, prefix);
-    }
-
-    @Override
-    public void injectManagementContext(ManagementContext mgmt) {
-        this.mgmt = mgmt;
-    }
-
-    @Override
-    public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
new file mode 100644
index 0000000..143f088
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
@@ -0,0 +1,47 @@
+/*
+ * 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.service;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.resolve.DelegatingServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+
+import com.google.common.collect.ImmutableList;
+
+public class CampServiceSpecResolver extends DelegatingServiceSpecResolver {
+
+    public CampServiceSpecResolver(ManagementContext mgmt, List<ServiceSpecResolver> overridingResolvers) {
+        super(getCampResolvers(mgmt, overridingResolvers));
+    }
+
+    private static List<ServiceSpecResolver> getCampResolvers(ManagementContext mgmt, List<ServiceSpecResolver> overridingResolvers) {
+        List<ServiceSpecResolver> resolvers = ImmutableList.<ServiceSpecResolver>builder()
+                .addAll(overridingResolvers)
+                .addAll(getRegisteredResolvers())
+                .add(new UrlServiceSpecResolver())
+                .build();
+        for (ServiceSpecResolver resolver : resolvers) {
+            resolver.injectManagementContext(mgmt);
+        }
+        return resolvers;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
deleted file mode 100644
index 81207ee..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
+++ /dev/null
@@ -1,118 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.catalog.CatalogItem;
-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.mgmt.ManagementContext;
-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.mgmt.persist.DeserializingClassRenamesProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableSet;
-
-public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class);
-
-    private static final String RESOLVER_NAME = "catalog";
-    private final ServiceSpecResolver hardcodedResolver;
-    
-    public CatalogServiceSpecResolver() {
-        super(RESOLVER_NAME);
-        hardcodedResolver = new HardcodedCatalogServiceSpecResolver();
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
-        if (item != null) {
-            try {
-                //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items.
-                checkUsable(item);
-                return true;
-            } catch (IllegalStateException e) {
-                return false;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> parentEncounteredTypes) {
-        String localType = getLocalType(type);
-        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
-        if (item != null) {
-            checkUsable(item);
-
-            //Take the symbolicName part of the catalog item only for recursion detection to prevent
-            //cross referencing of different versions. Not interested in non-catalog item types.
-            //Prevent catalog items self-referencing even if explicitly different version.
-            boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
-            if (nonRecursiveCall) {
-                // Make a copy of the encountered types, so that we add the item being resolved for
-                // dependency items only. Siblings must not see we are resolving this item.
-                Set<String> encounteredTypes = ImmutableSet.<String>builder()
-                        .addAll(parentEncounteredTypes)
-                        .add(item.getSymbolicName())
-                        .build();
-
-                // CatalogItem generics are just getting in the way, better get rid of them, we
-                // are casting anyway.
-                @SuppressWarnings({ "rawtypes" })
-                CatalogItem rawItem = item;
-                @SuppressWarnings({ "rawtypes", "unchecked" })
-                AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, encounteredTypes);
-                return (EntitySpec<?>) rawSpec;
-            } else {
-                return null;
-            }
-        } else {
-            return hardcodedResolver.resolve(type, loader, parentEncounteredTypes);
-        }
-    }
-
-    private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) {
-        if (item.isDisabled()) {
-            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        } else if (item.isDeprecated()) {
-            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        }
-    }
-
-    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) {
-        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
-        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
-    }
-
-    @Override
-    public void injectManagementContext(ManagementContext mgmt) {
-        super.injectManagementContext(mgmt);
-        hardcodedResolver.injectManagementContext(mgmt);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java
deleted file mode 100644
index 1910971..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java
+++ /dev/null
@@ -1,41 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.entity.chef.ChefConfig;
-import org.apache.brooklyn.entity.chef.ChefEntity;
-
-public class ChefServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_NAME = "chef";
-
-    public ChefServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        return EntitySpec.create(ChefEntity.class)
-                .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
deleted file mode 100644
index e1a2f19..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
+++ /dev/null
@@ -1,127 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableList;
-
-public class DelegatingServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_PREFIX_CATALOG = "catalog:";
-
-    private static final String RESOLVER_PREFIX_JAVA = "java:";
-
-    private static final Logger log = LoggerFactory.getLogger(DelegatingServiceSpecResolver.class);
-
-    private static final String RESOLVER_NAME = "brooklyn";
-
-    private Collection<ServiceSpecResolver> resolvers;
-
-    public DelegatingServiceSpecResolver(@Nonnull ManagementContext mgmt, @Nonnull List<ServiceSpecResolver> overridingResolvers) {
-        super(RESOLVER_NAME);
-        this.resolvers = ImmutableList.<ServiceSpecResolver>builder()
-                .addAll(overridingResolvers)
-                .addAll(ServiceLoader.load(ServiceSpecResolver.class))
-                .build();
-        for (ServiceSpecResolver resolver : resolvers) {
-            resolver.injectManagementContext(mgmt);
-        }
-
-        injectManagementContext(mgmt);
-    }
-
-    @Override
-    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
-        return accepts("", type, loader) ||
-                accepts(RESOLVER_PREFIX_CATALOG, type, loader) ||
-                accepts(RESOLVER_PREFIX_JAVA, type, loader);
-    }
-
-    private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) {
-        for (ServiceSpecResolver resolver : resolvers) {
-            String localType = getLocalType(type);
-            if (resolver.accepts(prefix + localType, loader)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-
-        EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes);
-        if (spec != null) {
-            return spec;
-        }
-        spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes);
-        if (spec != null) {
-            return spec;
-        }
-        return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes);
-    }
-
-    private EntitySpec<?> resolve(
-            Collection<ServiceSpecResolver> resolvers,
-            String localType,
-            BrooklynClassLoadingContext loader,
-            Set<String> encounteredTypes) {
-        Collection<String> resolversWhoDontSupport = new ArrayList<String>();
-        Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>();
-
-        for (ServiceSpecResolver resolver : resolvers) {
-            if (resolver.accepts(localType, loader)) {
-                try {
-                    EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes);
-                    if (spec != null) {
-                        return spec;
-                    } else {
-                        resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
-                    }
-                } catch (Exception e) {
-                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
-                            Exceptions.collapseText(e), e));
-                }
-            }
-        }
-        if (!otherProblemsFromResolvers.isEmpty()) {
-            // at least one thought he could do it
-            log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers);
-            throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) :
-                Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers);
-        }
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
deleted file mode 100644
index 2a3d7cd..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
+++ /dev/null
@@ -1,95 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
-import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
-import org.apache.brooklyn.entity.java.VanillaJavaApp;
-import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
-
-import com.google.common.base.CaseFormat;
-import com.google.common.base.Converter;
-import com.google.common.collect.ImmutableMap;
-
-public class HardcodedCatalogServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_NAME = "catalog";
-
-    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
-            .put("cluster", DynamicCluster.class.getName())
-            .put("fabric", DynamicRegionsFabric.class.getName())
-            .put("vanilla", VanillaSoftwareProcess.class.getName())
-            .put("software-process", VanillaSoftwareProcess.class.getName())
-            .put("java-app", VanillaJavaApp.class.getName())
-            .put("brooklyn-node", BrooklynNode.class.getName())
-            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
-            .build();
-
-    // Allow catalog-type or CatalogType as service type string
-    private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN);
-
-    public HardcodedCatalogServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        return specType != null;
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        if (specType != null) {
-            return buildSpec(specType);
-        } else {
-            return null;
-        }
-    }
-
-    private String getImplementation(String type) {
-        String specType = CATALOG_TYPES.get(type);
-        if (specType != null) {
-            return specType;
-        } else {
-            return CATALOG_TYPES.get(FMT.convert(type));
-        }
-    }
-
-    private EntitySpec<?> buildSpec(String specType) {
-        // TODO is this hardcoded list deprecated? If so log a warning.
-        try {
-            @SuppressWarnings("unchecked")
-            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
-            return EntitySpec.create(specClass);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
deleted file mode 100644
index fa0f9e5..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
+++ /dev/null
@@ -1,91 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.List;
-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.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.javalang.Reflections;
-
-public class JavaServiceSpecResolver extends AbstractServiceSpecResolver{
-    private static final String RESOLVER_NAME = "java";
-
-    public JavaServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        Maybe<?> javaType = tryLoadJavaType(localType, loader);
-        return javaType.isPresent();
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-        try {
-            return resolveInternal(localType, loader);
-        } catch (Exception e) {
-            boolean firstOccurrence = encounteredTypes.add(localType);
-            boolean recursiveButTryJava = !firstOccurrence;
-            if (recursiveButTryJava) {
-                throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e);
-            } else {
-                throw e;
-            }
-        }
-    }
-
-    private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) {
-        Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader);
-        if (javaTypeMaybe.isAbsent())
-            throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException());
-        Class<? extends Entity> javaType = javaTypeMaybe.get();
-
-        EntitySpec<? extends Entity> spec;
-        if (javaType.isInterface()) {
-            spec = EntitySpec.create(javaType);
-        } else {
-            // If this is a concrete class, particularly for an Application class, we want the proxy
-            // to expose all interfaces it implements.
-            Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class;
-            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType);
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz)
-                .impl((Class) javaType)
-                .additionalInterfaces(additionalInterfaceClazzes);
-            spec = rawSpec;
-        }
-        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
-
-        return spec;
-    }
-
-    private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) {
-        return loader.tryLoadClass(localType, Entity.class);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
deleted file mode 100644
index 00d6dd5..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
+++ /dev/null
@@ -1,56 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-
-/**
- * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
- * <p>
- * The resolver implementation will use the rest of the local part of the service type information
- * to create and decorate an appropriate {@link EntitySpec entity}.
- * <p>
- * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries
- * to add extra service type implementations that will be picked up at runtime.
- */
-// TODO Not CAMP specific, move to core, to be reused by other parsers
-public interface ServiceSpecResolver extends ManagementContextInjectable {
-    /**
-     * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time.
-     * For implementations: this usually matches the service type prefix, but not required.
-     */
-    String getName();
-
-    /**
-     * @return if the resolver can create a spec for the service type
-     */
-    boolean accepts(String type, BrooklynClassLoadingContext loader);
-
-    /**
-     * Create a spec for the service type
-     */
-    @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
index c1399ff..da472c6 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
+import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
 
 /**
  * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
index 60abd40..7b52977 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
@@ -23,6 +23,8 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
index 2e704ee..b55c064 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
@@ -26,11 +26,13 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampUtils;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.net.Urls;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/** Specific to CAMP because linked plans are assumed to be CAMP format. No type discovery available. */
 public class UrlServiceSpecResolver implements ServiceSpecResolver {
     private static final Logger log = LoggerFactory.getLogger(UrlServiceSpecResolver.class);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
deleted file mode 100644
index fa6ca8d..0000000
--- a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
+++ /dev/null
@@ -1,23 +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.
-#
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceSpecResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceSpecResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.HardcodedCatalogServiceSpecResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceSpecResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.UrlServiceSpecResolver
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
index 4953ba3..8b7a04e 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -23,15 +23,15 @@ import java.io.StringReader;
 import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
 import org.apache.brooklyn.camp.spi.Assembly;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.util.core.ResourceUtils;
@@ -144,6 +144,10 @@ public abstract class AbstractYamlTest {
         return app;
     }
 
+    protected EntitySpec<?> createEntitySpec(String... yaml) {
+        return EntityManagementUtils.createEntitySpecForApplication(mgmt(), joinLines(yaml));
+    }
+
     protected void addCatalogItems(Iterable<String> catalogYaml) {
         addCatalogItems(joinLines(catalogYaml));
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/883feaea/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index 9699b8e..f0c6e90 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -26,8 +26,6 @@ import java.io.InputStream;
 import java.util.Collection;
 import java.util.List;
 
-import org.testng.Assert;
-import org.testng.annotations.Test;
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
@@ -42,6 +40,8 @@ import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 import com.google.common.collect.Iterables;
 
@@ -783,7 +783,16 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
         Entity testEntity = Iterables.getOnlyElement(app.getChildren());
         assertEquals(testEntity.config().get(TestEntity.CONF_NAME), testName);
     }
-    
+
+    @Test
+    public void testHardcodedCatalog() throws Exception {
+        createEntitySpec(
+                "services:",
+                "- type: cluster",
+                "- type: vanilla",
+                "- type: web-app-cluster");
+    }
+
     private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType) throws Exception {
         addCatalogOSGiEntity(symbolicName, serviceType);
         String yaml = "name: simple-app-yaml\n" +


[08/16] incubator-brooklyn git commit: Fix catalog items recursive check

Posted by sj...@apache.org.
Fix catalog items recursive check

Identical sibling items shouldn't trigger the recursive check abort.


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

Branch: refs/heads/master
Commit: 73d279097d7a15eb7902c587ee2d5b4400c207b1
Parents: 073c203
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 15:35:40 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:11:07 2015 +0300

----------------------------------------------------------------------
 .../core/mgmt/EntityManagementUtils.java        |  4 ++--
 .../BrooklynAssemblyTemplateInstantiator.java   |  4 ++--
 .../BrooklynComponentTemplateResolver.java      | 25 ++++++++++++++------
 .../brooklyn/spi/creation/CampCatalogUtils.java | 11 +++++++--
 .../service/CatalogServiceSpecResolver.java     | 16 +++++++++----
 .../brooklyn/catalog/CatalogYamlEntityTest.java | 21 ++++++++++++++++
 6 files changed, 64 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index cda3f5b..0dca83c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -44,7 +44,6 @@ import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.TaskBuilder;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.text.Strings;
@@ -57,6 +56,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 
@@ -99,7 +99,7 @@ public class EntityManagementUtils {
     }
 
     public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, CatalogItem<T, SpecT> item) {
-        return createCatalogSpec(mgmt, item, MutableSet.<String>of());
+        return createCatalogSpec(mgmt, item, ImmutableSet.<String>of());
     }
 
     public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item, final Set<String> encounteredTypes) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/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 19aa100..f295e90 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
@@ -39,11 +39,11 @@ 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.entity.stock.BasicApplicationImpl;
-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.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
@@ -90,7 +90,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
 
         BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance(
             loader, buildWrapperAppTemplate(template));
-        EntitySpec<? extends Application> app = resolver.resolveSpec(MutableSet.<String>of());
+        EntitySpec<? extends Application> app = resolver.resolveSpec(ImmutableSet.<String>of());
         app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE);
 
         // first build the children into an empty shell app

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 05252f5..b57d4df 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
@@ -64,6 +65,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
 import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 
@@ -150,13 +152,22 @@ public class BrooklynComponentTemplateResolver {
         EntitySpec<?> spec = serviceSpecResolver.resolve(type, loader, encounteredCatalogTypes);
 
         if (spec == null) {
-            String proto = Urls.getProtocol(type);
-            if (proto != null) {
-                log.debug("The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
-                        proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
-                        "Not a catalog item or java type as well.");
+            // Try to provide some troubleshooting details
+            String msgDetails = "";
+            CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, Strings.removeFromStart(type, "catalog:"));
+            if (item != null && encounteredCatalogTypes.contains(item.getSymbolicName())) {
+                msgDetails = "Cycle between catalog items detected, starting from " + type +
+                        ". Other catalog items being resolved up the stack are " + encounteredCatalogTypes +
+                        ". Tried loading it as a Java class instead but failed.";
+            } else {
+                String proto = Urls.getProtocol(type);
+                if (proto != null) {
+                    msgDetails = "The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
+                            proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
+                            "Not a catalog item or java type as well.";
+                }
             }
-            throw new IllegalStateException("Unable to create spec for type " + type + ". No resolver knew how to handle it.");
+            throw new IllegalStateException("Unable to create spec for type " + type + ". No resolver knew how to handle it. " + msgDetails);
         }
 
         populateSpec(spec, encounteredCatalogTypes);
@@ -352,7 +363,7 @@ public class BrooklynComponentTemplateResolver {
                 @SuppressWarnings("unchecked")
                 Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(specConfig.getSpecConfiguration());
                 specConfig.setSpecConfiguration(resolvedConfig);
-                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(MutableSet.<String>of());
+                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(ImmutableSet.<String>of());
             }
             if (flag instanceof ManagementContextInjectable) {
                 log.debug("Injecting Brooklyn management context info object: {}", flag);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/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 4865241..29791dd 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
@@ -31,10 +31,11 @@ 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;
 
 public class CampCatalogUtils {
 
-    public static AbstractBrooklynObjectSpec<?, ?> createSpec(ManagementContext mgmt, CatalogItem<?, ?> item, Set<String> encounteredTypes) {
+    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;
@@ -43,9 +44,15 @@ public class CampCatalogUtils {
         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.add(item.getSymbolicName());
+            encounteredTypes = ImmutableSet.<String>builder()
+                    .addAll(parentEncounteredTypes)
+                    .add(item.getSymbolicName())
+                    .build();
+        } else {
+            encounteredTypes = parentEncounteredTypes;
         }
 
         AbstractBrooklynObjectSpec<?, ?> spec;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
index 19a76b3..81207ee 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableSet;
+
 public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
     private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class);
 
@@ -61,7 +63,7 @@ public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
     }
 
     @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> parentEncounteredTypes) {
         String localType = getLocalType(type);
         CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
         if (item != null) {
@@ -70,9 +72,15 @@ public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
             //Take the symbolicName part of the catalog item only for recursion detection to prevent
             //cross referencing of different versions. Not interested in non-catalog item types.
             //Prevent catalog items self-referencing even if explicitly different version.
-            boolean firstOccurrence = encounteredTypes.add(item.getSymbolicName());
-            boolean nonRecursiveCall = firstOccurrence;
+            boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
             if (nonRecursiveCall) {
+                // Make a copy of the encountered types, so that we add the item being resolved for
+                // dependency items only. Siblings must not see we are resolving this item.
+                Set<String> encounteredTypes = ImmutableSet.<String>builder()
+                        .addAll(parentEncounteredTypes)
+                        .add(item.getSymbolicName())
+                        .build();
+
                 // CatalogItem generics are just getting in the way, better get rid of them, we
                 // are casting anyway.
                 @SuppressWarnings({ "rawtypes" })
@@ -84,7 +92,7 @@ public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
                 return null;
             }
         } else {
-            return hardcodedResolver.resolve(type, loader, encounteredTypes);
+            return hardcodedResolver.resolve(type, loader, parentEncounteredTypes);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/73d27909/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index 53cd146..9699b8e 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -670,6 +670,27 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
     }
 
     @Test
+    public void testRecursiveCheckForDepenentsOnly() throws Exception {
+        String symbolicName = "my.catalog.app.id.basic";
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName,
+                "  version: " + TEST_VERSION,
+                "",
+                "services:",
+                "- type: org.apache.brooklyn.entity.stock.BasicEntity");
+
+        createAndStartApplication(
+                "services:",
+                "- type: " + ver(symbolicName),
+                "  brooklyn.children:",
+                "  - type: " + ver(symbolicName),
+                "- type: " + ver(symbolicName),
+                "  brooklyn.children:",
+                "  - type: " + ver(symbolicName));
+    }
+
+    @Test
     public void testOsgiNotLeakingToParent() {
         addCatalogOSGiEntity(SIMPLE_ENTITY_TYPE);
         try {


[04/16] incubator-brooklyn git commit: Test ServiceTypeResolver usage

Posted by sj...@apache.org.
Test ServiceTypeResolver usage


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

Branch: refs/heads/master
Commit: 09e9f1acf1f307b0da556ae96a3d2b7f3ef91c03
Parents: 883feae
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 17:07:43 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:11:07 2015 +0300

----------------------------------------------------------------------
 .../resolve/AbstractServiceSpecResolver.java    |  2 +-
 .../BrooklynComponentTemplateResolver.java      | 12 ++---
 .../service/ServiceTypeResolverAdaptor.java     | 10 +++-
 .../camp/brooklyn/AbstractYamlTest.java         |  2 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  2 +-
 .../service/ServiceTypeResolverTest.java        | 39 ++++++++++++++
 .../service/TestServiceTypeResolver.java        | 54 ++++++++++++++++++++
 ...lyn.spi.creation.service.ServiceTypeResolver | 19 +++++++
 8 files changed, 126 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
index 705ed0e..78c796a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
@@ -51,7 +51,7 @@ public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver
     }
 
     protected String getLocalType(String type) {
-        return Strings.removeFromStart(type, prefix);
+        return Strings.removeFromStart(type, prefix).trim();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 9c0e9c6..381b76b 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -179,15 +179,9 @@ public class BrooklynComponentTemplateResolver {
 
     private List<ServiceSpecResolver> getServiceTypeResolverOverrides() {
         List<ServiceSpecResolver> overrides = new ArrayList<>();
-        if (type.indexOf(':') != -1) {
-            String prefix = Splitter.on(":").splitToList(type).get(0);
-            ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class,
-                    mgmt.getCatalogClassLoader());
-            for (ServiceTypeResolver resolver : loader) {
-               if (prefix.equals(resolver.getTypePrefix())) {
-                   overrides.add(new ServiceTypeResolverAdaptor(this, resolver));
-               }
-            }
+        ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class, mgmt.getCatalogClassLoader());
+        for (ServiceTypeResolver resolver : loader) {
+           overrides.add(new ServiceTypeResolverAdaptor(this, resolver));
         }
         return overrides;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
index 7b52977..17f4e2b 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.camp.brooklyn.spi.creation.service;
 
 import java.util.Set;
 
+import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
@@ -28,7 +29,7 @@ import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import groovy.xml.Entity;
+import com.google.common.base.Splitter;
 
 @SuppressWarnings("deprecation")
 public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver {
@@ -44,7 +45,12 @@ public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver {
 
     @Override
     public boolean accepts(String type, BrooklynClassLoadingContext loader) {
-        return true;
+        if (type.indexOf(':') != -1) {
+            String prefix = Splitter.on(":").splitToList(type).get(0);
+            return prefix.equals(serviceTypeResolver.getTypePrefix());
+        } else {
+            return false;
+        }
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
index 8b7a04e..8a858cf 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -144,7 +144,7 @@ public abstract class AbstractYamlTest {
         return app;
     }
 
-    protected EntitySpec<?> createEntitySpec(String... yaml) {
+    protected EntitySpec<?> createAppEntitySpec(String... yaml) {
         return EntityManagementUtils.createEntitySpecForApplication(mgmt(), joinLines(yaml));
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index f0c6e90..b62ba60 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -786,7 +786,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
 
     @Test
     public void testHardcodedCatalog() throws Exception {
-        createEntitySpec(
+        createAppEntitySpec(
                 "services:",
                 "- type: cluster",
                 "- type: vanilla",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverTest.java
new file mode 100644
index 0000000..cbaccf0
--- /dev/null
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn.spi.creation.service;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+import org.apache.brooklyn.entity.stock.BasicEntity;
+import org.testng.annotations.Test;
+
+
+public class ServiceTypeResolverTest extends AbstractYamlTest {
+    
+    @Test
+    public void testAddCatalogItemVerySimple() throws Exception {
+        EntitySpec<?> spec = createAppEntitySpec(
+                "services:",
+                "- type: \"test-resolver:" + BasicEntity.class.getName() + "\"");
+        assertEquals(spec.getChildren().get(0).getFlags().get("resolver"), TestServiceTypeResolver.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/TestServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/TestServiceTypeResolver.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/TestServiceTypeResolver.java
new file mode 100644
index 0000000..7fd6d8a
--- /dev/null
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/TestServiceTypeResolver.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn.spi.creation.service;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.util.text.Strings;
+
+@SuppressWarnings("deprecation")
+public class TestServiceTypeResolver implements ServiceTypeResolver {
+
+    private static final String PREFIX = "test-resolver";
+
+    @Override
+    public String getTypePrefix() {
+        return PREFIX;
+    }
+
+    @Override
+    public String getBrooklynType(String serviceType) {
+        return Strings.removeFromStart(serviceType, PREFIX + ":");
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public CatalogItem<Entity, EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) {
+        return (CatalogItem<Entity, EntitySpec<?>>) CatalogUtils.getCatalogItemOptionalVersion(resolver.getManagementContext(), getBrooklynType(serviceType));
+    }
+
+    @Override
+    public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) {
+        spec.configure("resolver", TestServiceTypeResolver.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09e9f1ac/usage/camp/src/test/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver b/usage/camp/src/test/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
new file mode 100644
index 0000000..3bba7fb
--- /dev/null
+++ b/usage/camp/src/test/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
@@ -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.camp.brooklyn.spi.creation.service.TestServiceTypeResolver
\ No newline at end of file


[15/16] incubator-brooklyn git commit: Move policy & location resolving logic to core, allowing it to be reused

Posted by sj...@apache.org.
Move policy & location resolving logic to core, allowing it to be reused


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

Branch: refs/heads/master
Commit: 87e339586b4e79cababcfb509f0dfaf04c682fb9
Parents: 5d0c765
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 15 13:15:51 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 15 13:33:03 2015 +0300

----------------------------------------------------------------------
 .../brooklyn/core/resolve/ResolveUtils.java     | 87 ++++++++++++++++++++
 .../camp/brooklyn/spi/creation/CampUtils.java   | 39 +--------
 2 files changed, 90 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/87e33958/core/src/main/java/org/apache/brooklyn/core/resolve/ResolveUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/ResolveUtils.java b/core/src/main/java/org/apache/brooklyn/core/resolve/ResolveUtils.java
new file mode 100644
index 0000000..c3fc85f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/ResolveUtils.java
@@ -0,0 +1,87 @@
+/*
+ * 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.resolve;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+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.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
+import org.apache.brooklyn.util.guava.Maybe;
+
+public class ResolveUtils {
+
+    @SuppressWarnings("unchecked")
+    public static PolicySpec<? extends Policy> resolveSpec(
+            String versionedId,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredCatalogTypes) {
+        PolicySpec<? extends Policy> spec;
+        CatalogItem<?, ?> policyItem = CatalogUtils.getCatalogItemOptionalVersion(loader.getManagementContext(), versionedId);
+        if (policyItem != null && !encounteredCatalogTypes.contains(policyItem.getSymbolicName())) {
+            if (policyItem.getCatalogItemType() != CatalogItemType.POLICY) {
+                throw new IllegalStateException("Non-policy catalog item in policy context: " + policyItem);
+            }
+            @SuppressWarnings("rawtypes")
+            CatalogItem rawItem = policyItem;
+            spec = (PolicySpec<? extends Policy>) EntityManagementUtils.createCatalogSpec(loader.getManagementContext(), rawItem, encounteredCatalogTypes);
+        } else {
+            spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class));
+        }
+        return spec;
+    }
+
+    public 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/87e33958/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
index 289fb97..f3050c5 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
@@ -25,8 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
@@ -41,9 +39,9 @@ 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.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
+import org.apache.brooklyn.core.resolve.ResolveUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.stream.Streams;
@@ -110,16 +108,7 @@ public class CampUtils {
         }
 
         String versionedId = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "policy_type", "policyType", "type"), "policy type");
-        PolicySpec<? extends Policy> spec;
-        CatalogItem<?, ?> policyItem = CatalogUtils.getCatalogItemOptionalVersion(loader.getManagementContext(), versionedId);
-        if (policyItem != null && !encounteredCatalogTypes.contains(policyItem.getSymbolicName())) {
-            if (policyItem.getCatalogItemType() != CatalogItemType.POLICY) {
-                throw new IllegalStateException("Non-policy catalog item in policy context: " + policyItem);
-            }
-            spec = (PolicySpec<? extends Policy>) CampCatalogUtils.createSpec(loader.getManagementContext(), policyItem, encounteredCatalogTypes);
-        } else {
-            spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class));
-        }
+        PolicySpec<? extends Policy> spec = ResolveUtils.resolveSpec(versionedId, loader, encounteredCatalogTypes);
         Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config");
         if (brooklynConfig != null) {
             spec.configure(brooklynConfig);
@@ -152,29 +141,7 @@ public class CampUtils {
 
         String type = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "location_type", "locationType", "type"), "location type");
         Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config");
-        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);
-            }
-        }
+        return ResolveUtils.resolveLocationSpec(type, brooklynConfig, loader);
     }
 
     public static DeploymentPlan makePlanFromYaml(ManagementContext mgmt, String yaml) {


[16/16] incubator-brooklyn git commit: This closes #955

Posted by sj...@apache.org.
This closes #955


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

Branch: refs/heads/master
Commit: d53bd189cf5db6a722e49fb60e4a3bf8f283b3da
Parents: b0cadef 87e3395
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Thu Oct 15 15:01:57 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Thu Oct 15 15:01:57 2015 +0100

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  |  28 +-
 .../internal/JavaCatalogToSpecTransformer.java  |  98 +++++++
 .../core/mgmt/EntityManagementUtils.java        |  13 +-
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   2 +-
 .../core/plan/PlanToSpecTransformer.java        |  10 +-
 .../brooklyn/core/resolve/ResolveUtils.java     |  87 ++++++
 .../entity/AbstractEntitySpecResolver.java      |  65 +++++
 .../entity/CatalogEntitySpecResolver.java       |  99 +++++++
 .../entity/DelegatingEntitySpecResolver.java    | 127 ++++++++
 .../core/resolve/entity/EntitySpecResolver.java |  67 +++++
 .../resolve/entity/JavaEntitySpecResolver.java  |  91 ++++++
 ...che.brooklyn.core.plan.PlanToSpecTransformer |  19 ++
 ...oklyn.core.resolve.entity.EntitySpecResolver |  20 ++
 .../core/plan/XmlPlanToSpecTransformer.java     |   3 +-
 .../entity/resolve/ChefEntitySpecResolver.java  |  42 +++
 .../HardcodedCatalogEntitySpecResolver.java     |  96 ++++++
 ...oklyn.core.resolve.entity.EntitySpecResolver |  20 ++
 usage/camp/pom.xml                              |   5 -
 .../camp/brooklyn/BrooklynCampConstants.java    |   2 +-
 .../api/AssemblyTemplateSpecInstantiator.java   |  13 +-
 .../BrooklynAssemblyTemplateInstantiator.java   | 173 ++---------
 .../BrooklynComponentTemplateResolver.java      | 289 +++++--------------
 .../spi/creation/BrooklynEntityMatcher.java     |  15 +-
 .../brooklyn/spi/creation/CampCatalogUtils.java | 204 ++-----------
 .../spi/creation/CampToSpecTransformer.java     |  41 +--
 .../camp/brooklyn/spi/creation/CampUtils.java   | 161 +++++++++++
 .../service/BrooklynServiceTypeResolver.java    |  12 +-
 .../service/CampServiceSpecResolver.java        |  47 +++
 .../service/CatalogServiceTypeResolver.java     |  77 -----
 .../service/ChefServiceTypeResolver.java        |  61 ----
 .../service/JavaServiceTypeResolver.java        |  38 ---
 .../creation/service/ServiceTypeResolver.java   |   4 +
 .../service/ServiceTypeResolverAdaptor.java     |  70 +++++
 .../service/UrlServiceSpecResolver.java         |  72 +++++
 ...lyn.spi.creation.service.ServiceTypeResolver |  22 --
 .../camp/brooklyn/AbstractYamlTest.java         |   8 +-
 .../brooklyn/catalog/CatalogXmlOsgiTest.java    |  16 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java | 110 ++++++-
 .../service/ServiceTypeResolverTest.java        |  39 +++
 .../service/TestServiceTypeResolver.java        |  54 ++++
 .../test/lite/TestAppAssemblyInstantiator.java  |  12 +-
 ...lyn.spi.creation.service.ServiceTypeResolver |  19 ++
 .../rest/resources/ApplicationResource.java     |   4 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   2 +
 44 files changed, 1617 insertions(+), 840 deletions(-)
----------------------------------------------------------------------



[06/16] incubator-brooklyn git commit: Split BrooklynComponentTemplateResolver into independent ServiceSpecResolver

Posted by sj...@apache.org.
Split BrooklynComponentTemplateResolver into independent ServiceSpecResolver

ServiceSpecResolver is not specific to CAMP, it deals with converting a type (i.e. a catalog item, a java class, chef declaration) to a spec. BrooklynComponentTemplateResolver then takes the spec and applies the CAMP config on it.


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

Branch: refs/heads/master
Commit: 4485fe5c212ee5fddf4e6452c9fb17b77429b5b5
Parents: c71d722
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 15:02:26 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:11:07 2015 +0300

----------------------------------------------------------------------
 .../internal/JavaCatalogToSpecTransformer.java  |  13 +-
 .../core/mgmt/EntityManagementUtils.java        |   4 +-
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   2 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |  12 +-
 .../BrooklynComponentTemplateResolver.java      | 264 ++++---------------
 .../spi/creation/CampToSpecTransformer.java     |  17 +-
 .../service/AbstractServiceSpecResolver.java    |  65 +++++
 .../service/BrooklynServiceTypeResolver.java    |  80 ------
 .../service/CatalogServiceSpecResolver.java     | 110 ++++++++
 .../service/CatalogServiceTypeResolver.java     |  77 ------
 .../service/ChefServiceSpecResolver.java        |  41 +++
 .../service/ChefServiceTypeResolver.java        |  61 -----
 .../service/DefaultServiceTypeResolver.java     |  23 --
 .../service/DelegatingServiceSpecResolver.java  | 127 +++++++++
 .../HardcodedCatalogServiceSpecResolver.java    |  95 +++++++
 .../service/JavaServiceSpecResolver.java        |  91 +++++++
 .../service/JavaServiceTypeResolver.java        |  38 ---
 .../creation/service/ServiceSpecResolver.java   |  56 ++++
 .../creation/service/ServiceTypeResolver.java   |   3 +
 .../service/ServiceTypeResolverAdaptor.java     |  62 +++++
 .../service/UrlServiceSpecResolver.java         |  70 +++++
 ...lyn.spi.creation.service.ServiceSpecResolver |  23 ++
 ...lyn.spi.creation.service.ServiceTypeResolver |  22 --
 .../brooklyn/catalog/CatalogXmlOsgiTest.java    |  16 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  49 +++-
 .../rest/resources/ApplicationResource.java     |   4 +-
 26 files changed, 882 insertions(+), 543 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
index 9b4a83c..a6a8e3a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
@@ -34,6 +34,11 @@ import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Old-style catalog items (can be defined in catalog.xml only) don't have structure, only a single type, so
+ * they are loaded as a simple java type, only taking the class name from the catalog item instead of the
+ * type value in the YAML. Classpath entries in the item are also used (through the catalog root classloader).
+ */
 public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
     private static final Logger log = LoggerFactory.getLogger(JavaCatalogToSpecTransformer.class);
 
@@ -64,8 +69,12 @@ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
             CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException {
         if (item.getJavaType() != null) {
             log.warn("Deprecated functionality (since 0.9.0). Using old-style xml catalog items with java type attribute for " + item);
-            BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item);
-            Class<?> type = loader.loadClass(item.getJavaType());
+            Class<?> type;
+            try {
+                type = mgmt.getCatalogClassLoader().loadClass(item.getJavaType());
+            } catch (ClassNotFoundException e) {
+                throw new IllegalStateException("Unable to load old-style java catalog item type " + item.getJavaType() + " for item " + item, e);
+            }
             AbstractBrooklynObjectSpec<?,?> spec;
             if (Entity.class.isAssignableFrom(type)) {
                 @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index 0dca83c..cda3f5b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -44,6 +44,7 @@ import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.TaskBuilder;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.text.Strings;
@@ -56,7 +57,6 @@ import com.google.common.base.Function;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 
@@ -99,7 +99,7 @@ public class EntityManagementUtils {
     }
 
     public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, CatalogItem<T, SpecT> item) {
-        return createCatalogSpec(mgmt, item, ImmutableSet.<String>of());
+        return createCatalogSpec(mgmt, item, MutableSet.<String>of());
     }
 
     public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item, final Set<String> encounteredTypes) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/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 3328545..1b49170 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
@@ -117,7 +117,7 @@ public class PlanToSpecFactory {
             // at least one thought he could do it
             log.debug("Plan could not be transformed; failure will be propagated (other transformers tried = "+transformersWhoDontSupport+"): "+otherProblemsFromTransformers);
             result = otherProblemsFromTransformers.size()==1 ? Exceptions.create(null, otherProblemsFromTransformers) :
-                Exceptions.create("Plan transformers all failed", otherProblemsFromTransformers);
+                Exceptions.create("All plan transformers failed", otherProblemsFromTransformers);
         } else {
             result = new PlanNotRecognizedException("Invalid plan; format could not be recognized, trying with: "+transformersWhoDontSupport);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/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 e54e2ef..19aa100 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
@@ -39,6 +39,7 @@ 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.entity.stock.BasicApplicationImpl;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -71,10 +72,11 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
     }
 
     @Override
-    public List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template,
+    public List<EntitySpec<?>> createServiceSpecs(
+            AssemblyTemplate template,
             CampPlatform platform, BrooklynClassLoadingContext itemLoader,
             Set<String> encounteredCatalogTypes) {
-        return buildTemplateServicesAsSpecs(itemLoader, template, platform, encounteredCatalogTypes, true);
+        return buildTemplateServicesAsSpecs(itemLoader, template, platform, encounteredCatalogTypes);
     }
 
     @Override
@@ -88,7 +90,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
 
         BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance(
             loader, buildWrapperAppTemplate(template));
-        EntitySpec<? extends Application> app = resolver.resolveSpec(null, false);
+        EntitySpec<? extends Application> app = resolver.resolveSpec(MutableSet.<String>of());
         app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE);
 
         // first build the children into an empty shell app
@@ -124,13 +126,13 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         return EntityManagementUtils.canPromoteWrappedApplication(app);
     }
 
-    private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
+    private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes) {
         List<EntitySpec<?>> result = Lists.newArrayList();
 
         for (ResolvableLink<PlatformComponentTemplate> ctl: template.getPlatformComponentTemplates().links()) {
             PlatformComponentTemplate appChildComponentTemplate = ctl.resolve();
             BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, appChildComponentTemplate);
-            EntitySpec<?> spec = entityResolver.resolveSpec(encounteredCatalogTypes, canUseOtherTransformers);
+            EntitySpec<?> spec = entityResolver.resolveSpec(encounteredCatalogTypes);
             result.add(spec);
         }
         return result;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index f42145d..05252f5 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn.spi.creation;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -28,17 +29,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Nullable;
 
-import org.apache.brooklyn.api.catalog.CatalogItem;
-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.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DefaultServiceTypeResolver;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DelegatingServiceSpecResolver;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolverAdaptor;
 import org.apache.brooklyn.camp.spi.AbstractResource;
 import org.apache.brooklyn.camp.spi.ApplicationComponentTemplate;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
@@ -46,21 +46,17 @@ import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 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.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 import org.apache.brooklyn.util.core.flags.FlagUtils.FlagConfigKeyAndValueRecord;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
@@ -75,6 +71,7 @@ import com.google.common.collect.Maps;
  * This generates instances of a template resolver that use a {@link ServiceTypeResolver}
  * to parse the {@code serviceType} line in the template.
  */
+@SuppressWarnings("deprecation")  // Because of ServiceTypeResolver
 public class BrooklynComponentTemplateResolver {
 
     private static final Logger log = LoggerFactory.getLogger(BrooklynComponentTemplateResolver.class);
@@ -85,47 +82,29 @@ public class BrooklynComponentTemplateResolver {
     private final Maybe<AbstractResource> template;
     private final BrooklynYamlTypeInstantiator.Factory yamlLoader;
     private final String type;
-    private final ServiceTypeResolver typeResolver;
     private final AtomicBoolean alreadyBuilt = new AtomicBoolean(false);
+    private final ServiceSpecResolver serviceSpecResolver;
 
-    private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type, ServiceTypeResolver typeResolver) {
+    private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type) {
         this.loader = loader;
         this.mgmt = loader.getManagementContext();
         this.attrs = ConfigBag.newInstanceCopying(attrs);
         this.template = Maybe.fromNullable(optionalTemplate);
         this.yamlLoader = new BrooklynYamlTypeInstantiator.Factory(loader, this);
         this.type = type;
-        this.typeResolver = typeResolver;
+        this.serviceSpecResolver = new DelegatingServiceSpecResolver(mgmt, getServiceTypeResolverOverrides());
     }
 
-    public ManagementContext getManagementContext() { return mgmt; }
-    public ConfigBag getAttrs() { return attrs; }
-    public BrooklynYamlTypeInstantiator.Factory getYamlLoader() { return yamlLoader; }
-    public String getDeclaredType() { return type; }
+    // Deprecated because want to keep as much of the state private as possible
+    // Can't remove them because used by ServiceTypeResolver implementations
+    /** @deprecated since 0.9.0 */
+    @Deprecated public ManagementContext getManagementContext() { return mgmt; }
+    @Deprecated public ConfigBag getAttrs() { return attrs; }
+    @Deprecated public BrooklynYamlTypeInstantiator.Factory getYamlLoader() { return yamlLoader; }
+    @Deprecated public String getDeclaredType() { return type; }
 
     public static class Factory {
 
-        /** returns resolver type based on the service type, inspecting the arguments in order to determine the service type */
-        private static ServiceTypeResolver computeResolverType(BrooklynClassLoadingContext context, String knownServiceType, AbstractResource optionalTemplate, ConfigBag attrs) {
-            String type = getDeclaredType(knownServiceType, optionalTemplate, attrs);
-            return findService(context, type);
-        }
-
-        // TODO This could be extended to support multiple prefixes per resolver and a 'best-match' algorithm
-        private static ServiceTypeResolver findService(BrooklynClassLoadingContext context, String type) {
-            if (type.indexOf(':') != -1) {
-                String prefix = Splitter.on(":").splitToList(type).get(0);
-                ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class,
-                        context.getManagementContext().getCatalogClassLoader());
-                for (ServiceTypeResolver resolver : loader) {
-                   if (prefix.equals(resolver.getTypePrefix())) {
-                       return resolver;
-                   }
-                }
-            }
-            return null;
-        }
-
         public static BrooklynComponentTemplateResolver newInstance(BrooklynClassLoadingContext context, Map<String, ?> childAttrs) {
             return newInstance(context, ConfigBag.newInstance(childAttrs), null);
         }
@@ -139,11 +118,8 @@ public class BrooklynComponentTemplateResolver {
         }
 
         private static BrooklynComponentTemplateResolver newInstance(BrooklynClassLoadingContext context, ConfigBag attrs, AbstractResource optionalTemplate) {
-            ServiceTypeResolver typeResolver = computeResolverType(context, null, optionalTemplate, attrs);
             String type = getDeclaredType(null, optionalTemplate, attrs);
-            if (typeResolver == null) // use default
-                typeResolver = new DefaultServiceTypeResolver();
-            return new BrooklynComponentTemplateResolver(context, attrs, optionalTemplate, type, typeResolver);
+            return new BrooklynComponentTemplateResolver(context, attrs, optionalTemplate, type);
         }
 
         private static String getDeclaredType(String knownServiceType, AbstractResource optionalTemplate, @Nullable ConfigBag attrs) {
@@ -164,185 +140,49 @@ public class BrooklynComponentTemplateResolver {
     }
 
     public boolean canResolve() {
-        if (!(typeResolver instanceof DefaultServiceTypeResolver)) {
-            return true;
-        }
-
-        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
-        if (item != null) {
-            if (item.isDisabled()) {
-                log.warn("Disallowed attempt to use disabled catalog item "+item.getId());
-                return false;
-            } else if (item.isDeprecated()) {
-                log.warn("Use of deprecated catalog item "+item.getId());
-            }
-            return true;
-        }
-
-        if (tryLoadEntityClass().isPresent()) {
-            return true;
-        }
-
-        String protocol = Urls.getProtocol(type);
-        if (protocol != null) {
-            if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
-                return true;
-            } else {
-                log.debug("The reference '" + type + "' looks like a URL (running the CAMP Brooklyn entity-matcher) but the protocol '" + 
-                        protocol + "' isn't white listed " + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + ". " +
-                        "Not recognized as catalog item or java item as well!");
-            }
-        }
-
-        return true;
-    }
-
-    /** returns the entity class, if needed in contexts which scan its statics for example */
-    private Class<? extends Entity> loadEntityClass() {
-        Maybe<Class<? extends Entity>> result = tryLoadEntityClass();
-        if (result.isAbsent())
-            throw new IllegalStateException("Could not find "+typeResolver.getBrooklynType(type), ((Maybe.Absent<?>)result).getException());
-        return result.get();
-    }
-
-    /** tries to load the Java entity class */
-    private Maybe<Class<? extends Entity>> tryLoadEntityClass() {
-        return loader.tryLoadClass(getJavaType(), Entity.class);
-    }
-
-    // TODO Generalise to have other prefixes (e.g. explicit "catalog:" etc)?
-    private boolean isJavaTypePrefix() {
-        return type != null && (type.toLowerCase().startsWith("java:") || type.toLowerCase().startsWith("brooklyn:java:"));
-    }
-
-    private String getJavaType() {
-        return typeResolver.getBrooklynType(type);
+        return serviceSpecResolver.accepts(type, loader);
     }
 
-    public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
+    public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes) {
         if (alreadyBuilt.getAndSet(true))
             throw new IllegalStateException("Spec can only be used once: "+this);
 
-        String brooklynType = typeResolver.getBrooklynType(type);
-        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
-
-        if (log.isTraceEnabled()) log.trace("Building CAMP template services: type="+brooklynType+"; item="+item+"; loader="+loader+"; encounteredCatalogTypes="+encounteredCatalogTypes);
-
-        // TODO implement as service type
-        EntitySpec<T> spec = null;
-        String protocol = Urls.getProtocol(brooklynType);
-        if (protocol != null) {
-            if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
-                spec = tryResolveYamlUrlReferenceSpec(brooklynType, encounteredCatalogTypes);
-                if (spec != null) {
-                    populateSpec(spec);
-                }
-            } else {
-                // TODO this will probably be logged if we refer to  chef:cookbook  or other service types which BCTR accepts;
-                // better would be to have BCTR supporting the calls above
-                log.debug("The reference " + brooklynType + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
-                        protocol + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
-                        "Will try to load it as catalog item or java type.");
-            }
-        }
+        EntitySpec<?> spec = serviceSpecResolver.resolve(type, loader, encounteredCatalogTypes);
 
         if (spec == null) {
-            // load from java or yaml
-            spec = resolveLocalSpec(encounteredCatalogTypes, canUseOtherTransformers);
+            String proto = Urls.getProtocol(type);
+            if (proto != null) {
+                log.debug("The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
+                        proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
+                        "Not a catalog item or java type as well.");
+            }
+            throw new IllegalStateException("Unable to create spec for type " + type + ". No resolver knew how to handle it.");
         }
 
-        return spec;
-    }
+        populateSpec(spec, encounteredCatalogTypes);
 
-    @SuppressWarnings("unchecked")
-    private <T extends Entity> EntitySpec<T> tryResolveYamlUrlReferenceSpec(String brooklynType, Set<String> encounteredCatalogTypes) {
-        String yaml;
-        try {
-            yaml = ResourceUtils.create(this).getResourceAsString(brooklynType);
-        } catch (Exception e) {
-            log.warn("AssemblyTemplate type " + brooklynType + " which looks like a URL can't be fetched.", e);
-            return null;
-        }
-        // Referenced specs are expected to be CAMP format as well.
-        List<EntitySpec<?>> serviceSpecs = CampUtils.createServiceSpecs(yaml, loader, encounteredCatalogTypes);
-        if (serviceSpecs.size() > 1) {
-            throw new UnsupportedOperationException("Only supporting single service in remotely referenced plans: got "+serviceSpecs);
-        }
-        return (EntitySpec<T>) serviceSpecs.get(0);
+        @SuppressWarnings("unchecked")
+        EntitySpec<T> typedSpec = (EntitySpec<T>) spec;
+        return typedSpec;
     }
 
-    private <T extends Entity> EntitySpec<T> resolveLocalSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) {
-        CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type);
-        EntitySpec<T> spec = createSpec(item, encounteredCatalogTypes);
-        populateSpec(spec);
-        return spec;
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    private <T extends Entity,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> EntitySpec<T> createSpec(CatalogItem<Entity, EntitySpec<?>> item, Set<String> encounteredCatalogTypes) {
-        if (item == null) {
-            // ignore; presumably a java type or some such?
-        } else if (item.isDisabled()) {
-            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        } else if (item.isDeprecated()) {
-            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        }
-        
-        if (encounteredCatalogTypes==null) encounteredCatalogTypes = MutableSet.of();
-        
-        //Take the symbolicName part of the catalog item only for recursion detection to prevent
-        //cross referencing of different versions. Not interested in non-catalog item types.
-        //Prevent catalog items self-referencing even if explicitly different version.
-        boolean firstOccurrence = (item == null || encounteredCatalogTypes.add(item.getSymbolicName()));
-        boolean recursiveButTryJava = !firstOccurrence;
-
-        // Load a java class from current loader if explicit java prefix, or if no item, or if item is legacy / 
-        // old-style catalog item (item != null && item.getJavaType() != null).
-        // Old-style catalog items (can be defined in catalog.xml only) don't have structure, only a single type, so
-        // they are loaded as a simple java type, only taking the class name from the catalog item instead of the
-        // type value in the YAML. Classpath entries in the item are also used (through the catalog root classloader).
-        if (isJavaTypePrefix() || item == null) {
-            return createSpecFromJavaType();
-
-        // Same as above case, but this time force java type loading (either as plain class or through an old-style
-        // catalog item, since we have already loaded a class item with the same name as the type value.
-        } else if (recursiveButTryJava) {
-            if (tryLoadEntityClass().isAbsent()) {
-                throw new IllegalStateException("Recursive reference to " + item + " (and cannot be resolved as a Java type)");
+    private List<ServiceSpecResolver> getServiceTypeResolverOverrides() {
+        List<ServiceSpecResolver> overrides = new ArrayList<>();
+        if (type.indexOf(':') != -1) {
+            String prefix = Splitter.on(":").splitToList(type).get(0);
+            ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class,
+                    mgmt.getCatalogClassLoader());
+            for (ServiceTypeResolver resolver : loader) {
+               if (prefix.equals(resolver.getTypePrefix())) {
+                   overrides.add(new ServiceTypeResolverAdaptor(this, resolver));
+               }
             }
-            return createSpecFromJavaType();
-
-        // Only case that's left is a catalog item with CAMP YAML content - try to parse it recursively
-        // including its OSGi bundles in the loader classpath.
-        } else {
-            return (EntitySpec<T>) EntityManagementUtils.createCatalogSpec(mgmt, (CatalogItem<T,SpecT>)item, encounteredCatalogTypes);
         }
-    }
-    
-    @SuppressWarnings("unchecked")
-    private <T extends Entity> EntitySpec<T> createSpecFromJavaType() {
-        Class<T> type = (Class<T>) loadEntityClass();
-        
-        EntitySpec<T> spec;
-        if (type.isInterface()) {
-            spec = EntitySpec.create(type);
-        } else {
-            // If this is a concrete class, particularly for an Application class, we want the proxy
-            // to expose all interfaces it implements.
-            @SuppressWarnings("rawtypes")
-            Class interfaceclazz = (Application.class.isAssignableFrom(type)) ? Application.class : Entity.class;
-            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(type);
-            spec = EntitySpec.create(interfaceclazz).impl(type).additionalInterfaces(additionalInterfaceClazzes);
-        }
-        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
-        if (template.isPresent() && template.get().getSourceCode()!=null)
-            spec.tag(BrooklynTags.newYamlSpecTag(template.get().getSourceCode()));
-
-        return spec;
+        return overrides;
     }
 
     @SuppressWarnings("unchecked")
-    private <T extends Entity> void populateSpec(EntitySpec<T> spec) {
+    private <T extends Entity> void populateSpec(EntitySpec<T> spec, Set<String> encounteredCatalogTypes) {
         String name, templateId=null, planId=null;
         if (template.isPresent()) {
             name = template.get().getName();
@@ -356,15 +196,12 @@ public class BrooklynComponentTemplateResolver {
 
         Object childrenObj = attrs.getStringKey(BrooklynCampReservedKeys.BROOKLYN_CHILDREN);
         if (childrenObj != null) {
-            // Creating a new set of encounteredCatalogTypes means that this won't check things recursively;
-            // but we are looking at children so we probably *should* be resetting the recursive list we've looked at;
-            // (but see also, a previous comment here which suggested otherwise? - Apr 2015)
-            Set<String> encounteredCatalogTypes = MutableSet.of();
-
             Iterable<Map<String,?>> children = (Iterable<Map<String,?>>)childrenObj;
             for (Map<String,?> childAttrs : children) {
                 BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, childAttrs);
-                EntitySpec<? extends Entity> childSpec = entityResolver.resolveSpec(encounteredCatalogTypes, true);
+                // encounteredCatalogTypes must contain the items currently being loaded (the dependency chain),
+                // but not parent items in this catalog item already resolved.
+                EntitySpec<? extends Entity> childSpec = entityResolver.resolveSpec(encounteredCatalogTypes);
                 spec.child(childSpec);
             }
         }
@@ -379,7 +216,14 @@ public class BrooklynComponentTemplateResolver {
         if (childLocations != null)
             spec.locations(childLocations);
 
-        typeResolver.decorateSpec(this, spec);
+        decoreateSpec(spec);
+    }
+
+    private <T extends Entity> void decoreateSpec(EntitySpec<T> spec) {
+        new BrooklynEntityDecorationResolver.PolicySpecResolver(yamlLoader).decorate(spec, attrs);
+        new BrooklynEntityDecorationResolver.EnricherSpecResolver(yamlLoader).decorate(spec, attrs);
+        new BrooklynEntityDecorationResolver.InitializerResolver(yamlLoader).decorate(spec, attrs);
+
         configureEntityConfig(spec);
     }
 
@@ -508,7 +352,7 @@ public class BrooklynComponentTemplateResolver {
                 @SuppressWarnings("unchecked")
                 Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(specConfig.getSpecConfiguration());
                 specConfig.setSpecConfiguration(resolvedConfig);
-                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveLocalSpec(null, false);
+                return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(MutableSet.<String>of());
             }
             if (flag instanceof ManagementContextInjectable) {
                 log.debug("Injecting Brooklyn management context info object: {}", flag);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
index dd0a6f4..9104f8f 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
@@ -76,19 +76,15 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
                 if (at.getPlatformComponentTemplates()==null || at.getPlatformComponentTemplates().isEmpty()) {
                     if (at.getCustomAttributes().containsKey("brooklyn.catalog"))
                         throw new IllegalArgumentException("Unrecognized application blueprint format: expected an application, not a brooklyn.catalog");
-                    throw new IllegalArgumentException("Unrecognized application blueprint format: no services defined");
+                    throw new PlanNotRecognizedException("Unrecognized application blueprint format: no services defined");
                 }
                 // map this (expected) error to a nicer message
-                throw new IllegalArgumentException("Unrecognized application blueprint format");
+                throw new PlanNotRecognizedException("Unrecognized application blueprint format");
             }
         } catch (Exception e) {
-            if (e instanceof PlanNotRecognizedException) {
-                if (log.isTraceEnabled())
-                    log.debug("Failed to create entity from CAMP spec:\n" + plan, e);
-            } else {
-                if (log.isDebugEnabled())
-                    log.debug("Failed to create entity from CAMP spec:\n" + plan, e);
-            }
+            // TODO how do we figure out that the plan is not supported vs. invalid to wrap in a PlanNotRecognizedException?
+            if (log.isDebugEnabled())
+                log.debug("Failed to create entity from CAMP spec:\n" + plan, e);
             throw Exceptions.propagate(e);
         }
     }
@@ -96,6 +92,9 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
+        // Ignore old-style java type catalog items
+        if (item.getPlanYaml() == null) return null;
+
         // Not really clear what should happen to the top-level attributes, ignored until a good use case appears.
         return (SpecT) CampCatalogUtils.createSpec(mgmt, (CatalogItem)item, encounteredTypes);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
new file mode 100644
index 0000000..3fb3c89
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java
@@ -0,0 +1,65 @@
+/*
+ * 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.service;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.text.Strings;
+
+public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver {
+    private static final String PREFIX_DELIMITER = ":";
+    protected final String name;
+    protected final String prefix;
+    protected ManagementContext mgmt;
+
+    public AbstractServiceSpecResolver(String name) {
+        this.name = name;
+        this.prefix = name + PREFIX_DELIMITER;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return type.startsWith(prefix) && canResolve(type, loader);
+    }
+
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        return true;
+    }
+
+    protected String getLocalType(String type) {
+        return Strings.removeFromStart(type, prefix);
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+    }
+
+    @Override
+    public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
deleted file mode 100644
index e0d2e9e..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
+++ /dev/null
@@ -1,80 +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.camp.brooklyn.spi.creation.service;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityDecorationResolver;
-import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code brooklyn:}
- * to Brooklyn {@link EntitySpec} instances.
- */
-public class BrooklynServiceTypeResolver implements ServiceTypeResolver {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class);
-    
-    public BrooklynServiceTypeResolver() {
-    }
-    
-    @Override
-    public String getTypePrefix() { return DEFAULT_TYPE_PREFIX; }
-
-    @Override
-    public String getBrooklynType(String serviceType) {
-        String type = Strings.removeFromStart(serviceType, getTypePrefix() + ":").trim();
-        if (type == null) return null;
-        return type;
-    }
-
-    @Nullable
-    @Override
-    public CatalogItem<Entity,EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) {
-        String type = getBrooklynType(serviceType);
-        if (type != null) {
-            return getCatalogItemImpl(resolver.getManagementContext(),  type);
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) {
-        new BrooklynEntityDecorationResolver.PolicySpecResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs());
-        new BrooklynEntityDecorationResolver.EnricherSpecResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs());
-        new BrooklynEntityDecorationResolver.InitializerResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs());
-    }
-
-    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItemImpl(ManagementContext mgmt, String brooklynType) {
-        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
-        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
new file mode 100644
index 0000000..19a76b3
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java
@@ -0,0 +1,110 @@
+/*
+ * 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.service;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+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.mgmt.ManagementContext;
+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.mgmt.persist.DeserializingClassRenamesProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class);
+
+    private static final String RESOLVER_NAME = "catalog";
+    private final ServiceSpecResolver hardcodedResolver;
+    
+    public CatalogServiceSpecResolver() {
+        super(RESOLVER_NAME);
+        hardcodedResolver = new HardcodedCatalogServiceSpecResolver();
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+        if (item != null) {
+            try {
+                //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items.
+                checkUsable(item);
+                return true;
+            } catch (IllegalStateException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+        if (item != null) {
+            checkUsable(item);
+
+            //Take the symbolicName part of the catalog item only for recursion detection to prevent
+            //cross referencing of different versions. Not interested in non-catalog item types.
+            //Prevent catalog items self-referencing even if explicitly different version.
+            boolean firstOccurrence = encounteredTypes.add(item.getSymbolicName());
+            boolean nonRecursiveCall = firstOccurrence;
+            if (nonRecursiveCall) {
+                // CatalogItem generics are just getting in the way, better get rid of them, we
+                // are casting anyway.
+                @SuppressWarnings({ "rawtypes" })
+                CatalogItem rawItem = item;
+                @SuppressWarnings({ "rawtypes", "unchecked" })
+                AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, encounteredTypes);
+                return (EntitySpec<?>) rawSpec;
+            } else {
+                return null;
+            }
+        } else {
+            return hardcodedResolver.resolve(type, loader, encounteredTypes);
+        }
+    }
+
+    private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) {
+        if (item.isDisabled()) {
+            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        } else if (item.isDeprecated()) {
+            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        }
+    }
+
+    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) {
+        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
+        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        super.injectManagementContext(mgmt);
+        hardcodedResolver.injectManagementContext(mgmt);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java
deleted file mode 100644
index 94aa8fc..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java
+++ /dev/null
@@ -1,77 +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.camp.brooklyn.spi.creation.service;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
-import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
-import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
-import org.apache.brooklyn.entity.java.VanillaJavaApp;
-import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.CaseFormat;
-import com.google.common.base.Converter;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code catalog:}
- * to Brooklyn {@link EntitySpec} instances.
- */
-public class CatalogServiceTypeResolver extends BrooklynServiceTypeResolver {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class);
-
-    // TODO currently a hardcoded list of aliases; would like that to come from mgmt somehow
-    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
-            .put("cluster", DynamicCluster.class.getName())
-            .put("fabric", DynamicRegionsFabric.class.getName())
-            .put("vanilla", VanillaSoftwareProcess.class.getName())
-            .put("software-process", VanillaSoftwareProcess.class.getName())
-            .put("java-app", VanillaJavaApp.class.getName())
-            .put("brooklyn-node", BrooklynNode.class.getName())
-            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
-            .build();
-
-    // Allow catalog-type or CatalogType as service type string
-    private static final Converter<String, String> FMT = CaseFormat.LOWER_HYPHEN.converterTo(CaseFormat.UPPER_CAMEL);
-
-    @Override
-    public String getTypePrefix() { return "catalog"; }
-
-    @Override
-    public String getBrooklynType(String serviceType) {
-        String type = super.getBrooklynType(serviceType);
-        if (type == null) return null;
-
-        for (String check : CATALOG_TYPES.keySet()) {
-            if (type.equals(check) || type.equals(FMT.convert(check))) {
-                return CATALOG_TYPES.get(check);
-            }
-        }
-
-        return type;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java
new file mode 100644
index 0000000..1910971
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.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.camp.brooklyn.spi.creation.service;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.entity.chef.ChefConfig;
+import org.apache.brooklyn.entity.chef.ChefEntity;
+
+public class ChefServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_NAME = "chef";
+
+    public ChefServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        return EntitySpec.create(ChefEntity.class)
+                .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java
deleted file mode 100644
index b44deb7..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java
+++ /dev/null
@@ -1,61 +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.camp.brooklyn.spi.creation.service;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
-import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
-import org.apache.brooklyn.entity.chef.ChefConfig;
-import org.apache.brooklyn.entity.chef.ChefEntity;
-import org.apache.brooklyn.util.text.Strings;
-
-/**
- * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code chef:}
- * to Brooklyn {@link EntitySpec} instances.
- */
-public class ChefServiceTypeResolver extends BrooklynServiceTypeResolver {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class);
-
-    @Override
-    public String getTypePrefix() { return "chef"; }
-
-    @Override
-    public String getBrooklynType(String serviceType) {
-        return ChefEntity.class.getName();
-    }
-
-    /** Chef items are not in the catalog. */
-    @Override
-    public CatalogItem<Entity, EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) {
-        return null;
-    }
-
-    @Override
-    public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) {
-        spec.configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, Strings.removeFromStart(resolver.getDeclaredType(), "chef:"));
-        super.decorateSpec(resolver, spec);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
deleted file mode 100644
index fdd57d5..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java
+++ /dev/null
@@ -1,23 +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.camp.brooklyn.spi.creation.service;
-
-public class DefaultServiceTypeResolver extends BrooklynServiceTypeResolver {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
new file mode 100644
index 0000000..e1a2f19
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java
@@ -0,0 +1,127 @@
+/*
+ * 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.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+public class DelegatingServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_PREFIX_CATALOG = "catalog:";
+
+    private static final String RESOLVER_PREFIX_JAVA = "java:";
+
+    private static final Logger log = LoggerFactory.getLogger(DelegatingServiceSpecResolver.class);
+
+    private static final String RESOLVER_NAME = "brooklyn";
+
+    private Collection<ServiceSpecResolver> resolvers;
+
+    public DelegatingServiceSpecResolver(@Nonnull ManagementContext mgmt, @Nonnull List<ServiceSpecResolver> overridingResolvers) {
+        super(RESOLVER_NAME);
+        this.resolvers = ImmutableList.<ServiceSpecResolver>builder()
+                .addAll(overridingResolvers)
+                .addAll(ServiceLoader.load(ServiceSpecResolver.class))
+                .build();
+        for (ServiceSpecResolver resolver : resolvers) {
+            resolver.injectManagementContext(mgmt);
+        }
+
+        injectManagementContext(mgmt);
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return accepts("", type, loader) ||
+                accepts(RESOLVER_PREFIX_CATALOG, type, loader) ||
+                accepts(RESOLVER_PREFIX_JAVA, type, loader);
+    }
+
+    private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) {
+        for (ServiceSpecResolver resolver : resolvers) {
+            String localType = getLocalType(type);
+            if (resolver.accepts(prefix + localType, loader)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+
+        EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes);
+    }
+
+    private EntitySpec<?> resolve(
+            Collection<ServiceSpecResolver> resolvers,
+            String localType,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredTypes) {
+        Collection<String> resolversWhoDontSupport = new ArrayList<String>();
+        Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>();
+
+        for (ServiceSpecResolver resolver : resolvers) {
+            if (resolver.accepts(localType, loader)) {
+                try {
+                    EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes);
+                    if (spec != null) {
+                        return spec;
+                    } else {
+                        resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
+                    }
+                } catch (Exception e) {
+                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
+                            Exceptions.collapseText(e), e));
+                }
+            }
+        }
+        if (!otherProblemsFromResolvers.isEmpty()) {
+            // at least one thought he could do it
+            log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers);
+            throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) :
+                Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers);
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
new file mode 100644
index 0000000..2a3d7cd
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java
@@ -0,0 +1,95 @@
+/*
+ * 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.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
+import org.apache.brooklyn.entity.java.VanillaJavaApp;
+import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Converter;
+import com.google.common.collect.ImmutableMap;
+
+public class HardcodedCatalogServiceSpecResolver extends AbstractServiceSpecResolver {
+    private static final String RESOLVER_NAME = "catalog";
+
+    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
+            .put("cluster", DynamicCluster.class.getName())
+            .put("fabric", DynamicRegionsFabric.class.getName())
+            .put("vanilla", VanillaSoftwareProcess.class.getName())
+            .put("software-process", VanillaSoftwareProcess.class.getName())
+            .put("java-app", VanillaJavaApp.class.getName())
+            .put("brooklyn-node", BrooklynNode.class.getName())
+            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
+            .build();
+
+    // Allow catalog-type or CatalogType as service type string
+    private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN);
+
+    public HardcodedCatalogServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        return specType != null;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        if (specType != null) {
+            return buildSpec(specType);
+        } else {
+            return null;
+        }
+    }
+
+    private String getImplementation(String type) {
+        String specType = CATALOG_TYPES.get(type);
+        if (specType != null) {
+            return specType;
+        } else {
+            return CATALOG_TYPES.get(FMT.convert(type));
+        }
+    }
+
+    private EntitySpec<?> buildSpec(String specType) {
+        // TODO is this hardcoded list deprecated? If so log a warning.
+        try {
+            @SuppressWarnings("unchecked")
+            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
+            return EntitySpec.create(specClass);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
new file mode 100644
index 0000000..fa0f9e5
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java
@@ -0,0 +1,91 @@
+/*
+ * 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.service;
+
+import java.util.List;
+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.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Reflections;
+
+public class JavaServiceSpecResolver extends AbstractServiceSpecResolver{
+    private static final String RESOLVER_NAME = "java";
+
+    public JavaServiceSpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        Maybe<?> javaType = tryLoadJavaType(localType, loader);
+        return javaType.isPresent();
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        try {
+            return resolveInternal(localType, loader);
+        } catch (Exception e) {
+            boolean firstOccurrence = encounteredTypes.add(localType);
+            boolean recursiveButTryJava = !firstOccurrence;
+            if (recursiveButTryJava) {
+                throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) {
+        Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader);
+        if (javaTypeMaybe.isAbsent())
+            throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException());
+        Class<? extends Entity> javaType = javaTypeMaybe.get();
+
+        EntitySpec<? extends Entity> spec;
+        if (javaType.isInterface()) {
+            spec = EntitySpec.create(javaType);
+        } else {
+            // If this is a concrete class, particularly for an Application class, we want the proxy
+            // to expose all interfaces it implements.
+            Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class;
+            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType);
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz)
+                .impl((Class) javaType)
+                .additionalInterfaces(additionalInterfaceClazzes);
+            spec = rawSpec;
+        }
+        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
+
+        return spec;
+    }
+
+    private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) {
+        return loader.tryLoadClass(localType, Entity.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java
deleted file mode 100644
index d6c52f4..0000000
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java
+++ /dev/null
@@ -1,38 +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.camp.brooklyn.spi.creation.service;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code java:}
- * to Brooklyn {@link EntitySpec} instances.
- */
-public class JavaServiceTypeResolver extends BrooklynServiceTypeResolver {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class);
-
-    @Override
-    public String getTypePrefix() { return "java"; }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
new file mode 100644
index 0000000..00d6dd5
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java
@@ -0,0 +1,56 @@
+/*
+ * 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.service;
+
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+
+/**
+ * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
+ * <p>
+ * The resolver implementation will use the rest of the local part of the service type information
+ * to create and decorate an appropriate {@link EntitySpec entity}.
+ * <p>
+ * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries
+ * to add extra service type implementations that will be picked up at runtime.
+ */
+// TODO Not CAMP specific, move to core, to be reused by other parsers
+public interface ServiceSpecResolver extends ManagementContextInjectable {
+    /**
+     * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time.
+     * For implementations: this usually matches the service type prefix, but not required.
+     */
+    String getName();
+
+    /**
+     * @return if the resolver can create a spec for the service type
+     */
+    boolean accepts(String type, BrooklynClassLoadingContext loader);
+
+    /**
+     * Create a spec for the service type
+     */
+    @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
index dcbd971..c1399ff 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
@@ -37,7 +37,10 @@ import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateR
  *
  * @see BrooklynServiceTypeResolver
  * @see ChefServiceTypeResolver
+ * 
+ * @deprecated since 0.9.0, {@link ServiceSpecResolver} instead.
  */
+@Deprecated
 public interface ServiceTypeResolver {
 
     String DEFAULT_TYPE_PREFIX = "brooklyn";

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
new file mode 100644
index 0000000..60abd40
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.service;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import groovy.xml.Entity;
+
+@SuppressWarnings("deprecation")
+public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver {
+    private static final Logger log = LoggerFactory.getLogger(ServiceTypeResolverAdaptor.class);
+    private ServiceTypeResolver serviceTypeResolver;
+    private BrooklynComponentTemplateResolver resolver;
+
+    public ServiceTypeResolverAdaptor(BrooklynComponentTemplateResolver resolver, ServiceTypeResolver serviceTypeResolver) {
+        super(serviceTypeResolver.getTypePrefix());
+        this.serviceTypeResolver = serviceTypeResolver;
+        this.resolver = resolver;
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return true;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        // Assume this is interface! Only known implementation is DockerServiceTypeResolver.
+        String brooklynType = serviceTypeResolver.getBrooklynType(type);
+        Class<? extends Entity> javaType = loader.loadClass(brooklynType, Entity.class);
+        if (!javaType.isInterface()) {
+            log.warn("Using " + ServiceTypeResolver.class.getSimpleName() + " with a non-interface type - this usage is not supported. Use " + ServiceSpecResolver.class.getSimpleName() + " instead.");
+        }
+        EntitySpec<?> spec = EntitySpec.create((Class)javaType);
+        serviceTypeResolver.decorateSpec(resolver, spec);
+        return spec;
+    }
+
+}


[03/16] incubator-brooklyn git commit: White list https protocol for camp URL references

Posted by sj...@apache.org.
White list https protocol for camp URL references


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

Branch: refs/heads/master
Commit: 00615b770d6ecb75fa1513124ebbd3b721bc9580
Parents: 2a004d9
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 8 10:09:42 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 17:08:53 2015 +0300

----------------------------------------------------------------------
 .../org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/00615b77/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java
index 0c27a74..d3641f2 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/BrooklynCampConstants.java
@@ -45,5 +45,5 @@ public class BrooklynCampConstants {
     public static final ConfigKey<CampPlatform> CAMP_PLATFORM = ConfigKeys.newConfigKey(CampPlatform.class, "brooklyn.camp.platform",
             "Config set at brooklyn management platform to find the CampPlatform instance (bi-directional)");
 
-    public static final Set<String> YAML_URL_PROTOCOL_WHITELIST = ImmutableSet.of("classpath", "http");
+    public static final Set<String> YAML_URL_PROTOCOL_WHITELIST = ImmutableSet.of("classpath", "http", "https");
 }


[12/16] incubator-brooklyn git commit: Address code review comments (PR 955)

Posted by sj...@apache.org.
Address code review comments (PR 955)


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

Branch: refs/heads/master
Commit: 5fe288f27ad9902f52ad6601c09f7361f822d433
Parents: d79fd90
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 15 12:13:30 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 15 12:13:30 2015 +0300

----------------------------------------------------------------------
 .../brooklyn/core/mgmt/EntityManagementUtils.java       |  3 +++
 .../brooklyn/core/plan/PlanToSpecTransformer.java       |  7 ++++++-
 .../core/resolve/CatalogServiceSpecResolver.java        |  9 +--------
 .../brooklyn/core/resolve/ServiceSpecResolver.java      | 12 ++++++++++++
 .../spi/creation/BrooklynComponentTemplateResolver.java |  6 +++---
 .../brooklyn/spi/creation/CampToSpecTransformer.java    |  7 ++++++-
 .../spi/creation/service/UrlServiceSpecResolver.java    |  2 +-
 7 files changed, 32 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index 0dca83c..5536a1e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -103,6 +103,9 @@ public class EntityManagementUtils {
     }
 
     public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item, final Set<String> encounteredTypes) {
+        if (encounteredTypes.contains(item.getSymbolicName())) {
+            throw new IllegalStateException("Already encountered types " + encounteredTypes + " must not contain catalog item being resolver " + item.getSymbolicName());
+        }
         return PlanToSpecFactory.attemptWithLoaders(mgmt, new Function<PlanToSpecTransformer, SpecT>() {
             @Override
             public SpecT apply(PlanToSpecTransformer input) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/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 b9ca8ca..24753aa 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
@@ -56,7 +56,12 @@ public interface PlanToSpecTransformer extends ManagementContextInjectable {
      * the catalog item might be known by type, or its source plan fragment text might be inspected and transformed.
      * implementations will typically look at the {@link CatalogItem#getCatalogItemType()} first.
      * <p>
-     * should throw {@link PlanNotRecognizedException} if this transformer does not know what to do with the plan. */
+     * should throw {@link PlanNotRecognizedException} if this transformer does not know what to do with the plan.
+     * 
+     * @param item - The catalog item to convert to a spec. The item might not be fully populated (i.e. missing {@code symbolicName} if called
+     *        from the catalog parser).
+     * @param encounteredTypes - The {@code symbolicName}s of catalog items being resolved up the stack, but not including {@code item}.
+     */
     <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException;
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
index f05355a..ded4ed3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
@@ -73,19 +73,12 @@ public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
         //Prevent catalog items self-referencing even if explicitly different version.
         boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
         if (nonRecursiveCall) {
-            // Make a copy of the encountered types, so that we add the item being resolved for
-            // dependency items only. Siblings must not see we are resolving this item.
-            Set<String> encounteredTypes = ImmutableSet.<String>builder()
-                    .addAll(parentEncounteredTypes)
-                    .add(item.getSymbolicName())
-                    .build();
-
             // CatalogItem generics are just getting in the way, better get rid of them, we
             // are casting anyway.
             @SuppressWarnings({ "rawtypes" })
             CatalogItem rawItem = item;
             @SuppressWarnings({ "rawtypes", "unchecked" })
-            AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, encounteredTypes);
+            AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, parentEncounteredTypes);
             return (EntitySpec<?>) rawSpec;
         } else {
             return null;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
index 5e30cfa..64a6c66 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
@@ -50,6 +50,18 @@ public interface ServiceSpecResolver extends ManagementContextInjectable {
 
     /**
      * Create a spec for the service type
+     * 
+     * @param type - the string representation which should be converted to an EntitySpec
+     * @param loader - use it to load any Java classes
+     * @param encounteredTypes - an immutable set of the items which are currently being resolved up the stack,
+     *        used to prevent cycles. Implementations should not try to resolve the type if the symbolicName is
+     *        already contained in here. When resolving a type add it to a copy of the list before
+     *        passing the new instance down the stack. See {@link CatalogServiceSpecResolver} for example usage.
+     *
+     * @return The {@link EntitySpec} corresponding to the passed {@code type} argument, possibly pre-configured
+     *         based on the information contained in {@code type}. Return {@code null} value to indicate that
+     *         the implementation doesn't know how to convert {@code type} to an {@link EntitySpec}. Throw an
+     *         exception if {@code type} looks like a supported value, but can't be loaded.
      */
     @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index e6a866e..cfdfab2 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -163,7 +163,7 @@ public class BrooklynComponentTemplateResolver {
             } else if (proto != null) {
                 msgDetails = "The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
                         proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
-                        "Not a catalog item or java type as well.";
+                        "It's also neither a catalog item nor a java type.";
             } else {
                 msgDetails = "No resolver knew how to handle it. Using resolvers: " + serviceSpecResolver;
             }
@@ -226,10 +226,10 @@ public class BrooklynComponentTemplateResolver {
         if (childLocations != null)
             spec.locations(childLocations);
 
-        decoreateSpec(spec);
+        decorateSpec(spec);
     }
 
-    private <T extends Entity> void decoreateSpec(EntitySpec<T> spec) {
+    private <T extends Entity> void decorateSpec(EntitySpec<T> spec) {
         new BrooklynEntityDecorationResolver.PolicySpecResolver(yamlLoader).decorate(spec, attrs);
         new BrooklynEntityDecorationResolver.EnricherSpecResolver(yamlLoader).decorate(spec, attrs);
         new BrooklynEntityDecorationResolver.InitializerResolver(yamlLoader).decorate(spec, attrs);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
index 9104f8f..60f00c6 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
@@ -93,7 +93,12 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
     @Override
     public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
         // Ignore old-style java type catalog items
-        if (item.getPlanYaml() == null) return null;
+        if (item.getPlanYaml() == null) {
+            throw new PlanNotRecognizedException("Old style catalog item " + item + " not supported.");
+        }
+        if (encounteredTypes.contains(item.getSymbolicName())) {
+            throw new IllegalStateException("Already encountered types " + encounteredTypes + " must not contain catalog item being resolver " + item.getSymbolicName());
+        }
 
         // Not really clear what should happen to the top-level attributes, ignored until a good use case appears.
         return (SpecT) CampCatalogUtils.createSpec(mgmt, (CatalogItem)item, encounteredTypes);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5fe288f2/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
index b55c064..bde501b 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
@@ -54,7 +54,7 @@ public class UrlServiceSpecResolver implements ServiceSpecResolver {
         try {
             yaml = ResourceUtils.create(this).getResourceAsString(type);
         } catch (Exception e) {
-            log.warn("AssemblyTemplate type " + type + " which looks like a URL can't be fetched.", e);
+            log.warn("AssemblyTemplate type " + type + " looks like a URL that can't be fetched.", e);
             return null;
         }
         // Referenced specs are expected to be CAMP format as well.


[11/16] incubator-brooklyn git commit: Get back plan tagging in, so it's visible in UI

Posted by sj...@apache.org.
Get back plan tagging in, so it's visible in UI


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

Branch: refs/heads/master
Commit: d79fd90d0121ab5fc81c43c153e54566ee46633a
Parents: 1c72a20
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Wed Oct 14 19:03:14 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Oct 14 19:03:14 2015 +0300

----------------------------------------------------------------------
 .../spi/creation/BrooklynComponentTemplateResolver.java     | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d79fd90d/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 381b76b..e6a866e 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -46,6 +46,7 @@ import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 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.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
@@ -64,7 +65,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
-import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
@@ -188,10 +188,11 @@ public class BrooklynComponentTemplateResolver {
 
     @SuppressWarnings("unchecked")
     private <T extends Entity> void populateSpec(EntitySpec<T> spec, Set<String> encounteredCatalogTypes) {
-        String name, templateId=null, planId=null;
+        String name, source=null, templateId=null, planId=null;
         if (template.isPresent()) {
             name = template.get().getName();
             templateId = template.get().getId();
+            source = template.get().getSourceCode();
         } else {
             name = (String)attrs.getStringKey("name");
         }
@@ -210,6 +211,10 @@ public class BrooklynComponentTemplateResolver {
                 spec.child(childSpec);
             }
         }
+
+        if (source!=null)
+            spec.tag(BrooklynTags.newYamlSpecTag(source));
+
         if (!Strings.isBlank(name))
             spec.displayName(name);
         if (templateId != null)


[05/16] incubator-brooklyn git commit: Split BrooklynComponentTemplateResolver into independent ServiceSpecResolver

Posted by sj...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
new file mode 100644
index 0000000..2e704ee
--- /dev/null
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
@@ -0,0 +1,70 @@
+/*
+ * 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.service;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.CampUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.net.Urls;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UrlServiceSpecResolver implements ServiceSpecResolver {
+    private static final Logger log = LoggerFactory.getLogger(UrlServiceSpecResolver.class);
+
+    @Override
+    public String getName() {
+        return "url";
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        String protocol = Urls.getProtocol(type);
+        return protocol != null &&
+            BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol);
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String yaml;
+        try {
+            yaml = ResourceUtils.create(this).getResourceAsString(type);
+        } catch (Exception e) {
+            log.warn("AssemblyTemplate type " + type + " which looks like a URL can't be fetched.", e);
+            return null;
+        }
+        // Referenced specs are expected to be CAMP format as well.
+        List<EntitySpec<?>> serviceSpecs = CampUtils.createServiceSpecs(yaml, loader, encounteredTypes);
+        if (serviceSpecs.size() > 1) {
+            throw new UnsupportedOperationException("Only supporting single service in remotely referenced plans: got "+serviceSpecs);
+        }
+        return serviceSpecs.get(0);
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext managementContext) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
new file mode 100644
index 0000000..fa6ca8d
--- /dev/null
+++ b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
@@ -0,0 +1,23 @@
+#
+# 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.camp.brooklyn.spi.creation.service.CatalogServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.HardcodedCatalogServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.UrlServiceSpecResolver
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
deleted file mode 100644
index 9c941df..0000000
--- a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
+++ /dev/null
@@ -1,22 +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.
-#
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.BrooklynServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceTypeResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogXmlOsgiTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogXmlOsgiTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogXmlOsgiTest.java
index fc2c7e5..5a2362e 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogXmlOsgiTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogXmlOsgiTest.java
@@ -18,6 +18,11 @@
  */
 package org.apache.brooklyn.camp.brooklyn.catalog;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
 import org.testng.annotations.Test;
 
 public class CatalogXmlOsgiTest extends AbstractCatalogXmlTest {
@@ -29,9 +34,16 @@ public class CatalogXmlOsgiTest extends AbstractCatalogXmlTest {
     //OSGi libraries not supported with old-style catalog items
     //We treat those catalog items just as an alias to the java type they hold.
     //No loader wrapping their libraries is ever created.
-    @Test(expectedExceptions=IllegalStateException.class)
+    @Test
     public void testOsgiItem() throws Exception {
-        startApp("OsgiApp");
+        try {
+            startApp("OsgiApp");
+            fail();
+        } catch (PropagatedRuntimeException e) {
+            ClassNotFoundException ex = Exceptions.getFirstThrowableOfType(e, ClassNotFoundException.class);
+            if (ex == null) throw e;
+            assertEquals(ex.getMessage(), "org.apache.brooklyn.test.osgi.entities.SimpleApplication");
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index f7c98c0..53cd146 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -596,7 +596,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
     }
 
     @Test
-    public void testDeeplyNestedTypesDoesNotRecurse() throws Exception {
+    public void testIndirectRecursionFails() throws Exception {
         String symbolicName = "my.catalog.app.id.basic";
         // Need to have a stand alone caller first so we can create an item to depend on it.
         // After that replace it/insert a new version which completes the cycle
@@ -616,23 +616,54 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
                 "services:",
                 "- type: " + symbolicName + ".caller");
 
+        try {
+            addCatalogItems(
+                    "brooklyn.catalog:",
+                    "  id: " + symbolicName + ".caller",
+                    "  version: " + TEST_VERSION,
+                    "",
+                    "services:",
+                    "- type: " + symbolicName + ".callee");
+            fail();
+        } catch (IllegalStateException e) {
+            assertTrue(e.toString().contains("recursive"), "Unexpected error message: "+e);
+        }
+    }
+
+    @Test
+    public void testChildItemsDoNotRecurse() throws Exception {
+        String symbolicName = "my.catalog.app.id.basic";
+        // Need to have a stand alone caller first so we can create an item to depend on it.
+        // After that replace it/insert a new version which completes the cycle
         addCatalogItems(
                 "brooklyn.catalog:",
                 "  id: " + symbolicName + ".caller",
+                "  version: " + TEST_VERSION + "pre",
+                "",
+                "services:",
+                "- type: org.apache.brooklyn.entity.stock.BasicEntity");
+
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName + ".callee",
                 "  version: " + TEST_VERSION,
                 "",
                 "services:",
-                "- type: org.apache.brooklyn.entity.stock.BasicEntity",
-                // Being a child is important, triggers the case where
-                // we allow retrying with other transformers
-                // and thus breaking the recursive check.
-                "  brooklyn.children:",
-                "  - type: " + symbolicName + ".callee");
+                "- type: " + symbolicName + ".caller");
 
         try {
-            createAndStartApplication(
+            addCatalogItems(
+                    "brooklyn.catalog:",
+                    "  id: " + symbolicName + ".caller",
+                    "  version: " + TEST_VERSION,
+                    "",
                     "services:",
-                    "- type: " + symbolicName + ".caller");
+                    "- type: org.apache.brooklyn.entity.stock.BasicEntity",
+                    // Being a child is important, triggers the case where
+                    // we allow retrying with other transformers.
+                    "  brooklyn.children:",
+                    "  - type: " + symbolicName + ".callee");
+            fail();
         } catch (IllegalStateException e) {
             assertTrue(e.toString().contains("recursive"), "Unexpected error message: "+e);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
index 68a9198..c8c004c 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
@@ -372,8 +372,8 @@ public class ApplicationResource extends AbstractBrooklynRestResource implements
         } catch (IllegalStateException e) {
             // An IllegalArgumentException for creating the entity spec gets wrapped in a ISE.
             // But we want to return a 400 rather than 500, so ensure we throw IAE.
-            if (e.getCause() != null && Exceptions.getFirstInteresting(e.getCause()) instanceof IllegalArgumentException) {
-                IllegalArgumentException iae = (IllegalArgumentException) Exceptions.getFirstInteresting(e.getCause());
+            IllegalArgumentException iae = (IllegalArgumentException) Exceptions.getFirstThrowableOfType(e.getCause(), IllegalArgumentException.class);
+            if (iae != null) {
                 throw new IllegalArgumentException("Cannot create spec for app: "+iae.getMessage(), e);
             } else {
                 throw e;


[14/16] incubator-brooklyn git commit: Extract identical code to utils

Posted by sj...@apache.org.
Extract identical code to utils


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

Branch: refs/heads/master
Commit: 5d0c765ca869cfad497da85329f51a8354b11511
Parents: 1db8875
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 15 13:15:02 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 15 13:33:03 2015 +0300

----------------------------------------------------------------------
 .../spi/creation/CampToSpecTransformer.java     | 11 ++------
 .../camp/brooklyn/spi/creation/CampUtils.java   | 29 ++++++++++++--------
 2 files changed, 21 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5d0c765c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
index 60f00c6..ae995e4 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
@@ -60,15 +60,10 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
     public EntitySpec<? extends Application> createApplicationSpec(String plan) {
         try {
             CampPlatform camp = CampCatalogUtils.getCampPlatform(mgmt);
-            AssemblyTemplate at = camp.pdp().registerDeploymentPlan( new StringReader(plan) );
-            AssemblyTemplateInstantiator instantiator;
-            try {
-                instantiator = at.getInstantiator().newInstance();
-            } catch (Exception e) {
-                throw Exceptions.propagate(e);
-            }
+            BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt);
+            AssemblyTemplate at = CampUtils.registerDeploymentPlan(plan, loader, camp);
+            AssemblyTemplateInstantiator instantiator = CampUtils.getInstantiator(at);
             if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
-                BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt);
                 return ((AssemblyTemplateSpecInstantiator) instantiator).createApplicationSpec(at, camp, loader);
             } else {
                 // The unknown instantiator can create the app (Assembly), but not a spec.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5d0c765c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
index 83b85e2..289fb97 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
@@ -57,25 +57,32 @@ public class CampUtils {
     public static List<EntitySpec<?>> createServiceSpecs(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
         CampPlatform camp = getCampPlatform(loader.getManagementContext());
 
-        AssemblyTemplate at;
-        BrooklynLoaderTracker.setLoader(loader);
-        try {
-            at = camp.pdp().registerDeploymentPlan(new StringReader(plan));
-        } finally {
-            BrooklynLoaderTracker.unsetLoader(loader);
+        AssemblyTemplate at = registerDeploymentPlan(plan, loader, camp);
+        AssemblyTemplateInstantiator instantiator = getInstantiator(at);
+        if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
+            return ((AssemblyTemplateSpecInstantiator)instantiator).createServiceSpecs(at, camp, loader, encounteredTypes);
+        } else {
+            throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
         }
+    }
 
+    public static AssemblyTemplateInstantiator getInstantiator(AssemblyTemplate at) {
         try {
-            AssemblyTemplateInstantiator instantiator = at.getInstantiator().newInstance();
-            if (instantiator instanceof AssemblyTemplateSpecInstantiator) {
-                return ((AssemblyTemplateSpecInstantiator)instantiator).createServiceSpecs(at, camp, loader, encounteredTypes);
-            }
-            throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
+            return at.getInstantiator().newInstance();
         } catch (Exception e) {
             throw Exceptions.propagate(e);
         }
     }
 
+    public static AssemblyTemplate registerDeploymentPlan(String plan, BrooklynClassLoadingContext loader, CampPlatform camp) {
+        BrooklynLoaderTracker.setLoader(loader);
+        try {
+            return camp.pdp().registerDeploymentPlan(new StringReader(plan));
+        } finally {
+            BrooklynLoaderTracker.unsetLoader(loader);
+        }
+    }
+
     public static PolicySpec<?> createPolicySpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes) {
         DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan);
 


[13/16] incubator-brooklyn git commit: Rename entity resolvers to better match their functionality, now that they are CAMP independent

Posted by sj...@apache.org.
Rename entity resolvers to better match their functionality, now that they are CAMP independent


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

Branch: refs/heads/master
Commit: 1db88751e131011ff96625753e50e8942825dbcc
Parents: 5fe288f
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 15 13:01:07 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 15 13:32:59 2015 +0300

----------------------------------------------------------------------
 .../resolve/AbstractServiceSpecResolver.java    |  65 ----------
 .../resolve/CatalogServiceSpecResolver.java     | 101 ---------------
 .../resolve/DelegatingServiceSpecResolver.java  | 127 -------------------
 .../core/resolve/JavaServiceSpecResolver.java   |  91 -------------
 .../core/resolve/ServiceSpecResolver.java       |  67 ----------
 .../entity/AbstractEntitySpecResolver.java      |  65 ++++++++++
 .../entity/CatalogEntitySpecResolver.java       |  99 +++++++++++++++
 .../entity/DelegatingEntitySpecResolver.java    | 127 +++++++++++++++++++
 .../core/resolve/entity/EntitySpecResolver.java |  67 ++++++++++
 .../resolve/entity/JavaEntitySpecResolver.java  |  91 +++++++++++++
 ...he.brooklyn.core.resolve.ServiceSpecResolver |  20 ---
 ...oklyn.core.resolve.entity.EntitySpecResolver |  20 +++
 .../entity/resolve/ChefEntitySpecResolver.java  |  42 ++++++
 .../entity/resolve/ChefServiceSpecResolver.java |  42 ------
 .../HardcodedCatalogEntitySpecResolver.java     |  96 ++++++++++++++
 .../HardcodedCatalogServiceSpecResolver.java    |  96 --------------
 ...he.brooklyn.core.resolve.ServiceSpecResolver |  20 ---
 ...oklyn.core.resolve.entity.EntitySpecResolver |  20 +++
 .../BrooklynComponentTemplateResolver.java      |   8 +-
 .../camp/brooklyn/spi/creation/CampUtils.java   |   2 +-
 .../service/BrooklynServiceTypeResolver.java    |   4 +-
 .../service/CampServiceSpecResolver.java        |  14 +-
 .../creation/service/ServiceTypeResolver.java   |   4 +-
 .../service/ServiceTypeResolverAdaptor.java     |   8 +-
 .../service/UrlServiceSpecResolver.java         |   4 +-
 25 files changed, 649 insertions(+), 651 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
deleted file mode 100644
index 78c796a..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/AbstractServiceSpecResolver.java
+++ /dev/null
@@ -1,65 +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.resolve;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.text.Strings;
-
-public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver {
-    private static final String PREFIX_DELIMITER = ":";
-    protected final String name;
-    protected final String prefix;
-    protected ManagementContext mgmt;
-
-    public AbstractServiceSpecResolver(String name) {
-        this.name = name;
-        this.prefix = name + PREFIX_DELIMITER;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
-        return type.startsWith(prefix) && canResolve(type, loader);
-    }
-
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        return true;
-    }
-
-    protected String getLocalType(String type) {
-        return Strings.removeFromStart(type, prefix).trim();
-    }
-
-    @Override
-    public void injectManagementContext(ManagementContext mgmt) {
-        this.mgmt = mgmt;
-    }
-
-    @Override
-    public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
deleted file mode 100644
index ded4ed3..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/CatalogServiceSpecResolver.java
+++ /dev/null
@@ -1,101 +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.resolve;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.catalog.CatalogItem;
-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.mgmt.ManagementContext;
-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.mgmt.persist.DeserializingClassRenamesProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableSet;
-
-public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class);
-
-    private static final String RESOLVER_NAME = "catalog";
-
-    public CatalogServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
-        if (item != null) {
-            try {
-                //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items.
-                checkUsable(item);
-                return true;
-            } catch (IllegalStateException e) {
-                return false;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> parentEncounteredTypes) {
-        String localType = getLocalType(type);
-        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
-
-        if (item == null) return null;
-        checkUsable(item);
-
-        //Take the symbolicName part of the catalog item only for recursion detection to prevent
-        //cross referencing of different versions. Not interested in non-catalog item types.
-        //Prevent catalog items self-referencing even if explicitly different version.
-        boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
-        if (nonRecursiveCall) {
-            // CatalogItem generics are just getting in the way, better get rid of them, we
-            // are casting anyway.
-            @SuppressWarnings({ "rawtypes" })
-            CatalogItem rawItem = item;
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, parentEncounteredTypes);
-            return (EntitySpec<?>) rawSpec;
-        } else {
-            return null;
-        }
-    }
-
-    private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) {
-        if (item.isDisabled()) {
-            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        } else if (item.isDeprecated()) {
-            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
-        }
-    }
-
-    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) {
-        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
-        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
deleted file mode 100644
index 6dc7b87..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/DelegatingServiceSpecResolver.java
+++ /dev/null
@@ -1,127 +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.resolve;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableList;
-
-public class DelegatingServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_PREFIX_CATALOG = "catalog:";
-
-    private static final String RESOLVER_PREFIX_JAVA = "java:";
-
-    private static final Logger log = LoggerFactory.getLogger(DelegatingServiceSpecResolver.class);
-
-    private static final String RESOLVER_NAME = "brooklyn";
-
-    private Collection<ServiceSpecResolver> resolvers;
-
-    public DelegatingServiceSpecResolver(@Nonnull List<ServiceSpecResolver> resolvers) {
-        super(RESOLVER_NAME);
-        this.resolvers = resolvers;
-    }
-
-    protected static ImmutableList<ServiceSpecResolver> getRegisteredResolvers() {
-        return ImmutableList.copyOf(ServiceLoader.load(ServiceSpecResolver.class));
-    }
-
-    @Override
-    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
-        return accepts("", type, loader) ||
-                accepts(RESOLVER_PREFIX_CATALOG, type, loader) ||
-                accepts(RESOLVER_PREFIX_JAVA, type, loader);
-    }
-
-    private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) {
-        for (ServiceSpecResolver resolver : resolvers) {
-            String localType = getLocalType(type);
-            if (resolver.accepts(prefix + localType, loader)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-
-        EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes);
-        if (spec != null) {
-            return spec;
-        }
-        spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes);
-        if (spec != null) {
-            return spec;
-        }
-        return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes);
-    }
-
-    private EntitySpec<?> resolve(
-            Collection<ServiceSpecResolver> resolvers,
-            String localType,
-            BrooklynClassLoadingContext loader,
-            Set<String> encounteredTypes) {
-        Collection<String> resolversWhoDontSupport = new ArrayList<String>();
-        Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>();
-
-        for (ServiceSpecResolver resolver : resolvers) {
-            if (resolver.accepts(localType, loader)) {
-                try {
-                    EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes);
-                    if (spec != null) {
-                        return spec;
-                    } else {
-                        resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
-                    }
-                } catch (Exception e) {
-                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
-                            Exceptions.collapseText(e), e));
-                }
-            }
-        }
-        if (!otherProblemsFromResolvers.isEmpty()) {
-            // at least one thought he could do it
-            log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers);
-            throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) :
-                Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers);
-        }
-        return null;
-    }
-
-    @Override
-    public String toString() {
-        return this.getClass() + "[" + resolvers + "]";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
deleted file mode 100644
index af5ee5f..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/JavaServiceSpecResolver.java
+++ /dev/null
@@ -1,91 +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.resolve;
-
-import java.util.List;
-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.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.javalang.Reflections;
-
-public class JavaServiceSpecResolver extends AbstractServiceSpecResolver{
-    private static final String RESOLVER_NAME = "java";
-
-    public JavaServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        Maybe<?> javaType = tryLoadJavaType(localType, loader);
-        return javaType.isPresent();
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-        try {
-            return resolveInternal(localType, loader);
-        } catch (Exception e) {
-            boolean firstOccurrence = encounteredTypes.add(localType);
-            boolean recursiveButTryJava = !firstOccurrence;
-            if (recursiveButTryJava) {
-                throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e);
-            } else {
-                throw e;
-            }
-        }
-    }
-
-    private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) {
-        Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader);
-        if (javaTypeMaybe.isAbsent())
-            throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException());
-        Class<? extends Entity> javaType = javaTypeMaybe.get();
-
-        EntitySpec<? extends Entity> spec;
-        if (javaType.isInterface()) {
-            spec = EntitySpec.create(javaType);
-        } else {
-            // If this is a concrete class, particularly for an Application class, we want the proxy
-            // to expose all interfaces it implements.
-            Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class;
-            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType);
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz)
-                .impl((Class) javaType)
-                .additionalInterfaces(additionalInterfaceClazzes);
-            spec = rawSpec;
-        }
-        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
-
-        return spec;
-    }
-
-    private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) {
-        return loader.tryLoadClass(localType, Entity.class);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
deleted file mode 100644
index 64a6c66..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/ServiceSpecResolver.java
+++ /dev/null
@@ -1,67 +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.resolve;
-
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-
-/**
- * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
- * <p>
- * The resolver implementation will use the rest of the local part of the service type information
- * to create and decorate an appropriate {@link EntitySpec entity}.
- * <p>
- * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries
- * to add extra service type implementations that will be picked up at runtime.
- */
-public interface ServiceSpecResolver extends ManagementContextInjectable {
-    /**
-     * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time.
-     * For implementations: this usually matches the service type prefix, but not required.
-     */
-    String getName();
-
-    /**
-     * @return if the resolver can create a spec for the service type
-     */
-    boolean accepts(String type, BrooklynClassLoadingContext loader);
-
-    /**
-     * Create a spec for the service type
-     * 
-     * @param type - the string representation which should be converted to an EntitySpec
-     * @param loader - use it to load any Java classes
-     * @param encounteredTypes - an immutable set of the items which are currently being resolved up the stack,
-     *        used to prevent cycles. Implementations should not try to resolve the type if the symbolicName is
-     *        already contained in here. When resolving a type add it to a copy of the list before
-     *        passing the new instance down the stack. See {@link CatalogServiceSpecResolver} for example usage.
-     *
-     * @return The {@link EntitySpec} corresponding to the passed {@code type} argument, possibly pre-configured
-     *         based on the information contained in {@code type}. Return {@code null} value to indicate that
-     *         the implementation doesn't know how to convert {@code type} to an {@link EntitySpec}. Throw an
-     *         exception if {@code type} looks like a supported value, but can't be loaded.
-     */
-    @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/entity/AbstractEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/AbstractEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/AbstractEntitySpecResolver.java
new file mode 100644
index 0000000..ae3ddb2
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/AbstractEntitySpecResolver.java
@@ -0,0 +1,65 @@
+/*
+ * 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.resolve.entity;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.text.Strings;
+
+public abstract class AbstractEntitySpecResolver implements EntitySpecResolver {
+    private static final String PREFIX_DELIMITER = ":";
+    protected final String name;
+    protected final String prefix;
+    protected ManagementContext mgmt;
+
+    public AbstractEntitySpecResolver(String name) {
+        this.name = name;
+        this.prefix = name + PREFIX_DELIMITER;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return type.startsWith(prefix) && canResolve(type, loader);
+    }
+
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        return true;
+    }
+
+    protected String getLocalType(String type) {
+        return Strings.removeFromStart(type, prefix).trim();
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext mgmt) {
+        this.mgmt = mgmt;
+    }
+
+    @Override
+    public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/entity/CatalogEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/CatalogEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/CatalogEntitySpecResolver.java
new file mode 100644
index 0000000..399f9dc
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/CatalogEntitySpecResolver.java
@@ -0,0 +1,99 @@
+/*
+ * 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.resolve.entity;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+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.mgmt.ManagementContext;
+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.mgmt.persist.DeserializingClassRenamesProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CatalogEntitySpecResolver extends AbstractEntitySpecResolver {
+    private static final Logger log = LoggerFactory.getLogger(CatalogEntitySpecResolver.class);
+
+    private static final String RESOLVER_NAME = "catalog";
+
+    public CatalogEntitySpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+        if (item != null) {
+            try {
+                //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items.
+                checkUsable(item);
+                return true;
+            } catch (IllegalStateException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> parentEncounteredTypes) {
+        String localType = getLocalType(type);
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType);
+
+        if (item == null) return null;
+        checkUsable(item);
+
+        //Take the symbolicName part of the catalog item only for recursion detection to prevent
+        //cross referencing of different versions. Not interested in non-catalog item types.
+        //Prevent catalog items self-referencing even if explicitly different version.
+        boolean nonRecursiveCall = !parentEncounteredTypes.contains(item.getSymbolicName());
+        if (nonRecursiveCall) {
+            // CatalogItem generics are just getting in the way, better get rid of them, we
+            // are casting anyway.
+            @SuppressWarnings({ "rawtypes" })
+            CatalogItem rawItem = item;
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, parentEncounteredTypes);
+            return (EntitySpec<?>) rawSpec;
+        } else {
+            return null;
+        }
+    }
+
+    private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) {
+        if (item.isDisabled()) {
+            throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        } else if (item.isDeprecated()) {
+            log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion());
+        }
+    }
+
+    protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) {
+        brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType);
+        return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class,  brooklynType);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/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
new file mode 100644
index 0000000..2ccc468
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java
@@ -0,0 +1,127 @@
+/*
+ * 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.resolve.entity;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+public class DelegatingEntitySpecResolver extends AbstractEntitySpecResolver {
+    private static final String RESOLVER_PREFIX_CATALOG = "catalog:";
+
+    private static final String RESOLVER_PREFIX_JAVA = "java:";
+
+    private static final Logger log = LoggerFactory.getLogger(DelegatingEntitySpecResolver.class);
+
+    private static final String RESOLVER_NAME = "brooklyn";
+
+    private Collection<EntitySpecResolver> resolvers;
+
+    public DelegatingEntitySpecResolver(@Nonnull List<EntitySpecResolver> resolvers) {
+        super(RESOLVER_NAME);
+        this.resolvers = resolvers;
+    }
+
+    protected static ImmutableList<EntitySpecResolver> getRegisteredResolvers() {
+        return ImmutableList.copyOf(ServiceLoader.load(EntitySpecResolver.class));
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        return accepts("", type, loader) ||
+                accepts(RESOLVER_PREFIX_CATALOG, type, loader) ||
+                accepts(RESOLVER_PREFIX_JAVA, type, loader);
+    }
+
+    private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) {
+        for (EntitySpecResolver resolver : resolvers) {
+            String localType = getLocalType(type);
+            if (resolver.accepts(prefix + localType, loader)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+
+        EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes);
+        if (spec != null) {
+            return spec;
+        }
+        return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes);
+    }
+
+    private EntitySpec<?> resolve(
+            Collection<EntitySpecResolver> resolvers,
+            String localType,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredTypes) {
+        Collection<String> resolversWhoDontSupport = new ArrayList<String>();
+        Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>();
+
+        for (EntitySpecResolver resolver : resolvers) {
+            if (resolver.accepts(localType, loader)) {
+                try {
+                    EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes);
+                    if (spec != null) {
+                        return spec;
+                    } else {
+                        resolversWhoDontSupport.add(resolver.getName() + " (returned null)");
+                    }
+                } catch (Exception e) {
+                    otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+
+                            Exceptions.collapseText(e), e));
+                }
+            }
+        }
+        if (!otherProblemsFromResolvers.isEmpty()) {
+            // at least one thought he could do it
+            log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers);
+            throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) :
+                Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers);
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass() + "[" + resolvers + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/entity/EntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/EntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/EntitySpecResolver.java
new file mode 100644
index 0000000..83e0fab
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/EntitySpecResolver.java
@@ -0,0 +1,67 @@
+/*
+ * 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.resolve.entity;
+
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+
+/**
+ * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
+ * <p>
+ * The resolver implementation will use the rest of the local part of the service type information
+ * to create and decorate an appropriate {@link EntitySpec entity}.
+ * <p>
+ * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries
+ * to add extra service type implementations that will be picked up at runtime.
+ */
+public interface EntitySpecResolver extends ManagementContextInjectable {
+    /**
+     * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time.
+     * For implementations: this usually matches the service type prefix, but not required.
+     */
+    String getName();
+
+    /**
+     * @return if the resolver can create a spec for the service type
+     */
+    boolean accepts(String type, BrooklynClassLoadingContext loader);
+
+    /**
+     * Create a spec for the service type
+     * 
+     * @param type - the string representation which should be converted to an EntitySpec
+     * @param loader - use it to load any Java classes
+     * @param encounteredTypes - an immutable set of the items which are currently being resolved up the stack,
+     *        used to prevent cycles. Implementations should not try to resolve the type if the symbolicName is
+     *        already contained in here. When resolving a type add it to a copy of the list before
+     *        passing the new instance down the stack. See {@link CatalogEntitySpecResolver} for example usage.
+     *
+     * @return The {@link EntitySpec} corresponding to the passed {@code type} argument, possibly pre-configured
+     *         based on the information contained in {@code type}. Return {@code null} value to indicate that
+     *         the implementation doesn't know how to convert {@code type} to an {@link EntitySpec}. Throw an
+     *         exception if {@code type} looks like a supported value, but can't be loaded.
+     */
+    @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java
new file mode 100644
index 0000000..b8ce013
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java
@@ -0,0 +1,91 @@
+/*
+ * 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.resolve.entity;
+
+import java.util.List;
+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.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Reflections;
+
+public class JavaEntitySpecResolver extends AbstractEntitySpecResolver{
+    private static final String RESOLVER_NAME = "java";
+
+    public JavaEntitySpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        Maybe<?> javaType = tryLoadJavaType(localType, loader);
+        return javaType.isPresent();
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        try {
+            return resolveInternal(localType, loader);
+        } catch (Exception e) {
+            boolean firstOccurrence = encounteredTypes.add(localType);
+            boolean recursiveButTryJava = !firstOccurrence;
+            if (recursiveButTryJava) {
+                throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) {
+        Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader);
+        if (javaTypeMaybe.isAbsent())
+            throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException());
+        Class<? extends Entity> javaType = javaTypeMaybe.get();
+
+        EntitySpec<? extends Entity> spec;
+        if (javaType.isInterface()) {
+            spec = EntitySpec.create(javaType);
+        } else {
+            // If this is a concrete class, particularly for an Application class, we want the proxy
+            // to expose all interfaces it implements.
+            Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class;
+            List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType);
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz)
+                .impl((Class) javaType)
+                .additionalInterfaces(additionalInterfaceClazzes);
+            spec = rawSpec;
+        }
+        spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader));
+
+        return spec;
+    }
+
+    private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) {
+        return loader.tryLoadClass(localType, Entity.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
deleted file mode 100644
index df57859..0000000
--- a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
+++ /dev/null
@@ -1,20 +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.
-#
-org.apache.brooklyn.core.resolve.CatalogServiceSpecResolver
-org.apache.brooklyn.core.resolve.JavaServiceSpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
----------------------------------------------------------------------
diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
new file mode 100644
index 0000000..b3f8a51
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
@@ -0,0 +1,20 @@
+#
+# 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.resolve.entity.CatalogEntitySpecResolver
+org.apache.brooklyn.core.resolve.entity.JavaEntitySpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefEntitySpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefEntitySpecResolver.java
new file mode 100644
index 0000000..07d4342
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefEntitySpecResolver.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.entity.resolve;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver;
+import org.apache.brooklyn.entity.chef.ChefConfig;
+import org.apache.brooklyn.entity.chef.ChefEntity;
+
+public class ChefEntitySpecResolver extends AbstractEntitySpecResolver {
+    private static final String RESOLVER_NAME = "chef";
+
+    public ChefEntitySpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        return EntitySpec.create(ChefEntity.class)
+                .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java
deleted file mode 100644
index ea774c1..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/ChefServiceSpecResolver.java
+++ /dev/null
@@ -1,42 +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.entity.resolve;
-
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
-import org.apache.brooklyn.entity.chef.ChefConfig;
-import org.apache.brooklyn.entity.chef.ChefEntity;
-
-public class ChefServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_NAME = "chef";
-
-    public ChefServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        return EntitySpec.create(ChefEntity.class)
-                .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
new file mode 100644
index 0000000..5541996
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
@@ -0,0 +1,96 @@
+/*
+ * 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.entity.resolve;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver;
+import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
+import org.apache.brooklyn.entity.java.VanillaJavaApp;
+import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Converter;
+import com.google.common.collect.ImmutableMap;
+
+public class HardcodedCatalogEntitySpecResolver extends AbstractEntitySpecResolver {
+    private static final String RESOLVER_NAME = "catalog";
+
+    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
+            .put("cluster", DynamicCluster.class.getName())
+            .put("fabric", DynamicRegionsFabric.class.getName())
+            .put("vanilla", VanillaSoftwareProcess.class.getName())
+            .put("software-process", VanillaSoftwareProcess.class.getName())
+            .put("java-app", VanillaJavaApp.class.getName())
+            .put("brooklyn-node", BrooklynNode.class.getName())
+            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
+            .build();
+
+    // Allow catalog-type or CatalogType as service type string
+    private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN);
+
+    public HardcodedCatalogEntitySpecResolver() {
+        super(RESOLVER_NAME);
+    }
+
+    @Override
+    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        return specType != null;
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
+        String localType = getLocalType(type);
+        String specType = getImplementation(localType);
+        if (specType != null) {
+            return buildSpec(specType);
+        } else {
+            return null;
+        }
+    }
+
+    private String getImplementation(String type) {
+        String specType = CATALOG_TYPES.get(type);
+        if (specType != null) {
+            return specType;
+        } else {
+            return CATALOG_TYPES.get(FMT.convert(type));
+        }
+    }
+
+    private EntitySpec<?> buildSpec(String specType) {
+        // TODO is this hardcoded list deprecated? If so log a warning.
+        try {
+            @SuppressWarnings("unchecked")
+            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
+            return EntitySpec.create(specClass);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
deleted file mode 100644
index 7a073de..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogServiceSpecResolver.java
+++ /dev/null
@@ -1,96 +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.entity.resolve;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
-import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
-import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
-import org.apache.brooklyn.entity.java.VanillaJavaApp;
-import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
-
-import com.google.common.base.CaseFormat;
-import com.google.common.base.Converter;
-import com.google.common.collect.ImmutableMap;
-
-public class HardcodedCatalogServiceSpecResolver extends AbstractServiceSpecResolver {
-    private static final String RESOLVER_NAME = "catalog";
-
-    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
-            .put("cluster", DynamicCluster.class.getName())
-            .put("fabric", DynamicRegionsFabric.class.getName())
-            .put("vanilla", VanillaSoftwareProcess.class.getName())
-            .put("software-process", VanillaSoftwareProcess.class.getName())
-            .put("java-app", VanillaJavaApp.class.getName())
-            .put("brooklyn-node", BrooklynNode.class.getName())
-            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
-            .build();
-
-    // Allow catalog-type or CatalogType as service type string
-    private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN);
-
-    public HardcodedCatalogServiceSpecResolver() {
-        super(RESOLVER_NAME);
-    }
-
-    @Override
-    protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
-        String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        return specType != null;
-    }
-
-    @Override
-    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
-        String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        if (specType != null) {
-            return buildSpec(specType);
-        } else {
-            return null;
-        }
-    }
-
-    private String getImplementation(String type) {
-        String specType = CATALOG_TYPES.get(type);
-        if (specType != null) {
-            return specType;
-        } else {
-            return CATALOG_TYPES.get(FMT.convert(type));
-        }
-    }
-
-    private EntitySpec<?> buildSpec(String specType) {
-        // TODO is this hardcoded list deprecated? If so log a warning.
-        try {
-            @SuppressWarnings("unchecked")
-            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
-            return EntitySpec.create(specClass);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
----------------------------------------------------------------------
diff --git a/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver b/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
deleted file mode 100644
index d3471e0..0000000
--- a/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.ServiceSpecResolver
+++ /dev/null
@@ -1,20 +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.
-#
-org.apache.brooklyn.entity.resolve.ChefServiceSpecResolver
-org.apache.brooklyn.entity.resolve.HardcodedCatalogServiceSpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
----------------------------------------------------------------------
diff --git a/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver b/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
new file mode 100644
index 0000000..1224bd2
--- /dev/null
+++ b/software/base/src/main/resources/META-INF/services/org.apache.brooklyn.core.resolve.entity.EntitySpecResolver
@@ -0,0 +1,20 @@
+#
+# 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.entity.resolve.ChefEntitySpecResolver
+org.apache.brooklyn.entity.resolve.HardcodedCatalogEntitySpecResolver

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index cfdfab2..e9d22f1 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -51,7 +51,7 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
-import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
@@ -85,7 +85,7 @@ public class BrooklynComponentTemplateResolver {
     private final BrooklynYamlTypeInstantiator.Factory yamlLoader;
     private final String type;
     private final AtomicBoolean alreadyBuilt = new AtomicBoolean(false);
-    private final ServiceSpecResolver serviceSpecResolver;
+    private final EntitySpecResolver serviceSpecResolver;
 
     private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type) {
         this.loader = loader;
@@ -177,8 +177,8 @@ public class BrooklynComponentTemplateResolver {
         return typedSpec;
     }
 
-    private List<ServiceSpecResolver> getServiceTypeResolverOverrides() {
-        List<ServiceSpecResolver> overrides = new ArrayList<>();
+    private List<EntitySpecResolver> getServiceTypeResolverOverrides() {
+        List<EntitySpecResolver> overrides = new ArrayList<>();
         ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class, mgmt.getCatalogClassLoader());
         for (ServiceTypeResolver resolver : loader) {
            overrides.add(new ServiceTypeResolverAdaptor(this, resolver));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
index 4fca75c..83b85e2 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampUtils.java
@@ -40,8 +40,8 @@ import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 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.CatalogUtils;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
index edb1924..83f907b 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateR
 import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
-import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
  * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code brooklyn:}
  * to Brooklyn {@link EntitySpec} instances.
  * 
- * @deprecated since 0.9.0, use {@link AbstractServiceSpecResolver} instead
+ * @deprecated since 0.9.0, use {@link AbstractEntitySpecResolver} instead
  */
 @Deprecated
 public class BrooklynServiceTypeResolver implements ServiceTypeResolver {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
index 143f088..a993083 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CampServiceSpecResolver.java
@@ -21,24 +21,24 @@ package org.apache.brooklyn.camp.brooklyn.spi.creation.service;
 import java.util.List;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.resolve.DelegatingServiceSpecResolver;
-import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.DelegatingEntitySpecResolver;
+import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
 
 import com.google.common.collect.ImmutableList;
 
-public class CampServiceSpecResolver extends DelegatingServiceSpecResolver {
+public class CampServiceSpecResolver extends DelegatingEntitySpecResolver {
 
-    public CampServiceSpecResolver(ManagementContext mgmt, List<ServiceSpecResolver> overridingResolvers) {
+    public CampServiceSpecResolver(ManagementContext mgmt, List<EntitySpecResolver> overridingResolvers) {
         super(getCampResolvers(mgmt, overridingResolvers));
     }
 
-    private static List<ServiceSpecResolver> getCampResolvers(ManagementContext mgmt, List<ServiceSpecResolver> overridingResolvers) {
-        List<ServiceSpecResolver> resolvers = ImmutableList.<ServiceSpecResolver>builder()
+    private static List<EntitySpecResolver> getCampResolvers(ManagementContext mgmt, List<EntitySpecResolver> overridingResolvers) {
+        List<EntitySpecResolver> resolvers = ImmutableList.<EntitySpecResolver>builder()
                 .addAll(overridingResolvers)
                 .addAll(getRegisteredResolvers())
                 .add(new UrlServiceSpecResolver())
                 .build();
-        for (ServiceSpecResolver resolver : resolvers) {
+        for (EntitySpecResolver resolver : resolvers) {
             resolver.injectManagementContext(mgmt);
         }
         return resolvers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
index da472c6..14f855a 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java
@@ -24,7 +24,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
-import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
 
 /**
  * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template.
@@ -39,7 +39,7 @@ import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
  * @see BrooklynServiceTypeResolver
  * @see ChefServiceTypeResolver
  * 
- * @deprecated since 0.9.0, {@link ServiceSpecResolver} instead.
+ * @deprecated since 0.9.0, {@link EntitySpecResolver} instead.
  */
 @Deprecated
 public interface ServiceTypeResolver {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
index 17f4e2b..703a7cf 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java
@@ -24,15 +24,15 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.resolve.AbstractServiceSpecResolver;
-import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver;
+import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Splitter;
 
 @SuppressWarnings("deprecation")
-public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver {
+public class ServiceTypeResolverAdaptor extends AbstractEntitySpecResolver {
     private static final Logger log = LoggerFactory.getLogger(ServiceTypeResolverAdaptor.class);
     private ServiceTypeResolver serviceTypeResolver;
     private BrooklynComponentTemplateResolver resolver;
@@ -60,7 +60,7 @@ public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver {
         String brooklynType = serviceTypeResolver.getBrooklynType(type);
         Class<? extends Entity> javaType = loader.loadClass(brooklynType, Entity.class);
         if (!javaType.isInterface()) {
-            log.warn("Using " + ServiceTypeResolver.class.getSimpleName() + " with a non-interface type - this usage is not supported. Use " + ServiceSpecResolver.class.getSimpleName() + " instead.");
+            log.warn("Using " + ServiceTypeResolver.class.getSimpleName() + " with a non-interface type - this usage is not supported. Use " + EntitySpecResolver.class.getSimpleName() + " instead.");
         }
         EntitySpec<?> spec = EntitySpec.create((Class)javaType);
         serviceTypeResolver.decorateSpec(resolver, spec);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1db88751/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
index bde501b..ab058c7 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
@@ -26,14 +26,14 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampUtils;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.resolve.ServiceSpecResolver;
+import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.net.Urls;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /** Specific to CAMP because linked plans are assumed to be CAMP format. No type discovery available. */
-public class UrlServiceSpecResolver implements ServiceSpecResolver {
+public class UrlServiceSpecResolver implements EntitySpecResolver {
     private static final Logger log = LoggerFactory.getLogger(UrlServiceSpecResolver.class);
 
     @Override