You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2017/02/14 16:17:27 UTC
svn commit: r1782982 - in /felix/trunk/framework/src:
main/java/org/apache/felix/framework/BundleWiringImpl.java
test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java
Author: pauls
Date: Tue Feb 14 16:17:27 2017
New Revision: 1782982
URL: http://svn.apache.org/viewvc?rev=1782982&view=rev
Log:
Don't take implicit boot delegation into account on service assignability check (FELIX-5544).
Added:
felix/trunk/framework/src/test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java?rev=1782982&r1=1782981&r2=1782982&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java Tue Feb 14 16:17:27 2017
@@ -1748,6 +1748,12 @@ public class BundleWiringImpl implements
{
break;
}
+ // Break if this goes through ServiceRegistrationImpl.ServiceReferenceImpl
+ // because it must be a assignability check which should not implicitly boot delegate
+ else if (ServiceRegistrationImpl.ServiceReferenceImpl.class.equals(classes[i]))
+ {
+ break;
+ }
else if (isClassExternal(classes[i]))
{
try
Added: felix/trunk/framework/src/test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java?rev=1782982&view=auto
==============================================================================
--- felix/trunk/framework/src/test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java (added)
+++ felix/trunk/framework/src/test/java/org/apache/felix/framework/ImplicitBootDelegationTest.java Tue Feb 14 16:17:27 2017
@@ -0,0 +1,333 @@
+/*
+ * 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.felix.framework;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.Constants;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class ImplicitBootDelegationTest extends TestCase {
+
+ public void testDoesBootdelegateForClassloaderClassload() throws Exception{
+ withFelixDo(new ThrowingConsumer<Felix>() {
+ @Override
+ public void accept(Felix felix) throws Exception {
+ BundleImpl bundle = (BundleImpl) felix.getBundleContext().installBundle(createBundle(
+ ImplicitBootDelegationTestActivator.class).toURI().toURL().toString());
+
+ bundle.start();
+
+ Runnable testClass = felix.getBundleContext().getService(
+ felix.getBundleContext().getServiceReference(Runnable.class));
+
+ Assert.assertEquals(TestClass.class,
+ testClass.getClass().getClassLoader().loadClass(TestClass.class.getName()));
+ }
+ });
+ }
+
+ public void testDoesNotBootdelegateForClassloadFromInsideBundle() throws Exception{
+ withFelixDo(new ThrowingConsumer<Felix>() {
+ @Override
+ public void accept(Felix felix) throws Exception {
+ BundleImpl bundle = (BundleImpl) felix.getBundleContext().installBundle(createBundle(
+ ImplicitBootDelegationTestActivator.class).toURI().toURL().toString());
+
+ bundle.start();
+
+ Runnable testClass = felix.getBundleContext().getService(
+ felix.getBundleContext().getServiceReference(Runnable.class));
+
+ try
+ {
+ testClass.run();
+ Assert.fail("Expected to not be able to load an implicit bootdelegated class from inside the bundle");
+ } catch (NoClassDefFoundError ex) {
+
+ }
+ }
+ });
+ }
+
+ public void testDoesNotBootdelegateForBundleClassload() throws Exception {
+ withFelixDo(new ThrowingConsumer<Felix>() {
+ @Override
+ public void accept(Felix felix) throws Exception {
+ BundleImpl bundle = (BundleImpl) felix.getBundleContext().installBundle(createBundle(
+ ImplicitBootDelegationTestActivator.class).toURI().toURL().toString());
+ try
+ {
+ bundle.loadClass(TestClass.class.getName());
+ Assert.fail("Expected to not be able to bundle.loadClass an implicit bootdelegated class");
+ }
+ catch (ClassNotFoundException ex) {
+
+ }
+ }
+ });
+ }
+
+ public void testDoesNotBootdelegateForServiceAssignability() throws Exception {
+ withFelixDo(new ThrowingConsumer<Felix>() {
+ @Override
+ public void accept(Felix felix) throws Exception {
+ BundleImpl provider = (BundleImpl) felix.getBundleContext().installBundle(createBundle(
+ ProvidesActivator.class, TestClass.class).toURI().toURL().toString());
+
+ provider.start();
+
+ Assert.assertNotNull(felix.getBundleContext().getAllServiceReferences(TestClass.class.getName(), null));
+
+ BundleImpl requirer = (BundleImpl) felix.getBundleContext().installBundle(createBundle(
+ RequireActivator.class).toURI().toURL().toString());
+
+ requirer.start();
+
+ Runnable requirerActivtor = felix.getBundleContext().getService(
+ felix.getBundleContext().getServiceReference(Runnable.class));
+
+ Assume.assumeTrue(requirerActivtor.getClass().getClassLoader().loadClass(TestClass.class.getName())
+ == TestClass.class);
+
+ requirerActivtor.run();
+
+ Object service = requirer.getBundleContext().getService(
+ requirer.getBundleContext().getServiceReference(TestClass.class.getName()));
+
+ assertNotNull(service);
+ assertTrue(!(service instanceof TestClass));
+ assertTrue(service.getClass().getName().equals(TestClass.class.getName()));
+ }
+ });
+ }
+
+ public static class RequireActivator implements BundleActivator, Runnable {
+ private volatile BundleContext context;
+ @Override
+ public void start(BundleContext context) throws Exception {
+ this.context = context;
+ context.registerService(Runnable.class, this, null);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void run() {
+ Object service = context.getService(context.getServiceReference(
+ "org.apache.felix.framework.ImplicitBootDelegationTest$TestClass"));
+
+ if (service == null)
+ {
+ throw new IllegalStateException("Expected service to be available from inside bundle");
+ }
+
+ ClassLoader loader = service.getClass().getClassLoader();
+ if (!(service.getClass().getClassLoader() instanceof BundleReference))
+ {
+ throw new IllegalStateException("Expected service to be loaded from bundle");
+ }
+ try
+ {
+ getClass().getClassLoader().loadClass(service.getClass().getName());
+ throw new IllegalStateException("Expected to be unable to load service class");
+ }
+ catch (ClassNotFoundException ex) {
+
+ }
+
+ try {
+ TestClass test = new TestClass();
+ throw new IllegalStateException("Expected to be unable to create object of type TestClass");
+
+ } catch (NoClassDefFoundError ex) {
+
+ }
+ }
+ }
+
+ public static class ProvidesActivator implements BundleActivator {
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ context.registerService(TestClass.class, new TestClass(), null);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+ }
+
+ public static class TestClass {
+ }
+
+ private void withFelixDo(ThrowingConsumer<Felix> consumer) throws Exception {
+ File cacheDir = File.createTempFile("felix-cache", ".dir");
+ try
+ {
+ Felix felix = getFramework(cacheDir);
+ try
+ {
+ felix.init();
+ felix.start();
+ consumer.accept(felix);
+ }
+ finally
+ {
+ felix.stop();
+ felix.waitForStop(1000);
+ }
+ }
+ finally
+ {
+ delete(cacheDir);
+ }
+ }
+
+ @FunctionalInterface
+ private static interface ThrowingConsumer<T> {
+ public void accept(T t) throws Exception;
+ }
+
+
+ public static class ImplicitBootDelegationTestActivator implements BundleActivator, Runnable {
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ context.registerService(Runnable.class, this, null);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ }
+
+ public void run()
+ {
+ new TestClass();
+ }
+ }
+
+ private Felix getFramework(File cacheDir) {
+ Map params = new HashMap();
+ params.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
+ "org.osgi.framework; version=1.4.0,"
+ + "org.osgi.service.packageadmin; version=1.2.0,"
+ + "org.osgi.service.startlevel; version=1.1.0,"
+ + "org.osgi.util.tracker; version=1.3.3,"
+ + "org.osgi.service.url; version=1.0.0");
+ cacheDir.delete();
+ cacheDir.mkdirs();
+ String cache = cacheDir.getPath();
+ params.put("felix.cache.profiledir", cache);
+ params.put("felix.cache.dir", cache);
+ params.put(Constants.FRAMEWORK_STORAGE, cache);
+
+ return new Felix(params);
+ }
+
+ private static File createBundle(Class activator, Class...classes) throws IOException
+ {
+ String mf = "Bundle-SymbolicName: " + activator.getName() +"\n"
+ + "Bundle-Version: 1.0.0\n"
+ + "Bundle-ManifestVersion: 2\n"
+ + "Import-Package: org.osgi.framework\n"
+ + "Manifest-Version: 1.0\n"
+ + "Bundle-Activator: " + activator.getName() + "\n\n";
+
+ Class[] classesCombined;
+
+ if (classes.length > 0) {
+ List<Class> list = new ArrayList<Class>(Arrays.asList(classes));
+ list.add(activator);
+ classesCombined = list.toArray(new Class[0]);
+ }
+ else
+ {
+ classesCombined = new Class[]{activator};
+ }
+ return createBundle(mf,classesCombined);
+
+ }
+
+ private static File createBundle(String manifest, Class... classes) throws IOException
+ {
+ File f = File.createTempFile("felix-bundle", ".jar");
+ f.deleteOnExit();
+
+ Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("utf-8")));
+ JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf);
+
+ for (Class clazz : classes)
+ {
+ String path = clazz.getName().replace('.', '/') + ".class";
+ os.putNextEntry(new ZipEntry(path));
+
+ InputStream is = clazz.getClassLoader().getResourceAsStream(path);
+ byte[] buffer = new byte[8 * 1024];
+ for (int i = is.read(buffer); i != -1; i = is.read(buffer))
+ {
+ os.write(buffer, 0, i);
+ }
+ is.close();
+ os.closeEntry();
+ }
+ os.close();
+ return f;
+ }
+
+ private static void delete(File file) throws IOException
+ {
+ if (file.isDirectory())
+ {
+ for (File child : file.listFiles())
+ {
+ delete(child);
+ }
+ }
+ file.delete();
+ }
+}
+
+
+
\ No newline at end of file