http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
 
b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
new file mode 100644
index 0000000..2e704ee
--- /dev/null
+++ 
b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/UrlServiceSpecResolver.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn.spi.creation.service;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.CampUtils;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.net.Urls;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UrlServiceSpecResolver implements ServiceSpecResolver {
+    private static final Logger log = 
LoggerFactory.getLogger(UrlServiceSpecResolver.class);
+
+    @Override
+    public String getName() {
+        return "url";
+    }
+
+    @Override
+    public boolean accepts(String type, BrooklynClassLoadingContext loader) {
+        String protocol = Urls.getProtocol(type);
+        return protocol != null &&
+            
BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol);
+    }
+
+    @Override
+    public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext 
loader, Set<String> encounteredTypes) {
+        String yaml;
+        try {
+            yaml = ResourceUtils.create(this).getResourceAsString(type);
+        } catch (Exception e) {
+            log.warn("AssemblyTemplate type " + type + " which looks like a 
URL can't be fetched.", e);
+            return null;
+        }
+        // Referenced specs are expected to be CAMP format as well.
+        List<EntitySpec<?>> serviceSpecs = CampUtils.createServiceSpecs(yaml, 
loader, encounteredTypes);
+        if (serviceSpecs.size() > 1) {
+            throw new UnsupportedOperationException("Only supporting single 
service in remotely referenced plans: got "+serviceSpecs);
+        }
+        return serviceSpecs.get(0);
+    }
+
+    @Override
+    public void injectManagementContext(ManagementContext managementContext) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
 
b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
new file mode 100644
index 0000000..fa6ca8d
--- /dev/null
+++ 
b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.HardcodedCatalogServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceSpecResolver
+org.apache.brooklyn.camp.brooklyn.spi.creation.service.UrlServiceSpecResolver
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
 
b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
deleted file mode 100644
index 9c941df..0000000
--- 
a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#  http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.BrooklynServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceTypeResolver
-org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceTypeResolver

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

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

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

Reply via email to