You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2017/07/19 16:25:48 UTC

[18/39] brooklyn-server git commit: misc fixes related to type-reg / osgi, making the tests work

misc fixes related to type-reg / osgi, making the tests work

some failing tests still:
* still need to address TEMPLATEs in OSGi
* deprecation / catalog.xml persistence


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

Branch: refs/heads/master
Commit: 02cfe50a2075f0049e4d6c8b526bed1ca5bef4e4
Parents: bf31100
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jun 30 02:59:39 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Jun 30 14:08:25 2017 +0100

----------------------------------------------------------------------
 .../camp/brooklyn/AbstractYamlTest.java         | 39 +++++++++++-
 .../camp/brooklyn/ReferencedOsgiYamlTest.java   |  9 +--
 .../camp/brooklyn/ReferencedYamlOsgiTest.java   | 54 ++++++++++++++++
 .../camp/brooklyn/ReferencedYamlTest.java       | 10 +--
 .../catalog/CatalogOsgiLibraryTest.java         | 26 +++++---
 .../CatalogYamlEntityOsgiTypeRegistryTest.java  | 46 +++-----------
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  1 +
 .../core/BrooklynFeatureEnablement.java         |  3 +-
 .../catalog/internal/BasicBrooklynCatalog.java  | 27 +++++---
 .../catalog/internal/CatalogBundleLoader.java   |  7 ++-
 .../core/catalog/internal/CatalogUtils.java     | 65 +++++++++++++++-----
 .../core/typereg/BasicBrooklynTypeRegistry.java |  3 +-
 .../brooklyn/core/typereg/RegisteredTypes.java  | 12 ++++
 .../brooklyn/util/core/ClassLoaderUtils.java    | 40 ++++++++----
 .../brooklyn/util/core/LoaderDispatcher.java    |  3 +-
 .../util/text/BrooklynVersionSyntax.java        |  7 +++
 .../brooklyn/util/text/VersionComparator.java   |  6 +-
 17 files changed, 257 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
index 00b9d4e..0300fc0 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -18,9 +18,14 @@
  */
 package org.apache.brooklyn.camp.brooklyn;
 
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.Reader;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+import java.util.zip.ZipEntry;
 
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.entity.Application;
@@ -30,19 +35,28 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests.Builder;
+import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.core.osgi.BundleMaker;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.osgi.VersionedName;
 import org.apache.brooklyn.util.stream.Streams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -218,8 +232,31 @@ public abstract class AbstractYamlTest {
         mgmt().getCatalog().addItems(catalogYaml, forceUpdate);
     }
 
+    public static void addCatalogItemsAsOsgi(ManagementContext mgmt, String catalogYaml, VersionedName bundleName, boolean force) {
+        try {
+            BundleMaker bundleMaker = new BundleMaker(mgmt);
+            File bf = bundleMaker.createTempZip("test", MutableMap.of(
+                new ZipEntry(BasicBrooklynCatalog.CATALOG_BOM), new ByteArrayInputStream(catalogYaml.getBytes())));
+            ReferenceWithError<OsgiBundleInstallationResult> b = ((ManagementContextInternal)mgmt).getOsgiManager().get().installDeferredStart(
+                new BasicManagedBundle(bundleName.getSymbolicName(), bundleName.getVersionString(), null), 
+                new FileInputStream(bf),
+                false);
+            // bundle not started (no need), and BOM not installed nor validated above; 
+            // do BOM install and validation below manually to test the type registry approach
+            mgmt.getCatalog().addTypesFromBundleBom(catalogYaml, b.get().getMetadata(), force);
+            Map<RegisteredType, Collection<Throwable>> validation = mgmt.getCatalog().validateTypes( 
+                mgmt.getTypeRegistry().getMatching(RegisteredTypePredicates.containingBundle(b.get().getVersionedName())) );
+            if (!validation.isEmpty()) {
+                throw Exceptions.propagate("Brooklyn failed to load types: "+validation.keySet(), 
+                    Iterables.concat(validation.values()));
+            }
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
     protected void deleteCatalogEntity(String catalogItem) {
-        mgmt().getCatalog().deleteCatalogItem(catalogItem, TEST_VERSION);
+        ((BasicBrooklynTypeRegistry) mgmt().getTypeRegistry()).delete(new VersionedName(catalogItem, TEST_VERSION));
     }
 
     protected Logger getLogger() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedOsgiYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedOsgiYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedOsgiYamlTest.java
index 4fc647d..640e1c1 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedOsgiYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedOsgiYamlTest.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
@@ -193,10 +194,10 @@ public class ReferencedOsgiYamlTest extends AbstractYamlTest {
             "      item:",
             "        type: " + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY);
 
-        BrooklynCatalog catalog = mgmt().getCatalog();
-        Assert.assertNotNull(catalog.getCatalogItem("yaml.nested.catalog.nested", BrooklynCatalog.DEFAULT_VERSION));
-        Assert.assertNotNull(catalog.getCatalogItem("yaml.nested.catalog.simple", BrooklynCatalog.DEFAULT_VERSION));
-        Assert.assertNotNull(catalog.getCatalogItem("yaml.nested.catalog.more", BrooklynCatalog.DEFAULT_VERSION));
+        BrooklynTypeRegistry catalog = mgmt().getTypeRegistry();
+        Assert.assertNotNull(catalog.get("yaml.nested.catalog.nested", BrooklynCatalog.DEFAULT_VERSION));
+        Assert.assertNotNull(catalog.get("yaml.nested.catalog.simple", BrooklynCatalog.DEFAULT_VERSION));
+        Assert.assertNotNull(catalog.get("yaml.nested.catalog.more", BrooklynCatalog.DEFAULT_VERSION));
     }
 
     protected void assertCatalogReference() throws Exception {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlOsgiTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlOsgiTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlOsgiTest.java
new file mode 100644
index 0000000..e46a34f
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlOsgiTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.camp.brooklyn;
+
+import org.apache.brooklyn.util.osgi.VersionedName;
+import org.testng.annotations.Test;
+
+/** like superclass, but with OSGi enabled, complex references now work */
+public class ReferencedYamlOsgiTest extends ReferencedYamlTest {
+
+    @Override
+    protected boolean disableOsgi() {
+        return false;
+    }
+    
+    @Override
+    protected void addCatalogItems(String catalogYaml) {
+        addCatalogItemsAsOsgi(mgmt(), catalogYaml, VersionedName.fromString("sample-bundle:0-SNAPSHOT"), isForceUpdate());
+    }
+    
+    // these are not broken with OSGi
+    
+    @Test
+    public void testYamlReferencingEarlierItemLongFormEntity() throws Exception {
+        super.testYamlReferencingEarlierItemLongFormEntity();
+    }
+
+    @Test
+    public void testYamlReferencingEarlierItemInUrl() throws Exception {
+        super.testYamlReferencingEarlierItemInUrl();
+    }
+    
+    @Test
+    public void testYamlReferencingEarlierItemInUrlAsType() throws Exception {
+        super.testYamlReferencingEarlierItemInUrlAsType();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlTest.java
index e22a935..2626106 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencedYamlTest.java
@@ -169,7 +169,7 @@ public class ReferencedYamlTest extends AbstractYamlTest {
         checkChildEntitySpec(app, entityName);
     }
     
-    @Test  // long form discouraged but references should now still work
+    @Test(groups="Broken")  // long form discouraged but references should still work (but only in OSGi subclass)
     public void testYamlReferencingEarlierItemLongFormEntity() throws Exception {
         addCatalogItems(
             "brooklyn.catalog:",
@@ -222,7 +222,7 @@ public class ReferencedYamlTest extends AbstractYamlTest {
         checkChildEntitySpec(app, entityName);
     }
 
-    @Test  // references to co-bundled items work even in nested url yaml
+    @Test(groups="Broken")  // references to co-bundled items work even in nested url yaml (but only in OSGi subclass)
     public void testYamlReferencingEarlierItemInUrl() throws Exception {
         addCatalogItems(
             "brooklyn.catalog:",
@@ -231,7 +231,7 @@ public class ReferencedYamlTest extends AbstractYamlTest {
             "  - id: yaml.basic",
             "    version: " + TEST_VERSION,
             "    item:",
-            "      type: org.apache.brooklyn.entity.stock.BasicApplication",
+            "      type: org.apache.brooklyn.entity.stock.BasicEntity",
             "  - id: yaml.reference",
             "    version: " + TEST_VERSION,
             "    item: classpath://yaml-ref-catalog.yaml");  // this references yaml.basic above
@@ -245,7 +245,7 @@ public class ReferencedYamlTest extends AbstractYamlTest {
         checkChildEntitySpec(app, entityName);
     }
     
-    @Test  // reference to co-bundled items work also in nested url yaml as a type
+    @Test(groups="Broken")  // reference to co-bundled items work also in nested url yaml as a type (but only in OSGi subclass)
     public void testYamlReferencingEarlierItemInUrlAsType() throws Exception {
         addCatalogItems(
             "brooklyn.catalog:",
@@ -254,7 +254,7 @@ public class ReferencedYamlTest extends AbstractYamlTest {
             "  - id: yaml.basic",
             "    version: " + TEST_VERSION,
             "    item:",
-            "      type: org.apache.brooklyn.entity.stock.BasicApplication",
+            "      type: org.apache.brooklyn.entity.stock.BasicEntity",
             "  - id: yaml.reference",
             "    version: " + TEST_VERSION,
             "    item:",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
index 87a459e..bd07075 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
@@ -268,6 +268,15 @@ public class CatalogOsgiLibraryTest extends AbstractYamlTest {
             Assert.fail("Expected to find 'messages.txt'");
         }
     }
+
+    protected void assertCannotFindMessages(Entity entity) {
+        ResourceUtils ru = ResourceUtils.create(entity);
+        Iterable<URL> files = ru.getResources("org/apache/brooklyn/test/osgi/resources/message.txt");
+        if (files.iterator().hasNext()) {
+            Entities.dumpInfo(entity);
+            Assert.fail("Expected NOT to find 'messages.txt'");
+        }
+    }
     
     @Test
     public void testLibraryIsUsedByChildInCatalogItem() throws Exception {
@@ -295,16 +304,19 @@ public class CatalogOsgiLibraryTest extends AbstractYamlTest {
         // the spec has no catalog item ID except at the root Application
         
         Entity app = createAndStartApplication("services: [ { type: item-from-library } ]");
-        Entity entity = app.getChildren().iterator().next();
-        entity = entity.getChildren().iterator().next();
-        Entities.dumpInfo(entity);
+        Entity entity1 = app.getChildren().iterator().next();
+        
+        Entities.dumpInfo(app);
         
-        // TODO re-enable when we've converted to a search path;
+        Assert.assertEquals(entity1.getCatalogItemId(), "item-from-library:1.0");
+        assertCanFindMessages( entity1 );
+        
+        // TODO enable when we've converted to a search path;
         // currently this test method passes because of CatalogUtils.setCatalogItemIdOnAddition
         // but we don't want to be doing that, we only want the search path
-        //Assert.assertNull(entity.getCatalogItemId(), "Entity had a catalog item ID, even though it was stockj");
-        
-        assertCanFindMessages( entity );
+        //Entity entity2 = entity1.getChildren().iterator().next();
+        //Assert.assertNull(entity2.getCatalogItemId(), "Entity had a catalog item ID, even though it was stockj");
+        //assertCannotFindMessages( entity2 );
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityOsgiTypeRegistryTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityOsgiTypeRegistryTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityOsgiTypeRegistryTest.java
index cde5159..ac11898 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityOsgiTypeRegistryTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityOsgiTypeRegistryTest.java
@@ -18,25 +18,11 @@
  */
 package org.apache.brooklyn.camp.brooklyn.catalog;
 
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.util.Collection;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
-import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.osgi.BundleMaker;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.osgi.VersionedName;
 import org.testng.annotations.Test;
 
@@ -52,29 +38,7 @@ public class CatalogYamlEntityOsgiTypeRegistryTest extends CatalogYamlEntityTest
     // use type registry appraoch
     @Override
     protected void addCatalogItems(String catalogYaml) {
-        try {
-            BundleMaker bundleMaker = new BundleMaker(mgmt());
-            File bf = bundleMaker.createTempZip("test", MutableMap.of(
-                new ZipEntry(BasicBrooklynCatalog.CATALOG_BOM), new ByteArrayInputStream(catalogYaml.getBytes())));
-            ReferenceWithError<OsgiBundleInstallationResult> b = ((ManagementContextInternal)mgmt()).getOsgiManager().get().installDeferredStart(
-                new BasicManagedBundle(bundleName(), bundleVersion(), null), 
-                new FileInputStream(bf),
-                false);
-            // bundle not started (no need), and BOM not installed nor validated above; 
-            // do BOM install and validation below manually to test the type registry approach
-            mgmt().getCatalog().addTypesFromBundleBom(catalogYaml, b.get().getMetadata(), isForceUpdate());
-            Map<RegisteredType, Collection<Throwable>> validation = mgmt().getCatalog().validateTypes( mgmt().getTypeRegistry().getMatching(RegisteredTypePredicates.containingBundle(b.get().getVersionedName())) );
-            if (!validation.isEmpty()) {
-                throw Exceptions.propagate("Brooklyn failed to load types: "+validation.keySet(), 
-                    Iterables.concat(validation.values()));
-            }
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    protected void deleteCatalogEntity(String catalogItem) {
-        mgmt().getCatalog().deleteCatalogItem(catalogItem, TEST_VERSION);
+        addCatalogItemsAsOsgi(mgmt(), catalogYaml, new VersionedName(bundleName(), bundleVersion()), isForceUpdate());
     }
 
     protected String bundleName() { return "sample-bundle"; }
@@ -91,6 +55,12 @@ public class CatalogYamlEntityOsgiTypeRegistryTest extends CatalogYamlEntityTest
         Asserts.assertEquals(item, Iterables.getOnlyElement(itemsInstalled), "Wrong item; installed: "+itemsInstalled);
     }
 
-    // many other tests from super now run, with the type registry approach instead of catalog item / catalog approach
+    @Test // test broken in super works here
+    // TODO" comment at https://issues.apache.org/jira/browse/BROOKLYN-343
+    public void testSameCatalogReferences() {
+        super.testSameCatalogReferences();
+    }
+        
+    // also runs many other tests from super, here using the osgi/type-registry appraoch
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index d39a97e..9d907d9 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -552,6 +552,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
     
     @Test(groups = "Broken")
     // See https://issues.apache.org/jira/browse/BROOKLYN-343
+    // Fixed in OSGi subclass
     public void testSameCatalogReferences() {
         addCatalogItems(
             "brooklyn.catalog:",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
index fe3609a..2776d9b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
+++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
@@ -22,7 +22,6 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.internal.storage.BrooklynStorage;
 import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -121,6 +120,8 @@ public class BrooklynFeatureEnablement {
      * The functionality loads catalog items regardless of the persistence state so best used with persistence disabled.
      * If a bundle is uploaded its BOM is scanned regardless of this property (this only applies to bundles
      * installed through a non-brooklyn method, eg karaf.)
+     * 
+     * This installs legacy items and so should be deprecated in favour of uploading BOMs which Brooklyn manages.
      */
     public static final String FEATURE_LOAD_BUNDLE_CATALOG_BOM = FEATURE_PROPERTY_PREFIX+".osgi.catalog_bom";
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index 323c70f..8beb3be 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -627,11 +627,12 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             // don't scan
         } else {
             if (isNoBundleOrSimpleWrappingBundle(mgmt, containingBundle)) {
+                Collection<CatalogItemDtoAbstract<?, ?>> scanResult;
                 // BOMs wrapped in JARs, or without JARs, have special treatment
                 if (isLibrariesMoreThanJustContainingBundle(librariesAddedHereBundles, containingBundle)) {
                     // legacy mode, since 0.12.0, scan libraries referenced in a legacy non-bundle BOM
                     log.warn("Deprecated use of scanJavaAnnotations to scan other libraries ("+librariesAddedHereBundles+"); libraries should declare they scan themselves");
-                    result.addAll(scanAnnotationsLegacyInListOfLibraries(mgmt, librariesAddedHereBundles, catalogMetadata, containingBundle));
+                    scanResult = scanAnnotationsLegacyInListOfLibraries(mgmt, librariesAddedHereBundles, catalogMetadata, containingBundle);
                 } else if (!isLibrariesMoreThanJustContainingBundle(libraryBundles, containingBundle)) {
                     // for default catalog, no libraries declared, we want to scan local classpath
                     // bundle should be named "brooklyn-default-catalog"
@@ -642,10 +643,20 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
                         // since 0.12.0, require this to be right next to where libraries are defined, or at root
                         log.warn("Deprecated use of scanJavaAnnotations declared in item; should be declared at the top level of the BOM");
                     }
-                    result.addAll(scanAnnotationsFromLocalNonBundleClasspath(mgmt, catalogMetadata, containingBundle));
+                    scanResult = scanAnnotationsFromLocalNonBundleClasspath(mgmt, catalogMetadata, containingBundle);
                 } else {
                     throw new IllegalStateException("Cannot scan for Java catalog items when libraries declared on an ancestor; scanJavaAnnotations should be specified alongside brooklyn.libraries (or ideally those libraries should specify to scan)");
                 }
+                if (scanResult!=null && !scanResult.isEmpty()) {
+                    if (result!=null) {
+                        result.addAll( scanResult );
+                    } else {
+                        // not returning a result; we need to add here
+                        for (CatalogItem item: scanResult) {
+                            mgmt.getCatalog().addItem(item);
+                        }
+                    }
+                }
             } else {
                 throw new IllegalArgumentException("Scanning for Java annotations is not supported in BOMs in bundles; "
                     + "entries should be listed explicitly in the catalog.bom");
@@ -847,7 +858,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         // run again now that we know the ID to catch recursive definitions and possibly other mistakes (itemType inconsistency?)
         planInterpreter = new PlanInterpreterGuessingType(id, item, sourceYaml, itemType, libraryBundles, result).reconstruct();
         if (resolutionError==null && !planInterpreter.isResolved()) {
-            resolutionError = new IllegalStateException("Plan resolution breaks after id and itemType are set; is there a recursive reference or other type inconsistency?\n"+sourceYaml);
+            resolutionError = new IllegalStateException("Plan resolution for "+id+" breaks after id and itemType are set; is there a recursive reference or other type inconsistency?\n"+sourceYaml);
         }
         String sourcePlanYaml = planInterpreter.getPlanYaml();
 
@@ -951,7 +962,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
 
     private void collectUrlReferencedCatalogItems(String url, ManagedBundle containingBundle, List<CatalogItemDtoAbstract<?, ?>> result, boolean requireValidation, Map<Object, Object> parentMeta, int depth, boolean force) {
         @SuppressWarnings("unchecked")
-        List<?> parentLibrariesRaw = MutableList.copyOf(getFirstAs(parentMeta, List.class, "brooklyn.libraries", "libraries").orNull());
+        List<?> parentLibrariesRaw = MutableList.copyOf(getFirstAs(parentMeta, Iterable.class, "brooklyn.libraries", "libraries").orNull());
         Collection<CatalogBundle> parentLibraries = CatalogItemDtoAbstract.parseLibraries(parentLibrariesRaw);
         BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, "<catalog url reference loader>:0.0.0", parentLibraries);
         String yaml;
@@ -1626,11 +1637,11 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         CatalogItem<?, ?> existingDto = existingItem.getDto();
         if (existingDto.equals(itemDto)) {
             if (allowDuplicates) return existingItem;
-            throw new IllegalStateException("Updating existing catalog entries, even with the same content, is forbidden: " +
-                    itemDto.getSymbolicName() + ":" + itemDto.getVersion() + ". Use forceUpdate argument to override.");
+            throw new IllegalStateException("Not allowed to update existing catalog entries, even with the same content: " +
+                    itemDto.getSymbolicName() + ":" + itemDto.getVersion());
         } else {
-            throw new IllegalStateException("Updating existing catalog entries is forbidden: " +
-                    itemDto.getSymbolicName() + ":" + itemDto.getVersion() + ". Use forceUpdate argument to override.");
+            throw new IllegalStateException("Cannot add " + itemDto.getSymbolicName() + ":" + itemDto.getVersion() + 
+                " to catalog; a different definition is already present");
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
index bd9c7fa..90bc628 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
@@ -31,6 +31,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
@@ -90,6 +91,10 @@ public class CatalogBundleLoader {
         if (null != bom) {
             LOG.debug("Found catalog BOM in {} {} {}", CatalogUtils.bundleIds(bundle));
             String bomText = readBom(bom);
+            if (mb==null) {
+                LOG.warn("Bundle "+bundle+" containing BOM is not managed by Brooklyn; using legacy item installation");
+                legacy = true;
+            }
             if (legacy) {
                 catalogItems = this.managementContext.getCatalog().addItems(bomText, mb, force);
                 for (CatalogItem<?, ?> item : catalogItems) {
@@ -107,7 +112,7 @@ public class CatalogBundleLoader {
                 }
             }
             
-            if (BasicBrooklynCatalog.isNoBundleOrSimpleWrappingBundle(managementContext, mb)) {
+            if (!legacy && BasicBrooklynCatalog.isNoBundleOrSimpleWrappingBundle(managementContext, mb)) {
                 ((ManagementContextInternal)managementContext).getOsgiManager().get().addInstalledWrapperBundle(mb);
             }
         } else {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
index 473fa6b..81cbbcf 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.catalog.internal;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import javax.annotation.Nullable;
 
@@ -31,6 +32,7 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.BrooklynLogging;
@@ -50,7 +52,9 @@ import org.apache.brooklyn.core.typereg.RegisteredTypeNaming;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
 import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.osgi.VersionedName;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Time;
 import org.osgi.framework.Bundle;
@@ -97,11 +101,11 @@ public class CatalogUtils {
             log.warn("Cannot load "+catId+" to get classloader for "+entity+"; will try with standard loader, but might fail subsequently");
             return JavaBrooklynClassLoadingContext.create(mgmt);
         }
-        return newClassLoadingContext(mgmt, cat.get());
+        return newClassLoadingContext(mgmt, cat.get(), JavaBrooklynClassLoadingContext.create(mgmt));
     }
 
     public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries) {
-        return newClassLoadingContext(mgmt, catalogItemId, libraries, null);
+        return newClassLoadingContext(mgmt, catalogItemId, libraries, JavaBrooklynClassLoadingContext.create(mgmt));
     }
     
     @Deprecated /** @deprecated since 0.9.0; becoming private because we should now always have a registered type callers can pass instead of the catalog item id */
@@ -146,12 +150,12 @@ public class CatalogUtils {
     }
 
     public static BrooklynClassLoadingContext newClassLoadingContextForCatalogItems(
-        ManagementContext managementContext, String catalogItemId, List<String> searchPath) {
+        ManagementContext managementContext, String primaryItemId, List<String> searchPath) {
 
         BrooklynClassLoadingContextSequential seqLoader = new BrooklynClassLoadingContextSequential(managementContext);
-        addCatalogItemContext(managementContext, seqLoader, catalogItemId);
+        addSearchItem(managementContext, seqLoader, primaryItemId);
         for (String searchId : searchPath) {
-            addCatalogItemContext(managementContext, seqLoader, searchId);
+            addSearchItem(managementContext, seqLoader, searchId);
         }
         return seqLoader;
     }
@@ -341,29 +345,58 @@ public class CatalogUtils {
     @Deprecated
     public static void setDeprecated(ManagementContext mgmt, String symbolicName, String version, boolean newValue) {
         CatalogItem<?, ?> item = mgmt.getCatalog().getCatalogItem(symbolicName, version);
-        Preconditions.checkNotNull(item, "No such item: "+symbolicName+" v "+version);
-        item.setDeprecated(newValue);
-        mgmt.getCatalog().persist(item);
+        if (item!=null) {
+            item.setDeprecated(newValue);
+            mgmt.getCatalog().persist(item);
+        } else {
+            RegisteredType type = mgmt.getTypeRegistry().get(symbolicName, version);
+            if (type!=null) {
+                RegisteredTypes.setDeprecated(type, newValue);
+            } else {
+                throw new NoSuchElementException(symbolicName+":"+version);
+            }
+        }
     }
 
     /** @deprecated since it was introduced in 0.9.0; TBD where this should live */
     @Deprecated
     public static void setDisabled(ManagementContext mgmt, String symbolicName, String version, boolean newValue) {
         CatalogItem<?, ?> item = mgmt.getCatalog().getCatalogItem(symbolicName, version);
-        Preconditions.checkNotNull(item, "No such item: "+symbolicName+" v "+version);
-        item.setDisabled(newValue);
-        mgmt.getCatalog().persist(item);
+        if (item!=null) {
+            item.setDisabled(newValue);
+            mgmt.getCatalog().persist(item);
+        } else {
+            RegisteredType type = mgmt.getTypeRegistry().get(symbolicName, version);
+            if (type!=null) {
+                RegisteredTypes.setDisabled(type, newValue);
+            } else {
+                throw new NoSuchElementException(symbolicName+":"+version);
+            }
+        }
     }
 
-    private static void addCatalogItemContext(ManagementContext managementContext, BrooklynClassLoadingContextSequential loader, String catalogItemId) {
-        RegisteredType item = managementContext.getTypeRegistry().get(catalogItemId);
-
+    private static void addSearchItem(ManagementContext managementContext, BrooklynClassLoadingContextSequential loader, String itemId) {
+        OsgiManager osgi = ((ManagementContextInternal)managementContext).getOsgiManager().orNull();
+        boolean didSomething = false;
+        if (osgi!=null) {
+            ManagedBundle bundle = osgi.getManagedBundle(VersionedName.fromString(itemId));
+            if (bundle!=null) {
+                loader.add( newClassLoadingContext(managementContext, itemId, MutableSet.of(bundle)) );
+                didSomething = true;
+                // but also load entities, if name is same as a bundle and libraries are set on entity
+            }
+        }
+        
+        RegisteredType item = managementContext.getTypeRegistry().get(itemId);
         if (item != null) {
             BrooklynClassLoadingContext itemLoader = newClassLoadingContext(managementContext, item);
             loader.add(itemLoader);
-        } else {
+            didSomething = true;
+        }
+
+        if (!didSomething) {
             // TODO review what to do here
-            log.warn("Can't find catalog item " + catalogItemId);
+            log.warn("Can't find catalog item " + itemId);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
index 1d07a5a..5095f68 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
@@ -41,6 +41,7 @@ import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.osgi.VersionedName;
+import org.apache.brooklyn.util.text.BrooklynVersionSyntax;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -311,7 +312,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
             Asserts.fail("Registered type "+type+" has ID / symname mismatch");
         
         RegisteredType oldType = mgmt.getTypeRegistry().get(type.getId());
-        if (oldType==null || canForce) {
+        if (oldType==null || canForce || BrooklynVersionSyntax.isSnapshot(oldType.getVersion())) {
             log.debug("Inserting "+type+" into "+this);
             localRegisteredTypes.put(type.getId(), type);
         } else {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
index 2f205eb..06014c6 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
@@ -210,6 +210,18 @@ public class RegisteredTypes {
     }
 
     @Beta
+    public static RegisteredType setDeprecated(RegisteredType type, boolean deprecated) {
+        ((BasicRegisteredType)type).deprecated = deprecated;
+        return type;
+    }
+
+    @Beta
+    public static RegisteredType setDisabled(RegisteredType type, boolean disabled) {
+        ((BasicRegisteredType)type).disabled = disabled;
+        return type;
+    }
+
+    @Beta
     public static RegisteredType addSuperType(RegisteredType type, @Nullable Class<?> superType) {
         if (superType!=null) {
             ((BasicRegisteredType)type).superTypes.add(superType);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
index 8d5cf0f..c3e75be 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
@@ -27,20 +27,21 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
+import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
 import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.LoaderDispatcher.ClassLoaderDispatcher;
 import org.apache.brooklyn.util.core.LoaderDispatcher.MultipleResourceLoaderDispatcher;
 import org.apache.brooklyn.util.core.LoaderDispatcher.ResourceLoaderDispatcher;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.osgi.OsgiUtils;
-import org.apache.brooklyn.util.text.BrooklynVersionSyntax;
 import org.apache.brooklyn.util.text.Strings;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -253,18 +254,31 @@ public class ClassLoaderUtils {
         Maybe<T> cls;
         if (entity != null && mgmt != null) {
             String catalogItemId = entity.getCatalogItemId();
+
             if (catalogItemId != null) {
-//                RegisteredType type = mgmt.getTypeRegistry().get(catalogItemId);
-//                if (type != null) {
-//                    BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt);
-//                    loader.add(newClassLoadingContextForCatalogItems(mgmt, type.getId(),
-//                        type.getContainingBundle() + type.getLibraries() ?);
-//                    cls = dispatcher.tryLoadFrom(loader, className);
-//                    if (cls.isPresent()) {
-//                        return cls;
-//                    }
-                // TODO prefer above to below, but need to reconcile item.searchPath with RegisteredType?
-                // or use entity search path ?
+                {
+                    BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt);
+                    loader.add( newClassLoadingContextForCatalogItems(mgmt, catalogItemId,
+                        entity.getCatalogItemIdSearchPath()) );
+                    cls = dispatcher.tryLoadFrom(loader, className);
+                    if (cls.isPresent()) {
+                        return cls;
+                    }
+                }
+                // the above (entity) should be sufficient?
+                
+                RegisteredType type = mgmt.getTypeRegistry().get(catalogItemId);
+                if (type != null) {
+                    BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt);
+                    List<String> libs = MutableList.of();
+                    for (OsgiBundleWithUrl o: type.getLibraries()) libs.add(o.getVersionedName().toString());
+                    loader.add( newClassLoadingContextForCatalogItems(mgmt, type.getContainingBundle(), libs) );
+                    cls = dispatcher.tryLoadFrom(loader, className);
+                    if (cls.isPresent()) {
+                        return cls;
+                    }
+                }
+                
                 CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId);
                 if (item != null) {
                     BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/core/src/main/java/org/apache/brooklyn/util/core/LoaderDispatcher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/LoaderDispatcher.java b/core/src/main/java/org/apache/brooklyn/util/core/LoaderDispatcher.java
index 8fffa9d..4d13aa8 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/LoaderDispatcher.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/LoaderDispatcher.java
@@ -54,7 +54,8 @@ public interface LoaderDispatcher<T> {
         @Override
         public Maybe<Class<?>> tryLoadFrom(BrooklynClassLoadingContext loader, String className) {
             try {
-                return Maybe.<Class<?>>of(loader.loadClass(className));
+                // return Maybe.<Class<?>>of(loader.loadClass(className));
+                return loader.tryLoadClass(className);
             } catch (IllegalStateException e) {
                 propagateIfCauseNotClassNotFound(e);
                 return Maybe.absent("Failed to load class " + className + " from loader " + loader, e);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/utils/common/src/main/java/org/apache/brooklyn/util/text/BrooklynVersionSyntax.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/BrooklynVersionSyntax.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/BrooklynVersionSyntax.java
index 887ca6b..1e0e698 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/BrooklynVersionSyntax.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/BrooklynVersionSyntax.java
@@ -31,6 +31,8 @@ import com.google.common.base.Preconditions;
  */
 public class BrooklynVersionSyntax {
 
+    private static final String SNAPSHOT = "SNAPSHOT";
+
     public static final String USABLE_REGEX = "[^:\\s/\\\\]+";
     public static final String DOT = "\\.";
 
@@ -192,4 +194,9 @@ public class BrooklynVersionSyntax {
         return toValidOsgiVersion(v1).equals(toValidOsgiVersion(v2));
     }
 
+    public static boolean isSnapshot(String version) {
+        if (version==null) return false;
+        return version.toUpperCase().contains(SNAPSHOT);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02cfe50a/utils/common/src/main/java/org/apache/brooklyn/util/text/VersionComparator.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/VersionComparator.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/VersionComparator.java
index 120a210..449d0e5 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/VersionComparator.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/VersionComparator.java
@@ -44,8 +44,6 @@ import com.google.common.base.Objects;
  */
 public class VersionComparator implements Comparator<String> {
     
-    private static final String SNAPSHOT = "SNAPSHOT";
-
     public static final VersionComparator INSTANCE = new VersionComparator();
 
     public static VersionComparator getInstance() {
@@ -53,10 +51,8 @@ public class VersionComparator implements Comparator<String> {
     }
 
     public static boolean isSnapshot(String version) {
-        if (version==null) return false;
-        return version.toUpperCase().contains(SNAPSHOT);
+        return BrooklynVersionSyntax.isSnapshot(version);
     }
-
     
     @SuppressWarnings("unused")
     private static class TwoBooleans {