You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/07/04 11:51:10 UTC

[28/45] git commit: update generics for CatalogItem so it can supply a Spec, and add BrooklynCatalog.createSpec deprecating the loadClass methods

update generics for CatalogItem so it can supply a Spec, and add BrooklynCatalog.createSpec deprecating the loadClass methods


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

Branch: refs/heads/master
Commit: 407de80ae9f0b975ad45e283146adfcf881fdfb6
Parents: 5c3d32c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 2 17:17:25 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jul 2 17:17:25 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/catalog/BrooklynCatalog.java  | 25 ++++++---
 .../main/java/brooklyn/catalog/CatalogItem.java |  2 +-
 .../brooklyn/catalog/CatalogPredicates.java     | 42 +++++++-------
 .../catalog/internal/BasicBrooklynCatalog.java  | 58 +++++++++++---------
 .../catalog/internal/CatalogClasspathDo.java    |  6 +-
 .../internal/CatalogConfigurationDto.java       |  2 +-
 .../brooklyn/catalog/internal/CatalogDo.java    | 20 +++----
 .../brooklyn/catalog/internal/CatalogDto.java   |  2 +-
 .../catalog/internal/CatalogEntityItemDto.java  |  3 +-
 .../catalog/internal/CatalogItemDo.java         |  8 +--
 .../internal/CatalogItemDtoAbstract.java        |  2 +-
 .../catalog/internal/CatalogPolicyItemDto.java  |  3 +-
 .../internal/CatalogTemplateItemDto.java        |  3 +-
 .../catalog/internal/CatalogDtoTest.java        |  2 +-
 .../catalog/internal/CatalogLoadTest.java       |  2 +-
 .../catalog/internal/CatalogScanTest.java       | 15 ++---
 .../BrooklynAssemblyTemplateInstantiator.java   |  4 +-
 .../lookup/AbstractTemplateBrooklynLookup.java  |  7 ++-
 .../lookup/AssemblyTemplateBrooklynLookup.java  | 18 ++++--
 ...PlatformComponentTemplateBrooklynLookup.java |  7 ++-
 .../rest/resources/CatalogResource.java         | 13 +++--
 .../rest/transform/CatalogTransformer.java      | 12 ++--
 .../rest/util/BrooklynRestResourceUtils.java    |  9 ++-
 23 files changed, 149 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
index 0bbd9d3..38583cb 100644
--- a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
+++ b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
@@ -5,25 +5,32 @@ import com.google.common.base.Predicate;
 public interface BrooklynCatalog {
 
     /** @return The item with the given ID, or null if not found */
-    CatalogItem<?> getCatalogItem(String id);
+    CatalogItem<?,?> getCatalogItem(String id);
 
 
     /** variant of {@link #getCatalogItem(String)} which checks (and casts) type for convenience
      * (returns null if type does not match) */
-    <T> CatalogItem<T> getCatalogItem(Class<T> type, String id);
+    <T,SpecT> CatalogItem<T,SpecT> getCatalogItem(Class<T> type, String id);
 
     /** @return All items in the catalog */
-    <T> Iterable<CatalogItem<T>> getCatalogItems();
+    <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems();
 
     /** convenience for filtering items in the catalog; see CatalogPredicates for useful filters */
-    <T> Iterable<CatalogItem<T>> getCatalogItems(Predicate<? super CatalogItem<T>> filter);
+    <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems(Predicate<? super CatalogItem<T,SpecT>> filter);
 
     /** @return The classloader which should be used to load classes and entities;
      * this includes all the catalog's classloaders in the right order */
     public ClassLoader getRootClassLoader();
 
-    /** throws exceptions if any problems */
-    <T> Class<? extends T> loadClass(CatalogItem<T> item);
+    /** creates a spec for the given catalog item, throwing exceptions if any problems */
+    <T,SpecT> SpecT createSpec(CatalogItem<T,SpecT> item);
+    
+    /** throws exceptions if any problems 
+     * @deprecated since 0.7.0 use {@link #createSpec(CatalogItem)} */
+    @Deprecated
+    <T,SpecT> Class<? extends T> loadClass(CatalogItem<T,SpecT> item);
+    /** @deprecated since 0.7.0 use {@link #createSpec(CatalogItem)} */
+    @Deprecated
     <T> Class<? extends T> loadClassByType(String typeName, Class<T> typeClass);
 
     
@@ -32,7 +39,7 @@ public interface BrooklynCatalog {
      * 
      * @throws IllegalArgumentException if the yaml was invalid
      */
-    CatalogItem<?> addItem(String yaml);
+    CatalogItem<?,?> addItem(String yaml);
     
     /**
      * adds an item to the 'manual' catalog;
@@ -41,7 +48,7 @@ public interface BrooklynCatalog {
      * @deprecated since 0.7.0 Construct catalogs with OSGi bundles instead
      */
     @Deprecated
-    void addItem(CatalogItem<?> item);
+    void addItem(CatalogItem<?,?> item);
 
     /** creates a catalog item and adds it to the 'manual' catalog,
      * with the corresponding Class definition (loaded by a classloader)
@@ -55,6 +62,6 @@ public interface BrooklynCatalog {
      * @deprecated since 0.7.0 Construct catalogs with OSGi bundles instead
      */
     @Deprecated
-    CatalogItem<?> addItem(Class<?> clazz);
+    CatalogItem<?,?> addItem(Class<?> clazz);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/api/src/main/java/brooklyn/catalog/CatalogItem.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/catalog/CatalogItem.java b/api/src/main/java/brooklyn/catalog/CatalogItem.java
index 9888901..fe844b8 100644
--- a/api/src/main/java/brooklyn/catalog/CatalogItem.java
+++ b/api/src/main/java/brooklyn/catalog/CatalogItem.java
@@ -3,7 +3,7 @@ package brooklyn.catalog;
 import java.util.List;
 import javax.annotation.Nonnull;
 
-public interface CatalogItem<T> {
+public interface CatalogItem<T,SpecT> {
     
     public static enum CatalogItemType {
         TEMPLATE, ENTITY, POLICY, CONFIGURATION

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/CatalogPredicates.java b/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
index 7112282..5c3d884 100644
--- a/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
+++ b/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
@@ -5,59 +5,61 @@ import javax.annotation.Nullable;
 import brooklyn.catalog.CatalogItem.CatalogItemType;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.policy.Policy;
+import brooklyn.policy.PolicySpec;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 
 public class CatalogPredicates {
 
-    public static <T> Predicate<CatalogItem<T>> isCatalogItemType(final CatalogItemType ciType) {
-        return new Predicate<CatalogItem<T>>() {
+    public static <T,SpecT> Predicate<CatalogItem<T,SpecT>> isCatalogItemType(final CatalogItemType ciType) {
+        return new Predicate<CatalogItem<T,SpecT>>() {
             @Override
-            public boolean apply(@Nullable CatalogItem<T> item) {
+            public boolean apply(@Nullable CatalogItem<T,SpecT> item) {
                 return (item != null) && item.getCatalogItemType()==ciType;
             }
         };
     }
 
-    public static final Predicate<CatalogItem<Application>> IS_TEMPLATE = 
-            CatalogPredicates.<Application>isCatalogItemType(CatalogItemType.TEMPLATE);
-    public static final Predicate<CatalogItem<Entity>> IS_ENTITY = 
-            CatalogPredicates.<Entity>isCatalogItemType(CatalogItemType.ENTITY);
-    public static final Predicate<CatalogItem<Policy>> IS_POLICY = 
-            CatalogPredicates.<Policy>isCatalogItemType(CatalogItemType.POLICY);
+    public static final Predicate<CatalogItem<Application,EntitySpec<? extends Application>>> IS_TEMPLATE = 
+            CatalogPredicates.<Application,EntitySpec<? extends Application>>isCatalogItemType(CatalogItemType.TEMPLATE);
+    public static final Predicate<CatalogItem<Entity,EntitySpec<?>>> IS_ENTITY = 
+            CatalogPredicates.<Entity,EntitySpec<?>>isCatalogItemType(CatalogItemType.ENTITY);
+    public static final Predicate<CatalogItem<Policy,PolicySpec<?>>> IS_POLICY = 
+            CatalogPredicates.<Policy,PolicySpec<?>>isCatalogItemType(CatalogItemType.POLICY);
     
-    public static final Function<CatalogItem<?>,String> ID_OF_ITEM_TRANSFORMER = new Function<CatalogItem<?>, String>() {
+    public static final Function<CatalogItem<?,?>,String> ID_OF_ITEM_TRANSFORMER = new Function<CatalogItem<?,?>, String>() {
         @Override @Nullable
-        public String apply(@Nullable CatalogItem<?> input) {
+        public String apply(@Nullable CatalogItem<?,?> input) {
             if (input==null) return null;
             return input.getId();
         }
     };
 
-    public static <T> Predicate<CatalogItem<T>> name(final Predicate<? super String> filter) {
-        return new Predicate<CatalogItem<T>>() {
+    public static <T,SpecT> Predicate<CatalogItem<T,SpecT>> name(final Predicate<? super String> filter) {
+        return new Predicate<CatalogItem<T,SpecT>>() {
             @Override
-            public boolean apply(@Nullable CatalogItem<T> item) {
+            public boolean apply(@Nullable CatalogItem<T,SpecT> item) {
                 return (item != null) && filter.apply(item.getName());
             }
         };
     }
 
-    public static <T> Predicate<CatalogItem<T>> javaType(final Predicate<? super String> filter) {
-        return new Predicate<CatalogItem<T>>() {
+    public static <T,SpecT> Predicate<CatalogItem<T,SpecT>> javaType(final Predicate<? super String> filter) {
+        return new Predicate<CatalogItem<T,SpecT>>() {
             @Override
-            public boolean apply(@Nullable CatalogItem<T> item) {
+            public boolean apply(@Nullable CatalogItem<T,SpecT> item) {
                 return (item != null) && filter.apply(item.getJavaType());
             }
         };
     }
 
-    public static <T> Predicate<CatalogItem<T>> xml(final Predicate<? super String> filter) {
-        return new Predicate<CatalogItem<T>>() {
+    public static <T,SpecT> Predicate<CatalogItem<T,SpecT>> xml(final Predicate<? super String> filter) {
+        return new Predicate<CatalogItem<T,SpecT>>() {
             @Override
-            public boolean apply(@Nullable CatalogItem<T> item) {
+            public boolean apply(@Nullable CatalogItem<T,SpecT> item) {
                 return (item != null) && filter.apply(item.toXmlString());
             }
         };

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
index 67cbbe1..4bbb02c 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -59,25 +59,25 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         return catalog;
     }
 
-    protected CatalogItemDo<?> getCatalogItemDo(String id) {
+    protected CatalogItemDo<?,?> getCatalogItemDo(String id) {
         return catalog.getCache().get(id);
     }
     
     @Override
-    public CatalogItem<?> getCatalogItem(String id) {
+    public CatalogItem<?,?> getCatalogItem(String id) {
         if (id==null) return null;
-        CatalogItemDo<?> itemDo = getCatalogItemDo(id);
+        CatalogItemDo<?,?> itemDo = getCatalogItemDo(id);
         if (itemDo==null) return null;
         return itemDo.getDto();
     }
     
     @SuppressWarnings("unchecked")
     @Override
-    public <T> CatalogItem<T> getCatalogItem(Class<T> type, String id) {
+    public <T,SpecT> CatalogItem<T,SpecT> getCatalogItem(Class<T> type, String id) {
         if (id==null) return null;
-        CatalogItem<?> result = getCatalogItem(id);
+        CatalogItem<?,?> result = getCatalogItem(id);
         if (type==null || type.isAssignableFrom(result.getCatalogItemJavaType())) 
-            return (CatalogItem<T>)result;
+            return (CatalogItem<T,SpecT>)result;
         return null;
     }
     
@@ -96,13 +96,19 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         }
     }
 
+    @Override
+    public <T, SpecT> SpecT createSpec(CatalogItem<T, SpecT> item) {
+        // TODO #2
+        throw new UnsupportedOperationException();
+    }
+    
     @SuppressWarnings("unchecked")
     @Override
-    public <T> Class<? extends T> loadClass(CatalogItem<T> item) {
+    public <T,SpecT> Class<? extends T> loadClass(CatalogItem<T,SpecT> item) {
         if (log.isDebugEnabled())
             log.debug("Loading class for catalog item " + item);
         Preconditions.checkNotNull(item);
-        CatalogItemDo<?> loadedItem = getCatalogItemDo(item.getId());
+        CatalogItemDo<?,?> loadedItem = getCatalogItemDo(item.getId());
         if (loadedItem==null) throw new NoSuchElementException("Unable to load '"+item.getId()+"' to instantiate it");
         return (Class<? extends T>) loadedItem.getJavaClass();
     }
@@ -110,9 +116,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     @SuppressWarnings("unchecked")
     @Override
     public <T> Class<? extends T> loadClassByType(String typeName, Class<T> typeClass) {
-        Iterable<CatalogItem<Object>> resultL = getCatalogItems(CatalogPredicates.javaType(Predicates.equalTo(typeName)));
+        Iterable<CatalogItem<Object,Object>> resultL = getCatalogItems(CatalogPredicates.javaType(Predicates.equalTo(typeName)));
         if (Iterables.isEmpty(resultL)) throw new NoSuchElementException("Unable to find catalog item for type "+typeName);
-        CatalogItem<Object> resultI = resultL.iterator().next();
+        CatalogItem<?,?> resultI = resultL.iterator().next();
         if (log.isDebugEnabled() && Iterables.size(resultL)>1) {
             log.debug("Found "+Iterables.size(resultL)+" matches in catalog for type "+typeName+"; returning the first, "+resultI);
         }
@@ -120,14 +126,14 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     }
 
     @Deprecated
-    private <T> CatalogItemDtoAbstract<T> getAbstractCatalogItem(CatalogItem<T> item) {
-        while (item instanceof CatalogItemDo) item = ((CatalogItemDo<T>)item).itemDto;
+    private <T,SpecT> CatalogItemDtoAbstract<T,SpecT> getAbstractCatalogItem(CatalogItem<T,SpecT> item) {
+        while (item instanceof CatalogItemDo) item = ((CatalogItemDo<T,SpecT>)item).itemDto;
         if (item==null) return null;
-        if (item instanceof CatalogItemDtoAbstract) return (CatalogItemDtoAbstract<T>) item;
+        if (item instanceof CatalogItemDtoAbstract) return (CatalogItemDtoAbstract<T,SpecT>) item;
         throw new IllegalStateException("Cannot unwrap catalog item '"+item+"' (type "+item.getClass()+") to restore DTO");
     }
 
-    private <T> CatalogItemDtoAbstract<T> getAbstractCatalogItem(String yaml) {
+    private <T,SpecT> CatalogItemDtoAbstract<T,SpecT> getAbstractCatalogItem(String yaml) {
         CampPlatform camp = BrooklynServerConfig.getCampPlatform(mgmt).get();
         
         DeploymentPlan plan = camp.pdp().parseDeploymentPlan(Streams.newReaderWithContents(yaml));
@@ -145,17 +151,17 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     }
 
     @Override
-    public CatalogItem<?> addItem(String yaml) {
+    public CatalogItem<?,?> addItem(String yaml) {
         log.debug("Adding manual catalog item to "+mgmt+": "+yaml);
         Preconditions.checkNotNull(yaml, "yaml");
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
-        CatalogItemDtoAbstract<Object> itemDto = getAbstractCatalogItem(yaml);
+        CatalogItemDtoAbstract<?,?> itemDto = getAbstractCatalogItem(yaml);
         manualAdditionsCatalog.addEntry(itemDto);
         return itemDto;
     }
 
     @Override @Deprecated
-    public void addItem(CatalogItem<?> item) {
+    public void addItem(CatalogItem<?,?> item) {
         log.debug("Adding manual catalog item to "+mgmt+": "+item);
         Preconditions.checkNotNull(item, "item");
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
@@ -163,7 +169,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     }
 
     @Override @Deprecated
-    public CatalogItem<?> addItem(Class<?> type) {
+    public CatalogItem<?,?> addItem(Class<?> type) {
         log.debug("Adding manual catalog item to "+mgmt+": "+type);
         Preconditions.checkNotNull(type, "type");
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
@@ -201,23 +207,23 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
-    public <T> Iterable<CatalogItem<T>> getCatalogItems() {
+    public <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems() {
         return ImmutableList.copyOf((Iterable)catalog.getCache().values());
     }
     
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
-    public <T> Iterable<CatalogItem<T>> getCatalogItems(Predicate<? super CatalogItem<T>> filter) {
-        Iterable<CatalogItemDo<T>> filtered = Iterables.filter((Iterable)catalog.getCache().values(), (Predicate<CatalogItem<T>>)(Predicate) filter);
-        return Iterables.transform(filtered, BasicBrooklynCatalog.<T,T>itemDoToDto());
+    public <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems(Predicate<? super CatalogItem<T,SpecT>> filter) {
+        Iterable<CatalogItemDo<T,SpecT>> filtered = Iterables.filter((Iterable)catalog.getCache().values(), (Predicate<CatalogItem<T,SpecT>>)(Predicate) filter);
+        return Iterables.transform(filtered, BasicBrooklynCatalog.<T,SpecT>itemDoToDto());
     }
 
     @SuppressWarnings({ "unchecked" })
-    private static <T2,T> Function<CatalogItemDo<T2>, CatalogItem<T>> itemDoToDto() {
-        return new Function<CatalogItemDo<T2>, CatalogItem<T>>() {
+    private static <T,SpecT> Function<CatalogItemDo<T,SpecT>, CatalogItem<T,SpecT>> itemDoToDto() {
+        return new Function<CatalogItemDo<T,SpecT>, CatalogItem<T,SpecT>>() {
             @Override
-            public CatalogItem<T> apply(@Nullable CatalogItemDo<T2> item) {
-                return (CatalogItem<T>) item.getDto();
+            public CatalogItem<T,SpecT> apply(@Nullable CatalogItemDo<T,SpecT> item) {
+                return item.getDto();
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogClasspathDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogClasspathDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogClasspathDo.java
index de5a7fb..06d0914 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogClasspathDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogClasspathDo.java
@@ -146,7 +146,7 @@ public class CatalogClasspathDo {
                 Set<Class<?>> catalogClasses = scanner.getTypesAnnotatedWith(Catalog.class);
                 for (Class<?> c: catalogClasses) {
                     try {
-                        CatalogItem<?> item = addCatalogEntry(c);
+                        CatalogItem<?,?> item = addCatalogEntry(c);
                         count++;
                         if (CatalogTemplateItemDto.class.isInstance(item)) countApps++;
                     } catch (Exception e) {
@@ -208,7 +208,7 @@ public class CatalogClasspathDo {
     }
 
     /** augments the given item with annotations and class data for the given class, then adds to catalog */
-    public CatalogItem<?> addCatalogEntry(Class<?> c) {
+    public CatalogItem<?,?> addCatalogEntry(Class<?> c) {
         if (Application.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogTemplateItemDto(), c);
         if (ApplicationBuilder.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogTemplateItemDto(), c);
         if (Entity.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogEntityItemDto(), c);
@@ -218,7 +218,7 @@ public class CatalogClasspathDo {
     
     /** augments the given item with annotations and class data for the given class, then adds to catalog 
      */
-    public CatalogItem<?> addCatalogEntry(CatalogItemDtoAbstract<?> item, Class<?> c) {
+    public CatalogItem<?,?> addCatalogEntry(CatalogItemDtoAbstract<?,?> item, Class<?> c) {
         Catalog annotations = c.getAnnotation(Catalog.class);
         item.type = c.getName();
         item.name = firstNonEmpty(c.getSimpleName(), c.getName());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogConfigurationDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogConfigurationDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogConfigurationDto.java
index 9a6694e..d52b539 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogConfigurationDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogConfigurationDto.java
@@ -4,7 +4,7 @@ import brooklyn.config.ConfigKey;
 
 
 @SuppressWarnings("rawtypes")
-public class CatalogConfigurationDto extends CatalogItemDtoAbstract<ConfigKey> {
+public class CatalogConfigurationDto extends CatalogItemDtoAbstract<ConfigKey,Void> {
     
     @Override
     public CatalogItemType getCatalogItemType() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
index b8759a4..c571585 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
@@ -32,7 +32,7 @@ public class CatalogDo {
     
     List<CatalogDo> childrenCatalogs = new ArrayList<CatalogDo>();
     CatalogClasspathDo classpath;
-    Map<String, CatalogItemDo<?>> cache;
+    Map<String, CatalogItemDo<?,?>> cache;
     
     AggregateClassLoader childrenClassLoader = AggregateClassLoader.newInstanceWithNoLoaders();
     ClassLoader recursiveClassLoader;
@@ -92,7 +92,7 @@ public class CatalogDo {
 
     private void loadCatalogItems() {
         List<CatalogLibrariesDo> loadedLibraries = Lists.newLinkedList();
-        for (CatalogItemDtoAbstract entry : dto.entries) {
+        for (CatalogItemDtoAbstract<?,?> entry : dto.entries) {
             CatalogLibrariesDo library = new CatalogLibrariesDo(entry.getLibrariesDto());
             library.load(mgmt);
             loadedLibraries.add(library);
@@ -128,20 +128,20 @@ public class CatalogDo {
         return childL;
     }
 
-    protected Map<String, CatalogItemDo<?>> getCache() {
-        Map<String, CatalogItemDo<?>> cache = this.cache;
+    protected Map<String, CatalogItemDo<?,?>> getCache() {
+        Map<String, CatalogItemDo<?,?>> cache = this.cache;
         if (cache==null) cache = buildCache();
         return cache;
     }
     
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected synchronized Map<String, CatalogItemDo<?>> buildCache() {
+    protected synchronized Map<String, CatalogItemDo<?,?>> buildCache() {
         if (cache!=null) return cache;
         log.debug("Building cache for "+this);
         if (!isLoaded()) 
             log.debug("Catalog not fully loaded when loading cache of "+this);
         
-        Map<String, CatalogItemDo<?>> cache = new LinkedHashMap<String, CatalogItemDo<?>>();
+        Map<String, CatalogItemDo<?,?>> cache = new LinkedHashMap<String, CatalogItemDo<?,?>>();
         
         // build the cache; first from children catalogs, then from local entities
         // so that root and near-root takes precedence over deeper items;
@@ -155,9 +155,9 @@ public class CatalogDo {
                 cache.putAll(child.getCache());
         }
         if (dto.entries!=null) {
-            List<CatalogItemDtoAbstract<?>> entriesReversed = new ArrayList<CatalogItemDtoAbstract<?>>(dto.entries);
+            List<CatalogItemDtoAbstract<?,?>> entriesReversed = new ArrayList<CatalogItemDtoAbstract<?,?>>(dto.entries);
             Collections.reverse(entriesReversed);
-            for (CatalogItemDtoAbstract<?> entry: entriesReversed)
+            for (CatalogItemDtoAbstract<?,?> entry: entriesReversed)
                 cache.put(entry.getId(), new CatalogItemDo(this, entry));
         }
         
@@ -175,9 +175,9 @@ public class CatalogDo {
      * callers may prefer {@link CatalogClasspathDo#addCatalogEntry(CatalogItemDtoAbstract, Class)}
      */
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public synchronized void addEntry(CatalogItemDtoAbstract<?> entry) {
+    public synchronized void addEntry(CatalogItemDtoAbstract<?,?> entry) {
         if (dto.entries==null) 
-            dto.entries = new ArrayList<CatalogItemDtoAbstract<?>>();
+            dto.entries = new ArrayList<CatalogItemDtoAbstract<?,?>>();
         dto.entries.add(entry);
         if (cache!=null)
             cache.put(entry.getId(), new CatalogItemDo(this, entry));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
index f222215..bd34020 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
@@ -21,7 +21,7 @@ public class CatalogDto {
     String name;
     String description;
     CatalogClasspathDto classpath;
-    List<CatalogItemDtoAbstract<?>> entries = null;
+    List<CatalogItemDtoAbstract<?,?>> entries = null;
     
     // for thread-safety, any dynamic additions to this should be handled by a method 
     // in this class which does copy-on-write

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogEntityItemDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogEntityItemDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogEntityItemDto.java
index 234de98..8a61f24 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogEntityItemDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogEntityItemDto.java
@@ -1,9 +1,10 @@
 package brooklyn.catalog.internal;
 
 import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 
 
-public class CatalogEntityItemDto extends CatalogItemDtoAbstract<Entity> {
+public class CatalogEntityItemDto extends CatalogItemDtoAbstract<Entity,EntitySpec<?>> {
     
     @Override
     public CatalogItemType getCatalogItemType() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
index edce2e7..1a6c804 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
@@ -7,19 +7,19 @@ import com.google.common.base.Preconditions;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.util.exceptions.Exceptions;
 
-public class CatalogItemDo<T> implements CatalogItem<T> {
+public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT> {
 
     protected final CatalogDo catalog;
-    protected final CatalogItem<T> itemDto;
+    protected final CatalogItem<T,SpecT> itemDto;
 
     protected volatile Class<T> javaClass; 
     
-    public CatalogItemDo(CatalogDo catalog, CatalogItem<T> itemDto) {
+    public CatalogItemDo(CatalogDo catalog, CatalogItem<T,SpecT> itemDto) {
         this.catalog = Preconditions.checkNotNull(catalog, "catalog");
         this.itemDto = Preconditions.checkNotNull(itemDto, "itemDto");
     }
 
-    public CatalogItem<?> getDto() {
+    public CatalogItem<T,SpecT> getDto() {
         return itemDto;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
index d834911..771e37b 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
@@ -4,7 +4,7 @@ import javax.annotation.Nonnull;
 
 import brooklyn.catalog.CatalogItem;
 
-public abstract class CatalogItemDtoAbstract<T> implements CatalogItem<T> {
+public abstract class CatalogItemDtoAbstract<T,SpecT> implements CatalogItem<T,SpecT> {
 
     String id;
     String type;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogPolicyItemDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogPolicyItemDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogPolicyItemDto.java
index 032a352..00ba3f6 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogPolicyItemDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogPolicyItemDto.java
@@ -1,9 +1,10 @@
 package brooklyn.catalog.internal;
 
 import brooklyn.policy.Policy;
+import brooklyn.policy.PolicySpec;
 
 
-public class CatalogPolicyItemDto extends CatalogItemDtoAbstract<Policy> {
+public class CatalogPolicyItemDto extends CatalogItemDtoAbstract<Policy,PolicySpec<?>> {
     
     @Override
     public CatalogItemType getCatalogItemType() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/main/java/brooklyn/catalog/internal/CatalogTemplateItemDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogTemplateItemDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogTemplateItemDto.java
index 32b4313..e4016d9 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogTemplateItemDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogTemplateItemDto.java
@@ -1,8 +1,9 @@
 package brooklyn.catalog.internal;
 
 import brooklyn.entity.Application;
+import brooklyn.entity.proxying.EntitySpec;
 
-public class CatalogTemplateItemDto extends CatalogItemDtoAbstract<Application> {
+public class CatalogTemplateItemDto extends CatalogItemDtoAbstract<Application,EntitySpec<?>> {
 
     @Override
     public CatalogItemType getCatalogItemType() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
index ba5a863..51c60ee 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
@@ -50,7 +50,7 @@ public class CatalogDtoTest {
         Assert.assertEquals(root.catalogs.size(), 5);
         CatalogDo loader = new CatalogDo(root).load(managementContext, null);
         
-        CatalogItemDo<?> worker = loader.getCache().get("io.brooklyn.mapr.m3.WorkerNode");
+        CatalogItemDo<?,?> worker = loader.getCache().get("io.brooklyn.mapr.m3.WorkerNode");
         Assert.assertNotNull(worker);
         Assert.assertEquals(worker.getName(), "M3 Worker Node");
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
index 9961d3a..b2c4fdd 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
@@ -33,7 +33,7 @@ public class CatalogLoadTest {
         assertEquals(catalog.name, "OSGi catalogue");
         assertEquals(catalog.entries.size(), 1, "Catalog entries = " + Joiner.on(", ").join(catalog.entries));
 
-        CatalogItemDtoAbstract<?> template = Iterables.getOnlyElement(catalog.entries);
+        CatalogItemDtoAbstract<?,?> template = Iterables.getOnlyElement(catalog.entries);
         assertEquals(template.getName(), "Entity name");
         assertEquals(template.getVersion(), "9.1.3");
         assertEquals(template.getJavaType(), "com.example.ExampleApp");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
index 86b62ef..538f9cc 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
@@ -16,6 +16,7 @@ import brooklyn.catalog.internal.MyCatalogItems.MySillyAppTemplate;
 import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.Application;
 import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.util.net.Urls;
 import brooklyn.util.text.Strings;
@@ -80,17 +81,17 @@ public class CatalogScanTest {
         loadAnnotationsOnlyCatalog();
         BrooklynCatalog c = annotsCatalog;
         
-        Iterable<CatalogItem<Object>> bases = c.getCatalogItems(CatalogPredicates.name(Predicates.containsPattern("MyBaseEntity")));
+        Iterable<CatalogItem<Object,Object>> bases = c.getCatalogItems(CatalogPredicates.name(Predicates.containsPattern("MyBaseEntity")));
         Assert.assertEquals(Iterables.size(bases), 0, "should have been empty: "+bases);
         
-        Iterable<CatalogItem<Object>> asdfjkls = c.getCatalogItems(CatalogPredicates.name(Predicates.containsPattern("__asdfjkls__shouldnotbefound")));
+        Iterable<CatalogItem<Object,Object>> asdfjkls = c.getCatalogItems(CatalogPredicates.name(Predicates.containsPattern("__asdfjkls__shouldnotbefound")));
         Assert.assertEquals(Iterables.size(asdfjkls), 0);
         
-        Iterable<CatalogItem<Object>> silly1 = c.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppTemplate")));
-        Iterable<CatalogItem<Object>> silly2 = c.getCatalogItems(CatalogPredicates.javaType(Predicates.equalTo(MySillyAppTemplate.class.getName())));
+        Iterable<CatalogItem<Object,Object>> silly1 = c.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppTemplate")));
+        Iterable<CatalogItem<Object,Object>> silly2 = c.getCatalogItems(CatalogPredicates.javaType(Predicates.equalTo(MySillyAppTemplate.class.getName())));
         Assert.assertEquals(Iterables.getOnlyElement(silly1), Iterables.getOnlyElement(silly2));
         
-        CatalogItem<Application> s1 = c.getCatalogItem(Application.class, silly1.iterator().next().getId());
+        CatalogItem<Application,EntitySpec<? extends Application>> s1 = c.getCatalogItem(Application.class, silly1.iterator().next().getId());
         Assert.assertEquals(s1, Iterables.getOnlyElement(silly1));
         
         Assert.assertEquals(s1.getDescription(), "Some silly app test");
@@ -106,14 +107,14 @@ public class CatalogScanTest {
     @Test
     public void testAnnotationLoadsSomeApps() {
         loadAnnotationsOnlyCatalog();
-        Iterable<CatalogItem<Object>> silly1 = annotsCatalog.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppTemplate")));
+        Iterable<CatalogItem<Object,Object>> silly1 = annotsCatalog.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppTemplate")));
         Assert.assertEquals(Iterables.getOnlyElement(silly1).getDescription(), "Some silly app test");
     }
     
     @Test
     public void testAnnotationLoadsSomeAppBuilders() {
         loadAnnotationsOnlyCatalog();
-        Iterable<CatalogItem<Object>> silly1 = annotsCatalog.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppBuilderTemplate")));
+        Iterable<CatalogItem<Object,Object>> silly1 = annotsCatalog.getCatalogItems(CatalogPredicates.name(Predicates.equalTo("MySillyAppBuilderTemplate")));
         Assert.assertEquals(Iterables.getOnlyElement(silly1).getDescription(), "Some silly app builder test");
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
index 9e5ad6f..2652c59 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
@@ -67,7 +67,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateIns
         // createApplicationFromCatalog branch below is never taken.  If `id'
         // key is given in blueprint it is available with:
         // Object customId = template.getCustomAttributes().get("id");
-        CatalogItem<?> item = catalog.getCatalogItem(template.getId());
+        CatalogItem<?,?> item = catalog.getCatalogItem(template.getId());
 
         if (item==null) {
             return createApplicationFromNonCatalogCampTemplate(template, platform);
@@ -76,7 +76,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateIns
         }
     }
 
-    protected Application createApplicationFromCatalog(CampPlatform platform, CatalogItem<?> item, AssemblyTemplate template) {
+    protected Application createApplicationFromCatalog(CampPlatform platform, CatalogItem<?,?> item, AssemblyTemplate template) {
         ManagementContext mgmt = getBrooklynManagementContext(platform);
 
         if (!template.getApplicationComponentTemplates().isEmpty() ||

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java
index 8a5acf8..3680091 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.catalog.CatalogItem;
 import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.management.ManagementContext;
 
 public abstract class AbstractTemplateBrooklynLookup<T extends AbstractResource>  extends AbstractBrooklynResourceLookup<T> {
@@ -21,7 +22,7 @@ public abstract class AbstractTemplateBrooklynLookup<T extends AbstractResource>
 
     @Override
     public T get(String id) {
-        CatalogItem<?> item = bmc.getCatalog().getCatalogItem(id);
+        CatalogItem<?,?> item = bmc.getCatalog().getCatalogItem(id);
         if (item==null) {
             log.warn("Could not find item '"+id+"' in Brooklyn catalog; returning null");
             return null;
@@ -29,9 +30,9 @@ public abstract class AbstractTemplateBrooklynLookup<T extends AbstractResource>
         return adapt(item);
     }
 
-    public abstract T adapt(CatalogItem<?> item);
+    public abstract T adapt(CatalogItem<?,?> item);
 
-    protected ResolvableLink<T> newLink(CatalogItem<? extends Entity> li) {
+    protected ResolvableLink<T> newLink(CatalogItem<? extends Entity,EntitySpec<?>> li) {
         return newLink(li.getId(), li.getName());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java
index e818073..5057c2f 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java
@@ -11,6 +11,8 @@ import java.util.List;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.entity.Application;
+import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.management.ManagementContext;
 
 public class AssemblyTemplateBrooklynLookup extends AbstractTemplateBrooklynLookup<AssemblyTemplate> {
@@ -20,7 +22,7 @@ public class AssemblyTemplateBrooklynLookup extends AbstractTemplateBrooklynLook
     }
 
     @Override
-    public AssemblyTemplate adapt(CatalogItem<?> item) {
+    public AssemblyTemplate adapt(CatalogItem<?,?> item) {
         return AssemblyTemplate.builder().
                 name(item.getName()).
                 id(item.getId()).
@@ -30,12 +32,20 @@ public class AssemblyTemplateBrooklynLookup extends AbstractTemplateBrooklynLook
                 build();
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    // why can I not pass an EntitySpec<? extends Application> to    newLink(EntitySpec<?> spec)  ?
+    // feels to me (alexheneveld) that `? extends Application` should be both covariant and contravariant to `?` ..
+    // but it's not, so we introduce this conversion method
+    protected ResolvableLink<AssemblyTemplate> newApplicationLink(CatalogItem<? extends Entity, EntitySpec<? extends Application>> li) {
+        return super.newLink((CatalogItem)li);
+    }
+    
     @Override
     public List<ResolvableLink<AssemblyTemplate>> links() {
-        Iterable<CatalogItem<Application>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_TEMPLATE);
+        Iterable<CatalogItem<Application,EntitySpec<? extends Application>>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_TEMPLATE);
         List<ResolvableLink<AssemblyTemplate>> result = new ArrayList<ResolvableLink<AssemblyTemplate>>();
-        for (CatalogItem<Application> li: l)
-            result.add(newLink(li));
+        for (CatalogItem<Application,EntitySpec<? extends Application>> li: l)
+            result.add(newApplicationLink(li));
         return result;
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java
index 891b96d..f0b6cce 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java
@@ -10,6 +10,7 @@ import java.util.List;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.management.ManagementContext;
 
 public class PlatformComponentTemplateBrooklynLookup extends AbstractTemplateBrooklynLookup<PlatformComponentTemplate> {
@@ -19,7 +20,7 @@ public class PlatformComponentTemplateBrooklynLookup extends AbstractTemplateBro
     }
 
     @Override
-    public PlatformComponentTemplate adapt(CatalogItem<?> item) {
+    public PlatformComponentTemplate adapt(CatalogItem<?,?> item) {
         return PlatformComponentTemplate.builder().
                 name(item.getName()).
                 id(item.getId()).
@@ -30,9 +31,9 @@ public class PlatformComponentTemplateBrooklynLookup extends AbstractTemplateBro
 
     @Override
     public List<ResolvableLink<PlatformComponentTemplate>> links() {
-        Iterable<CatalogItem<Entity>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_ENTITY);
+        Iterable<CatalogItem<Entity,EntitySpec<?>>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_ENTITY);
         List<ResolvableLink<PlatformComponentTemplate>> result = new ArrayList<ResolvableLink<PlatformComponentTemplate>>();
-        for (CatalogItem<Entity> li: l)
+        for (CatalogItem<Entity,EntitySpec<?>> li: l)
             result.add(newLink(li));
         return result;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
index fe266cf..78ca63c 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.entity.Entity;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.rest.api.CatalogApi;
 import brooklyn.rest.domain.ApiError;
 import brooklyn.rest.domain.CatalogEntitySummary;
@@ -57,7 +58,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
 
     @Override
     public Response create(String yaml) {
-        CatalogItem<?> item;
+        CatalogItem<?,?> item;
         try {
             item = brooklyn().getCatalog().addItem(yaml);
         } catch (IllegalArgumentException e) {
@@ -98,12 +99,12 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     @Override
     @SuppressWarnings("unchecked")
     public CatalogEntitySummary getEntity(String entityId) throws Exception {
-      CatalogItem<?> result = brooklyn().getCatalog().getCatalogItem(entityId);
+      CatalogItem<?,?> result = brooklyn().getCatalog().getCatalogItem(entityId);
       if (result==null) {
         throw WebResourceUtils.notFound("Entity with id '%s' not found", entityId);
       }
 
-      return CatalogTransformer.catalogEntitySummary(brooklyn(), (CatalogItem<? extends Entity>) result);
+      return CatalogTransformer.catalogEntitySummary(brooklyn(), (CatalogItem<? extends Entity,EntitySpec<?>>) result);
     }
 
     @Override
@@ -117,7 +118,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     @Override
     public CatalogItemSummary getPolicy(
         String policyId) throws Exception {
-        CatalogItem<?> result = brooklyn().getCatalog().getCatalogItem(policyId);
+        CatalogItem<?,?> result = brooklyn().getCatalog().getCatalogItem(policyId);
         if (result==null) {
           throw WebResourceUtils.notFound("Policy with id '%s' not found", policyId);
         }
@@ -126,7 +127,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    private <T> List<CatalogItemSummary> getCatalogItemSummariesMatchingRegexFragment(Predicate<CatalogItem<T>> type, String regex, String fragment) {
+    private <T,SpecT> List<CatalogItemSummary> getCatalogItemSummariesMatchingRegexFragment(Predicate<CatalogItem<T,SpecT>> type, String regex, String fragment) {
         List filters = new ArrayList();
         filters.add(type);
         if (Strings.isNonEmpty(regex))
@@ -140,7 +141,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
 
     @Override
     public Response getIcon(String itemId) {
-        CatalogItem<?> result = brooklyn().getCatalog().getCatalogItem(itemId);
+        CatalogItem<?,?> result = brooklyn().getCatalog().getCatalogItem(itemId);
         String url = result.getIconUrl();
         if (url==null) {
             log.debug("No icon available for "+result+"; returning "+Status.NO_CONTENT);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
index 5d2cf80..8b05bd9 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
@@ -13,8 +13,10 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.EntityType;
 import brooklyn.entity.basic.EntityDynamicType;
 import brooklyn.entity.basic.EntityTypes;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.Sensor;
 import brooklyn.policy.Policy;
+import brooklyn.policy.PolicySpec;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.domain.CatalogItemSummary;
 import brooklyn.rest.domain.CatalogPolicySummary;
@@ -33,7 +35,7 @@ public class CatalogTransformer {
     @SuppressWarnings("unused")
     private static final org.slf4j.Logger log = LoggerFactory.getLogger(CatalogTransformer.class);
     
-    public static CatalogEntitySummary catalogEntitySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Entity> item) {
+    public static CatalogEntitySummary catalogEntitySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Entity,EntitySpec<?>> item) {
         Class<? extends Entity> clazz = b.getCatalog().loadClass(item);
         EntityDynamicType typeMap = EntityTypes.getDefinedEntityType(clazz);
         EntityType type = typeMap.getSnapshot();
@@ -52,23 +54,23 @@ public class CatalogTransformer {
                 makeLinks(item));
     }
 
-    public static CatalogItemSummary catalogItemSummary(BrooklynRestResourceUtils b, CatalogItem<?> item) {
+    public static CatalogItemSummary catalogItemSummary(BrooklynRestResourceUtils b, CatalogItem<?,?> item) {
         return new CatalogItemSummary(item.getId(), item.getName(), item.getJavaType(),
                 item.getDescription(), tidyIconLink(b, item, item.getIconUrl()), makeLinks(item));
     }
 
-    public static CatalogPolicySummary catalogPolicySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Policy> item) {
+    public static CatalogPolicySummary catalogPolicySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Policy,PolicySpec<?>> item) {
         Set<PolicyConfigSummary> config = ImmutableSet.of();
         return new CatalogPolicySummary(item.getId(), item.getName(), item.getJavaType(),
                 item.getDescription(), tidyIconLink(b, item, item.getIconUrl()), config,
                 makeLinks(item));
     }
 
-    protected static Map<String, URI> makeLinks(CatalogItem<?> item) {
+    protected static Map<String, URI> makeLinks(CatalogItem<?,?> item) {
         return MutableMap.<String, URI>of();
     }
     
-    private static String tidyIconLink(BrooklynRestResourceUtils b, CatalogItem<?> item, String iconUrl) {
+    private static String tidyIconLink(BrooklynRestResourceUtils b, CatalogItem<?,?> item, String iconUrl) {
         if (b.isUrlServerSideAndSafe(iconUrl))
             return "/v1/catalog/icon/"+item.getId();
         return iconUrl;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/407de80a/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java b/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
index 8fc83bc..9fb3ca7 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -2,7 +2,6 @@ package brooklyn.rest.util;
 
 import static brooklyn.rest.util.WebResourceUtils.notFound;
 import static com.google.common.collect.Iterables.transform;
-import brooklyn.management.entitlement.Entitlements;
 import groovy.lang.GroovyClassLoader;
 
 import java.lang.reflect.Constructor;
@@ -23,7 +22,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.catalog.BrooklynCatalog;
 import brooklyn.catalog.CatalogItem;
-import brooklyn.catalog.CatalogItem.CatalogItemType;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Application;
@@ -40,6 +38,7 @@ import brooklyn.location.Location;
 import brooklyn.location.LocationRegistry;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.Task;
+import brooklyn.management.entitlement.Entitlements;
 import brooklyn.policy.Policy;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.rest.domain.ApplicationSpec;
@@ -346,7 +345,7 @@ public class BrooklynRestResourceUtils {
 
     protected Map<?, ?> getRenderingConfigurationFor(String catalogId) {
         MutableMap<Object, Object> result = MutableMap.of();
-        CatalogItem<?> item = mgmt.getCatalog().getCatalogItem(catalogId);
+        CatalogItem<?,?> item = mgmt.getCatalog().getCatalogItem(catalogId);
         if (item==null) return result;
         
         result.addIfNotNull("iconUrl", item.getIconUrl());
@@ -432,12 +431,12 @@ public class BrooklynRestResourceUtils {
         Class clazz = loader.parseClass(groovyCode);
 
         if (AbstractEntity.class.isAssignableFrom(clazz)) {
-            CatalogItem<?> item = getCatalog().addItem(clazz);
+            CatalogItem<?,?> item = getCatalog().addItem(clazz);
             log.info("REST created "+item);
             return Response.created(URI.create("entities/" + clazz.getName())).build();
 
         } else if (AbstractPolicy.class.isAssignableFrom(clazz)) {
-            CatalogItem<?> item = getCatalog().addItem(clazz);
+            CatalogItem<?,?> item = getCatalog().addItem(clazz);
             log.info("REST created "+item);
             return Response.created(URI.create("policies/" + clazz.getName())).build();
         }