Make implicit boot delegation configurable. (FELIX-712)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@808561 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
index d07390f..581cdb6 100644
--- a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
@@ -123,6 +123,9 @@
private final String[] m_bootPkgs;
private final boolean[] m_bootPkgWildcards;
+ // Boolean flag to enable/disable implicit boot delegation.
+ private final boolean m_implicitBootDelegation;
+
// Re-usable security manager for accessing class context.
private static SecurityManagerEx m_sm = new SecurityManagerEx();
@@ -167,6 +170,7 @@
m_declaredActivationPolicy = EAGER_ACTIVATION;
m_activationExcludes = null;
m_activationIncludes = null;
+ m_implicitBootDelegation = false;
}
public ModuleImpl(
@@ -187,6 +191,12 @@
m_bootPkgs = bootPkgs;
m_bootPkgWildcards = bootPkgWildcards;
+ m_implicitBootDelegation =
+ (m_configMap.get(FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP) == null)
+ || Boolean.valueOf(
+ (String) m_configMap.get(
+ FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP)).booleanValue();
+
ManifestParser mp = new ManifestParser(m_logger, m_configMap, m_headerMap);
// Record some of the parsed metadata. Note, if this is an extension
@@ -1374,82 +1384,87 @@
: (Object) wire.getResource(name);
}
- // At this point, the class/resource could not be found by the bundle's
- // static or dynamic imports, nor its own content. Before we throw
- // an exception, we will try to determine if the instigator of the
- // class/resource load was a class from a bundle or not. This is necessary
- // because the specification mandates that classes on the class path
- // should be hidden (except for java.*), but it does allow for these
- // classes/resources to be exposed by the system bundle as an export.
- // However, in some situations classes on the class path make the faulty
- // assumption that they can access everything on the class path from
- // every other class loader that they come in contact with. This is
- // not true if the class loader in question is from a bundle. Thus,
- // this code tries to detect that situation. If the class
- // instigating the load request was NOT from a bundle, then we will
- // make the assumption that the caller actually wanted to use the
- // parent class loader and we will delegate to it. If the class was
- // from a bundle, then we will enforce strict class loading rules
- // for the bundle and throw an exception.
-
- // Get the class context to see the classes on the stack.
- Class[] classes = m_sm.getClassContext();
- // Start from 1 to skip security manager class.
- for (int i = 1; i < classes.length; i++)
+ // If implicit boot delegation is enabled, then try to guess whether
+ // we should boot delegate.
+ if (m_implicitBootDelegation)
{
- // Find the first class on the call stack that is not from
- // the class loader that loaded the Felix classes or is not
- // a class loader or class itself, because we want to ignore
- // calls to ClassLoader.loadClass() and Class.forName() since
- // we are trying to find out who instigated the class load.
- // Also ignore inner classes of class loaders, since we can
- // assume they are a class loader too.
+ // At this point, the class/resource could not be found by the bundle's
+ // static or dynamic imports, nor its own content. Before we throw
+ // an exception, we will try to determine if the instigator of the
+ // class/resource load was a class from a bundle or not. This is necessary
+ // because the specification mandates that classes on the class path
+ // should be hidden (except for java.*), but it does allow for these
+ // classes/resources to be exposed by the system bundle as an export.
+ // However, in some situations classes on the class path make the faulty
+ // assumption that they can access everything on the class path from
+ // every other class loader that they come in contact with. This is
+ // not true if the class loader in question is from a bundle. Thus,
+ // this code tries to detect that situation. If the class instigating
+ // the load request was NOT from a bundle, then we will make the
+ // assumption that the caller actually wanted to use the parent class
+ // loader and we will delegate to it. If the class was
+ // from a bundle, then we will enforce strict class loading rules
+ // for the bundle and throw an exception.
+
+ // Get the class context to see the classes on the stack.
+ Class[] classes = m_sm.getClassContext();
+ // Start from 1 to skip security manager class.
+ for (int i = 1; i < classes.length; i++)
+ {
+ // Find the first class on the call stack that is not from
+ // the class loader that loaded the Felix classes or is not
+ // a class loader or class itself, because we want to ignore
+ // calls to ClassLoader.loadClass() and Class.forName() since
+ // we are trying to find out who instigated the class load.
+ // Also ignore inner classes of class loaders, since we can
+ // assume they are a class loader too.
// TODO: FRAMEWORK - This check is a hack and we should see if we can think
// of another way to do it, since it won't necessarily work in all situations.
- // Since Felix uses threads for changing the start level
- // and refreshing packages, it is possible that there is no
- // module classes on the call stack; therefore, as soon as we
- // see Thread on the call stack we exit this loop. Other cases
- // where modules actually use threads are not an issue because
- // the module classes will be on the call stack before the
- // Thread class.
- if (Thread.class.equals(classes[i]))
- {
- break;
- }
- else if (isClassNotLoadedFromBundle(classes[i]))
- {
- // If the instigating class was not from a bundle,
- // then delegate to the parent class loader; otherwise,
- // break out of loop and return null.
- boolean delegate = true;
- for (ClassLoader cl = classes[i].getClassLoader(); cl != null; cl = cl.getClass().getClassLoader())
+ // Since Felix uses threads for changing the start level
+ // and refreshing packages, it is possible that there is no
+ // module classes on the call stack; therefore, as soon as we
+ // see Thread on the call stack we exit this loop. Other cases
+ // where modules actually use threads are not an issue because
+ // the module classes will be on the call stack before the
+ // Thread class.
+ if (Thread.class.equals(classes[i]))
{
- if (ModuleClassLoader.class.isInstance(cl))
- {
- delegate = false;
- break;
- }
+ break;
}
- // Delegate to the parent class loader unless this call
- // is due to outside code calling a method on the bundle
- // interface (e.g., Bundle.loadClass()).
- if (delegate && !Bundle.class.isAssignableFrom(classes[i - 1]))
+ else if (isClassNotLoadedFromBundle(classes[i]))
{
- try
+ // If the instigating class was not from a bundle,
+ // then delegate to the parent class loader; otherwise,
+ // break out of loop and return null.
+ boolean delegate = true;
+ for (ClassLoader cl = classes[i].getClassLoader(); cl != null; cl = cl.getClass().getClassLoader())
{
- // Return the class or resource from the parent class loader.
- return (isClass)
- ? (Object) this.getClass().getClassLoader().loadClass(name)
- : (Object) this.getClass().getClassLoader().getResource(name);
+ if (ModuleClassLoader.class.isInstance(cl))
+ {
+ delegate = false;
+ break;
+ }
}
- catch (NoClassDefFoundError ex)
+ // Delegate to the parent class loader unless this call
+ // is due to outside code calling a method on the bundle
+ // interface (e.g., Bundle.loadClass()).
+ if (delegate && !Bundle.class.isAssignableFrom(classes[i - 1]))
{
- // Ignore, will return null
+ try
+ {
+ // Return the class or resource from the parent class loader.
+ return (isClass)
+ ? (Object) this.getClass().getClassLoader().loadClass(name)
+ : (Object) this.getClass().getClassLoader().getResource(name);
+ }
+ catch (NoClassDefFoundError ex)
+ {
+ // Ignore, will return null
+ }
}
+ break;
}
- break;
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java b/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java
index 6131ea3..e3a46ba 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java
@@ -51,6 +51,7 @@
public static final String BUNDLE_STARTLEVEL_PROP
= "felix.startlevel.bundle";
public static final String SERVICE_URLHANDLERS_PROP = "felix.service.urlhandlers";
+ public static final String IMPLICIT_BOOT_DELEGATION_PROP = "felix.bootdelegation.implicit";
// Start level-related constants.
public static final int FRAMEWORK_INACTIVE_STARTLEVEL = 0;
diff --git a/main/src/main/resources/config.properties b/main/src/main/resources/config.properties
index 515e7c5..0134b89 100644
--- a/main/src/main/resources/config.properties
+++ b/main/src/main/resources/config.properties
@@ -31,6 +31,11 @@
# available to all bundles. You should avoid using this property.
#org.osgi.framework.bootdelegation=sun.*,com.sun.*
+# Felix tries to guess when to implicitly boot delegate in certain
+# situations to ease integration without outside code. This feature
+# is enabled by default, uncomment the following line to disable it.
+#felix.bootdelegation.implicit=false
+
# The following property explicitly specifies the location of the bundle
# cache, which defaults to "felix-cache" in the current working directory.
# If this value is not absolute, then the felix.cache.rootdir controls