You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2014/07/09 23:46:36 UTC

[23/50] git commit: Fixing catalog listing/instantating from REST via yaml

Fixing catalog listing/instantating from REST via yaml


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

Branch: refs/heads/master
Commit: f241a1773526be76fb75116f24ea3a7d135ce4f2
Parents: fce9001
Author: Aled Sage <al...@gmail.com>
Authored: Mon Jul 7 16:49:22 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jul 9 22:34:44 2014 +0100

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  |  38 ++++++++++-
 .../entity/proxying/InternalEntityFactory.java  |  13 +++-
 .../osgi/brooklyn-tests-osgi-entities-0.1.0.jar | Bin 4810 -> 10752 bytes
 .../BrooklynAssemblyTemplateInstantiator.java   |  63 ++++++++++++++++---
 .../BrooklynComponentTemplateResolver.java      |  14 +++--
 .../spi/creation/BrooklynEntityMatcher.java     |  13 +++-
 .../resources/CatalogBundleResourceTest.java    |  62 ++++++++++++++++--
 7 files changed, 180 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/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 0d45cc8..bddac1a 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -18,7 +18,6 @@
  */
 package brooklyn.catalog.internal;
 
-import brooklyn.util.guava.Maybe;
 import io.brooklyn.camp.CampPlatform;
 import io.brooklyn.camp.spi.AssemblyTemplate;
 import io.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
@@ -40,8 +39,10 @@ import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.management.ManagementContext;
+import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.AggregateClassLoader;
 import brooklyn.util.javalang.LoadedClassLoader;
 import brooklyn.util.javalang.Reflections;
@@ -60,7 +61,24 @@ import com.google.common.collect.Iterables;
 public class BasicBrooklynCatalog implements BrooklynCatalog {
 
     private static final Logger log = LoggerFactory.getLogger(BasicBrooklynCatalog.class);
-    
+
+    public static class BrooklynLoaderTracker {
+        public static final ThreadLocal<BrooklynClassLoadingContext> loader = new ThreadLocal<BrooklynClassLoadingContext>();
+        
+        public static void setLoader(BrooklynClassLoadingContext val) {
+            loader.set(val);
+        }
+        
+        // TODO Stack, for recursive calls?
+        public static void unsetLoader(BrooklynClassLoadingContext val) {
+            loader.set(null);
+        }
+        
+        public static BrooklynClassLoadingContext getLoader() {
+            return loader.get();
+        }
+    }
+
     private final ManagementContext mgmt;
     private final CatalogDo catalog;
     private volatile CatalogDo manualAdditionsCatalog;
@@ -141,7 +159,14 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             CampPlatform camp = BrooklynServerConfig.getCampPlatform(mgmt).get();
             
             // TODO should not register new AT each time we instantiate from the same plan; use some kind of cache
-            AssemblyTemplate at = camp.pdp().registerDeploymentPlan(plan);
+            AssemblyTemplate at;
+            BrooklynClassLoadingContext loader = loadedItem.newClassLoadingContext(mgmt);
+            BrooklynLoaderTracker.setLoader(loader);
+            try {
+                at = camp.pdp().registerDeploymentPlan(plan);
+            } finally {
+                BrooklynLoaderTracker.unsetLoader(loader);
+            }
             
             try {
                 AssemblyTemplateInstantiator instantiator = at.getInstantiator().newInstance();
@@ -276,6 +301,13 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
         CatalogItemDtoAbstract<?,?> itemDto = getAbstractCatalogItem(yaml);
         manualAdditionsCatalog.addEntry(itemDto);
+        
+        // Load the libraries now.
+        // Otherwise, when CAMP looks up BrooklynEntityMatcher.accepts then it
+        // won't know about this bundle:class (via the catalog item's
+        // BrooklynClassLoadingContext) so will reject it as not-for-brooklyn.
+        new CatalogLibrariesDo(itemDto.getLibrariesDto()).load(mgmt);
+        
         return itemDto;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
index 4f8381c..931c2d3 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@ -45,6 +45,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.flags.FlagUtils;
+import brooklyn.util.javalang.AggregateClassLoader;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.task.Tasks;
 
@@ -139,8 +140,18 @@ public class InternalEntityFactory {
         builder.addAll(spec.getAdditionalInterfaces());
         Set<Class<?>> interfaces = builder.build();
         
+        // TODO OSGi strangeness! The classloader obtained from the type should be enough.
+        // If an OSGi class loader, it should delegate to find things like Entity.class etc.
+        // However, we get errors such as:
+        //    NoClassDefFoundError: brooklyn.event.AttributeSensor not found by io.brooklyn.brooklyn-test-osgi-entities
+        // Building our own aggregating class loader gets around this.
+        // But we really should not have to do this! What are the consequences?
+        AggregateClassLoader aggregateClassLoader =  AggregateClassLoader.newInstanceWithNoLoaders();
+        aggregateClassLoader.addFirst(classloader);
+        aggregateClassLoader.addLast(Entity.class.getClassLoader());
+
         return (T) java.lang.reflect.Proxy.newProxyInstance(
-                classloader,
+                aggregateClassLoader,
                 interfaces.toArray(new Class[interfaces.size()]),
                 new EntityProxyImpl(entity));
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/core/src/test/resources/brooklyn/osgi/brooklyn-tests-osgi-entities-0.1.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-tests-osgi-entities-0.1.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-tests-osgi-entities-0.1.0.jar
index 82d4f2e..fa1396d 100644
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-tests-osgi-entities-0.1.0.jar and b/core/src/test/resources/brooklyn/osgi/brooklyn-tests-osgi-entities-0.1.0.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/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 13f2180..a8c8ff6 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
@@ -23,7 +23,10 @@ import io.brooklyn.camp.spi.Assembly;
 import io.brooklyn.camp.spi.AssemblyTemplate;
 import io.brooklyn.camp.spi.PlatformComponentTemplate;
 import io.brooklyn.camp.spi.collection.ResolvableLink;
+import io.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
 
+import java.io.Reader;
+import java.io.StringReader;
 import java.lang.reflect.Constructor;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -37,6 +40,7 @@ import brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
 import brooklyn.camp.brooklyn.api.HasBrooklynManagementContext;
 import brooklyn.catalog.BrooklynCatalog;
 import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
@@ -109,18 +113,22 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         ManagementContext mgmt = getBrooklynManagementContext(platform);
         BrooklynCatalog catalog = mgmt.getCatalog();
         
-        CatalogItem<?,?> item = catalog.getCatalogItem(template.getId());
+        CatalogItem<?,?> item = catalog.getCatalogItem(template.getName());
+        BrooklynClassLoadingContext loader;
         if (item!=null) {
+            loader = item.newClassLoadingContext(mgmt);
             // TODO legacy path - currently item is always null because template.id is a random String,
             // and pretty sure that is the desired behaviour; we now (Jul 2014) automatically promote
             // so fine for users always to put the catalog registeredType in the services block;
             // if we did want to support users supplying an `id' that would be available not via the above
             // but via template.getCustomAttributes().get("id");
             
-            return createApplicationFromCatalog(platform, item, template, requireSpec);
+            // FIXME No longer called; delete:
+            // return createApplicationFromCatalog(platform, item, template, requireSpec);
         } else {
-            return new AppOrSpec(createApplicationFromNonCatalogCampTemplate(template, platform));
+            loader = JavaBrooklynClassLoadingContext.newDefault(mgmt);
         }
+        return new AppOrSpec(createApplicationFromNonCatalogCampTemplate(template, platform, loader));
     }
     
     private static class AppOrSpec {
@@ -282,16 +290,16 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
     }
 
     @SuppressWarnings("unchecked")
-    protected EntitySpec<? extends Application> createApplicationFromNonCatalogCampTemplate(AssemblyTemplate template, CampPlatform platform) {
+    protected EntitySpec<? extends Application> createApplicationFromNonCatalogCampTemplate(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader) {
         // AssemblyTemplates created via PDP, _specifying_ then entities to put in
         final ManagementContext mgmt = getBrooklynManagementContext(platform);
 
         BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance(
-            JavaBrooklynClassLoadingContext.newDefault(mgmt), template);
+            loader, template);
         EntitySpec<? extends Application> app = resolver.resolveSpec(StartableApplication.class, BasicApplicationImpl.class);
         
         // first build the children into an empty shell app
-        buildTemplateServicesAsSpecs(JavaBrooklynClassLoadingContext.newDefault(mgmt), template, app);
+        buildTemplateServicesAsSpecs(loader, template, platform, app);
         
         if (shouldUnwrap(template, app)) {
             EntitySpec<? extends Application> oldApp = app;
@@ -338,12 +346,51 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
         return true;
     }
 
-    private void buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, EntitySpec<? extends Application> root) {
+    private void buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, EntitySpec<? extends Application> root) {
         for (ResolvableLink<PlatformComponentTemplate> ctl: template.getPlatformComponentTemplates().links()) {
             PlatformComponentTemplate appChildComponentTemplate = ctl.resolve();
             BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, appChildComponentTemplate);
             
-            EntitySpec<? extends Entity> spec = entityResolver.resolveSpec();
+            EntitySpec<? extends Entity> spec;
+            
+            ManagementContext mgmt = loader.getManagementContext();
+            
+            CatalogItem<Entity, EntitySpec<?>> item = entityResolver.getCatalogItem();
+            if (item != null) {
+                String yaml = item.getPlanYaml();
+                Reader input = new StringReader(yaml);
+                
+                AssemblyTemplate at;
+                BrooklynClassLoadingContext itemLoader = item.newClassLoadingContext(mgmt);
+                BrooklynLoaderTracker.setLoader(itemLoader);
+                try {
+                    at = platform.pdp().registerDeploymentPlan(input);
+                } finally {
+                    BrooklynLoaderTracker.unsetLoader(itemLoader);
+                }
+
+
+                // FIXME Entitlement?
+//                if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, at)) {
+//                    throw WebResourceUtils.unauthorized("User '%s' is not authorized to start application %s",
+//                        Entitlements.getEntitlementContext().user(), yaml);
+//                }
+                
+                try {
+                    AssemblyTemplateInstantiator ati = at.getInstantiator().newInstance();
+                    if (ati instanceof BrooklynAssemblyTemplateInstantiator) {
+                        spec = EntitySpec.create(BasicApplication.class);
+                        ((BrooklynAssemblyTemplateInstantiator)ati).buildTemplateServicesAsSpecs(itemLoader, at, platform, (EntitySpec)spec);
+                    } else {
+                        throw new IllegalStateException("Cannot create application with instantiator: " + ati);
+                    }
+                } catch (Exception e) {
+                    throw Exceptions.propagate(e);
+                }
+            } else {
+                spec = entityResolver.resolveSpec();
+            }
+
             root.child(spec);
             
             BrooklynClassLoadingContext newLoader = entityResolver.loader;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 1bfc308..667d497 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -18,15 +18,12 @@
  */
 package io.brooklyn.camp.brooklyn.spi.creation;
 
-import io.brooklyn.camp.CampPlatform;
 import io.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import io.brooklyn.camp.spi.AbstractResource;
 import io.brooklyn.camp.spi.ApplicationComponentTemplate;
-import io.brooklyn.camp.spi.Assembly;
 import io.brooklyn.camp.spi.AssemblyTemplate;
 import io.brooklyn.camp.spi.PlatformComponentTemplate;
 
-import java.io.StringReader;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -35,9 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Nullable;
 
-import brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
 import brooklyn.catalog.CatalogItem;
-import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
@@ -160,6 +155,7 @@ public class BrooklynComponentTemplateResolver {
     protected String getCatalogIdOrJavaType() {
         String type = getDeclaredType();
         type = Strings.removeFromStart(type, "brooklyn:", "java:");
+        if (type == null) return null;
         
         // TODO currently a hardcoded list of aliases; would like that to come from mgmt somehow
         if (type.equals("cluster") || type.equals("Cluster")) return DynamicCluster.class.getName();
@@ -177,7 +173,12 @@ public class BrooklynComponentTemplateResolver {
      */
     @Nullable
     public CatalogItem<Entity,EntitySpec<?>> getCatalogItem() {
-        return loader.getManagementContext().getCatalog().getCatalogItem(Entity.class, getCatalogIdOrJavaType());
+        String type = getCatalogIdOrJavaType();
+        if (type != null) {
+            return loader.getManagementContext().getCatalog().getCatalogItem(Entity.class, type);
+        } else {
+            return null;
+        }
     }
     
     public boolean canResolve() {
@@ -219,6 +220,7 @@ public class BrooklynComponentTemplateResolver {
     /** resolves the spec, updating the loader if a catalog item is loaded */
     @SuppressWarnings("unchecked")
     public <T extends Entity> EntitySpec<T> resolveSpec() {
+        CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem();
         return (EntitySpec<T>)resolveSpec(loadEntityClass(), null);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
index 673e13f..218b6ea 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
@@ -18,6 +18,7 @@
  */
 package io.brooklyn.camp.brooklyn.spi.creation;
 
+import io.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import io.brooklyn.camp.spi.PlatformComponentTemplate;
 import io.brooklyn.camp.spi.PlatformComponentTemplate.Builder;
 import io.brooklyn.camp.spi.pdp.AssemblyTemplateConstructor;
@@ -30,8 +31,10 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.catalog.internal.BasicBrooklynCatalog;
 import brooklyn.entity.Entity;
 import brooklyn.management.ManagementContext;
+import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.classloading.JavaBrooklynClassLoadingContext;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
@@ -63,8 +66,16 @@ public class BrooklynEntityMatcher implements PdpMatcher {
      * or null if not supported */
     protected String lookupType(Object deploymentPlanItem) {
         if (deploymentPlanItem instanceof Service) {
+            String name = ((Service)deploymentPlanItem).getName();
+            if (mgmt.getCatalog().getCatalogItem(name) != null) {
+                return name;
+            }
+        }
+        if (deploymentPlanItem instanceof Service) {
             String serviceType = ((Service)deploymentPlanItem).getServiceType();
-            if (!BrooklynComponentTemplateResolver.Factory.supportsType(JavaBrooklynClassLoadingContext.newDefault(mgmt), serviceType))
+            BrooklynClassLoadingContext loader = BasicBrooklynCatalog.BrooklynLoaderTracker.getLoader();
+            if (loader == null) loader = JavaBrooklynClassLoadingContext.newDefault(mgmt);
+            if (!BrooklynComponentTemplateResolver.Factory.supportsType(loader, serviceType))
                 return null;
             return serviceType;
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f241a177/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogBundleResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogBundleResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogBundleResourceTest.java
index f4884e8..c3ccaca 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogBundleResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogBundleResourceTest.java
@@ -9,11 +9,14 @@ import javax.ws.rs.core.Response;
 
 import org.testng.annotations.Test;
 
+import brooklyn.entity.Application;
+import brooklyn.entity.Entity;
 import brooklyn.management.osgi.OsgiStandaloneTest;
 import brooklyn.rest.domain.ApplicationSummary;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.testing.BrooklynRestResourceTest;
 
+import com.google.common.collect.Iterables;
 import com.sun.jersey.api.client.ClientResponse;
 
 public class CatalogBundleResourceTest extends BrooklynRestResourceTest {
@@ -22,7 +25,6 @@ public class CatalogBundleResourceTest extends BrooklynRestResourceTest {
     public void testListApplicationYaml() throws Exception {
         String registeredTypeName = "my.catalog.app.id.load";
         addCatalogOSGiEntity(registeredTypeName);
-
         CatalogEntitySummary entityItem = client().resource("/v1/catalog/entities/"+registeredTypeName)
                 .get(CatalogEntitySummary.class);
 
@@ -45,8 +47,40 @@ public class CatalogBundleResourceTest extends BrooklynRestResourceTest {
         // Expect app to be running
         URI appUri = response.getLocation();
         waitForApplicationToBeRunning(response.getLocation());
-        assertEquals(client().resource(appUri).get(ApplicationSummary.class).getSpec().getName(), "simple-app-yaml");
-      }
+        ApplicationSummary appSummary = client().resource(appUri).get(ApplicationSummary.class);
+        String appId = appSummary.getId();
+        assertEquals(appSummary.getSpec().getName(), "simple-app-yaml");
+
+        Application app = (Application) getManagementContext().getEntityManager().getEntity(appId);
+        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
+        assertEquals(simpleEntity.getEntityType().getName(), "brooklyn.osgi.tests.SimpleEntity");
+    }
+
+//    @Test
+//    public void testLaunchApplicationWithCatalogReferencingOtherCatalogYaml() throws Exception {
+//        String referencedRegisteredTypeName = "my.catalog.app.id.referenced";
+//        String referrerRegisteredTypeName = "my.catalog.app.id.referring";
+//        addCatalogOSGiEntity(referencedRegisteredTypeName);
+//        addCatalogEntityReferencingCatalogEntry(referrerRegisteredTypeName, referencedRegisteredTypeName);
+//
+//        String yaml = "{ name: simple-app-yaml, location: localhost, services: [ { serviceType: "+referrerRegisteredTypeName+" } ] }";
+//        
+//        ClientResponse response = client().resource("/v1/applications")
+//            .entity(yaml, "application/x-yaml")
+//            .post(ClientResponse.class);
+//        assertTrue(response.getStatus()/100 == 2, "response is "+response);
+//        
+//        // Expect app to be running
+//        URI appUri = response.getLocation();
+//        waitForApplicationToBeRunning(response.getLocation());
+//        ApplicationSummary appSummary = client().resource(appUri).get(ApplicationSummary.class);
+//        String appId = appSummary.getId();
+//        assertEquals(appSummary.getSpec().getName(), "simple-app-yaml");
+//
+//        Application app = (Application) getManagementContext().getEntityManager().getEntity(appId);
+//        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
+//        assertEquals(simpleEntity.getEntityType().getName(), "brooklyn.osgi.tests.SimpleEntity");
+//    }
 
     private void addCatalogOSGiEntity(String registeredTypeName) {
         String catalogYaml =
@@ -64,10 +98,30 @@ public class CatalogBundleResourceTest extends BrooklynRestResourceTest {
             "services:\n"+
             "- type: brooklyn.osgi.tests.SimpleEntity\n";
 
+        addCatalogEntity(registeredTypeName, catalogYaml);
+    }
+
+    private void addCatalogEntityReferencingCatalogEntry(String ownRegisteredTypeName, String otherRegisteredTypeName) {
+        String catalogYaml =
+            "name: "+ownRegisteredTypeName+"\n"+
+            // FIXME name above should be unnecessary when brooklyn.catalog below is working
+            "brooklyn.catalog:\n"+
+            "  id: " + ownRegisteredTypeName + "\n"+
+            "  name: My Referrer Catalog App\n"+
+            "  description: My referrer description\n"+
+            "  icon_url: classpath://path/to/myicon.jpg\n"+
+            "  version: 0.2.1\n"+
+            "\n"+
+            "services:\n"+
+            "- type: "+otherRegisteredTypeName+"\n";
+
+        addCatalogEntity(ownRegisteredTypeName, catalogYaml);
+    }
+
+    private void addCatalogEntity(String registeredTypeName, String catalogYaml) {
         ClientResponse catalogResponse = client().resource("/v1/catalog")
             .post(ClientResponse.class, catalogYaml);
 
         assertEquals(catalogResponse.getStatus(), Response.Status.CREATED.getStatusCode());
     }
-
 }