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

[14/18] git commit: OSGi catalog item test (see full msg for details)

OSGi catalog item test (see full msg for details)

Add some more OSGi test bundles - see OsgiTestResources.
Write lots more tests of OSGi loading and item ID - in OsgiEntitiesTest, and in camp project using YAML e.g. Catalog*Osgi*Test.java .
Also load OSGi on addItem(CatalogItem), and improve OSGi loading error messages when OSGi loading fails.
Better error messages on OSGi failures.


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

Branch: refs/heads/master
Commit: 35fd634154c0248f16ea3f5f09e4229b13f902e2
Parents: a76208a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Nov 3 09:57:13 2014 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Nov 4 11:10:55 2014 +0000

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  |  12 +-
 .../brooklyn/catalog/internal/CatalogDo.java    |   1 -
 .../internal/CatalogItemDtoAbstract.java        |  13 +
 .../BrooklynClassLoadingContextSequential.java  |  12 +-
 .../OsgiBrooklynClassLoadingContext.java        |   1 +
 .../brooklyn/management/ha/OsgiManager.java     |  26 +-
 core/src/test/dependencies/osgi/README.md       |  29 ++
 .../src/test/dependencies/osgi/entities/pom.xml |   5 +-
 .../dependencies/osgi/more-entities-v1/pom.xml  |  82 +++++
 .../brooklyn/osgi/tests/more/MoreEntity.java    |  38 +++
 .../osgi/tests/more/MoreEntityImpl.java         |  44 +++
 .../dependencies/osgi/more-entities-v2/pom.xml  |  87 +++++
 .../brooklyn/osgi/tests/more/MoreEntity.java    |  38 +++
 .../osgi/tests/more/MoreEntityImpl.java         |  47 +++
 .../brooklyn/catalog/internal/CatalogItems.java |   4 +-
 .../management/osgi/OsgiEntitiesTest.java       |  92 ------
 .../management/osgi/OsgiStandaloneTest.java     |   5 +-
 .../management/osgi/OsgiTestResources.java      |  50 ++-
 .../osgi/OsgiVersionMoreEntityTest.java         | 318 +++++++++++++++++++
 core/src/test/resources/brooklyn/osgi/README.md |   2 +
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 12378 -> 12406 bytes
 .../brooklyn-test-osgi-more-entities_0.1.0.jar  | Bin 0 -> 12452 bytes
 .../brooklyn-test-osgi-more-entities_0.2.0.jar  | Bin 0 -> 12615 bytes
 .../spi/creation/BrooklynEntityMatcher.java     |  11 +-
 .../camp/brooklyn/CatalogYamlEntityTest.java    | 184 -----------
 .../camp/brooklyn/CatalogYamlPolicyTest.java    | 136 --------
 .../CatalogOsgiVersionMoreEntityTest.java       | 130 ++++++++
 .../brooklyn/catalog/CatalogYamlEntityTest.java | 187 +++++++++++
 .../brooklyn/catalog/CatalogYamlPolicyTest.java | 135 ++++++++
 .../more-entity-v1-called-v1-osgi-catalog.yaml  |  10 +
 .../catalog/more-entity-v1-osgi-catalog.yaml    |  10 +
 ...more-entity-v1-with-policy-osgi-catalog.yaml |  12 +
 .../catalog/more-entity-v2-osgi-catalog.yaml    |  11 +
 .../catalog/simple-policy-osgi-catalog.yaml     |  10 +
 .../brooklyn/util/exceptions/Exceptions.java    |  56 +++-
 .../java/brooklyn/util/guava/Functionals.java   |   1 -
 .../guava/IllegalStateExceptionSupplier.java    |   2 +-
 37 files changed, 1344 insertions(+), 457 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/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 53cb2de..0236999 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -167,10 +167,13 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     }
 
     protected CatalogItemDo<?,?> getCatalogItemDo(String idOrRegisteredTypeName) {
-        CatalogItemDo<?, ?> item = catalog.getIdCache().get(idOrRegisteredTypeName);
-        if (item == null) {
-            item = catalog.getRegisteredTypeNameCache().get(idOrRegisteredTypeName);
-        }
+        CatalogItemDo<?, ?> item = null;
+        // TODO really need to remove redundancy of id v registered type;
+        // should also remove "manual additions" bucket; just have one map a la osgi
+        if (manualAdditionsCatalog!=null) item = manualAdditionsCatalog.getIdCache().get(idOrRegisteredTypeName);
+        if (item == null) item = catalog.getIdCache().get(idOrRegisteredTypeName);
+        if (item == null && manualAdditionsCatalog!=null) item = manualAdditionsCatalog.getRegisteredTypeNameCache().get(idOrRegisteredTypeName);
+        if (item == null) item = catalog.getRegisteredTypeNameCache().get(idOrRegisteredTypeName);
         return item;
     }
     
@@ -498,6 +501,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     public void addItem(CatalogItem<?,?> item) {
         log.debug("Adding manual catalog item to "+mgmt+": "+item);
         checkNotNull(item, "item");
+        CatalogUtils.installLibraries(mgmt, item.getLibraries());
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
         manualAdditionsCatalog.addEntry(getAbstractCatalogItem(item));
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
index 749c275..a4ba086 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
@@ -20,7 +20,6 @@ package brooklyn.catalog.internal;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
index 6507ba7..704976b 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java
@@ -24,6 +24,9 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.entity.rebind.BasicCatalogItemRebindSupport;
@@ -38,6 +41,8 @@ import com.google.common.collect.Sets;
 
 public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynObject implements CatalogItem<T, SpecT> {
 
+    private static final Logger log = LoggerFactory.getLogger(CatalogItemDtoAbstract.class);
+    
     // TODO are ID and registeredType the same?
     @SetFromFlag Set<Object> tags = Sets.newLinkedHashSet();
     @SetFromFlag String registeredType;
@@ -229,4 +234,12 @@ public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynO
         }
     }
 
+    /** Use of this method is discouraged unless it is assigning the same (final) ID that this object already has. */
+    @Override
+    public void setCatalogItemId(String id) {
+        if (id!=null && !id.equals(getRegisteredTypeName())) {
+            log.warn("Setting 'catalog-item ID' of catalog item "+getId()+"/"+getRegisteredTypeName()+" to "+id+"; if set, catalog-item ID should match the registered type name.");
+        }
+        super.setCatalogItemId(id);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/main/java/brooklyn/management/classloading/BrooklynClassLoadingContextSequential.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/classloading/BrooklynClassLoadingContextSequential.java b/core/src/main/java/brooklyn/management/classloading/BrooklynClassLoadingContextSequential.java
index 5012dc0..551168b 100644
--- a/core/src/main/java/brooklyn/management/classloading/BrooklynClassLoadingContextSequential.java
+++ b/core/src/main/java/brooklyn/management/classloading/BrooklynClassLoadingContextSequential.java
@@ -25,13 +25,14 @@ import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Objects;
-
 import brooklyn.management.ManagementContext;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableSet;
+import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 
+import com.google.common.base.Objects;
+
 public final class BrooklynClassLoadingContextSequential extends AbstractBrooklynClassLoadingContext {
 
     private static final Logger log = LoggerFactory.getLogger(BrooklynClassLoadingContextSequential.class);
@@ -66,18 +67,23 @@ public final class BrooklynClassLoadingContextSequential extends AbstractBrookly
     }
     
     public Maybe<Class<?>> tryLoadClass(String className) {
+        List<Throwable> errors = MutableList.of();
         for (BrooklynClassLoadingContext target: primaries) {
             Maybe<Class<?>> clazz = target.tryLoadClass(className);
             if (clazz.isPresent())
                 return clazz;
+            errors.add( ((Maybe.Absent<?>)clazz).getException() );
         }
+        boolean noPrimaryErrors = errors.isEmpty();
         for (BrooklynClassLoadingContext target: secondaries) {
             Maybe<Class<?>> clazz = target.tryLoadClass(className);
             if (clazz.isPresent())
                 return clazz;
+            if (noPrimaryErrors)
+                errors.add( ((Maybe.Absent<?>)clazz).getException() );
         }
 
-        return Maybe.absent("Unable to load "+className+" from "+primaries);
+        return Maybe.absent(Exceptions.create("Unable to load "+className+" from "+primaries, errors));
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java b/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java
index 7dbc037..74cc6cf 100644
--- a/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java
+++ b/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java
@@ -24,6 +24,7 @@ import java.util.List;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.ha.OsgiManager;
 import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/main/java/brooklyn/management/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/OsgiManager.java b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
index bde7360..7f6ca52 100644
--- a/core/src/main/java/brooklyn/management/ha/OsgiManager.java
+++ b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
@@ -38,6 +38,7 @@ import brooklyn.util.os.Os;
 import brooklyn.util.osgi.Osgis;
 
 import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
 
 public class OsgiManager {
 
@@ -91,7 +92,7 @@ public class OsgiManager {
             Bundle b = Osgis.install(framework, bundleUrl);
             nv = b.getSymbolicName()+":"+b.getVersion().toString();
             bundleUrlToNameVersionString.put(bundleUrl, nv);
-            log.debug("Bundle from "+bundleUrl+" successfully installed as " + nv);
+            log.debug("Bundle from "+bundleUrl+" successfully installed as " + nv + " ("+b+")");
         } catch (BundleException e) {
             log.debug("Bundle from "+bundleUrl+" failed to install (rethrowing): "+e);
             throw Throwables.propagate(e);
@@ -104,9 +105,11 @@ public class OsgiManager {
     public <T> Maybe<Class<T>> tryResolveClass(String type, Iterable<String> bundleUrlsOrNameVersionString) {
         Map<String,Throwable> bundleProblems = MutableMap.of();
         for (String bundleUrlOrNameVersionString: bundleUrlsOrNameVersionString) {
+            boolean noVersionInstalled = false;
             try {
                 String bundleNameVersion = bundleUrlToNameVersionString.get(bundleUrlOrNameVersionString);
                 if (bundleNameVersion==null) {
+                    noVersionInstalled = true;
                     bundleNameVersion = bundleUrlOrNameVersionString;
                 }
 
@@ -131,7 +134,16 @@ public class OsgiManager {
                 }
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
-                bundleProblems.put(bundleUrlOrNameVersionString, e);
+                if (noVersionInstalled) {
+                    if (bundleUrlOrNameVersionString.contains("/")) {
+                        // suppress misleading nested trace if the input string looked like a URL
+                        bundleProblems.put(bundleUrlOrNameVersionString, new IllegalStateException("Bundle does not appear to be installed"));
+                    } else {
+                        bundleProblems.put(bundleUrlOrNameVersionString, new IllegalStateException("Bundle does not appear to be installed", e));
+                    }
+                } else {
+                    bundleProblems.put(bundleUrlOrNameVersionString, e);
+                }
 
                 Throwable cause = e.getCause();
                 if (cause != null && cause.getMessage().contains("Unresolved constraint in bundle")) {
@@ -140,7 +152,15 @@ public class OsgiManager {
                 }
             }
         }
-        return Maybe.absent("Unable to resolve class "+type+": "+bundleProblems);
+        if (bundleProblems.size()==1) {
+            Throwable error = Iterables.getOnlyElement(bundleProblems.values());
+            if (error instanceof ClassNotFoundException && error.getCause()!=null && error.getCause().getMessage()!=null) {
+                error = Exceptions.collapseIncludingAllCausalMessages(error);
+            }
+            return Maybe.absent("Unable to resolve class "+type+" in "+Iterables.getOnlyElement(bundleProblems.keySet()), error);
+        } else {
+            return Maybe.absent(Exceptions.create("Unable to resolve class "+type+": "+bundleProblems, bundleProblems.values()));
+        }
     }
 
     public URL getResource(String name, Iterable<String> bundleUrlsOrNameVersionString) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/README.md
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/README.md b/core/src/test/dependencies/osgi/README.md
new file mode 100644
index 0000000..ee8539b
--- /dev/null
+++ b/core/src/test/dependencies/osgi/README.md
@@ -0,0 +1,29 @@
+This directory contains source code for OSGi bundle files 
+used for testing.
+
+Binaries are included under src/test/resources.  They are
+copied there when these projects are built, and the binaries
+are included in source control to speed up build times
+(as these projects do not change much).  These projects are
+NOT built as part of the normal brooklyn build.
+
+See OsgiTestResources.java for information on the bundles.
+
+----
+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.
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/entities/pom.xml
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/entities/pom.xml b/core/src/test/dependencies/osgi/entities/pom.xml
index 41551f4..d143ea2 100644
--- a/core/src/test/dependencies/osgi/entities/pom.xml
+++ b/core/src/test/dependencies/osgi/entities/pom.xml
@@ -70,11 +70,10 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <version>1.4.0</version>
-                <extensions>true</extensions>
+                <version>2.5.3</version>
                 <configuration>
                     <instructions>
-                        <Bundle-Version>0.1.0</Bundle-Version>
+                        <Bundle-Version>${project.version}</Bundle-Version>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v1/pom.xml
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v1/pom.xml b/core/src/test/dependencies/osgi/more-entities-v1/pom.xml
new file mode 100644
index 0000000..aab4774
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v1/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+
+    <groupId>org.apache.brooklyn.test.resources.osgi</groupId>
+    <artifactId>brooklyn-test-osgi-more-entities</artifactId>
+    <version>0.1.0</version>
+
+    <name>OSGi bundled test entities</name>
+
+    <description>
+        Simple entities for testing the OSGi functionality
+    </description>
+
+    <parent>
+        <groupId>org.apache.brooklyn</groupId>
+        <artifactId>brooklyn-parent</artifactId>
+        <version>0.7.0-SNAPSHOT</version><!-- BROOKLYN_VERSION -->
+        <relativePath>../../../../../../pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-core</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-api</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-common</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <outputDirectory>../../../resources/brooklyn/osgi</outputDirectory>
+                    <finalName>brooklyn-test-osgi-more-entities_${version}</finalName>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.5.3</version>
+                <configuration>
+                    <instructions>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
new file mode 100644
index 0000000..f26f1f1
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 brooklyn.osgi.tests.more;
+
+
+import brooklyn.entity.Effector;
+import brooklyn.entity.Entity;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.proxying.ImplementedBy;
+
+@ImplementedBy(MoreEntityImpl.class)
+public interface MoreEntity extends Entity {
+
+    public static final Effector<String> SAY_HI = Effectors.effector(String.class, "sayHI")
+        .description("says HI to an uppercased name")
+        .parameter(String.class, "name")
+        .buildAbstract();
+
+    /** Makes a string saying hi to the given name, in uppercase, for testing. */
+    String sayHI(String name);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
new file mode 100644
index 0000000..5eb1de5
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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 brooklyn.osgi.tests.more;
+
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.util.config.ConfigBag;
+
+
+public class MoreEntityImpl extends AbstractEntity implements MoreEntity {
+
+    @Override
+    public void init() {
+        super.init();
+        getMutableEntityType().addEffector(SAY_HI, new EffectorBody<String>() {
+            @Override
+            public String call(ConfigBag parameters) {
+                return sayHI((String)parameters.getStringKey("name"));
+            }
+        });
+    }
+    
+    @Override
+    public String sayHI(String name) {
+        return "Hi "+name.toUpperCase();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v2/pom.xml
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2/pom.xml b/core/src/test/dependencies/osgi/more-entities-v2/pom.xml
new file mode 100644
index 0000000..a29247d
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+
+    <groupId>org.apache.brooklyn.test.resources.osgi</groupId>
+    <artifactId>brooklyn-test-osgi-more-entities</artifactId>
+    <version>0.2.0</version>
+
+    <name>OSGi bundled test entities</name>
+
+    <description>
+        Simple entities for testing the OSGi functionality
+    </description>
+
+    <parent>
+        <groupId>org.apache.brooklyn</groupId>
+        <artifactId>brooklyn-parent</artifactId>
+        <version>0.7.0-SNAPSHOT</version><!-- BROOKLYN_VERSION -->
+        <relativePath>../../../../../../pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-core</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-api</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-common</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn.test.resources.osgi</groupId>
+            <artifactId>brooklyn-test-osgi-entities</artifactId>
+            <version>0.1.0</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <outputDirectory>../../../resources/brooklyn/osgi</outputDirectory>
+                    <finalName>brooklyn-test-osgi-more-entities_${version}</finalName>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.5.3</version>
+                <configuration>
+                    <instructions>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
new file mode 100644
index 0000000..f26f1f1
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 brooklyn.osgi.tests.more;
+
+
+import brooklyn.entity.Effector;
+import brooklyn.entity.Entity;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.proxying.ImplementedBy;
+
+@ImplementedBy(MoreEntityImpl.class)
+public interface MoreEntity extends Entity {
+
+    public static final Effector<String> SAY_HI = Effectors.effector(String.class, "sayHI")
+        .description("says HI to an uppercased name")
+        .parameter(String.class, "name")
+        .buildAbstract();
+
+    /** Makes a string saying hi to the given name, in uppercase, for testing. */
+    String sayHI(String name);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
new file mode 100644
index 0000000..355c43a
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.osgi.tests.more;
+
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.policy.PolicySpec;
+import brooklyn.util.config.ConfigBag;
+
+
+public class MoreEntityImpl extends AbstractEntity implements MoreEntity {
+
+    /** Unlike v1, this declares an explicit dependency on SimplePolicy */
+    @Override
+    public void init() {
+        super.init();
+        getMutableEntityType().addEffector(SAY_HI, new EffectorBody<String>() {
+            @Override
+            public String call(ConfigBag parameters) {
+                return sayHI((String)parameters.getStringKey("name"));
+            }
+        });
+        addPolicy(PolicySpec.create(brooklyn.osgi.tests.SimplePolicy.class));
+    }
+    
+    /** Unlike v1, this returns "HI " rather than "Hi " */
+    public String sayHI(String name) {
+        return "HI "+name.toUpperCase();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java b/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
index 44bb9d5..dcefbcc 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
@@ -20,8 +20,8 @@ package brooklyn.catalog.internal;
 
 import io.brooklyn.camp.spi.pdp.DeploymentPlan;
 
-/** Deliberately package-private. Only for internal use. */
-class CatalogItems {
+/** Only for internal use / use in tests. */
+public class CatalogItems {
 
     public static CatalogTemplateItemDto newTemplateFromJava(String javaType, String name) {
         return newTemplateFromJava(javaType, name, null, null);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/java/brooklyn/management/osgi/OsgiEntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiEntitiesTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiEntitiesTest.java
deleted file mode 100644
index 9b92b0c..0000000
--- a/core/src/test/java/brooklyn/management/osgi/OsgiEntitiesTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.management.osgi;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.launch.Framework;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.proxying.InternalEntityFactory;
-import brooklyn.entity.proxying.InternalPolicyFactory;
-import brooklyn.management.internal.ManagementContextInternal;
-import brooklyn.test.entity.LocalManagementContextForTests;
-import brooklyn.util.os.Os;
-import brooklyn.util.osgi.Osgis;
-
-
-/** 
- * Tests that OSGi entities load correctly and have the right catalog information set.
- *     
- */
-public class OsgiEntitiesTest {
-   
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_URL;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws BundleException, IOException, InterruptedException {
-    }
-    
-    /**
-     * Test fix for
-     * java.lang.NoClassDefFoundError: brooklyn.event.AttributeSensor not found by io.brooklyn.brooklyn-test-osgi-entities [41]
-     */
-    @Test
-    public void testEntityProxy() throws Exception {
-        File storageTempDir = Os.newTempDir("osgi-standalone");
-        Framework framework = Osgis.newFrameworkStarted(storageTempDir.getAbsolutePath(), true, null);
-        
-        try {
-        ManagementContextInternal managementContext;
-        InternalEntityFactory factory;
-
-        managementContext = new LocalManagementContextForTests();
-        InternalPolicyFactory policyFactory = new InternalPolicyFactory(managementContext);
-        factory = new InternalEntityFactory(managementContext, managementContext.getEntityManager().getEntityTypeRegistry(), policyFactory);
-
-        Bundle bundle = Osgis.install(framework, BROOKLYN_TEST_OSGI_ENTITIES_PATH);
-        @SuppressWarnings("unchecked")
-        Class<? extends Entity> bundleCls = (Class<? extends Entity>) bundle.loadClass("brooklyn.osgi.tests.SimpleEntityImpl");
-        @SuppressWarnings("unchecked")
-        Class<? extends Entity> bundleInterface = (Class<? extends Entity>) bundle.loadClass("brooklyn.osgi.tests.SimpleEntity");
-
-        @SuppressWarnings("unchecked")
-        EntitySpec<Entity> spec = (EntitySpec<Entity>) (((EntitySpec<Entity>)EntitySpec.create(bundleInterface))).impl(bundleCls);
-        Entity entity = bundleCls.newInstance();
-        factory.createEntityProxy(spec, entity);
-
-        if (managementContext != null) Entities.destroyAll(managementContext);
-        } finally {
-            OsgiStandaloneTest.tearDownOsgiFramework(framework, storageTempDir);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java
index c2f9d51..94b9e9e 100644
--- a/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java
@@ -57,10 +57,11 @@ public class OsgiStandaloneTest {
 
     private static final Logger log = LoggerFactory.getLogger(OsgiStandaloneTest.class);
 
-    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_URL = OsgiTestResources.BROOKLYN_OSGI_TEST_A_0_1_0_URL;
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_PATH = OsgiTestResources.BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_URL = "classpath:"+BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
 
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_URL;
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+BROOKLYN_TEST_OSGI_ENTITIES_PATH;
 
     protected Framework framework = null;
     private File storageTempDir;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java b/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
index 3ab2055..de889be 100644
--- a/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
@@ -19,25 +19,43 @@
 package brooklyn.management.osgi;
 
 /**
-* Many OSGi tests require OSGi bundles (of course). Test bundles have been collected here
-* for convenience and clarity. Available bundles (on the classpath, with source code
-* either embedded or in /src/dependencies) are:
-* <p>
-* <li>brooklyn-osgi-test-a_0.1.0 -
-*     defines TestA which has a "times" method and a static multiplier field;
-*     we set the multiplier to determine when we are sharing versions and when not
-*     
-* <li>brooklyn-test-osgi-entities (also version 0.1.0) -
-*     defines an entity and an application, to confirm it can be read and used by brooklyn
-* <p>
-* Some of these bundles are also used in REST API tests, as that stretches catalog further
-* (using CAMP) and that is one area where OSGi is heavily used. 
-*/
+ * Many OSGi tests require OSGi bundles (of course). Test bundles have been collected here
+ * for convenience and clarity. Available bundles (on the classpath, with source code
+ * either embedded or in /src/dependencies) are described by the constants in this class.
+ * <p>
+ * Some of these bundles are also used in REST API tests, as that stretches catalog further
+ * (using CAMP) and that is one area where OSGi is heavily used. 
+ */
 public class OsgiTestResources {
 
-    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_URL = "classpath:/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar";
+    /**
+     * brooklyn-osgi-test-a_0.1.0 -
+     * defines TestA which has a "times" method and a static multiplier field;
+     * we set the multiplier to determine when we are sharing versions and when not
+     */
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_PATH = "/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar";
 
+    /**
+     * brooklyn-test-osgi-entities (v 0.1.0) -
+     * defines an entity and an application, to confirm it can be read and used by brooklyn
+     */
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = "/brooklyn/osgi/brooklyn-test-osgi-entities.jar";
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+BROOKLYN_TEST_OSGI_ENTITIES_PATH;
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY = "brooklyn.osgi.tests.SimpleEntity";
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY = "brooklyn.osgi.tests.SimplePolicy";
 
+    /**
+     * brooklyn-test-osgi-more-entities_0.1.0 -
+     * another bundle with a minimal sayHi effector, used to test versioning and dependencies
+     * (this one has no dependencies, but see also {@value #BROOKLYN_TEST_MORE_ENTITIES_V2_PATH})
+     */
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar";
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY = "brooklyn.osgi.tests.more.MoreEntity";
+    
+    /**
+     * brooklyn-test-osgi-more-entities_0.2.0 -
+     * similar to {@link #BROOKLYN_TEST_MORE_ENTITIES_V1_PATH} but saying "HI NAME" rather than "Hi NAME",
+     * and declaring an explicit dependency on SimplePolicy from {@link #BROOKLYN_TEST_OSGI_ENTITIES_PATH}
+     */
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar";
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
new file mode 100644
index 0000000..4175639
--- /dev/null
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
@@ -0,0 +1,318 @@
+/*
+ * 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 brooklyn.management.osgi;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.internal.CatalogEntityItemDto;
+import brooklyn.catalog.internal.CatalogItems;
+import brooklyn.catalog.internal.CatalogUtils;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.proxying.InternalEntityFactory;
+import brooklyn.entity.proxying.InternalPolicyFactory;
+import brooklyn.management.classloading.BrooklynClassLoadingContext;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.policy.PolicySpec;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.util.os.Os;
+import brooklyn.util.osgi.Osgis;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+
+/** 
+ * Tests that OSGi entities load correctly and have the right catalog information set.
+ * Note further tests done elsewhere using CAMP YAML (referring to methods in this class).
+ */
+public class OsgiVersionMoreEntityTest {
+   
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
+
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
+    
+    protected LocalManagementContext mgmt;
+    protected TestApplication app;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        mgmt = LocalManagementContextForTests.builder(true).disableOsgi(false).build();
+        app = TestApplication.Factory.newManagedInstanceForTests(mgmt);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws BundleException, IOException, InterruptedException {
+        Entities.destroyAll(mgmt);
+    }
+    
+    /**
+     * Test fix for
+     * java.lang.NoClassDefFoundError: brooklyn.event.AttributeSensor not found by io.brooklyn.brooklyn-test-osgi-entities [41]
+     */
+    @Test
+    public void testEntityProxy() throws Exception {
+        File storageTempDir = Os.newTempDir("osgi-standalone");
+        Framework framework = Osgis.newFrameworkStarted(storageTempDir.getAbsolutePath(), true, null);
+        
+        try {
+            ManagementContextInternal managementContext;
+            InternalEntityFactory factory;
+
+            managementContext = new LocalManagementContextForTests();
+            InternalPolicyFactory policyFactory = new InternalPolicyFactory(managementContext);
+            factory = new InternalEntityFactory(managementContext, managementContext.getEntityManager().getEntityTypeRegistry(), policyFactory);
+
+            Bundle bundle = Osgis.install(framework, BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+            @SuppressWarnings("unchecked")
+            Class<? extends Entity> bundleCls = (Class<? extends Entity>) bundle.loadClass("brooklyn.osgi.tests.SimpleEntityImpl");
+            @SuppressWarnings("unchecked")
+            Class<? extends Entity> bundleInterface = (Class<? extends Entity>) bundle.loadClass("brooklyn.osgi.tests.SimpleEntity");
+
+            @SuppressWarnings("unchecked")
+            EntitySpec<Entity> spec = (EntitySpec<Entity>) (((EntitySpec<Entity>)EntitySpec.create(bundleInterface))).impl(bundleCls);
+            Entity entity = bundleCls.newInstance();
+            factory.createEntityProxy(spec, entity);
+
+            if (managementContext != null) Entities.destroyAll(managementContext);
+        } finally {
+            OsgiStandaloneTest.tearDownOsgiFramework(framework, storageTempDir);
+        }
+    }
+    
+    @SuppressWarnings("deprecation")
+    protected CatalogItem<?, ?> addCatalogItem(String type, String ...libraries) {
+        CatalogEntityItemDto c1 = newCatalogItem(type, libraries);
+        mgmt.getCatalog().addItem(c1);
+        CatalogItem<?, ?> c2 = mgmt.getCatalog().getCatalogItem(type);
+        return c2;
+    }
+
+    static CatalogEntityItemDto newCatalogItem(String type, String ...libraries) {
+        CatalogEntityItemDto c1 = CatalogItems.newEntityFromJava(type, type);
+        c1.setCatalogItemId(type);
+        for (String library: libraries)
+            c1.getLibrariesDto().addBundle(library);
+        return c1;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected Entity addItemFromCatalog(CatalogItem<?, ?> c2) {
+        BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, c2);
+        EntitySpec spec = EntitySpec.create( (Class)loader.loadClass(c2.getJavaType()) );
+        // not a great test as we set the ID here; but:
+        // YAML test will do better;
+        // and we can check that downstream items are loaded correctly
+        spec.catalogItemId(c2.getRegisteredTypeName());
+        Entity me = app.createAndManageChild(spec);
+        return me;
+    }
+
+    public static void assertV1MethodCall(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        Assert.assertEquals(doMethodCallBrooklyn(me), "Hi BROOKLYN");
+    }
+    public static void assertV2MethodCall(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        Assert.assertEquals(doMethodCallBrooklyn(me), "HI BROOKLYN");
+    }
+
+    public static Object doMethodCallBrooklyn(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        return me.getClass().getMethod("sayHI", String.class).invoke(me, "Brooklyn");
+    }
+
+    public static void assertV1EffectorCall(Entity me) {
+        Assert.assertEquals(doEffectorCallBrooklyn(me), "Hi BROOKLYN");
+    }
+    public static void assertV2EffectorCall(Entity me) {
+        Assert.assertEquals(doEffectorCallBrooklyn(me), "HI BROOKLYN");
+    }
+
+    public static String doEffectorCallBrooklyn(Entity me) {
+        return me.invoke(Effectors.effector(String.class, "sayHI").buildAbstract(), ImmutableMap.of("name", "brooklyn")).getUnchecked();
+    }
+
+    @Test
+    public void testMoreEntitiesV1() throws Exception {
+        CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+        
+        // test load and instantiate
+        Entity me = addItemFromCatalog(c2);
+        Assert.assertEquals(me.getCatalogItemId(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY);
+        
+        assertV1MethodCall(me);
+        assertV1EffectorCall(me);
+        
+        // test adding a child gets the right type; this time by entity parent hierarchy
+        BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, c2);
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        Entity me2 = me.addChild(EntitySpec.create( (Class)loader.loadClass(c2.getJavaType()) ));
+        Assert.assertEquals(me2.getCatalogItemId(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected PolicySpec<?> getPolicySpec(CatalogItem<?, ?> cp) {
+        BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, cp);
+        PolicySpec spec = PolicySpec.create( (Class)loader.loadClass(cp.getJavaType()) );
+        spec.catalogItemId(cp.getRegisteredTypeName());
+        return spec;
+    }
+
+    @Test
+    public void testMoreEntitiesV1Policy() throws Exception {
+        CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+        
+        // test load and instantiate
+        Entity me = addItemFromCatalog(c2);
+
+        CatalogItem<?, ?> cp = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY, 
+            BROOKLYN_TEST_OSGI_ENTITIES_URL);
+        me.addPolicy(getPolicySpec(cp));
+        
+        Assert.assertEquals(me.getPolicies().size(), 1, "Wrong number of policies: "+me.getPolicies());
+        
+        String catalogItemId = Iterables.getOnlyElement( me.getPolicies() ).getCatalogItemId();
+        Assert.assertNotNull(catalogItemId);
+        // must be the actual source bundle
+        Assert.assertFalse(catalogItemId.equals(me.getCatalogItemId()));
+        Assert.assertTrue(catalogItemId.startsWith("brooklyn-test-osgi-entities"));
+    }
+
+    @Test
+    public void testMoreEntitiesV2FailsWithoutBasicTestOsgiEntitiesBundle() throws Exception {
+        CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V2_URL);
+        
+        // test load and instantiate
+        try {
+            Entity me = addItemFromCatalog(c2);
+            Assert.fail("Should have failed, with unresolved dependency; instead got "+me);
+        } catch (Exception e) {
+            Assert.assertTrue(e.toString().toLowerCase().contains("unresolved constraint"), "Missing expected text in error: "+e);
+            Assert.assertTrue(e.toString().toLowerCase().contains("wiring.package"), "Missing expected text in error: "+e);
+            Assert.assertTrue(e.toString().toLowerCase().contains("brooklyn.osgi.tests"), "Missing expected text in error: "+e);
+        }
+    }
+    
+    // V2 works with dependency declared, and can load
+    // and has policy, with policy item catalog ID is reasonable
+    @Test
+    public void testMoreEntitiesV2() throws Exception {
+        CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
+        
+        // test load and instantiate
+        Entity me = addItemFromCatalog(c2);
+        Assert.assertEquals(me.getCatalogItemId(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY);
+        
+        assertV2MethodCall(me);
+        assertV2EffectorCall(me);
+        Assert.assertEquals(me.getPolicies().size(), 1, "Wrong number of policies: "+me.getPolicies());
+        
+        String catalogItemId = Iterables.getOnlyElement( me.getPolicies() ).getCatalogItemId();
+        Assert.assertNotNull(catalogItemId);
+        // allow either me's bundle (more) or the actual source bundle
+        Assert.assertTrue(catalogItemId.equals(me.getCatalogItemId()) || catalogItemId.startsWith("brooklyn-test-osgi-entities"));
+    }
+
+    @Test
+    public void testMoreEntitiesV1ThenV2GivesV2() throws Exception {
+        addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+        addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
+        
+        // test load and instantiate
+        Entity me = addItemFromCatalog( mgmt.getCatalog().getCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY) );
+        
+        assertV2MethodCall(me);
+        assertV2EffectorCall(me);
+        Assert.assertEquals(me.getPolicies().size(), 1, "Wrong number of policies: "+me.getPolicies());
+    }
+
+    @Test
+    public void testMoreEntitiesV2ThenV1GivesV1() throws Exception {
+        addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
+        addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, 
+            BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+        
+        // test load and instantiate
+        Entity me = addItemFromCatalog( mgmt.getCatalog().getCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY) );
+        /*
+         * WARNING - Weird maven-bundle-plugin and OSGi behaviour.  Some caveats:
+         * <p>
+         * (1) When "import-package" declares a version, that is the *minimum* version;
+         *     it may be that semantic versioning is applied, so 1.3.1 = [1.3.1,4.0.0);
+         *     or it may be just a minimum 1.3.1 = [1.3.1,) ... i can't find good docs
+         *     [but see http://www.christianposta.com/blog/?p=241]
+         * <p>
+         * (2) Different versions of maven-bundle-plugin do wildly different things.
+         *     * v1.4.0 attaches the version to import-package (so you get the minimum
+         *       which can cause this test to fail);
+         *     * v2.x does not seem to declare the exported package at all in import-package
+         *       (violating the so-called best practice, see
+         *       http://blog.osgi.org/2007/04/importance-of-exporting-nd-importing.html )
+         *     * v2.4.0 gives a huge list in import/export package, with semver ranges;
+         *       but the other versions seem not to list much and they do NOT have versions
+         * <p>
+         * The tests are all working with 2.5.3 but if version dependencies become any
+         * more intertwined maven-bundle-plugin will almost certainly NOT do the wrong
+         * thing because packages do not have versions. (Ironically, 1.4.0 seems the
+         * best behaved, but for the minimum/semver package version behaviour, and
+         * even that wouldn't be so bad if you're doing semver, or if you figure out
+         * how to override with a _versionpolicy tag!)
+         */
+        assertV1MethodCall(me);
+        assertV1EffectorCall(me);
+        Assert.assertEquals(me.getPolicies().size(), 0, "Wrong number of policies: "+me.getPolicies());
+    }
+
+    // TODO test YAML for many of the above (in the camp project CAMP, using other code below)
+    
+    // TODO versioning (WIP until #92), install both V1 and V2 with version number, and test that both work
+    
+    // TODO other code which might be useful - but requires CAMP:
+//        mgmt.getCatalog().addItem(Strings.lines(
+//            "brooklyn.catalog:",
+//            "  id: my-entity",
+//            "brooklyn.library:",
+//            "- url: "+BROOKLYN_TEST_MORE_ENTITIES_V1_URL,
+//            "services:",
+//            "- type: "+OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY
+//        ));
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/resources/brooklyn/osgi/README.md
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/README.md b/core/src/test/resources/brooklyn/osgi/README.md
index 4109080..1d78ddb 100644
--- a/core/src/test/resources/brooklyn/osgi/README.md
+++ b/core/src/test/resources/brooklyn/osgi/README.md
@@ -3,6 +3,8 @@ This directory contains OSGi bundle files used for testing.
 Source code including pom.xml is contained in the bundles,
 or in /src/dependencies, or both.
 
+See OsgiTestResources.java for information on the bundles.
+
 ----
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
index 494de30..5dad391 100644
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar and b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar
new file mode 100644
index 0000000..a71f428
Binary files /dev/null and b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar
new file mode 100644
index 0000000..c75c092
Binary files /dev/null and b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/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 1e4a877..54bd4a6 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
@@ -215,6 +215,8 @@ public class BrooklynEntityMatcher implements PdpMatcher {
         if (attrs==null || attrs.isEmpty())
             return null;
         try {
+            // TODO don't use the mgmt loader, but instead use something like catalog.createSpec
+            // currently we get warnings and are unable to retrieve flags for items which come from catalog 
             Class<? extends Entity> type = BrooklynComponentTemplateResolver.Factory.newInstance(JavaBrooklynClassLoadingContext.newDefault(mgmt), typeName).loadEntityClass();
             ConfigBag bag = ConfigBag.newInstance(attrs);
             List<FlagConfigKeyAndValueRecord> values = FlagUtils.findAllFlagsAndConfigKeys(null, type, bag);
@@ -231,7 +233,14 @@ public class BrooklynEntityMatcher implements PdpMatcher {
             return values;
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            log.warn("Ignoring configuration attributes on "+typeName+" due to "+e, e);
+            if (e.toString().contains("Could not find")) {
+                // TODO currently we get this error if a catalog item is passed, giving stack trace is too scary;
+                // when we are doing catalog.createSpec let's remove this block
+                log.warn("Ignoring configuration attributes on "+typeName+", item probably loaded from catalog and flags are not yet supported here");
+                log.debug("Ignoring configuration attributes on "+typeName+", details: "+e);
+            } else {
+                log.warn("Ignoring configuration attributes on "+typeName+" due to "+e, e);
+            }
             return null;
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlEntityTest.java
deleted file mode 100644
index 249e2f5..0000000
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlEntityTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package io.brooklyn.camp.brooklyn;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.Collection;
-
-import org.testng.annotations.Test;
-
-import brooklyn.catalog.CatalogItem;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.BasicEntity;
-import brooklyn.management.osgi.OsgiStandaloneTest;
-
-import com.google.common.collect.Iterables;
-
-
-public class CatalogYamlEntityTest extends AbstractYamlTest {
-    private static final String SIMPLE_ENTITY_TYPE = "brooklyn.osgi.tests.SimpleEntity";
-
-    @Test
-    public void testAddCatalogItem() throws Exception {
-        String registeredTypeName = "my.catalog.app.id.load";
-        addCatalogOSGiEntity(registeredTypeName);
-
-        CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(registeredTypeName);
-        assertEquals(item.getRegisteredTypeName(), registeredTypeName);
-
-        deleteCatalogEntity(registeredTypeName);
-    }
-
-    @Test
-    public void testLaunchApplicationReferencingCatalog() throws Exception {
-        String registeredTypeName = "my.catalog.app.id.launch";
-        registerAndLaunchAndAssertSimpleEntity(registeredTypeName, SIMPLE_ENTITY_TYPE);
-    }
-
-    @Test
-    public void testLaunchApplicationWithCatalogReferencingOtherCatalog() throws Exception {
-        String referencedRegisteredTypeName = "my.catalog.app.id.referenced";
-        String referrerRegisteredTypeName = "my.catalog.app.id.referring";
-        addCatalogOSGiEntity(referencedRegisteredTypeName, SIMPLE_ENTITY_TYPE);
-        addCatalogOSGiEntity(referrerRegisteredTypeName, referencedRegisteredTypeName);
-
-        String yaml = "name: simple-app-yaml\n" +
-                      "location: localhost\n" +
-                      "services: \n" +
-                      "  - serviceType: "+referrerRegisteredTypeName;
-        Entity app = createAndStartApplication(yaml);
-
-        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
-        assertEquals(simpleEntity.getEntityType().getName(), SIMPLE_ENTITY_TYPE);
-
-        deleteCatalogEntity(referencedRegisteredTypeName);
-        deleteCatalogEntity(referrerRegisteredTypeName);
-    }
-
-    @Test
-    public void testLaunchApplicationChildWithCatalogReferencingOtherCatalog() throws Exception {
-        String referencedRegisteredTypeName = "my.catalog.app.id.child.referenced";
-        String referrerRegisteredTypeName = "my.catalog.app.id.child.referring";
-        addCatalogOSGiEntity(referencedRegisteredTypeName, SIMPLE_ENTITY_TYPE);
-        addCatalogChildOSGiEntity(referrerRegisteredTypeName, referencedRegisteredTypeName);
-
-        Entity app = createAndStartApplication(
-            "name: simple-app-yaml",
-            "location: localhost",
-            "services:",
-            "- serviceType: "+BasicEntity.class.getName(),
-            "  brooklyn.children:",
-            "  - type: " + referrerRegisteredTypeName);
-
-        Collection<Entity> children = app.getChildren();
-        assertEquals(children.size(), 1);
-        Entity child = Iterables.getOnlyElement(children);
-        assertEquals(child.getEntityType().getName(), BasicEntity.class.getName());
-        Collection<Entity> grandChildren = child.getChildren();
-        assertEquals(grandChildren.size(), 1);
-        Entity grandChild = Iterables.getOnlyElement(grandChildren);
-        assertEquals(grandChild.getEntityType().getName(), BasicEntity.class.getName());
-        Collection<Entity> grandGrandChildren = grandChild.getChildren();
-        assertEquals(grandGrandChildren.size(), 1);
-        Entity grandGrandChild = Iterables.getOnlyElement(grandGrandChildren);
-        assertEquals(grandGrandChild.getEntityType().getName(), SIMPLE_ENTITY_TYPE);
-
-        deleteCatalogEntity(referencedRegisteredTypeName);
-        deleteCatalogEntity(referrerRegisteredTypeName);
-    }
-
-    @Test
-    public void testLaunchApplicationWithTypeUsingJavaColonPrefix() throws Exception {
-        String registeredTypeName = SIMPLE_ENTITY_TYPE;
-        String serviceName = "java:"+SIMPLE_ENTITY_TYPE;
-        registerAndLaunchAndAssertSimpleEntity(registeredTypeName, serviceName);
-    }
-
-    @Test
-    public void testLaunchApplicationLoopWithJavaTypeName() throws Exception {
-        String registeredTypeName = SIMPLE_ENTITY_TYPE;
-        String serviceName = SIMPLE_ENTITY_TYPE;
-        registerAndLaunchAndAssertSimpleEntity(registeredTypeName, serviceName);
-    }
-
-    @Test
-    public void testLaunchApplicationChildLoopCatalogIdFails() throws Exception {
-        String referrerRegisteredTypeName = "my.catalog.app.id.child.referring";
-        try {
-            addCatalogChildOSGiEntity(referrerRegisteredTypeName, referrerRegisteredTypeName);
-            fail("Expected to throw IllegalStateException");
-        } catch (IllegalStateException e) {
-            assertTrue(e.getMessage().contains("Could not find "+referrerRegisteredTypeName));
-        }
-    }
-
-    private void registerAndLaunchAndAssertSimpleEntity(String registeredTypeName, String serviceType) throws Exception {
-        addCatalogOSGiEntity(registeredTypeName, serviceType);
-        String yaml = "name: simple-app-yaml\n" +
-                      "location: localhost\n" +
-                      "services: \n" +
-                      "  - serviceType: "+registeredTypeName;
-        Entity app = createAndStartApplication(yaml);
-
-        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
-        assertEquals(simpleEntity.getEntityType().getName(), SIMPLE_ENTITY_TYPE);
-
-        deleteCatalogEntity(registeredTypeName);
-    }
-
-    private void addCatalogOSGiEntity(String registeredTypeName) {
-        addCatalogOSGiEntity(registeredTypeName, SIMPLE_ENTITY_TYPE);
-    }
-
-    private void addCatalogOSGiEntity(String registeredTypeName, String serviceType) {
-        addCatalogItem(
-            "brooklyn.catalog:",
-            "  id: " + registeredTypeName,
-            "  name: My Catalog App",
-            "  description: My description",
-            "  icon_url: classpath://path/to/myicon.jpg",
-            "  version: 0.1.2",
-            "  libraries:",
-            "  - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
-            "",
-            "services:",
-            "- type: " + serviceType);
-    }
-
-    private void addCatalogChildOSGiEntity(String registeredTypeName, String serviceType) {
-        addCatalogItem(
-            "brooklyn.catalog:",
-            "  id: " + registeredTypeName,
-            "  name: My Catalog App",
-            "  description: My description",
-            "  icon_url: classpath://path/to/myicon.jpg",
-            "  version: 0.1.2",
-            "  libraries:",
-            "  - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
-            "",
-            "services:",
-            "- type: " + BasicEntity.class.getName(),
-            "  brooklyn.children:",
-            "  - type: " + serviceType);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlPolicyTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlPolicyTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlPolicyTest.java
deleted file mode 100644
index 88545c8..0000000
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/CatalogYamlPolicyTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package io.brooklyn.camp.brooklyn;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import org.testng.annotations.Test;
-
-import brooklyn.catalog.CatalogItem;
-import brooklyn.catalog.CatalogPredicates;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.BasicEntity;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.management.osgi.OsgiStandaloneTest;
-import brooklyn.policy.Policy;
-
-import com.google.common.collect.Iterables;
-
-public class CatalogYamlPolicyTest extends AbstractYamlTest {
-    private static final String SIMPLE_POLICY_TYPE = "brooklyn.osgi.tests.SimplePolicy";
-    private static final String SIMPLE_ENTITY_TYPE = "brooklyn.osgi.tests.SimpleEntity";
-
-    @Test
-    public void testAddCatalogItem() throws Exception {
-        assertEquals(countCatalogPolicies(), 0);
-
-        String registeredTypeName = "my.catalog.policy.id.load";
-        addCatalogOSGiPolicy(registeredTypeName, SIMPLE_POLICY_TYPE);
-
-        CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(registeredTypeName);
-        assertEquals(item.getRegisteredTypeName(), registeredTypeName);
-        assertEquals(countCatalogPolicies(), 1);
-
-        deleteCatalogEntity(registeredTypeName);
-    }
-
-    @Test
-    public void testLaunchApplicationReferencingPolicy() throws Exception {
-        String registeredTypeName = "my.catalog.policy.id.launch";
-        addCatalogOSGiPolicy(registeredTypeName, SIMPLE_POLICY_TYPE);
-        Entity app = createAndStartApplication(
-            "name: simple-app-yaml",
-            "location: localhost",
-            "services: ",
-            "  - type: brooklyn.entity.basic.BasicEntity\n" +
-            "    brooklyn.policies:\n" +
-            "    - type: " + registeredTypeName,
-            "      brooklyn.config:",
-            "        config2: config2 override",
-            "        config3: config3");
-
-        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
-        Policy policy = Iterables.getOnlyElement(simpleEntity.getPolicies());
-        assertEquals(policy.getPolicyType().getName(), SIMPLE_POLICY_TYPE);
-        assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config1")), "config1");
-        assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config2")), "config2 override");
-        assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config3")), "config3");
-
-        deleteCatalogEntity(registeredTypeName);
-    }
-
-    @Test
-    public void testLaunchApplicationWithCatalogReferencingOtherCatalog() throws Exception {
-        String referencedRegisteredTypeName = "my.catalog.policy.id.referenced";
-        String referrerRegisteredTypeName = "my.catalog.policy.id.referring";
-        addCatalogOSGiPolicy(referencedRegisteredTypeName, SIMPLE_POLICY_TYPE);
-
-        addCatalogItem(
-            "brooklyn.catalog:",
-            "  id: " + referrerRegisteredTypeName,
-            "  name: My Catalog App",
-            "  description: My description",
-            "  icon_url: classpath://path/to/myicon.jpg",
-            "  version: 0.1.2",
-            "  libraries:",
-            "  - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
-            "",
-            "services:",
-            "- type: " + SIMPLE_ENTITY_TYPE,
-            "  brooklyn.policies:",
-            "  - type: " + referencedRegisteredTypeName);
-
-        String yaml = "name: simple-app-yaml\n" +
-                      "location: localhost\n" +
-                      "services: \n" +
-                      "  - serviceType: "+referrerRegisteredTypeName;
-
-        Entity app = createAndStartApplication(yaml);
-
-        Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
-        Policy policy = Iterables.getOnlyElement(simpleEntity.getPolicies());
-        assertEquals(policy.getPolicyType().getName(), SIMPLE_POLICY_TYPE);
-
-        deleteCatalogEntity(referencedRegisteredTypeName);
-    }
-
-    private void addCatalogOSGiPolicy(String registeredTypeName, String serviceType) {
-        addCatalogItem(
-            "brooklyn.catalog:",
-            "  id: " + registeredTypeName,
-            "  name: My Catalog Policy",
-            "  description: My description",
-            "  icon_url: classpath://path/to/myicon.jpg",
-            "  version: 0.1.2",
-            "  libraries:",
-            "  - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
-            "",
-            "brooklyn.policies:",
-            "- type: " + serviceType,
-            "  brooklyn.config:",
-            "    config1: config1",
-            "    config2: config2");
-    }
-
-    private int countCatalogPolicies() {
-        return Iterables.size(mgmt().getCatalog().getCatalogItems(CatalogPredicates.IS_POLICY));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/35fd6341/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
new file mode 100644
index 0000000..9281e61
--- /dev/null
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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 io.brooklyn.camp.brooklyn.catalog;
+
+import io.brooklyn.camp.brooklyn.AbstractYamlTest;
+import io.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityMatcher;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.management.osgi.OsgiVersionMoreEntityTest;
+import brooklyn.policy.Policy;
+import brooklyn.util.ResourceUtils;
+
+import com.google.common.collect.Iterables;
+
+/** Many of the same tests as per {@link OsgiVersionMoreEntityTest} but using YAML for catalog and entities, so catalog item ID is set automatically */
+public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest {
+    
+    private static String getLocalResource(String filename) {
+        return ResourceUtils.create(CatalogOsgiVersionMoreEntityTest.class).getResourceAsString(
+            "classpath:/"+CatalogOsgiVersionMoreEntityTest.class.getPackage().getName().replace('.', '/')+"/"+filename);
+    }
+    
+    @Test
+    public void testMoreEntityV1() throws Exception {
+        addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml"));
+        Entity app = createAndStartApplication("services: [ { type: more-entity } ]");
+        Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
+        
+        Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity");
+        OsgiVersionMoreEntityTest.assertV1EffectorCall(moreEntity);
+        OsgiVersionMoreEntityTest.assertV1MethodCall(moreEntity);
+    }
+
+    /** TODO we get warnings from {@link BrooklynEntityMatcher#extractValidConfigFlagsOrKeys};
+     * if we passed the correct loader at that point we could avoid those warnings. */ 
+    @Test
+    public void testMoreEntityV1WithPolicy() throws Exception {
+        addCatalogItem(getLocalResource("simple-policy-osgi-catalog.yaml"));
+        addCatalogItem(getLocalResource("more-entity-v1-with-policy-osgi-catalog.yaml"));
+        Entity app = createAndStartApplication("services: [ { type: more-entity } ]");
+        Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
+        
+        Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity");
+        
+        Assert.assertEquals(moreEntity.getPolicies().size(), 1, "wrong policies: "+moreEntity.getPolicies());
+        Policy policy = Iterables.getOnlyElement(moreEntity.getPolicies());
+        // it was loaded by yaml w ref to catalog, so should have the simple-policy catalog-id
+        Assert.assertEquals(policy.getCatalogItemId(), "simple-policy");
+    }
+
+    @Test
+    public void testMoreEntityV2() throws Exception {
+        addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml"));
+        Entity app = createAndStartApplication("services: [ { type: more-entity } ]");
+        Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
+        
+        Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity");
+        OsgiVersionMoreEntityTest.assertV2EffectorCall(moreEntity);
+        OsgiVersionMoreEntityTest.assertV2MethodCall(moreEntity);
+        
+        Assert.assertEquals(moreEntity.getPolicies().size(), 1, "wrong policies: "+moreEntity.getPolicies());
+        Policy policy = Iterables.getOnlyElement(moreEntity.getPolicies());
+        // it was loaded from the java so should have the base more-entity catalog id
+        Assert.assertEquals(policy.getCatalogItemId(), "more-entity");
+    }
+
+    @Test
+    /** TODO this test works if we assume most recent version wins, but semantics TBC */
+    public void testMoreEntityV2ThenV1GivesV1() throws Exception {
+        addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml"));
+        addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml"));
+        Entity app = createAndStartApplication("services: [ { type: more-entity } ]");
+        Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
+        
+        OsgiVersionMoreEntityTest.assertV1EffectorCall(moreEntity);
+        OsgiVersionMoreEntityTest.assertV1MethodCall(moreEntity);
+    }
+
+    /** unlike {@link #testMoreEntityV2ThenV1GivesV1()} this test should always work,
+     * because default should probably be either most-recent version or highest version,
+     * in either case this works */
+    @Test
+    public void testMoreEntityV1ThenV2GivesV2() throws Exception {
+        addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml"));
+        addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml"));
+        Entity app = createAndStartApplication("services: [ { type: more-entity } ]");
+        Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
+        
+        OsgiVersionMoreEntityTest.assertV2EffectorCall(moreEntity);
+        OsgiVersionMoreEntityTest.assertV2MethodCall(moreEntity);
+    }
+
+    @Test
+    public void testMoreEntityBothV1AndV2() throws Exception {
+        addCatalogItem(getLocalResource("more-entity-v1-called-v1-osgi-catalog.yaml"));
+        addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml"));
+        Entity v1 = createAndStartApplication("services: [ { type: more-entity-v1 } ]");
+        Entity v2 = createAndStartApplication("services: [ { type: more-entity } ]");
+        
+        Entity moreEntityV1 = Iterables.getOnlyElement(v1.getChildren());
+        Entity moreEntityV2 = Iterables.getOnlyElement(v2.getChildren());
+        
+        OsgiVersionMoreEntityTest.assertV1EffectorCall(moreEntityV1);
+        OsgiVersionMoreEntityTest.assertV1MethodCall(moreEntityV1);
+        
+        OsgiVersionMoreEntityTest.assertV2EffectorCall(moreEntityV2);
+        OsgiVersionMoreEntityTest.assertV2MethodCall(moreEntityV2);
+    }
+
+
+}