You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2016/11/29 08:21:50 UTC

[1/6] brooklyn-server git commit: Tidy EntityAsserts

Repository: brooklyn-server
Updated Branches:
  refs/heads/master a20fdeac4 -> 721ced78d


Tidy EntityAsserts

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

Branch: refs/heads/master
Commit: bad328004bdedf7771d350aa25839e9dc4c6dc2c
Parents: 72dccf0
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 17 11:11:40 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 25 23:28:19 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/core/entity/EntityAsserts.java     | 40 +++++++++++++-------
 1 file changed, 27 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bad32800/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java
index 449d498..043332a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java
@@ -33,9 +33,10 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 import java.util.Map;
@@ -51,6 +52,7 @@ import static org.apache.brooklyn.test.Asserts.*;
  */
 public class EntityAsserts {
 
+    private static final Logger LOG = LoggerFactory.getLogger(EntityAsserts.class);
 
     public static <T> void assertAttributeEquals(Entity entity, AttributeSensor<T> attribute, T expected) {
         assertEquals(entity.getAttribute(attribute), expected, "entity=" + entity + "; attribute=" + attribute);
@@ -66,7 +68,7 @@ public class EntityAsserts {
 
     public static <T> void assertAttributeEqualsEventually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final T expected) {
         // Not using assertAttributeEventually(predicate) so get nicer error message
-        Asserts.succeedsEventually((Map) flags, new Runnable() {
+        Asserts.succeedsEventually(castToMapWithStringKeys(flags), new Runnable() {
             @Override
             public void run() {
                 assertAttributeEquals(entity, attribute, expected);
@@ -88,10 +90,9 @@ public class EntityAsserts {
 
     public static <T> T assertAttributeEventually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final Predicate<? super T> predicate) {
         final AtomicReference<T> result = new AtomicReference<T>();
-        Asserts.succeedsEventually((Map)flags, new Runnable() {
+        Asserts.succeedsEventually(castToMapWithStringKeys(flags), new Runnable() {
             @Override public void run() {
-                T val = entity.getAttribute(attribute);
-                Asserts.assertTrue(predicate.apply(val), "val=" + val);
+                T val = assertAttribute(entity, attribute, predicate);
                 result.set(val);
             }});
         return result.get();
@@ -99,24 +100,24 @@ public class EntityAsserts {
 
     public static <T> T assertAttribute(final Entity entity, final AttributeSensor<T> attribute, final Predicate<? super T> predicate) {
         T val = entity.getAttribute(attribute);
-        Asserts.assertTrue(predicate.apply(val), "val=" + val);
+        Asserts.assertTrue(predicate.apply(val), "attribute="+attribute+"; val=" + val);
         return val;
     }
 
 
     public static <T extends Entity> void assertPredicateEventuallyTrue(final T entity, final Predicate<? super T> predicate) {
-        assertPredicateEventuallyTrue(Maps.newLinkedHashMap(), entity, predicate);
+        assertPredicateEventuallyTrue(ImmutableMap.of(), entity, predicate);
     }
 
     public static <T extends Entity> void assertPredicateEventuallyTrue(Map<?,?> flags, final T entity, final Predicate<? super T> predicate) {
-        Asserts.succeedsEventually((Map)flags, new Runnable() {
+        Asserts.succeedsEventually(castToMapWithStringKeys(flags), new Runnable() {
             @Override public void run() {
-                Asserts.assertTrue(predicate.apply(entity), "predicate unsatisfied");
+                Asserts.assertTrue(predicate.apply(entity), "predicate " + predicate + " unsatisfied for "+ entity);
             }});
     }
 
     public static <T> void assertAttributeEqualsContinually(final Entity entity, final AttributeSensor<T> attribute, final T expected) {
-        assertAttributeEqualsContinually(Maps.newLinkedHashMap(), entity, attribute, expected);
+        assertAttributeEqualsContinually(ImmutableMap.of(), entity, attribute, expected);
     }
 
     public static <T> void assertAttributeEqualsContinually(Map<?,?> flags, final Entity entity, final AttributeSensor<T> attribute, final T expected) {
@@ -131,14 +132,13 @@ public class EntityAsserts {
     }
 
     public static void assertGroupSizeEqualsEventually(Map<?,?> flags, final Group group, final int expected) {
-        Asserts.succeedsEventually((Map)flags, new Runnable() {
+        Asserts.succeedsEventually(castToMapWithStringKeys(flags), new Runnable() {
             @Override public void run() {
                 Collection<Entity> members = group.getMembers();
                 assertEquals(members.size(), expected, "members=" + members);
             }});
     }
 
-
     /**
      * Asserts that the entity's value for this attribute changes, by registering a subscription and checking the value.
      *
@@ -253,4 +253,18 @@ public class EntityAsserts {
         assertAttributeEquals(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
     }
 
-}
\ No newline at end of file
+    @SuppressWarnings("unchecked")
+    private static Map<String, ?> castToMapWithStringKeys(Map<?, ?> map) {
+        // TODO when checking that all keys are strings
+        if (map == null) return ImmutableMap.of();
+        for (Object key : map.keySet()) {
+            if (!(key instanceof String)) {
+                IllegalArgumentException e = new IllegalArgumentException("Invalid non-string key(s), type " + key.getClass().getName()+" in map");
+                e.fillInStackTrace();
+                LOG.warn("Deprecated: invalid key(s) in map (continuing)", e);
+                break;
+            }
+        }
+        return (Map<String, ?>) map;
+    }
+}


[6/6] brooklyn-server git commit: Closes #442

Posted by sv...@apache.org.
Closes #442

BROOKLYN-379: Fix rebind when bundle prefixes are used to load classes

This replaces https://github.com/apache/brooklyn-server/pull/396

See also https://github.com/neykov/brooklyn-server/pull/4 (but I'll replay all the comments from that PR into this PR).


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

Branch: refs/heads/master
Commit: 721ced78dcad1135efac4cc4c09348c49725b963
Parents: a20fdea bad3280
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Tue Nov 29 10:21:41 2016 +0200
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Tue Nov 29 10:21:41 2016 +0200

----------------------------------------------------------------------
 .../brooklyn/catalog/CatalogYamlRebindTest.java |  73 +++++++++---
 .../brooklyn/core/entity/EntityAsserts.java     |  40 ++++---
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |  18 ++-
 .../core/mgmt/persist/OsgiClassPrefixer.java    |  78 +++++++++++++
 .../core/mgmt/persist/XmlMementoSerializer.java |  15 +--
 .../mgmt/rebind/dto/MementosGenerators.java     |   6 +-
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |   1 +
 .../mgmt/persist/OsgiClassPrefixerTest.java     | 111 +++++++++++++++++++
 .../entities/SimpleEffectorInitializer.java     |  48 ++++++++
 .../brooklyn/util/osgi/OsgiTestResources.java   |   4 +
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 19168 -> 20814 bytes
 11 files changed, 351 insertions(+), 43 deletions(-)
----------------------------------------------------------------------



[5/6] brooklyn-server git commit: BROOKLYN-379: Fix osgi resolveClass to strip bundle prefix

Posted by sv...@apache.org.
BROOKLYN-379: Fix osgi resolveClass to strip bundle prefix

Without this, RebindOsgiTest.testUsesCatalogBundleVersion fails


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

Branch: refs/heads/master
Commit: 6e68d74e043e38fed811bba03a5218b32469dc66
Parents: a72d1f2
Author: Aled Sage <al...@gmail.com>
Authored: Mon Nov 7 18:03:30 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 25 23:28:19 2016 +0000

----------------------------------------------------------------------
 .../org/apache/brooklyn/core/mgmt/ha/OsgiManager.java  | 13 +++++++++----
 .../brooklyn/core/mgmt/persist/OsgiClassPrefixer.java  |  8 ++++++++
 2 files changed, 17 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6e68d74e/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
index 56d98a0..d58dbad 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
+import org.apache.brooklyn.core.mgmt.persist.OsgiClassPrefixer;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.core.server.BrooklynServerPaths;
 import org.apache.brooklyn.util.collections.MutableMap;
@@ -53,6 +54,7 @@ import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 
@@ -64,12 +66,14 @@ public class OsgiManager {
     
     /* see Osgis for info on starting framework etc */
     
-    protected ManagementContext mgmt;
+    protected final ManagementContext mgmt;
+    protected final OsgiClassPrefixer osgiClassPrefixer;
     protected Framework framework;
     protected File osgiCacheDir;
-
+    
     public OsgiManager(ManagementContext mgmt) {
         this.mgmt = mgmt;
+        this.osgiClassPrefixer = new OsgiClassPrefixer();
     }
 
     public void start() {
@@ -189,10 +193,11 @@ public class OsgiManager {
                 Maybe<Bundle> bundle = findBundle(osgiBundle);
                 if (bundle.isPresent()) {
                     Bundle b = bundle.get();
-                    Class<T> clazz;
+                    Optional<String> strippedType = osgiClassPrefixer.stripMatchingPrefix(b, type);
+                    String typeToLoad = strippedType.isPresent() ? strippedType.get() : type;
                     //Extension bundles don't support loadClass.
                     //Instead load from the app classpath.
-                    clazz = SystemFrameworkLoader.get().loadClassFromBundle(type, b);
+                    Class<T> clazz = SystemFrameworkLoader.get().loadClassFromBundle(typeToLoad, b);
                     return Maybe.of(clazz);
                 } else {
                     bundleProblems.put(osgiBundle, Maybe.getException(bundle));

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6e68d74e/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
index a76c02a..c1650f4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
@@ -48,4 +48,12 @@ public class OsgiClassPrefixer {
         }
         return Optional.absent();
     }
+    
+    public Optional<String> stripMatchingPrefix(Bundle bundle, String type) {
+        String symbolicName = bundle.getSymbolicName();
+        if (symbolicName != null && type.startsWith(symbolicName + ":")) {
+            return Optional.of(type.substring((symbolicName + ":").length()));
+        }
+        return Optional.absent();
+    }
 }


[2/6] brooklyn-server git commit: BROOKLYN-379: address review comments

Posted by sv...@apache.org.
BROOKLYN-379: address review comments

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

Branch: refs/heads/master
Commit: 72dccf08bc4198d5abf466c43e7294c838cf80b5
Parents: 6e68d74
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 17 09:56:42 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 25 23:28:19 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |   5 +
 .../core/mgmt/persist/OsgiClassPrefixer.java    |  29 ++++-
 .../mgmt/persist/OsgiClassPrefixerTest.java     | 111 +++++++++++++++++++
 3 files changed, 140 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/72dccf08/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
index d58dbad..7e68a31 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
@@ -43,6 +43,7 @@ import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.core.osgi.Osgis.BundleFinder;
 import org.apache.brooklyn.util.core.osgi.SystemFrameworkLoader;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.UserFacingException;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.os.Os.DeletionResult;
@@ -195,6 +196,10 @@ public class OsgiManager {
                     Bundle b = bundle.get();
                     Optional<String> strippedType = osgiClassPrefixer.stripMatchingPrefix(b, type);
                     String typeToLoad = strippedType.isPresent() ? strippedType.get() : type;
+                    if (osgiClassPrefixer.hasPrefix(typeToLoad)) {
+                        bundleProblems.put(osgiBundle, new UserFacingException("Bundle does not match prefix in type name '"+typeToLoad+"'"));
+                        continue;
+                    }
                     //Extension bundles don't support loadClass.
                     //Instead load from the app classpath.
                     Class<T> clazz = SystemFrameworkLoader.get().loadClassFromBundle(typeToLoad, b);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/72dccf08/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
index c1650f4..f252f8e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
@@ -18,11 +18,16 @@
  */
 package org.apache.brooklyn.core.mgmt.persist;
 
+import javax.annotation.Nullable;
+
 import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.osgi.framework.Bundle;
 
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
 
 /**
@@ -33,27 +38,41 @@ import com.google.common.base.Optional;
  * In that situation, the code writing the field must include the prefix (e.g. see
  * {@link MementosGenerators}.
  */
+@Beta
 public class OsgiClassPrefixer {
 
+    private static final String DELIMITER = ":";
+    
     private final ClassLoaderUtils whiteListRetriever;
+    private final Function<Class<?>, Optional<Bundle>> bundleRetriever;
     
     public OsgiClassPrefixer() {
-        whiteListRetriever = new ClassLoaderUtils(getClass());
+        this(null);
+    }
+    
+    @VisibleForTesting
+    protected OsgiClassPrefixer(@Nullable Function<Class<?>, Optional<Bundle>> bundleRetriever) {
+        this.whiteListRetriever = new ClassLoaderUtils(getClass());
+        this.bundleRetriever = bundleRetriever;
     }
     
     public Optional<String> getPrefix(Class<?> type) {
-        Optional<Bundle> bundle  = Osgis.getBundleOf(type);
+        Optional<Bundle> bundle  = (bundleRetriever != null) ? bundleRetriever.apply(type) : Osgis.getBundleOf(type);
         if (bundle.isPresent() && !whiteListRetriever.isBundleWhiteListed(bundle.get())) {
-            return Optional.of(bundle.get().getSymbolicName() + ":");
+            return Optional.of(bundle.get().getSymbolicName() + DELIMITER);
         }
         return Optional.absent();
     }
     
     public Optional<String> stripMatchingPrefix(Bundle bundle, String type) {
         String symbolicName = bundle.getSymbolicName();
-        if (symbolicName != null && type.startsWith(symbolicName + ":")) {
-            return Optional.of(type.substring((symbolicName + ":").length()));
+        if (symbolicName != null && type.startsWith(symbolicName + DELIMITER)) {
+            return Optional.of(type.substring(type.lastIndexOf(DELIMITER) + 1));
         }
         return Optional.absent();
     }
+    
+    public boolean hasPrefix(String type) {
+        return type != null && type.contains(":");
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/72dccf08/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixerTest.java
new file mode 100644
index 0000000..19a5610
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.core.mgmt.persist;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.core.BrooklynVersion;
+import org.apache.brooklyn.util.osgi.OsgiUtils;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+
+public class OsgiClassPrefixerTest {
+
+    @Test
+    public void testGetPrefixFromNonBundle() throws Exception {
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer();
+        assertAbsent(prefixer.getPrefix(String.class));
+    }
+    
+    @Test
+    public void testGetPrefixWithBundle() throws Exception {
+        final Class<?> classInBundle = String.class;
+        
+        final Bundle bundle = Mockito.mock(Bundle.class);
+        Mockito.when(bundle.getSymbolicName()).thenReturn("my.symbolic.name");
+        Mockito.when(bundle.getVersion()).thenReturn(Version.valueOf("1.2.3"));
+        
+        Function<Class<?>, Optional<Bundle>> bundleRetriever = new Function<Class<?>, Optional<Bundle>>() {
+            @Override public Optional<Bundle> apply(Class<?> input) {
+                return (classInBundle.equals(input)) ? Optional.of(bundle) : Optional.<Bundle>absent();
+            }
+        };
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer(bundleRetriever);
+        assertAbsent(prefixer.getPrefix(Number.class));
+        assertPresent(prefixer.getPrefix(String.class), "my.symbolic.name:");
+    }
+    
+    @Test
+    public void testGetPrefixWithWhitelistedBundle() throws Exception {
+        final Bundle bundle = Mockito.mock(Bundle.class);
+        Mockito.when(bundle.getSymbolicName()).thenReturn("org.apache.brooklyn.my-bundle");
+        Mockito.when(bundle.getVersion()).thenReturn(Version.valueOf(OsgiUtils.toOsgiVersion(BrooklynVersion.get())));
+        
+        Function<Class<?>, Optional<Bundle>> bundleRetriever = new Function<Class<?>, Optional<Bundle>>() {
+            @Override public Optional<Bundle> apply(Class<?> input) {
+                return Optional.of(bundle);
+            }
+        };
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer(bundleRetriever);
+        assertAbsent(prefixer.getPrefix(String.class));
+    }
+    
+    @Test
+    public void testStringPrefix() throws Exception {
+        Bundle bundle = Mockito.mock(Bundle.class);
+        Mockito.when(bundle.getSymbolicName()).thenReturn("my.symbolic.name");
+        Mockito.when(bundle.getVersion()).thenReturn(Version.valueOf("1.2.3"));
+        
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer();
+        assertAbsent(prefixer.stripMatchingPrefix(bundle, "my.package.MyClass"));
+        assertAbsent(prefixer.stripMatchingPrefix(bundle, "different.symbolic.name:my.package.MyClass"));
+        assertAbsent(prefixer.stripMatchingPrefix(bundle, "different.symbolic.name:1.2.3:my.package.MyClass"));
+        assertPresent(prefixer.stripMatchingPrefix(bundle, "my.symbolic.name:my.package.MyClass"), "my.package.MyClass");
+        assertPresent(prefixer.stripMatchingPrefix(bundle, "my.symbolic.name:1.2.3:my.package.MyClass"), "my.package.MyClass");
+        
+        // TODO Will match any version - is that good enough?
+        // Is it the right thing to do, to make upgrades simpler?!
+        assertPresent(prefixer.stripMatchingPrefix(bundle, "my.symbolic.name:1.0.0:my.package.MyClass"), "my.package.MyClass");
+    }
+
+    @Test
+    public void testHasPrefix() throws Exception {
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer();
+        assertFalse(prefixer.hasPrefix("MyClassInDefaultPackage"));
+        assertFalse(prefixer.hasPrefix("my.package.MyClass"));
+        assertTrue(prefixer.hasPrefix("my.symbolic.name:my.package.MyClass"));
+        assertTrue(prefixer.hasPrefix("my.symbolic.name:1.2.3:my.package.MyClass"));
+    }
+
+    private void assertAbsent(Optional<?> val) {
+        assertFalse(val.isPresent(), "val="+val);
+    }
+    
+    private <T> void assertPresent(Optional<T> val, T expected) {
+        assertTrue(val.isPresent(), "val="+val);
+        assertEquals(val.get(), expected);
+    }
+}


[4/6] brooklyn-server git commit: BROOKLYN-379: entity type includes OSGi prefix

Posted by sv...@apache.org.
BROOKLYN-379: entity type includes OSGi prefix

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

Branch: refs/heads/master
Commit: a72d1f20ed78504a9b690df1467465b781ac917a
Parents: cd9447a
Author: Aled Sage <al...@gmail.com>
Authored: Mon Nov 7 17:11:45 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 25 23:28:19 2016 +0000

----------------------------------------------------------------------
 .../core/mgmt/persist/OsgiClassPrefixer.java    | 51 ++++++++++++++++++++
 .../core/mgmt/persist/XmlMementoSerializer.java | 15 ++----
 .../mgmt/rebind/dto/MementosGenerators.java     |  6 ++-
 3 files changed, 61 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a72d1f20/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
new file mode 100644
index 0000000..a76c02a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/OsgiClassPrefixer.java
@@ -0,0 +1,51 @@
+/*
+ * 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.core.mgmt.persist;
+
+import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
+import org.apache.brooklyn.util.core.osgi.Osgis;
+import org.osgi.framework.Bundle;
+
+import com.google.common.base.Optional;
+
+/**
+ * For serialize/deserialize of persisted state, we need to prefix classes with their OSGi bundle 
+ * (so we know which classloader to use when deserializing). In most cases, this can be done when
+ * serializing the instances. However, in some cases the field of a memento is the String representation  
+ * of the type (e.g. see (@link {@link org.apache.brooklyn.core.mgmt.rebind.dto.AbstractMemento#getType()}).
+ * In that situation, the code writing the field must include the prefix (e.g. see
+ * {@link MementosGenerators}.
+ */
+public class OsgiClassPrefixer {
+
+    private final ClassLoaderUtils whiteListRetriever;
+    
+    public OsgiClassPrefixer() {
+        whiteListRetriever = new ClassLoaderUtils(getClass());
+    }
+    
+    public Optional<String> getPrefix(Class<?> type) {
+        Optional<Bundle> bundle  = Osgis.getBundleOf(type);
+        if (bundle.isPresent() && !whiteListRetriever.isBundleWhiteListed(bundle.get())) {
+            return Optional.of(bundle.get().getSymbolicName() + ":");
+        }
+        return Optional.absent();
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a72d1f20/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
index 15b3346..891e042 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
@@ -61,11 +61,9 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BasicPolicyMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MutableBrooklynMemento;
 import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
-import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.core.xstream.XmlSerializer;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
-import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -76,14 +74,11 @@ import com.thoughtworks.xstream.converters.MarshallingContext;
 import com.thoughtworks.xstream.converters.SingleValueConverter;
 import com.thoughtworks.xstream.converters.UnmarshallingContext;
 import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
-import com.thoughtworks.xstream.core.ClassLoaderReference;
 import com.thoughtworks.xstream.core.ReferencingMarshallingContext;
-import com.thoughtworks.xstream.core.util.Primitives;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 import com.thoughtworks.xstream.io.path.PathTrackingReader;
 import com.thoughtworks.xstream.mapper.CannotResolveClassException;
-import com.thoughtworks.xstream.mapper.DefaultMapper;
 import com.thoughtworks.xstream.mapper.Mapper;
 import com.thoughtworks.xstream.mapper.MapperWrapper;
 
@@ -407,11 +402,11 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
     }
 
     public class OsgiClassnameMapper extends MapperWrapper {
-        private final ClassLoaderUtils whiteListRetriever;
+        private final OsgiClassPrefixer prefixer;
         
         OsgiClassnameMapper(MapperWrapper mapper) {
             super(mapper);
-            whiteListRetriever = new ClassLoaderUtils(getClass());
+            prefixer = new OsgiClassPrefixer();
         }
         
         @Override
@@ -420,9 +415,9 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
             // For example the "outer class renaming stuff"?!
             String superResult = super.serializedClass(type);
             if (type != null && type.getName().equals(superResult)) {
-                Optional<Bundle> bundle  = Osgis.getBundleOf(type);
-                if (bundle.isPresent() && !whiteListRetriever.isBundleWhiteListed(bundle.get())) {
-                    return bundle.get().getSymbolicName() + ":" + superResult;
+                Optional<String> prefix = prefixer.getPrefix(type);
+                if (prefix.isPresent()) {
+                    return prefix.get() + superResult;
                 }
             }
             return superResult;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a72d1f20/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 33d38a1..debc381 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -56,6 +56,7 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
+import org.apache.brooklyn.core.mgmt.persist.OsgiClassPrefixer;
 import org.apache.brooklyn.core.mgmt.rebind.AbstractBrooklynObjectRebindSupport;
 import org.apache.brooklyn.core.mgmt.rebind.TreeUtils;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
@@ -70,6 +71,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Sets;
 
@@ -441,11 +443,13 @@ public class MementosGenerators {
         if (Proxy.isProxyClass(instance.getClass())) {
             throw new IllegalStateException("Attempt to create memento from proxy "+instance+" (would fail with wrong type)");
         }
+        OsgiClassPrefixer prefixer = new OsgiClassPrefixer();
+        Optional<String> typePrefix = prefixer.getPrefix(instance.getClass());
         
         builder.id = instance.getId();
         builder.displayName = instance.getDisplayName();
         builder.catalogItemId = instance.getCatalogItemId();
-        builder.type = instance.getClass().getName();
+        builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName();
         builder.typeClass = instance.getClass();
         if (instance instanceof EntityAdjunct) {
             builder.uniqueTag = ((EntityAdjunct)instance).getUniqueTag();


[3/6] brooklyn-server git commit: A test to check rebind when bundle prefixes are used to load classes in catalog items

Posted by sv...@apache.org.
A test to check rebind when bundle prefixes are used to load classes in catalog items


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

Branch: refs/heads/master
Commit: cd9447a35156ca110b8bd2e8290dfe3323b7c9d0
Parents: 870986b
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Mon Oct 31 17:22:37 2016 +0200
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 25 23:28:19 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/catalog/CatalogYamlRebindTest.java |  73 +++++++++++++++----
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |   1 +
 .../entities/SimpleEffectorInitializer.java     |  48 ++++++++++++
 .../brooklyn/util/osgi/OsgiTestResources.java   |   4 +
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 19168 -> 20814 bytes
 5 files changed, 111 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cd9447a3/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java
index 692a45b..4cac9af 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java
@@ -83,9 +83,11 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest {
     //   - config/attribute cannot be instantiated (e.g. because class no longer on classpath)
     //   - entity file corrupt
 
+    private static final String OSGI_BUNDLE_SYMBOLID_NAME_FULL = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL;
     private static final String OSGI_BUNDLE_URL = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
     private static final String OSGI_SIMPLE_ENTITY_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY;
     private static final String OSGI_SIMPLE_POLICY_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY;
+    private static final String OSGI_SIMPLE_EFFECTOR_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_EFFECTOR;
 
     enum RebindWithCatalogTestMode {
         NO_OP,
@@ -96,6 +98,12 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest {
         REPLACE_CATALOG_WITH_NEWER_VERSION;
     }
     
+    enum OsgiMode {
+        NONE,
+        LIBRARY,
+        PREFIX
+    }
+    
     private Boolean defaultEnablementOfFeatureAutoFixatalogRefOnRebind;
     
     @BeforeMethod(alwaysRun=true)
@@ -121,36 +129,43 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest {
     @DataProvider
     public Object[][] dataProvider() {
         return new Object[][] {
-            {RebindWithCatalogTestMode.NO_OP, false},
-            {RebindWithCatalogTestMode.NO_OP, true},
+            {RebindWithCatalogTestMode.NO_OP, OsgiMode.NONE},
+            {RebindWithCatalogTestMode.NO_OP, OsgiMode.LIBRARY},
+            {RebindWithCatalogTestMode.NO_OP, OsgiMode.PREFIX},
             
-            {RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM, false},
-            {RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM, true},
+            {RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM, OsgiMode.NONE},
+            {RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM, OsgiMode.LIBRARY},
+            {RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM, OsgiMode.PREFIX},
             
-            {RebindWithCatalogTestMode.DEPRECATE_CATALOG, false},
-            {RebindWithCatalogTestMode.DEPRECATE_CATALOG, true},
+            {RebindWithCatalogTestMode.DEPRECATE_CATALOG, OsgiMode.NONE},
+            {RebindWithCatalogTestMode.DEPRECATE_CATALOG, OsgiMode.LIBRARY},
+            {RebindWithCatalogTestMode.DEPRECATE_CATALOG, OsgiMode.PREFIX},
             
-            {RebindWithCatalogTestMode.DISABLE_CATALOG, false},
-            {RebindWithCatalogTestMode.DISABLE_CATALOG, true},
+            {RebindWithCatalogTestMode.DISABLE_CATALOG, OsgiMode.NONE},
+            {RebindWithCatalogTestMode.DISABLE_CATALOG, OsgiMode.LIBRARY},
+            {RebindWithCatalogTestMode.DISABLE_CATALOG, OsgiMode.PREFIX},
             
             // For DELETE_CATALOG, see https://issues.apache.org/jira/browse/BROOKLYN-149.
             // Deletes the catalog item before rebind, but the referenced types are still on the 
             // default classpath. Will fallback to loading from classpath.
             //
             // Does not work for OSGi, because our bundle will no longer be available.
-            {RebindWithCatalogTestMode.DELETE_CATALOG, false},
+            {RebindWithCatalogTestMode.DELETE_CATALOG, OsgiMode.NONE},
             
             // Upgrades the catalog item before rebind, deleting the old version.
             // Will automatically upgrade. Test will enable "FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND"
-            {RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION, false},
-            {RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION, true},
+            {RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION, OsgiMode.NONE},
+            {RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION, OsgiMode.LIBRARY},
+            {RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION, OsgiMode.PREFIX},
         };
     }
 
     @Test(dataProvider = "dataProvider")
     @SuppressWarnings({ "deprecation", "unused" })
-    public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception {
-        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+    public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception {
+        if (osgiMode != OsgiMode.NONE) {
+            TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+        }
 
         if (mode == RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION) {
             BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND);
@@ -160,7 +175,7 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest {
         String appVersion = "0.1.0";
         
         String appCatalogFormat;
-        if (useOsgi) {
+        if (osgiMode == OsgiMode.LIBRARY) {
             appCatalogFormat = Joiner.on("\n").join(
                     "brooklyn.catalog:",
                     "  id: " + appSymbolicName,
@@ -173,7 +188,35 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest {
                     "    brooklyn.enrichers:",
                     "    - type: " + TestEnricher.class.getName(),
                     "    brooklyn.policies:",
-                    "    - type: " + OSGI_SIMPLE_POLICY_TYPE);
+                    "    - type: " + OSGI_SIMPLE_POLICY_TYPE,
+                    "    brooklyn.initializers:",
+                    "    - type: " + OSGI_SIMPLE_EFFECTOR_TYPE);
+        } else if (osgiMode == OsgiMode.PREFIX) {
+            // This catalog item is just meant to load the bundle in the OSGi environment. Its content is irrelevant.
+            String libraryItem = Joiner.on("\n").join(
+                    "brooklyn.catalog:",
+                    "  id: dummy",
+                    "  version: %s",
+                    "  itemType: entity",
+                    "  libraries:",
+                    "  - url: " + OSGI_BUNDLE_URL,
+                    "  item: " + BasicEntity.class.getName());
+            addCatalogItems(String.format(libraryItem, appVersion));
+
+            // Use bundle prefixes here, pointing to the bundle already loaded above
+            appCatalogFormat = Joiner.on("\n").join(
+                    "brooklyn.catalog:",
+                    "  id: " + appSymbolicName,
+                    "  version: %s",
+                    "  itemType: entity",
+                    "  item:",
+                    "    type: " + OSGI_BUNDLE_SYMBOLID_NAME_FULL + ":" + OSGI_SIMPLE_ENTITY_TYPE,
+                    "    brooklyn.enrichers:",
+                    "    - type: " + TestEnricher.class.getName(),
+                    "    brooklyn.policies:",
+                    "    - type: " + OSGI_BUNDLE_SYMBOLID_NAME_FULL + ":" + OSGI_SIMPLE_POLICY_TYPE,
+                    "    brooklyn.initializers:",
+                    "    - type: " + OSGI_BUNDLE_SYMBOLID_NAME_FULL + ":" + OSGI_SIMPLE_EFFECTOR_TYPE);
         } else {
             appCatalogFormat = Joiner.on("\n").join(
                     "brooklyn.catalog:",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cd9447a3/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java
index b399d60..96830bf 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java
@@ -49,6 +49,7 @@ public class OsgiStandaloneTest extends OsgiTestBase {
     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_SYMBOLIC_NAME_FULL = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL;
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+BROOKLYN_TEST_OSGI_ENTITIES_PATH;
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_NAME = "org.apache.brooklyn.test.resources.osgi.brooklyn-test-osgi-entities";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_VERSION = "0.1.0";

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cd9447a3/utils/common/dependencies/osgi/entities/src/main/java/org/apache/brooklyn/test/osgi/entities/SimpleEffectorInitializer.java
----------------------------------------------------------------------
diff --git a/utils/common/dependencies/osgi/entities/src/main/java/org/apache/brooklyn/test/osgi/entities/SimpleEffectorInitializer.java b/utils/common/dependencies/osgi/entities/src/main/java/org/apache/brooklyn/test/osgi/entities/SimpleEffectorInitializer.java
new file mode 100644
index 0000000..bbe23c1
--- /dev/null
+++ b/utils/common/dependencies/osgi/entities/src/main/java/org/apache/brooklyn/test/osgi/entities/SimpleEffectorInitializer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Apache Software Foundation.
+ *
+ * Licensed 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.test.osgi.entities;
+
+import org.apache.brooklyn.core.effector.AddEffector;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+
+public class SimpleEffectorInitializer extends AddEffector {
+
+    public SimpleEffectorInitializer() {
+        super(newEffectorBuilder().build());
+    }
+
+    public static Effectors.EffectorBuilder<Void> newEffectorBuilder() {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(EFFECTOR_NAME, SimpleEffectorInitializer.class.getSimpleName());
+
+        return AddEffector.newEffectorBuilder(Void.class, bag)
+                .description("A bare-bones effector")
+                .impl(new Body());
+    }
+
+
+    public static class Body extends EffectorBody<Void> {
+
+        @Override
+        public Void call(ConfigBag parameters) {
+            return null;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cd9447a3/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
index 181849d..574316d 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
@@ -40,10 +40,14 @@ public class OsgiTestResources {
      * 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_SYMBOLIC_NAME_FINAL_PART = "brooklyn-test-osgi-entities";
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL =
+        "org.apache.brooklyn.test.resources.osgi."+BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FINAL_PART;
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = "/brooklyn/osgi/brooklyn-test-osgi-entities.jar";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_APPLICATION = "org.apache.brooklyn.test.osgi.entities.SimpleApplication";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY = "org.apache.brooklyn.test.osgi.entities.SimpleEntity";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY = "org.apache.brooklyn.test.osgi.entities.SimplePolicy";
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_EFFECTOR = "org.apache.brooklyn.test.osgi.entities.SimpleEffectorInitializer";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_OBJECT = "org.apache.brooklyn.test.osgi.entities.SimpleObject";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY_CONFIG_NAME = "simple.config";
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY_SENSOR_NAME = "simple.sensor";

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cd9447a3/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
index 42ba7ca..51d57bb 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar differ