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

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

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" +