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 <alex.henev...@cloudsoftcorp.com> Authored: Wed Jun 7 13:46:50 2017 +0100 Committer: Alex Heneveld <alex.henev...@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); - } -}