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 2017/06/08 09:37:42 UTC

[08/11] brooklyn-server git commit: extract OsgiClassLoader as more general ClassLoaderFromStackOfBrooklynClassLoadingContext

extract OsgiClassLoader as more general ClassLoaderFromStackOfBrooklynClassLoadingContext

so we can use and test it from XmlSerializer (ie memento-free)


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

Branch: refs/heads/master
Commit: f9566273d3c748e16a1733cd00489bef29d9f53a
Parents: f23f4cb
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jun 7 13:46:50 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 7 13:47:40 2017 +0100

----------------------------------------------------------------------
 .../BrooklynClassLoadingContextSequential.java  |   2 -
 ...rFromStackOfBrooklynClassLoadingContext.java | 132 +++++++++++++++++
 .../core/mgmt/persist/XmlMementoSerializer.java | 108 +-------------
 ...mStackOfBrooklynClassLoadingContextTest.java | 143 +++++++++++++++++++
 ...entoSerializerDelegatingClassLoaderTest.java | 143 -------------------
 5 files changed, 280 insertions(+), 248 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f9566273/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java
index 50a0509..ddd5c5b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java
@@ -32,8 +32,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 
 public final class BrooklynClassLoadingContextSequential extends AbstractBrooklynClassLoadingContext {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f9566273/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContext.java
new file mode 100644
index 0000000..f42ecd2
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContext.java
@@ -0,0 +1,132 @@
+/*
+ * 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.classloading;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Stack;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
+import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.javalang.ClassLoadingContext;
+
+/** Provides a stack where {@link ClassLoadingContext} instances can be pushed and popped,
+ * with the most recently pushed one in effect at any given time.
+ * <p>
+ * This is useful when traversing a tree some of whose elements may bring custom search paths,
+ * and the worker wants to have a simple view of the loader to use at any point in time.
+ * For example XStream keeps a class-loader in effect but when deserializing things 
+ * some of those things may define bundles to use. */
+public class ClassLoaderFromStackOfBrooklynClassLoadingContext extends ClassLoader {
+    
+    private final Stack<BrooklynClassLoadingContext> contexts = new Stack<BrooklynClassLoadingContext>();
+    private final Stack<ClassLoader> cls = new Stack<ClassLoader>();
+    private final AtomicReference<Thread> lockOwner = new AtomicReference<Thread>();
+    private ManagementContext mgmt;
+    private ClassLoader currentClassLoader;
+    private AtomicReference<ClassLoaderUtils> currentLoader = new AtomicReference<>();
+    private int lockCount;
+    
+    public ClassLoaderFromStackOfBrooklynClassLoadingContext(ClassLoader classLoader) {
+        setCurrentClassLoader(classLoader);
+    }
+    
+    public void setManagementContext(ManagementContext mgmt) {
+        this.mgmt = checkNotNull(mgmt, "mgmt");
+        currentLoader.set(new ClassLoaderUtils(currentClassLoader, mgmt));
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        return currentLoader.get().loadClass(name);
+    }
+
+    /** Must be accompanied by a corresponding {@link #popClassLoadingContext()} when finished. */
+    @SuppressWarnings("deprecation")
+    public void pushClassLoadingContext(BrooklynClassLoadingContext clcNew) {
+        acquireLock();
+        BrooklynClassLoadingContext oldClc;
+        if (!contexts.isEmpty()) {
+            oldClc = contexts.peek();
+        } else {
+            // TODO xml serializers using this should take a BCLC instead of a CL
+            oldClc = JavaBrooklynClassLoadingContext.create(mgmt, getCurrentClassLoader());
+        }
+        BrooklynClassLoadingContextSequential clcMerged = new BrooklynClassLoadingContextSequential(mgmt, oldClc, clcNew);
+        ClassLoader newCL = ClassLoaderFromBrooklynClassLoadingContext.of(clcMerged);
+        contexts.push(clcMerged);
+        cls.push(getCurrentClassLoader());
+        setCurrentClassLoader(newCL);
+    }
+
+    public void popClassLoadingContext() {
+        synchronized (lockOwner) {
+            releaseXstreamLock();
+            setCurrentClassLoader(cls.pop());
+            contexts.pop();
+        }
+    }
+    
+    private ClassLoader getCurrentClassLoader() {
+        return currentClassLoader;
+    }
+    
+    private void setCurrentClassLoader(ClassLoader classLoader) {
+        currentClassLoader = checkNotNull(classLoader);
+        currentLoader.set(new ClassLoaderUtils(currentClassLoader, mgmt));
+    }
+    
+    protected void acquireLock() {
+        synchronized (lockOwner) {
+            while (true) {
+                if (lockOwner.compareAndSet(null, Thread.currentThread()) || 
+                    Thread.currentThread().equals( lockOwner.get() )) {
+                    break;
+                }
+                try {
+                    lockOwner.wait(1000);
+                } catch (InterruptedException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+            lockCount++;
+        }
+    }
+
+    protected void releaseXstreamLock() {
+        synchronized (lockOwner) {
+            if (lockCount<=0) {
+                throw new IllegalStateException("not locked");
+            }
+            if (--lockCount == 0) {
+                if (!lockOwner.compareAndSet(Thread.currentThread(), null)) {
+                    Thread oldOwner = lockOwner.getAndSet(null);
+                    throw new IllegalStateException("locked by "+oldOwner+" but unlock attempt by "+Thread.currentThread());
+                }
+                lockOwner.notifyAll();
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f9566273/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 dac3ca7..e83b5ea 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
@@ -24,9 +24,7 @@ import java.io.IOException;
 import java.io.Writer;
 import java.util.Map;
 import java.util.NoSuchElementException;
-import java.util.Stack;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.effector.Effector;
@@ -49,9 +47,7 @@ import org.apache.brooklyn.core.effector.BasicParameterType;
 import org.apache.brooklyn.core.effector.EffectorAndBody;
 import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory;
 import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
-import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
-import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext;
-import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromStackOfBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicCatalogItemMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicEnricherMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicEntityMemento;
@@ -60,14 +56,12 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BasicLocationMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicManagedBundleMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicPolicyMemento;
 import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.xstream.XmlSerializer;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.thoughtworks.xstream.converters.Converter;
 import com.thoughtworks.xstream.converters.MarshallingContext;
 import com.thoughtworks.xstream.converters.SingleValueConverter;
@@ -88,7 +82,7 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
 
     private static final Logger LOG = LoggerFactory.getLogger(XmlMementoSerializer.class);
 
-    private final OsgiClassLoader delegatingClassLoader;
+    private final ClassLoaderFromStackOfBrooklynClassLoadingContext delegatingClassLoader;
     private LookupContext lookupContext;
     
     public XmlMementoSerializer(ClassLoader classLoader) {
@@ -97,7 +91,7 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
     
     public XmlMementoSerializer(ClassLoader classLoader, Map<String, String> deserializingClassRenames) {
         super(deserializingClassRenames);
-        this.delegatingClassLoader = new OsgiClassLoader(classLoader);
+        this.delegatingClassLoader = new ClassLoaderFromStackOfBrooklynClassLoadingContext(classLoader);
         xstream.setClassLoader(this.delegatingClassLoader);
         
         xstream.alias("entity", BasicEntityMemento.class);
@@ -449,7 +443,7 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
                     RegisteredType cat = lookupContext.lookupManagementContext().getTypeRegistry().get(catalogItemId);
                     if (cat==null) throw new NoSuchElementException("catalog item: "+catalogItemId);
                     BrooklynClassLoadingContext clcNew = CatalogUtils.newClassLoadingContext(lookupContext.lookupManagementContext(), cat);
-                    delegatingClassLoader.pushXstreamCustomClassLoader(clcNew);
+                    delegatingClassLoader.pushClassLoadingContext(clcNew);
                     customLoaderSet = true;
                 }
                 
@@ -460,7 +454,7 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
             } finally {
                 context.put("SpecConverter.instance", null);
                 if (customLoaderSet) {
-                    delegatingClassLoader.popXstreamCustomClassLoader();
+                    delegatingClassLoader.popClassLoadingContext();
                 }
             }
         }
@@ -483,96 +477,4 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
             context.put("SpecConverter.instance", instance);
         }
     }
-    
-    @VisibleForTesting
-    static class OsgiClassLoader extends ClassLoader {
-        private final Stack<BrooklynClassLoadingContext> contexts = new Stack<BrooklynClassLoadingContext>();
-        private final Stack<ClassLoader> cls = new Stack<ClassLoader>();
-        private final AtomicReference<Thread> xstreamLockOwner = new AtomicReference<Thread>();
-        private ManagementContext mgmt;
-        private ClassLoader currentClassLoader;
-        private AtomicReference<ClassLoaderUtils> currentLoader = new AtomicReference<>();
-        private int lockCount;
-        
-        protected OsgiClassLoader(ClassLoader classLoader) {
-            setCurrentClassLoader(classLoader);
-        }
-        
-        protected void setManagementContext(ManagementContext mgmt) {
-            this.mgmt = checkNotNull(mgmt, "mgmt");
-            currentLoader.set(new ClassLoaderUtils(currentClassLoader, mgmt));
-        }
-
-        @Override
-        protected Class<?> findClass(String name) throws ClassNotFoundException {
-            return currentLoader.get().loadClass(name);
-        }
-
-        /** Must be accompanied by a corresponding {@link #popXstreamCustomClassLoader()} when finished. */
-        @SuppressWarnings("deprecation")
-        protected void pushXstreamCustomClassLoader(BrooklynClassLoadingContext clcNew) {
-            acquireXstreamLock();
-            BrooklynClassLoadingContext oldClc;
-            if (!contexts.isEmpty()) {
-                oldClc = contexts.peek();
-            } else {
-                // TODO XmlMementoSerializer should take a BCLC instead of a CL
-                oldClc = JavaBrooklynClassLoadingContext.create(mgmt, getCurrentClassLoader());
-            }
-            BrooklynClassLoadingContextSequential clcMerged = new BrooklynClassLoadingContextSequential(mgmt, oldClc, clcNew);
-            ClassLoader newCL = ClassLoaderFromBrooklynClassLoadingContext.of(clcMerged);
-            contexts.push(clcMerged);
-            cls.push(getCurrentClassLoader());
-            setCurrentClassLoader(newCL);
-        }
-
-        protected void popXstreamCustomClassLoader() {
-            synchronized (xstreamLockOwner) {
-                releaseXstreamLock();
-                setCurrentClassLoader(cls.pop());
-                contexts.pop();
-            }
-        }
-        
-        private ClassLoader getCurrentClassLoader() {
-            return currentClassLoader;
-        }
-        
-        private void setCurrentClassLoader(ClassLoader classLoader) {
-            currentClassLoader = checkNotNull(classLoader);
-            currentLoader.set(new ClassLoaderUtils(currentClassLoader, mgmt));
-        }
-        
-        protected void acquireXstreamLock() {
-            synchronized (xstreamLockOwner) {
-                while (true) {
-                    if (xstreamLockOwner.compareAndSet(null, Thread.currentThread()) || 
-                        Thread.currentThread().equals( xstreamLockOwner.get() )) {
-                        break;
-                    }
-                    try {
-                        xstreamLockOwner.wait(1000);
-                    } catch (InterruptedException e) {
-                        throw Exceptions.propagate(e);
-                    }
-                }
-                lockCount++;
-            }
-        }
-
-        protected void releaseXstreamLock() {
-            synchronized (xstreamLockOwner) {
-                if (lockCount<=0) {
-                    throw new IllegalStateException("xstream not locked");
-                }
-                if (--lockCount == 0) {
-                    if (!xstreamLockOwner.compareAndSet(Thread.currentThread(), null)) {
-                        Thread oldOwner = xstreamLockOwner.getAndSet(null);
-                        throw new IllegalStateException("xstream was locked by "+oldOwner+" but unlock attempt by "+Thread.currentThread());
-                    }
-                    xstreamLockOwner.notifyAll();
-                }
-            }
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f9566273/core/src/test/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContextTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContextTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContextTest.java
new file mode 100644
index 0000000..a2237af
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/classloading/ClassLoaderFromStackOfBrooklynClassLoadingContextTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.classloading;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromStackOfBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.test.support.TestResourceUnavailableException;
+import org.apache.brooklyn.util.core.osgi.Osgis;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+public class ClassLoaderFromStackOfBrooklynClassLoadingContextTest {
+
+    private LocalManagementContext mgmt;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) {
+            Entities.destroyAll(mgmt);
+        }
+    }
+    
+    @Test
+    public void testLoadClassFromBundle() throws Exception {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+        ClassLoader classLoader = getClass().getClassLoader();
+        Bundle apiBundle = getBundle(mgmt, "org.apache.brooklyn.api");
+        Bundle coreBundle = getBundle(mgmt, "org.apache.brooklyn.core");
+        
+        String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
+        Bundle otherBundle = installBundle(mgmt, bundleUrl);
+        
+        assertLoads(classLoader, Entity.class, Optional.of(apiBundle));
+        assertLoads(classLoader, AbstractEntity.class, Optional.of(coreBundle));
+        assertLoads(classLoader, OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY, Optional.of(otherBundle));
+    }
+    
+    @Test
+    public void testLoadClassVanilla() throws Exception {
+        ClassLoader classLoader = getClass().getClassLoader();
+        
+        assertLoads(classLoader, Entity.class, Optional.<Bundle>absent());
+        assertLoads(classLoader, AbstractEntity.class, Optional.<Bundle>absent());
+    }
+    
+    // Tests we can do funny stuff, like return a differently named class from that expected!
+    @Test
+    public void testLoadClassReturningDifferentlyNamedClass() throws Exception {
+        final String specialClassName = "my.madeup.Clazz";
+        
+        ClassLoader classLoader = new ClassLoader() {
+            @Override
+            protected Class<?> findClass(String name) throws ClassNotFoundException {
+                if (name != null && name.equals(specialClassName)) {
+                    return Entity.class;
+                }
+                return getClass().getClassLoader().loadClass(name);
+            }
+        };
+        
+        ClassLoaderFromStackOfBrooklynClassLoadingContext ocl = new ClassLoaderFromStackOfBrooklynClassLoadingContext(classLoader);
+        ocl.setManagementContext(mgmt);
+        assertEquals(ocl.loadClass(specialClassName), Entity.class);
+        
+        // TODO The line below fails: java.lang.ClassNotFoundException: my/madeup/Clazz
+        //assertEquals(Class.forName(specialClassName, false, ocl).getName(), Entity.class.getName());
+    }
+    
+    private void assertLoads(ClassLoader delegateClassLoader, Class<?> clazz, Optional<Bundle> bundle) throws Exception {
+        ClassLoaderFromStackOfBrooklynClassLoadingContext ocl = new ClassLoaderFromStackOfBrooklynClassLoadingContext(delegateClassLoader);
+        ocl.setManagementContext(mgmt);
+        String classname = (bundle.isPresent() ? bundle.get().getSymbolicName() + ":" : "") + clazz.getName();
+        assertEquals(ocl.loadClass(classname), clazz);
+        
+        // TODO The line below fails, e.g.: java.lang.ClassNotFoundException: org/apache/brooklyn/api:org/apache/brooklyn/api/entity/Entity
+        //assertEquals(Class.forName(classname, false, ocl), clazz);
+        
+    }
+
+    private void assertLoads(ClassLoader delegateClassLoader, String clazz, Optional<Bundle> bundle) throws Exception {
+        ClassLoaderFromStackOfBrooklynClassLoadingContext ocl = new ClassLoaderFromStackOfBrooklynClassLoadingContext(delegateClassLoader);
+        ocl.setManagementContext(mgmt);
+        String classname = (bundle.isPresent() ? bundle.get().getSymbolicName() + ":" : "") + clazz;
+        assertEquals(ocl.loadClass(classname).getName(), clazz);
+        
+        // TODO The line below fails, e.g.: java.lang.ClassNotFoundException: org/apache/brooklyn/test/resources/osgi/brooklyn-test-osgi-entities:org/apache/brooklyn/test/osgi/entities/SimpleEntity
+        //assertEquals(Class.forName(classname, false, ocl).getName(), clazz);
+    }
+
+    private Bundle getBundle(ManagementContext mgmt, final String symbolicName) throws Exception {
+        OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
+        Framework framework = osgiManager.getFramework();
+        Maybe<Bundle> result = Osgis.bundleFinder(framework)
+                .symbolicName(symbolicName)
+                .find();
+        return result.get();
+    }
+    
+    private Bundle installBundle(ManagementContext mgmt, String bundleUrl) throws Exception {
+        OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
+        Framework framework = osgiManager.getFramework();
+        return Osgis.install(framework, bundleUrl);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f9566273/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerDelegatingClassLoaderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerDelegatingClassLoaderTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerDelegatingClassLoaderTest.java
deleted file mode 100644
index 38c9982..0000000
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerDelegatingClassLoaderTest.java
+++ /dev/null
@@ -1,143 +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.persist;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
-import org.apache.brooklyn.core.mgmt.persist.XmlMementoSerializer.OsgiClassLoader;
-import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.test.support.TestResourceUnavailableException;
-import org.apache.brooklyn.util.core.osgi.Osgis;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.osgi.OsgiTestResources;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.launch.Framework;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Optional;
-
-public class XmlMementoSerializerDelegatingClassLoaderTest {
-
-    private LocalManagementContext mgmt;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (mgmt != null) {
-            Entities.destroyAll(mgmt);
-        }
-    }
-    
-    @Test
-    public void testLoadClassFromBundle() throws Exception {
-        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
-
-        ClassLoader classLoader = getClass().getClassLoader();
-        Bundle apiBundle = getBundle(mgmt, "org.apache.brooklyn.api");
-        Bundle coreBundle = getBundle(mgmt, "org.apache.brooklyn.core");
-        
-        String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
-        Bundle otherBundle = installBundle(mgmt, bundleUrl);
-        
-        assertLoads(classLoader, Entity.class, Optional.of(apiBundle));
-        assertLoads(classLoader, AbstractEntity.class, Optional.of(coreBundle));
-        assertLoads(classLoader, OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY, Optional.of(otherBundle));
-    }
-    
-    @Test
-    public void testLoadClassVanilla() throws Exception {
-        ClassLoader classLoader = getClass().getClassLoader();
-        
-        assertLoads(classLoader, Entity.class, Optional.<Bundle>absent());
-        assertLoads(classLoader, AbstractEntity.class, Optional.<Bundle>absent());
-    }
-    
-    // Tests we can do funny stuff, like return a differently named class from that expected!
-    @Test
-    public void testLoadClassReturningDifferentlyNamedClass() throws Exception {
-        final String specialClassName = "my.madeup.Clazz";
-        
-        ClassLoader classLoader = new ClassLoader() {
-            @Override
-            protected Class<?> findClass(String name) throws ClassNotFoundException {
-                if (name != null && name.equals(specialClassName)) {
-                    return Entity.class;
-                }
-                return getClass().getClassLoader().loadClass(name);
-            }
-        };
-        
-        OsgiClassLoader ocl = new XmlMementoSerializer.OsgiClassLoader(classLoader);
-        ocl.setManagementContext(mgmt);
-        assertEquals(ocl.loadClass(specialClassName), Entity.class);
-        
-        // TODO The line below fails: java.lang.ClassNotFoundException: my/madeup/Clazz
-        //assertEquals(Class.forName(specialClassName, false, ocl).getName(), Entity.class.getName());
-    }
-    
-    private void assertLoads(ClassLoader delegateClassLoader, Class<?> clazz, Optional<Bundle> bundle) throws Exception {
-        OsgiClassLoader ocl = new XmlMementoSerializer.OsgiClassLoader(delegateClassLoader);
-        ocl.setManagementContext(mgmt);
-        String classname = (bundle.isPresent() ? bundle.get().getSymbolicName() + ":" : "") + clazz.getName();
-        assertEquals(ocl.loadClass(classname), clazz);
-        
-        // TODO The line below fails, e.g.: java.lang.ClassNotFoundException: org/apache/brooklyn/api:org/apache/brooklyn/api/entity/Entity
-        //assertEquals(Class.forName(classname, false, ocl), clazz);
-        
-    }
-
-    private void assertLoads(ClassLoader delegateClassLoader, String clazz, Optional<Bundle> bundle) throws Exception {
-        OsgiClassLoader ocl = new XmlMementoSerializer.OsgiClassLoader(delegateClassLoader);
-        ocl.setManagementContext(mgmt);
-        String classname = (bundle.isPresent() ? bundle.get().getSymbolicName() + ":" : "") + clazz;
-        assertEquals(ocl.loadClass(classname).getName(), clazz);
-        
-        // TODO The line below fails, e.g.: java.lang.ClassNotFoundException: org/apache/brooklyn/test/resources/osgi/brooklyn-test-osgi-entities:org/apache/brooklyn/test/osgi/entities/SimpleEntity
-        //assertEquals(Class.forName(classname, false, ocl).getName(), clazz);
-    }
-
-    private Bundle getBundle(ManagementContext mgmt, final String symbolicName) throws Exception {
-        OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
-        Framework framework = osgiManager.getFramework();
-        Maybe<Bundle> result = Osgis.bundleFinder(framework)
-                .symbolicName(symbolicName)
-                .find();
-        return result.get();
-    }
-    
-    private Bundle installBundle(ManagementContext mgmt, String bundleUrl) throws Exception {
-        OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
-        Framework framework = osgiManager.getFramework();
-        return Osgis.install(framework, bundleUrl);
-    }
-}