brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject [09/11] brooklyn-server git commit: test the osgi-prefixing for classes, and improve javadoc
Date Thu, 08 Jun 2017 09:37:43 GMT
test the osgi-prefixing for classes, and improve javadoc


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

Branch: refs/heads/master
Commit: 9d448f3204ee26b7f716f5e339fe07d814fb37c3
Parents: f956627
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Wed Jun 7 14:36:39 2017 +0100
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Wed Jun 7 14:43:25 2017 +0100

----------------------------------------------------------------------
 ...rFromStackOfBrooklynClassLoadingContext.java |   5 +
 .../core/mgmt/persist/XmlMementoSerializer.java |  14 ++-
 .../util/core/xstream/ClassRenamingMapper.java  |  22 ++--
 .../util/core/xstream/OsgiClassnameMapper.java  |  14 +++
 .../util/core/xstream/XmlSerializer.java        |  28 ++++-
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |  21 ----
 .../brooklyn/util/core/osgi/OsgiTestBase.java   |  23 ++++
 .../core/xstream/XmlSerializerOsgiTest.java     | 111 +++++++++++++++++++
 .../brooklyn/util/osgi/OsgiTestResources.java   |   3 +-
 9 files changed, 200 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/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
index f42ecd2..102a27c 100644
--- 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
@@ -62,6 +62,11 @@ public class ClassLoaderFromStackOfBrooklynClassLoadingContext extends
ClassLoad
     protected Class<?> findClass(String name) throws ClassNotFoundException {
         return currentLoader.get().loadClass(name);
     }
+    
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
+        return findClass(name);
+    }
 
     /** Must be accompanied by a corresponding {@link #popClassLoadingContext()} when finished.
*/
     @SuppressWarnings("deprecation")

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/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 e83b5ea..9265a1f 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
@@ -90,9 +90,8 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T>
implements Memento
     }
     
     public XmlMementoSerializer(ClassLoader classLoader, Map<String, String> deserializingClassRenames)
{
-        super(deserializingClassRenames);
-        this.delegatingClassLoader = new ClassLoaderFromStackOfBrooklynClassLoadingContext(classLoader);
-        xstream.setClassLoader(this.delegatingClassLoader);
+        super(new ClassLoaderFromStackOfBrooklynClassLoadingContext(classLoader), deserializingClassRenames);
+        this.delegatingClassLoader = (ClassLoaderFromStackOfBrooklynClassLoadingContext)
xstream.getClassLoader();
         
         xstream.alias("entity", BasicEntityMemento.class);
         xstream.alias("location", BasicLocationMemento.class);
@@ -128,6 +127,11 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T>
implements Memento
     
         //For compatibility with existing persistence stores content.
         xstream.aliasField("registeredTypeName", BasicCatalogItemMemento.class, "symbolicName");
+        configureXstreamWithDeprecatedItems();
+    }
+
+    @SuppressWarnings("deprecation")
+    private void configureXstreamWithDeprecatedItems() {
         xstream.registerLocalConverter(BasicCatalogItemMemento.class, "libraries", new CatalogItemLibrariesConverter());
     }
     
@@ -353,9 +357,9 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T>
implements Memento
     // Perhaps context.getRequiredType(); can be used instead?
     // Other users of xstream (e.g. jenkinsci) manually check for resoved-to and class attributes
     //   for compatibility with older versions of xstream
-    private static Class readClassType(HierarchicalStreamReader reader, Mapper mapper) {
+    private static Class<?> readClassType(HierarchicalStreamReader reader, Mapper mapper)
{
         String classAttribute = readClassAttribute(reader, mapper);
-        Class type;
+        Class<?> type;
         if (classAttribute == null) {
             type = mapper.realClass(reader.getNodeName());
         } else {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
b/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
index a2fa7ae..5691198 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.Map;
 
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Reflections;
 import org.slf4j.Logger;
@@ -79,11 +80,6 @@ public class ClassRenamingMapper extends MapperWrapper {
      *  3. As mentioned under the use-cases, the rename could include the full bundle name
prefix, 
      *     or it might just be the classname. We want to handle both, so need to implement
yet
      *     more fallback behaviour.
-     * 
-     * ---
-     * TODO Wanted to pass xstream, rather than Supplier<ClassLoader>, in constructor.
However, 
-     * this caused NPE because of how this is constructed from inside 
-     * XmlMementoSerializer.wrapMapperForNormalUsage, called from within an anonymous subclass
of XStream!
      */
     
     public static final Logger LOG = LoggerFactory.getLogger(ClassRenamingMapper.class);
@@ -94,6 +90,12 @@ public class ClassRenamingMapper extends MapperWrapper {
     public ClassRenamingMapper(Mapper wrapped, Map<String, String> nameToType, Supplier<?
extends ClassLoader> classLoaderSupplier) {
         super(wrapped);
         this.nameToType = checkNotNull(nameToType, "nameToType");
+        /*
+         * NB: wanted to pass xstream, rather than Supplier<ClassLoader>, in constructor.
However, 
+         * this caused NPE because of how this is constructed from inside 
+         * XmlMementoSerializer.wrapMapperForNormalUsage, called from within an anonymous
subclass of XStream!
+         * (Similar as for OsgiClassnameMapper.)
+         */
         this.classLoaderSupplier = checkNotNull(classLoaderSupplier, "classLoaderSupplier");
     }
     
@@ -106,10 +108,14 @@ public class ClassRenamingMapper extends MapperWrapper {
             elementName = elementNameOpt.get();
         }
 
-        CannotResolveClassException tothrow;
+        Exception tothrow;
         try {
             return super.realClass(elementName);
-        } catch (CannotResolveClassException e) {
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // CannotResolveClassException is what should be thrown, but
+            // sneakily you can get other, e.g. 
+            // IAE if you have a ":" in the name and a URLClassLoader tries to read it
             LOG.trace("Failed to load class using super.realClass({}), for orig class {},
attempting fallbacks: {}", new Object[] {elementName, elementNamOrig, e});
             tothrow = e;
         }
@@ -157,7 +163,7 @@ public class ClassRenamingMapper extends MapperWrapper {
             }
         }
         
-        throw tothrow;
+        throw Exceptions.propagate(tothrow);
     }
     
     private boolean hasBundlePrefix(String type) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/core/src/main/java/org/apache/brooklyn/util/core/xstream/OsgiClassnameMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/xstream/OsgiClassnameMapper.java
b/core/src/main/java/org/apache/brooklyn/util/core/xstream/OsgiClassnameMapper.java
index 7bdf9f7..f82e743 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/xstream/OsgiClassnameMapper.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/xstream/OsgiClassnameMapper.java
@@ -24,6 +24,20 @@ import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.mapper.CannotResolveClassException;
 import com.thoughtworks.xstream.mapper.MapperWrapper;
 
+/** Attaches a prefix to _all_ classes written out.
+ * Ensures the xstream class loader is used to read 
+ * (because that's where we set the OSGi-prefix-aware code).
+ * <p>
+ * We also have the context in that loader so if we wanted to optimize
+ * we could scan that for bundles and suppress bundles if it's in scope.
+ * However if we plan to move to referring to RegisteredTypes for anything
+ * serialized that's irrelevant.
+ * <p>
+ * We could have code that uses the search path from that loader
+ * to prefers types in local bundles, ignoring the bundle name
+ * if the class is found there (either always, or just if the bundle is not found / deprecated).
+ */
+// TODO above, and also see discussion at https://github.com/apache/brooklyn-server/pull/718
 public class OsgiClassnameMapper extends MapperWrapper {
     private final OsgiClassPrefixer prefixer;
     private final Supplier<XStream> xstream;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlSerializer.java b/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlSerializer.java
index 26b6788..c0349b6 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlSerializer.java
@@ -50,13 +50,20 @@ public class XmlSerializer<T> {
     }
     
     public XmlSerializer(Map<String, String> deserializingClassRenames) {
+        this(null, deserializingClassRenames);
+    }
+    
+    public XmlSerializer(ClassLoader loader, Map<String, String> deserializingClassRenames)
{
         this.deserializingClassRenames = deserializingClassRenames;
-        this.xstream = new XStream() {
+        xstream = new XStream() {
             @Override
             protected MapperWrapper wrapMapper(MapperWrapper next) {
                 return XmlSerializer.this.wrapMapperForNormalUsage( super.wrapMapper(next)
);
             }
         };
+        if (loader!=null) {
+            xstream.setClassLoader(loader);
+        }
         
         xstream.registerConverter(newCustomJavaClassConverter(), XStream.PRIORITY_NORMAL);
         
@@ -89,15 +96,18 @@ public class XmlSerializer<T> {
     }
 
     /**
-     * JCC is used when class names are serialized/deserialized and no alias is defined;
-     * it is configured in XStream *without* access to the XStream mapper.
+     * JCC is used when Class instances are serialized/deserialized as a value 
+     * (not as tags) and there are no aliases configured for that type.
+     * It is configured in XStream default *without* access to the XStream mapper,
+     * which is meant to apply when serializing the type name for instances of that type.
+     * <p>
      * However we need a few selected mappers (see {@link #wrapMapperForAllLowLevelMentions(Mapper)}
)
-     * in order to effect renames at the low level, but many of the mappers must NOT be used,
+     * to apply to all class renames, but many of the mappers must NOT be used,
      * e.g. because some might intercept all Class<? extends Entity> references
      * (and that interception is only wanted when serializing <i>instances</i>,
      * as in {@link #wrapMapperForNormalUsage(Mapper)}).
      * <p>
-     * This can typically be done simply by registering our own instance (due to order guarantee
of PrioritizedList),
+     * This can typically be done simply by registering our own instance of this (due to
order guarantee of PrioritizedList),
      * after the instance added by XStream.setupConverters()
      */
     private JavaClassConverter newCustomJavaClassConverter() {
@@ -105,7 +115,7 @@ public class XmlSerializer<T> {
     }
     
     /** Adds mappers needed for *any* reference to a class, both "normal" usage (when xstream
wants a mapper)
-     * and class conversion (when xstream needs to make a class name and doesn't have an
alias).
+     * and Class conversion (when xstream needs to serialize an instance of Class and doesn't
have an alias).
      * <p>
      * This should apply when nice names are used for inner classes, or classes are renamed;
      * however mappers which affect aliases or intercept references to entities are usually

@@ -114,6 +124,7 @@ public class XmlSerializer<T> {
     // so very few fields are populated
     protected MapperWrapper wrapMapperForAllLowLevelMentions(Mapper next) {
         MapperWrapper result = new CompilerIndependentOuterClassFieldMapper(next);
+        
         Supplier<ClassLoader> classLoaderSupplier = new Supplier<ClassLoader>()
{
             @Override public ClassLoader get() {
                 return xstream.getClassLoaderReference().getReference();
@@ -122,6 +133,11 @@ public class XmlSerializer<T> {
         result = new ClassRenamingMapper(result, deserializingClassRenames, classLoaderSupplier);
         result = new OsgiClassnameMapper(new Supplier<XStream>() {
             @Override public XStream get() { return xstream; } }, result);
+        // TODO as noted in ClassRenamingMapper that class can be simplified if 
+        // we swap the order of the above calls, because it _will_ be able to rely on
+        // OsgiClassnameMapper to attempt to load with the xstream reference stack
+        // (not doing it just now because close to a release)
+        
         return result;
     }
     /** Extension point where sub-classes can add mappers wanted when instances of a class
are serialized, 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/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 b21ba28..3bb5358 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
@@ -45,9 +45,6 @@ public class OsgiStandaloneTest extends OsgiTestBase {
 
     private static final Logger log = LoggerFactory.getLogger(OsgiStandaloneTest.class);
 
-    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_PATH = OsgiTestResources.BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
-    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_URL = "classpath:"+BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
-
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
     public static final String BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL;
     public static final String BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH;
@@ -56,24 +53,6 @@ public class OsgiStandaloneTest extends OsgiTestBase {
     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 Bundle install(String url) throws BundleException {
-        try {
-            return Osgis.install(framework, url);
-        } catch (Exception e) {
-            throw new IllegalStateException("test resources not available; may be an IDE
issue, so try a mvn rebuild of this project", e);
-        }
-    }
-
-    protected Bundle installFromClasspath(String resourceName) throws BundleException {
-        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), resourceName);
-        try {
-            return Osgis.install(framework, String.format("classpath:%s", resourceName));
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
     @Test
     public void testInstallBundle() throws Exception {
         Bundle bundle = installFromClasspath(BROOKLYN_OSGI_TEST_A_0_1_0_PATH);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/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
index 0e6d751..4bc1e58 100644
--- 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
@@ -20,9 +20,12 @@ import java.io.IOException;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.commons.io.FileUtils;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.launch.Framework;
 import org.testng.annotations.AfterMethod;
@@ -34,6 +37,26 @@ import org.testng.annotations.BeforeMethod;
  */
 public class OsgiTestBase {
 
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_PATH = OsgiTestResources.BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_URL = "classpath:"+BROOKLYN_OSGI_TEST_A_0_1_0_PATH;
+
+    protected Bundle install(String url) throws BundleException {
+        try {
+            return Osgis.install(framework, url);
+        } catch (Exception e) {
+            throw new IllegalStateException("test resources not available; may be an IDE
issue, so try a mvn rebuild of this project", e);
+        }
+    }
+
+    protected Bundle installFromClasspath(String resourceName) throws BundleException {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), resourceName);
+        try {
+            return Osgis.install(framework, String.format("classpath:%s", resourceName));
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
     protected Framework framework = null;
     private File storageTempDir;
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/core/src/test/java/org/apache/brooklyn/util/core/xstream/XmlSerializerOsgiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/xstream/XmlSerializerOsgiTest.java
b/core/src/test/java/org/apache/brooklyn/util/core/xstream/XmlSerializerOsgiTest.java
new file mode 100644
index 0000000..5db2a5f
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/util/core/xstream/XmlSerializerOsgiTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.core.xstream;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromStackOfBrooklynClassLoadingContext;
+import org.apache.brooklyn.util.core.osgi.OsgiTestBase;
+import org.apache.brooklyn.util.core.osgi.Osgis;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
+import org.apache.brooklyn.util.text.Strings;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class XmlSerializerOsgiTest extends OsgiTestBase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(XmlSerializerOsgiTest.class);
+
+    protected XmlSerializer<Object> serializer;
+    
+    /** Simple osgi-prefix-aware class loader. In the real world this function is done by
OsgiManager. */
+    public static class OsgiPrefixStrippingClassLoader extends ClassLoader {
+        private final Framework framework;
+
+        public OsgiPrefixStrippingClassLoader(Framework framework, ClassLoader parent) {

+            super(parent);
+            this.framework = framework;
+        }
+        
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            int separator = name.indexOf(":");
+            if (separator>=0) {
+                Bundle bundle = Osgis.bundleFinder(framework).symbolicName(name.substring(0,
separator)).find().get();
+                return bundle.loadClass(name.substring(separator+1));
+            } else {
+                return super.findClass(name);
+            }
+        }
+        
+        @Override
+        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
+            int separator = name.indexOf(":");
+            if (separator>=0) {
+                Bundle bundle = Osgis.bundleFinder(framework).symbolicName(name.substring(0,
separator)).find().get();
+                return bundle.loadClass(name.substring(separator+1));
+            } else {
+                return super.loadClass(name, resolve);
+            }
+        }
+    }
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        serializer = new XmlSerializer<Object>(
+            new OsgiPrefixStrippingClassLoader(framework, getClass().getClassLoader()), 
+            ImmutableMap.<String, String>of());
+    }
+    
+    @Test
+    public void testPrefixesOnClassAndInstance() throws Exception {
+        Bundle bundle = installFromClasspath(BROOKLYN_OSGI_TEST_A_0_1_0_PATH);
+        
+        final String TYPE = "brooklyn.test.osgi.TestA";
+        final String FQTN = OsgiTestResources.BROOKLYN_OSGI_TEST_A_SYMBOLIC_NAME + ":" +
TYPE;
+        
+        Class<?> aClass = bundle.loadClass(TYPE);
+        String rc = assertSerializeEqualsAndCanDeserialize(aClass, "<java-class>"+FQTN+"</java-class>");
+        
+        Object aInst = aClass.newInstance();
+        String ri = assertSerializeEqualsAndCanDeserialize(aInst, "<"+FQTN+"/>");
+        
+        List<Object> l = Arrays.asList(aClass, aInst);
+        assertSerializeEqualsAndCanDeserialize(l, "<java.util.Arrays_-ArrayList><a>"+rc+ri+"</a></java.util.Arrays_-ArrayList>");
+    }
+
+    protected String assertSerializeEqualsAndCanDeserialize(Object val, String expected)
throws Exception {
+        String xml = serializer.toString(val);
+        assertEquals(Strings.replaceAllRegex(xml, "\\s+", ""), Strings.replaceAllRegex(expected,
"\\s+", ""));
+        Object result = serializer.fromString(xml);
+        LOG.debug("val="+val+"'; xml="+xml+"; result="+result);
+        assertEquals(result.getClass(), val.getClass());
+        return expected;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d448f32/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
index f9f1998..048e0f5 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
@@ -33,7 +33,8 @@ public interface OsgiTestResources {
      * 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";
+    public static final String BROOKLYN_OSGI_TEST_A_SYMBOLIC_NAME = "brooklyn-osgi-test-a";
+    public static final String BROOKLYN_OSGI_TEST_A_0_1_0_PATH = "/brooklyn/osgi/" + BROOKLYN_OSGI_TEST_A_SYMBOLIC_NAME
+ "_0.1.0.jar";
 
     /**
      * brooklyn-test-osgi-entities (v 0.1.0) -


Mime
View raw message