You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/10/27 00:58:22 UTC

[04/12] incubator-brooklyn git commit: [BROOKLYN-183] Move Apache Felix code into specific jar

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MorePolicy.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MorePolicy.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MorePolicy.java
deleted file mode 100644
index 7909d5b..0000000
--- a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MorePolicy.java
+++ /dev/null
@@ -1,29 +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 org.apache.brooklyn.test.osgi.entities.more;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.core.policy.AbstractPolicy;
-
-@Catalog(name="More Policy", description="Cataliog item OSGi test policy")
-public class MorePolicy extends AbstractPolicy {
-    public String sayHI(String name) {
-        return "HI "+name.toUpperCase()+" FROM V2";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreTemplate.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreTemplate.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreTemplate.java
deleted file mode 100644
index 9e0fc85..0000000
--- a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreTemplate.java
+++ /dev/null
@@ -1,26 +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 org.apache.brooklyn.test.osgi.entities.more;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.core.entity.AbstractApplication;
-
-@Catalog(name="More Template", description="Cataliog item OSGi test template")
-public class MoreTemplate extends AbstractApplication {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/core/BrooklynVersionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/BrooklynVersionTest.java b/core/src/test/java/org/apache/brooklyn/core/BrooklynVersionTest.java
index 424e176..87121bf 100644
--- a/core/src/test/java/org/apache/brooklyn/core/BrooklynVersionTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/BrooklynVersionTest.java
@@ -29,7 +29,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogEntityItemDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDtoAbstract;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/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 5fdcc3a..e48ff70 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
@@ -18,34 +18,29 @@
  */
 package org.apache.brooklyn.core.mgmt.osgi;
 
-import java.io.File;
-import java.io.IOException;
 
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.core.osgi.OsgiTestBase;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.maven.MavenArtifact;
 import org.apache.brooklyn.util.maven.MavenRetriever;
 import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.commons.io.FileUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
-import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /** 
  * Tests some assumptions about OSGi behaviour, in standalone mode (not part of brooklyn).
  * See {@link OsgiTestResources} for description of test resources.
  */
-public class OsgiStandaloneTest {
+public class OsgiStandaloneTest extends OsgiTestBase {
 
     private static final Logger log = LoggerFactory.getLogger(OsgiStandaloneTest.class);
 
@@ -57,28 +52,6 @@ public class OsgiStandaloneTest {
     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";
 
-    protected Framework framework = null;
-    private File storageTempDir;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        storageTempDir = Os.newTempDir("osgi-standalone");
-        framework = Osgis.getFramework(storageTempDir.getAbsolutePath(), true);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws BundleException, IOException, InterruptedException {
-        tearDownOsgiFramework(framework, storageTempDir);
-    }
-
-    public static void tearDownOsgiFramework(Framework framework, File storageTempDir) throws BundleException, InterruptedException, IOException {
-        Osgis.ungetFramework(framework);
-        framework = null;
-        if (storageTempDir!=null) {
-            FileUtils.deleteDirectory(storageTempDir);
-            storageTempDir = null;
-        }
-    }
 
     protected Bundle install(String url) throws BundleException {
         try {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiTestResources.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiTestResources.java
deleted file mode 100644
index 3def0ed..0000000
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiTestResources.java
+++ /dev/null
@@ -1,74 +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 org.apache.brooklyn.core.mgmt.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 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 {
-
-
-    /**
-     * 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_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";
-
-    /**
-     * 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_SYMBOLIC_NAME_FINAL_PART = "brooklyn-test-osgi-more-entities";
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL = 
-        "org.apache.brooklyn.test.resources.osgi."+BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.1.0.jar";
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY = "org.apache.brooklyn.test.osgi.entities.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_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.2.0.jar";
-    
-    /**
-     * bundle with identical metadata (same symbolic name and version -- hence being an evil twin) 
-     * as {@link #BROOKLYN_TEST_MORE_ENTITIES_V2_PATH},
-     * but slightly different behaviour -- saying "HO NAME" -- in order to make sure we can differentiate two two
-     * at runtime.
-     */
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_evil-twin_0.2.0.jar";
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
index 9445b7c..b434aa1 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.mgmt.osgi;
 
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -59,6 +60,7 @@ import org.apache.brooklyn.util.os.Os;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+import org.apache.brooklyn.util.core.osgi.OsgiTestBase;
 
 
 /** 
@@ -129,7 +131,7 @@ public class OsgiVersionMoreEntityTest {
 
             if (managementContext != null) Entities.destroyAll(managementContext);
         } finally {
-            OsgiStandaloneTest.tearDownOsgiFramework(framework, storageTempDir);
+            OsgiTestBase.tearDownOsgiFramework(framework, storageTempDir);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
index 8f1a248..246e214 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
@@ -48,7 +48,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogItemDtoAbstract;
 import org.apache.brooklyn.core.catalog.internal.CatalogTestUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiVersionMoreEntityTest;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/util/core/osgi/EmbeddedFelixFrameworkTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/osgi/EmbeddedFelixFrameworkTest.java b/core/src/test/java/org/apache/brooklyn/util/core/osgi/EmbeddedFelixFrameworkTest.java
deleted file mode 100644
index f48bbca..0000000
--- a/core/src/test/java/org/apache/brooklyn/util/core/osgi/EmbeddedFelixFrameworkTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2015 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.util.core.osgi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.jar.JarInputStream;
-
-import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
-import org.apache.brooklyn.test.support.TestResourceUnavailableException;
-import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.osgi.ManifestHelper;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.stream.Streams;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.launch.Framework;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-
-/**
- *
- * @author Ciprian Ciubotariu <ch...@gmx.net>
- */
-public class EmbeddedFelixFrameworkTest {
-
-    private static final Logger log = LoggerFactory.getLogger(OsgiStandaloneTest.class);
-
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
-
-    protected Framework framework = null;
-    private File storageTempDir;
-
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() throws Exception {
-        storageTempDir = Os.newTempDir("osgi-standalone");
-        framework = Osgis.getFramework(storageTempDir.getAbsolutePath(), false);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() throws BundleException, IOException, InterruptedException {
-        OsgiStandaloneTest.tearDownOsgiFramework(framework, storageTempDir);
-    }
-
-    @org.testng.annotations.Test
-    public void testReadAManifest() throws Exception {
-        Enumeration<URL> manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
-        log.info("Bundles and exported packages:");
-        MutableSet<String> allPackages = MutableSet.of();
-        while (manifests.hasMoreElements()) {
-            ManifestHelper mf = ManifestHelper.forManifestContents(Streams.readFullyString(manifests.nextElement().openStream()));
-            List<String> mfPackages = mf.getExportedPackages();
-            log.info("  " + mf.getSymbolicNameVersion() + ": " + mfPackages);
-            allPackages.addAll(mfPackages);
-        }
-        log.info("Total export package count: " + allPackages.size());
-        Assert.assertTrue(allPackages.size() > 20, "did not find enough packages"); // probably much larger
-        Assert.assertTrue(allPackages.contains(Osgis.class.getPackage().getName()));
-    }
-
-    @org.testng.annotations.Test
-    public void testReadKnownManifest() throws Exception {
-        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), BROOKLYN_TEST_OSGI_ENTITIES_PATH);
-        InputStream in = this.getClass().getResourceAsStream(BROOKLYN_TEST_OSGI_ENTITIES_PATH);
-        JarInputStream jarIn = new JarInputStream(in);
-        ManifestHelper helper = ManifestHelper.forManifest(jarIn.getManifest());
-        jarIn.close();
-        Assert.assertEquals(helper.getVersion().toString(), "0.1.0");
-        Assert.assertTrue(helper.getExportedPackages().contains("org.apache.brooklyn.test.osgi.entities"));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgiTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgiTestBase.java b/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgiTestBase.java
new file mode 100644
index 0000000..db66c13
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgiTestBase.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 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.util.core.osgi;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.commons.io.FileUtils;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ *
+ * @author Ciprian Ciubotariu <ch...@gmx.net>
+ */
+public class OsgiTestBase {
+
+    protected Framework framework = null;
+    private File storageTempDir;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        storageTempDir = Os.newTempDir("osgi-standalone");
+        framework = Osgis.getFramework(storageTempDir.getAbsolutePath(), true);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws BundleException, IOException, InterruptedException {
+        tearDownOsgiFramework(framework, storageTempDir);
+    }
+
+    public static void tearDownOsgiFramework(Framework framework, File storageTempDir) throws BundleException, InterruptedException, IOException {
+        Osgis.ungetFramework(framework);
+        framework = null;
+        if (storageTempDir != null) {
+            FileUtils.deleteDirectory(storageTempDir);
+            storageTempDir = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgisTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgisTest.java b/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgisTest.java
deleted file mode 100644
index cac9f40..0000000
--- a/core/src/test/java/org/apache/brooklyn/util/core/osgi/OsgisTest.java
+++ /dev/null
@@ -1,41 +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 org.apache.brooklyn.util.core.osgi;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-
-import org.apache.brooklyn.util.core.osgi.Osgis;
-import org.apache.brooklyn.util.core.osgi.Osgis.VersionedName;
-import org.osgi.framework.Version;
-import org.testng.annotations.Test;
-
-public class OsgisTest {
-
-    @Test
-    public void testParseOsgiIdentifier() throws Exception {
-        assertEquals(Osgis.parseOsgiIdentifier("a.b").get(), new VersionedName("a.b", null));
-        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.1.2").get(), new VersionedName("a.b", Version.parseVersion("0.1.2")));
-        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.0.0.SNAPSHOT").get(), new VersionedName("a.b", Version.parseVersion("0.0.0.SNAPSHOT")));
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.notanumber.2").isPresent()); // invalid version
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.1.2:3.4.5").isPresent());    // too many colons
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.0.0_SNAPSHOT").isPresent()); // invalid version
-        assertFalse(Osgis.parseOsgiIdentifier("").isPresent());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/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
deleted file mode 100644
index 1d78ddb..0000000
--- a/core/src/test/resources/brooklyn/osgi/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-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
-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/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar
deleted file mode 100644
index b4c777c..0000000
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.txt
deleted file mode 100644
index e6dde72..0000000
--- a/core/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.txt
+++ /dev/null
@@ -1,26 +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.
-
-The file brooklyn-osgi-test-a_0.1.0.jar is an extremely simple OSGi bundle,
-used in brooklyn.management.osgi.OsgiStandaloneTest.
-
-The jar contains its source.
-
-Under Apache conventions, binary files are not part of the source
-release. If you are using the source release, you may add this file
-by copying it from the master repository, which is accessible on the
-web at https://github.com/apache/incubator-brooklyn

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/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
deleted file mode 100644
index c76d03b..0000000
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.txt
deleted file mode 100644
index 9cf43a4..0000000
--- a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.txt
+++ /dev/null
@@ -1,26 +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.
-
-The file brooklyn-test-osgi-entities.jar is for testing a deployment of
-an OSGi bundle containing entities.
-
-The source is in core/src/test/dependencies/osgi/entities
-
-Under Apache conventions, binary files are not part of the source
-release. If you are using the source release, you may add this file
-by copying it from the master repository, which is accessible on the
-web at https://github.com/apache/incubator-brooklyn

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/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
deleted file mode 100644
index 1101112..0000000
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.txt
deleted file mode 100644
index 80067a4..0000000
--- a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.txt
+++ /dev/null
@@ -1,26 +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.
-
-The file brooklyn-test-osgi-entities.jar is for testing a deployment of
-an OSGi bundle containing entities.
-
-The source is in core/src/test/dependencies/osgi/more-entities-v1
-
-Under Apache conventions, binary files are not part of the source
-release. If you are using the source release, you may add this file
-by copying it from the master repository, which is accessible on the
-web at https://github.com/apache/incubator-brooklyn

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/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
deleted file mode 100644
index 5587e25..0000000
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.txt
deleted file mode 100644
index 3fb2d31..0000000
--- a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.txt
+++ /dev/null
@@ -1,26 +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.
-
-The file brooklyn-test-osgi-entities.jar is for testing a deployment of
-an OSGi bundle containing entities.
-
-The source is in core/src/test/dependencies/osgi/more-entities-v2
-
-Under Apache conventions, binary files are not part of the source
-release. If you are using the source release, you may add this file
-by copying it from the master repository, which is accessible on the
-web at https://github.com/apache/incubator-brooklyn

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
deleted file mode 100644
index 95d697b..0000000
Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
deleted file mode 100644
index 1b9c2ab..0000000
--- a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
+++ /dev/null
@@ -1,26 +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.
-
-The file brooklyn-test-osgi-entities.jar is for testing a deployment of
-an OSGi bundle containing entities.
-
-The source is in core/src/test/dependencies/osgi/more-entities-v2-evil-twin
-
-Under Apache conventions, binary files are not part of the source
-release. If you are using the source release, you may add this file
-by copying it from the master repository, which is accessible on the
-web at https://github.com/apache/incubator-brooklyn

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/karaf/apache-brooklyn/src/main/resources/etc/custom.properties
----------------------------------------------------------------------
diff --git a/karaf/apache-brooklyn/src/main/resources/etc/custom.properties b/karaf/apache-brooklyn/src/main/resources/etc/custom.properties
index f2db8c2..7da5c63 100644
--- a/karaf/apache-brooklyn/src/main/resources/etc/custom.properties
+++ b/karaf/apache-brooklyn/src/main/resources/etc/custom.properties
@@ -22,6 +22,12 @@
 # All the values specified here will override the default value.
 #
 
+# Brooklyn used to bundle Apache Felix, so force felix
+karaf.framework=felix
+
+# brooklyn used 4.4.0 at the time of osgification, which differs from karaf's bundled felix version
+#karaf.framework.felix=mvn\:org.apache.felix/org.apache.felix.framework/${felix.framework.version}
+
 #karaf.systemBundlesStartLevel=50
 #
 #org.osgi.framework.bootdelegation=org.apache.karaf.jaas.boot,!com.sun.xml.messaging.saaj.*,!com.sun.xml.internal.bind.*,sun.*,com.sun.*,javax.transaction,javax.transaction.*,org.apache.xalan.processor,org.apache.xpath.jaxp,org.apache.xml.dtm.ref,org.apache.xerces.jaxp.datatype,org.apache.xerces.stax,org.apache.xerces.parsers,org.apache.xerces.jaxp,org.apache.xerces.jaxp.validation,org.apache.xerces.dom

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0461e7a..804b9e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,6 +245,10 @@
         <module>utils/jmx/jmxrmi-agent</module>
         <module>utils/test-support</module>
         <module>utils/rest-swagger</module>
+
+        <module>utils/rt-osgi</module>
+        <module>utils/rt-felix</module>
+
     </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/usage/camp/pom.xml
----------------------------------------------------------------------
diff --git a/usage/camp/pom.xml b/usage/camp/pom.xml
index 9173a58..35ceca2 100644
--- a/usage/camp/pom.xml
+++ b/usage/camp/pom.xml
@@ -127,6 +127,13 @@
         </dependency>
         <dependency>
             <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-rt-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
             <artifactId>brooklyn-software-base</artifactId>
             <version>${project.version}</version>
             <classifier>tests</classifier>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
index 8575202..7985bb8 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index b62ba60..20d0a1d 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -32,7 +32,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.entity.stock.BasicEntity;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
index 3bf299a..bc55be9 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-felix/pom.xml
----------------------------------------------------------------------
diff --git a/utils/rt-felix/pom.xml b/utils/rt-felix/pom.xml
new file mode 100644
index 0000000..147e1de
--- /dev/null
+++ b/utils/rt-felix/pom.xml
@@ -0,0 +1,61 @@
+<!--
+    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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.brooklyn</groupId>
+        <artifactId>brooklyn-parent</artifactId>
+        <version>0.9.0-SNAPSHOT</version>  <!-- BROOKLYN_VERSION -->
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <name>Brooklyn Felix Runtime</name>
+    <artifactId>brooklyn-rt-felix</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-rt-osgi</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-test-support</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-rt-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFramework.java
----------------------------------------------------------------------
diff --git a/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFramework.java b/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFramework.java
new file mode 100644
index 0000000..6d2bb5f
--- /dev/null
+++ b/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFramework.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2015 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.rt.felix;
+
+import com.google.common.base.Stopwatch;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.osgi.OsgiUtils;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.apache.felix.framework.FrameworkFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.launch.Framework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Functions for starting an Apache Felix OSGi framework inside a non-OSGi Brooklyn distro.
+ * 
+ * @author Ciprian Ciubotariu <ch...@gmx.net>
+ */
+public class EmbeddedFelixFramework {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EmbeddedFelixFramework.class);
+
+    private static final String EXTENSION_PROTOCOL = "system";
+    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+    private static final Set<String> SYSTEM_BUNDLES = MutableSet.of();
+
+
+    // -------- creating
+
+    /*
+     * loading framework factory and starting framework based on:
+     * http://felix.apache.org/documentation/subprojects/apache-felix-framework/apache-felix-framework-launching-and-embedding.html
+     */
+
+    public static FrameworkFactory newFrameworkFactory() {
+        URL url = EmbeddedFelixFramework.class.getClassLoader().getResource(
+                "META-INF/services/org.osgi.framework.launch.FrameworkFactory");
+        if (url != null) {
+            try {
+                BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
+                try {
+                    for (String s = br.readLine(); s != null; s = br.readLine()) {
+                        s = s.trim();
+                        // load the first non-empty, non-commented line
+                        if ((s.length() > 0) && (s.charAt(0) != '#')) {
+                            return (FrameworkFactory) Class.forName(s).newInstance();
+                        }
+                    }
+                } finally {
+                    if (br != null) br.close();
+                }
+            } catch (Exception e) {
+                // class creation exceptions are not interesting to caller...
+                throw Exceptions.propagate(e);
+            }
+        }
+        throw new IllegalStateException("Could not find framework factory.");
+    }
+
+    public static Framework newFrameworkStarted(String felixCacheDir, boolean clean, Map<?,?> extraStartupConfig) {
+        Map<Object,Object> cfg = MutableMap.copyOf(extraStartupConfig);
+        if (clean) cfg.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
+        if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir);
+        cfg.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MULTIPLE);
+        FrameworkFactory factory = newFrameworkFactory();
+
+        Stopwatch timer = Stopwatch.createStarted();
+        Framework framework = factory.newFramework(cfg);
+        try {
+            framework.init();
+            installBootBundles(framework);
+            framework.start();
+        } catch (Exception e) {
+            // framework bundle start exceptions are not interesting to caller...
+            throw Exceptions.propagate(e);
+        }
+        LOG.debug("System bundles are: "+SYSTEM_BUNDLES);
+        LOG.debug("OSGi framework started in " + Duration.of(timer));
+        return framework;
+    }
+
+        public static void stopFramework(Framework framework) throws RuntimeException {
+        try {
+            if (framework != null) {
+                framework.stop();
+                framework.waitForStop(0);
+            }
+        } catch (BundleException | InterruptedException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /* --- helper functions */
+
+    private static void installBootBundles(Framework framework) {
+        Stopwatch timer = Stopwatch.createStarted();
+        LOG.debug("Installing OSGi boot bundles from "+EmbeddedFelixFramework.class.getClassLoader()+"...");
+        Enumeration<URL> resources;
+        try {
+            resources = EmbeddedFelixFramework.class.getClassLoader().getResources(MANIFEST_PATH);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        }
+        BundleContext bundleContext = framework.getBundleContext();
+        Map<String, Bundle> installedBundles = getInstalledBundlesById(bundleContext);
+        while(resources.hasMoreElements()) {
+            URL url = resources.nextElement();
+            ReferenceWithError<?> installResult = installExtensionBundle(bundleContext, url, installedBundles, OsgiUtils.getVersionedId(framework));
+            if (installResult.hasError() && !installResult.masksErrorIfPresent()) {
+                // it's reported as a critical error, so warn here
+                LOG.warn("Unable to install manifest from "+url+": "+installResult.getError(), installResult.getError());
+            } else {
+                Object result = installResult.getWithoutError();
+                if (result instanceof Bundle) {
+                    String v = OsgiUtils.getVersionedId( (Bundle)result );
+                    SYSTEM_BUNDLES.add(v);
+                    if (installResult.hasError()) {
+                        LOG.debug(installResult.getError().getMessage()+(result!=null ? " ("+result+"/"+v+")" : ""));
+                    } else {
+                        LOG.debug("Installed "+v+" from "+url);
+                    }
+                } else if (installResult.hasError()) {
+                    LOG.debug(installResult.getError().getMessage());
+                }
+            }
+        }
+        LOG.debug("Installed OSGi boot bundles in "+Time.makeTimeStringRounded(timer)+": "+Arrays.asList(framework.getBundleContext().getBundles()));
+    }
+
+    private static Map<String, Bundle> getInstalledBundlesById(BundleContext bundleContext) {
+        Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
+        Bundle[] bundles = bundleContext.getBundles();
+        for (Bundle b : bundles) {
+            installedBundles.put(OsgiUtils.getVersionedId(b), b);
+        }
+        return installedBundles;
+    }
+
+    /** Wraps the bundle if successful or already installed, wraps TRUE if it's the system entry,
+     * wraps null if the bundle is already installed from somewhere else;
+     * in all these cases <i>masking</i> an explanatory error if already installed or it's the system entry.
+     * <p>
+     * Returns an instance wrapping null and <i>throwing</i> an error if the bundle could not be installed.
+     */
+    private static ReferenceWithError<?> installExtensionBundle(BundleContext bundleContext, URL manifestUrl, Map<String, Bundle> installedBundles, String frameworkVersionedId) {
+        //ignore http://felix.extensions:9/ system entry
+        if("felix.extensions".equals(manifestUrl.getHost()))
+            return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Skipping install of internal extension bundle from "+manifestUrl));
+
+        try {
+            Manifest manifest = readManifest(manifestUrl);
+            if (!isValidBundle(manifest))
+                return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Resource at "+manifestUrl+" is not an OSGi bundle: no valid manifest"));
+
+            String versionedId = OsgiUtils.getVersionedId(manifest);
+            URL bundleUrl = OsgiUtils.getContainerUrl(manifestUrl, MANIFEST_PATH);
+
+            Bundle existingBundle = installedBundles.get(versionedId);
+            if (existingBundle != null) {
+                if (!bundleUrl.equals(existingBundle.getLocation()) &&
+                        //the framework bundle is always pre-installed, don't display duplicate info
+                        !versionedId.equals(frameworkVersionedId)) {
+                    return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Bundle "+versionedId+" (from manifest " + manifestUrl + ") is already installed, from " + existingBundle.getLocation()));
+                }
+                return ReferenceWithError.newInstanceMaskingError(existingBundle, new IllegalArgumentException("Bundle "+versionedId+" from manifest " + manifestUrl + " is already installed"));
+            }
+
+            byte[] jar = buildExtensionBundle(manifest);
+            LOG.debug("Installing boot bundle " + bundleUrl);
+            //mark the bundle as extension so we can detect it later using the "system:" protocol
+            //(since we cannot access BundleImpl.isExtension)
+            Bundle newBundle = bundleContext.installBundle(EXTENSION_PROTOCOL + ":" + bundleUrl.toString(), new ByteArrayInputStream(jar));
+            installedBundles.put(versionedId, newBundle);
+            return ReferenceWithError.newInstanceWithoutError(newBundle);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            return ReferenceWithError.newInstanceThrowingError(null,
+                new IllegalStateException("Problem installing extension bundle " + manifestUrl + ": "+e, e));
+        }
+    }
+
+    private static Manifest readManifest(URL manifestUrl) throws IOException {
+        Manifest manifest;
+        InputStream in = null;
+        try {
+            in = manifestUrl.openStream();
+            manifest = new Manifest(in);
+        } finally {
+            if (in != null) {
+                try {in.close();}
+                catch (Exception e) {};
+            }
+        }
+        return manifest;
+    }
+
+    private static byte[] buildExtensionBundle(Manifest manifest) throws IOException {
+        Attributes atts = manifest.getMainAttributes();
+
+        //the following properties are invalid in extension bundles
+        atts.remove(new Attributes.Name(Constants.IMPORT_PACKAGE));
+        atts.remove(new Attributes.Name(Constants.REQUIRE_BUNDLE));
+        atts.remove(new Attributes.Name(Constants.BUNDLE_NATIVECODE));
+        atts.remove(new Attributes.Name(Constants.DYNAMICIMPORT_PACKAGE));
+        atts.remove(new Attributes.Name(Constants.BUNDLE_ACTIVATOR));
+
+        //mark as extension bundle
+        atts.putValue(Constants.FRAGMENT_HOST, "system.bundle; extension:=framework");
+
+        //create the jar containing the manifest
+        ByteArrayOutputStream jar = new ByteArrayOutputStream();
+        JarOutputStream out = new JarOutputStream(jar, manifest);
+        out.close();
+        return jar.toByteArray();
+    }
+
+    private static boolean isValidBundle(Manifest manifest) {
+        Attributes atts = manifest.getMainAttributes();
+        return atts.containsKey(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/ManifestHelper.java
----------------------------------------------------------------------
diff --git a/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/ManifestHelper.java b/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/ManifestHelper.java
new file mode 100644
index 0000000..164a96f
--- /dev/null
+++ b/utils/rt-felix/src/main/java/org/apache/brooklyn/rt/felix/ManifestHelper.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2015 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.rt.felix;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.jar.Manifest;
+import javax.annotation.Nullable;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+
+/**
+ * The class is not used, staying for future reference.
+ * Remove after OSGi transition is completed.
+ */
+public class ManifestHelper {
+    private static ManifestParser parse;
+    private Manifest manifest;
+    private String source;
+    private static final String WIRING_PACKAGE = PackageNamespace.PACKAGE_NAMESPACE;
+
+    public static ManifestHelper forManifestContents(String contents) throws IOException, BundleException {
+        ManifestHelper result = forManifest(Streams.newInputStreamWithContents(contents));
+        result.source = contents;
+        return result;
+    }
+
+    public static ManifestHelper forManifest(URL url) throws IOException, BundleException {
+        InputStream in = null;
+        try {
+            in = url.openStream();
+            return forManifest(in);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+    public static ManifestHelper forManifest(InputStream in) throws IOException, BundleException {
+        return forManifest(new Manifest(in));
+    }
+
+    public static ManifestHelper forManifest(Manifest manifest) throws BundleException {
+        ManifestHelper result = new ManifestHelper();
+        result.manifest = manifest;
+        parse = new ManifestParser(null, null, null, new StringMap(manifest.getMainAttributes()));
+        return result;
+    }
+
+    public String getSymbolicName() {
+        return parse.getSymbolicName();
+    }
+
+    public Version getVersion() {
+        return parse.getBundleVersion();
+    }
+
+    public String getSymbolicNameVersion() {
+        return getSymbolicName() + ":" + getVersion();
+    }
+
+    public List<String> getExportedPackages() {
+        MutableList<String> result = MutableList.of();
+        for (BundleCapability c : parse.getCapabilities()) {
+            if (WIRING_PACKAGE.equals(c.getNamespace())) {
+                result.add((String) c.getAttributes().get(WIRING_PACKAGE));
+            }
+        }
+        return result;
+    }
+
+    @Nullable
+    public String getSource() {
+        return source;
+    }
+
+    public Manifest getManifest() {
+        return manifest;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-felix/src/test/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFrameworkTest.java
----------------------------------------------------------------------
diff --git a/utils/rt-felix/src/test/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFrameworkTest.java b/utils/rt-felix/src/test/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFrameworkTest.java
new file mode 100644
index 0000000..c1730d0
--- /dev/null
+++ b/utils/rt-felix/src/test/java/org/apache/brooklyn/rt/felix/EmbeddedFelixFrameworkTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 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.rt.felix;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarInputStream;
+
+import org.apache.brooklyn.test.support.TestResourceUnavailableException;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.commons.io.FileUtils;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Ciprian Ciubotariu <ch...@gmx.net>
+ */
+public class EmbeddedFelixFrameworkTest {
+
+    private static final Logger log = LoggerFactory.getLogger(EmbeddedFelixFrameworkTest.class);
+
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
+
+    protected Framework framework = null;
+    private File storageTempDir;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        storageTempDir = Os.newTempDir("osgi-standalone");
+        framework = EmbeddedFelixFramework.newFrameworkStarted(storageTempDir.getAbsolutePath(), true, null);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws BundleException, IOException, InterruptedException {
+        tearDownOsgiFramework(framework, storageTempDir);
+    }
+
+    public static void tearDownOsgiFramework(Framework framework, File storageTempDir) throws BundleException, InterruptedException, IOException {
+        EmbeddedFelixFramework.stopFramework(framework);
+        framework = null;
+        if (storageTempDir != null) {
+            FileUtils.deleteDirectory(storageTempDir);
+            storageTempDir = null;
+        }
+    }
+
+    @Test
+    public void testReadAManifest() throws Exception {
+        Enumeration<URL> manifests = this.getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
+        log.info("Bundles and exported packages:");
+        MutableSet<String> allPackages = MutableSet.of();
+        while (manifests.hasMoreElements()) {
+            ManifestHelper mf = ManifestHelper.forManifestContents(Streams.readFullyString(manifests.nextElement().openStream()));
+            List<String> mfPackages = mf.getExportedPackages();
+            log.info("  " + mf.getSymbolicNameVersion() + ": " + mfPackages);
+            allPackages.addAll(mfPackages);
+        }
+        log.info("Total export package count: " + allPackages.size());
+        Assert.assertTrue(allPackages.size() > 20, "did not find enough packages"); // probably much larger
+        Assert.assertTrue(allPackages.contains(EmbeddedFelixFramework.class.getPackage().getName()));
+    }
+
+    @Test
+    public void testReadKnownManifest() throws Exception {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+        InputStream in = this.getClass().getResourceAsStream(BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+        JarInputStream jarIn = new JarInputStream(in);
+        ManifestHelper helper = ManifestHelper.forManifest(jarIn.getManifest());
+        jarIn.close();
+        Assert.assertEquals(helper.getVersion().toString(), "0.1.0");
+        Assert.assertTrue(helper.getExportedPackages().contains("org.apache.brooklyn.test.osgi.entities"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/pom.xml
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/pom.xml b/utils/rt-osgi/pom.xml
new file mode 100644
index 0000000..2cac7f0
--- /dev/null
+++ b/utils/rt-osgi/pom.xml
@@ -0,0 +1,53 @@
+<!--
+    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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.brooklyn</groupId>
+        <artifactId>brooklyn-parent</artifactId>
+        <version>0.9.0-SNAPSHOT</version>  <!-- BROOKLYN_VERSION -->
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <name>Brooklyn OSGi Utils</name>
+    <artifactId>brooklyn-rt-osgi</artifactId>
+    <packaging>jar</packaging>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-test-support</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/OsgiUtils.java
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/OsgiUtils.java b/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/OsgiUtils.java
new file mode 100644
index 0000000..4e28720
--- /dev/null
+++ b/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/OsgiUtils.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 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.util.osgi;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.Strings;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * Simple OSGi utilities.
+ * 
+ * @author Ciprian Ciubotariu <ch...@gmx.net>
+ */
+public class OsgiUtils {
+
+    public static URL getContainerUrl(URL url, String resourceInThatDir) {
+        //Switching from manual parsing of jar: and file: URLs to java provided functionality.
+        //The old code was breaking on any Windows path and instead of fixing it, using
+        //the provided Java APIs seemed like the better option since they are already tested
+        //on multiple platforms.
+        boolean isJar = "jar".equals(url.getProtocol());
+        if(isJar) {
+            try {
+                //let java handle the parsing of jar URL, no network connection is established.
+                //Strips the jar protocol:
+                //  jar:file:/<path to jar>!<resourceInThatDir>
+                //  becomes
+                //  file:/<path to jar>
+                JarURLConnection connection = (JarURLConnection) url.openConnection();
+                url = connection.getJarFileURL();
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+        } else {
+            //Remove the trailing resouceInThatDir path from the URL, thus getting the parent folder.
+            String path = url.toString();
+            int i = path.indexOf(resourceInThatDir);
+            if (i==-1) throw new IllegalStateException("Resource path ("+resourceInThatDir+") not in url substring ("+url+")");
+            String parent = path.substring(0, i);
+            try {
+                url = new URL(parent);
+            } catch (MalformedURLException e) {
+                throw new IllegalStateException("Resource ("+resourceInThatDir+") found at invalid URL parent (" + parent + ")", e);
+            }
+        }
+        return url;
+    }
+
+    public static String getVersionedId(Manifest manifest) {
+        Attributes atts = manifest.getMainAttributes();
+        return atts.getValue(Constants.BUNDLE_SYMBOLICNAME) + ":" + atts.getValue(Constants.BUNDLE_VERSION);
+    }
+
+    public static String getVersionedId(Bundle b) {
+        return b.getSymbolicName() + ":" + b.getVersion();
+    }
+
+    /** Takes a string which might be of the form "symbolic-name" or "symbolic-name:version" (or something else entirely)
+     * and returns a VersionedName. The versionedName.getVersion() will be null if if there was no version in the input
+     * (or returning {@link Maybe#absent()} if not valid, with a suitable error message). */
+    public static Maybe<VersionedName> parseOsgiIdentifier(String symbolicNameOptionalWithVersion) {
+        if (Strings.isBlank(symbolicNameOptionalWithVersion)) {
+            return Maybe.absent("OSGi identifier is blank");
+        }
+        String[] parts = symbolicNameOptionalWithVersion.split(":");
+        if (parts.length > 2) {
+            return Maybe.absent("OSGi identifier has too many parts; max one ':' symbol");
+        }
+        Version v = null;
+        if (parts.length == 2) {
+            try {
+                v = Version.parseVersion(parts[1]);
+            } catch (IllegalArgumentException e) {
+                return Maybe.absent("OSGi identifier has invalid version string (" + e.getMessage() + ")");
+            }
+        }
+        return Maybe.of(new VersionedName(parts[0], v));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java b/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
new file mode 100644
index 0000000..df36a80
--- /dev/null
+++ b/utils/rt-osgi/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 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.util.osgi;
+
+import com.google.common.base.Objects;
+import org.apache.brooklyn.util.text.Strings;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * Versioned name of an OSGi bundle.
+ * @author Ciprian Ciubotariu <ch...@gmx.net>
+ */
+public class VersionedName {
+    private final String symbolicName;
+    private final Version version;
+
+    public VersionedName(Bundle b) {
+        this.symbolicName = b.getSymbolicName();
+        this.version = b.getVersion();
+    }
+
+    public VersionedName(String symbolicName, Version version) {
+        this.symbolicName = symbolicName;
+        this.version = version;
+    }
+
+    @Override
+    public String toString() {
+        return symbolicName + ":" + Strings.toString(version);
+    }
+
+    public boolean equals(String sn, String v) {
+        return symbolicName.equals(sn) && (version == null && v == null || version != null && version.toString().equals(v));
+    }
+
+    public boolean equals(String sn, Version v) {
+        return symbolicName.equals(sn) && (version == null && v == null || version != null && version.equals(v));
+    }
+
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    public Version getVersion() {
+        return version;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(symbolicName, version);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof VersionedName)) {
+            return false;
+        }
+        VersionedName o = (VersionedName) other;
+        return Objects.equal(symbolicName, o.symbolicName) && Objects.equal(version, o.version);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java b/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
new file mode 100644
index 0000000..21827a0
--- /dev/null
+++ b/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util.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 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 {
+
+
+    /**
+     * 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_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";
+
+    /**
+     * 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_SYMBOLIC_NAME_FINAL_PART = "brooklyn-test-osgi-more-entities";
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL = 
+        "org.apache.brooklyn.test.resources.osgi."+BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.1.0.jar";
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY = "org.apache.brooklyn.test.osgi.entities.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_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.2.0.jar";
+    
+    /**
+     * bundle with identical metadata (same symbolic name and version -- hence being an evil twin) 
+     * as {@link #BROOKLYN_TEST_MORE_ENTITIES_V2_PATH},
+     * but slightly different behaviour -- saying "HO NAME" -- in order to make sure we can differentiate two two
+     * at runtime.
+     */
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_evil-twin_0.2.0.jar";
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgisTest.java
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgisTest.java b/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgisTest.java
new file mode 100644
index 0000000..c86670a
--- /dev/null
+++ b/utils/rt-osgi/src/test/java/org/apache/brooklyn/util/osgi/OsgisTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util.osgi;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import org.osgi.framework.Version;
+import org.testng.annotations.Test;
+
+public class OsgisTest {
+
+    @Test
+    public void testParseOsgiIdentifier() throws Exception {
+        assertEquals(OsgiUtils.parseOsgiIdentifier("a.b").get(), new VersionedName("a.b", null));
+        assertEquals(OsgiUtils.parseOsgiIdentifier("a.b:0.1.2").get(), new VersionedName("a.b", Version.parseVersion("0.1.2")));
+        assertEquals(OsgiUtils.parseOsgiIdentifier("a.b:0.0.0.SNAPSHOT").get(), new VersionedName("a.b", Version.parseVersion("0.0.0.SNAPSHOT")));
+        assertFalse(OsgiUtils.parseOsgiIdentifier("a.b:0.notanumber.2").isPresent()); // invalid version
+        assertFalse(OsgiUtils.parseOsgiIdentifier("a.b:0.1.2:3.4.5").isPresent());    // too many colons
+        assertFalse(OsgiUtils.parseOsgiIdentifier("a.b:0.0.0_SNAPSHOT").isPresent()); // invalid version
+        assertFalse(OsgiUtils.parseOsgiIdentifier("").isPresent());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04bb1f2d/utils/rt-osgi/src/test/resources/brooklyn/osgi/README.md
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/test/resources/brooklyn/osgi/README.md b/utils/rt-osgi/src/test/resources/brooklyn/osgi/README.md
new file mode 100644
index 0000000..1d78ddb
--- /dev/null
+++ b/utils/rt-osgi/src/test/resources/brooklyn/osgi/README.md
@@ -0,0 +1,25 @@
+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
+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/04bb1f2d/utils/rt-osgi/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar
----------------------------------------------------------------------
diff --git a/utils/rt-osgi/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar b/utils/rt-osgi/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar
new file mode 100644
index 0000000..b4c777c
Binary files /dev/null and b/utils/rt-osgi/src/test/resources/brooklyn/osgi/brooklyn-osgi-test-a_0.1.0.jar differ