Apply patch to utilize parallel class loaders on Java 7. (FELIX-3553)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1441094 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index 79de81c..dde7632 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -1804,18 +1804,33 @@
}
}
- public class BundleClassLoaderJava5 extends BundleClassLoader
+ public static class BundleClassLoaderJava5 extends BundleClassLoader
{
- public BundleClassLoaderJava5(ClassLoader parent)
+ static
{
- super(parent);
+ try
+ {
+ ClassLoader.registerAsParallelCapable();
+ }
+ catch (Throwable th)
+ {
+ // This is OK on older java versions
+ }
+ }
+
+ private BundleWiringImpl m_wiring;
+
+ public BundleClassLoaderJava5(BundleWiringImpl wiring, ClassLoader parent)
+ {
+ super(wiring, parent);
+ m_wiring = wiring;
}
@Override
public Enumeration getResources(String name)
{
- Enumeration urls = BundleWiringImpl.this.getResourcesByDelegation(name);
- if (m_useLocalURLs)
+ Enumeration urls = m_wiring.getResourcesByDelegation(name);
+ if (m_wiring.m_useLocalURLs)
{
urls = new ToLocalUrlEnumeration(urls);
}
@@ -1825,12 +1840,24 @@
@Override
protected Enumeration findResources(String name)
{
- return m_revision.getResourcesLocal(name);
+ return m_wiring.m_revision.getResourcesLocal(name);
}
}
- public class BundleClassLoader extends SecureClassLoader implements BundleReference
+ public static class BundleClassLoader extends SecureClassLoader implements BundleReference
{
+ static
+ {
+ try
+ {
+ ClassLoader.registerAsParallelCapable();
+ }
+ catch (Throwable th)
+ {
+ // This is OK on older java versions
+ }
+ }
+
// Flag used to determine if a class has been loaded from this class
// loader or not.
private volatile boolean m_isActivationTriggered = false;
@@ -1839,8 +1866,10 @@
private Object[][] m_cachedLibs = new Object[0][];
private static final int LIBNAME_IDX = 0;
private static final int LIBPATH_IDX = 1;
+ private final Map<String, Thread> m_classLocks = new HashMap<String, Thread>();
+ private BundleWiringImpl m_wiring;
- public BundleClassLoader(ClassLoader parent)
+ public BundleClassLoader(BundleWiringImpl wiring, ClassLoader parent)
{
super(parent);
if (m_dexFileClassLoadClass != null)
@@ -1851,6 +1880,7 @@
{
m_jarContentToDexFile = null;
}
+ m_wiring = wiring;
}
public boolean isActivationTriggered()
@@ -1860,17 +1890,17 @@
public Bundle getBundle()
{
- return BundleWiringImpl.this.getBundle();
+ return m_wiring.getBundle();
}
@Override
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
- Class clazz = null;
+ Class clazz;
// Make sure the class was not already loaded.
- synchronized (this)
+ synchronized (m_classLocks)
{
clazz = findLoadedClass(name);
}
@@ -1879,7 +1909,7 @@
{
try
{
- clazz = (Class) findClassOrResourceByDelegation(name, true);
+ clazz = (Class) m_wiring.findClassOrResourceByDelegation(name, true);
}
catch (ResourceNotFoundException ex)
{
@@ -1889,10 +1919,9 @@
catch (ClassNotFoundException cnfe)
{
ClassNotFoundException ex = cnfe;
- String msg = name;
- if (m_logger.getLogLevel() >= Logger.LOG_DEBUG)
+ if (m_wiring.m_logger.getLogLevel() >= Logger.LOG_DEBUG)
{
- msg = diagnoseClassLoadError(m_resolver, m_revision, name);
+ String msg = diagnoseClassLoadError(m_wiring.m_resolver, m_wiring.m_revision, name);
ex = (msg != null)
? new ClassNotFoundException(msg, cnfe)
: ex;
@@ -1922,7 +1951,7 @@
byte[] bytes = null;
// Check the bundle class path.
- List<Content> contentPath = m_revision.getContentPath();
+ List<Content> contentPath = m_wiring.m_revision.getContentPath();
Content content = null;
for (int i = 0;
(bytes == null) &&
@@ -1944,14 +1973,14 @@
// or removal, we just get a snapshot and leave any changes
// as a race condition, doing any necessary clean up in
// the error handling.
- Felix felix = ((BundleImpl) m_revision.getBundle()).getFramework();
+ Felix felix = ((BundleImpl) m_wiring.m_revision.getBundle()).getFramework();
Set<ServiceReference<WeavingHook>> hooks =
felix.getHooks(WeavingHook.class);
WovenClassImpl wci = null;
if (!hooks.isEmpty())
{
// Create woven class to be used for hooks.
- wci = new WovenClassImpl(name, BundleWiringImpl.this, bytes);
+ wci = new WovenClassImpl(name, m_wiring, bytes);
// Loop through hooks in service ranking order.
for (ServiceReference<WeavingHook> sr : hooks)
{
@@ -2000,199 +2029,225 @@
// Before we actually attempt to define the class, grab
// the lock for this class loader and make sure than no
// other thread has defined this class in the meantime.
- synchronized (this)
+ synchronized (m_classLocks)
{
- byte[] wovenBytes = null;
- Class wovenClass = null;
- List<String> wovenImports = null;
- try
+ Thread me = Thread.currentThread();
+ while (m_classLocks.containsKey(name) && (m_classLocks.get(name) != me))
{
- clazz = findLoadedClass(name);
- if (clazz == null)
+ try
{
- // If we have a woven class then get the class bytes from
- // it since they may have changed.
- // NOTE: We are taking a snapshot of these values and
- // are not preventing a malbehaving weaving hook from
- // modifying them after the fact. The price of preventing
- // this isn't worth it, since they can already wreck
- // havoc via weaving anyway. However, we do pass the
- // snapshot values into the woven class when we mark it
- // as complete so that it will refect the actual values
- // we used to define the class.
- if (wci != null)
- {
- bytes = wovenBytes = wci._getBytes();
- wovenImports = wci.getDynamicImportsInternal();
+ m_classLocks.wait();
+ }
+ catch (InterruptedException e)
+ {
+ // TODO: WHAT TO DO HERE?
+ throw new RuntimeException(e);
+ }
+ }
+ // Lock released, try loading class.
+ clazz = findLoadedClass(name);
+ if (clazz == null)
+ {
+ // Not found, we should try load it.
+ m_classLocks.put(name, me);
+ }
+ }
- // Try to add any woven dynamic imports, since they
- // could potentially be needed when defining the class.
- List<BundleRequirement> allWovenReqs =
- new ArrayList<BundleRequirement>();
- for (String s : wovenImports)
+ byte[] wovenBytes = null;
+ Class wovenClass = null;
+ List<String> wovenImports = null;
+ try
+ {
+ if (clazz == null)
+ {
+ // If we have a woven class then get the class bytes from
+ // it since they may have changed.
+ // NOTE: We are taking a snapshot of these values and
+ // are not preventing a malbehaving weaving hook from
+ // modifying them after the fact. The price of preventing
+ // this isn't worth it, since they can already wreck
+ // havoc via weaving anyway. However, we do pass the
+ // snapshot values into the woven class when we mark it
+ // as complete so that it will refect the actual values
+ // we used to define the class.
+ if (wci != null)
+ {
+ bytes = wovenBytes = wci._getBytes();
+ wovenImports = wci.getDynamicImportsInternal();
+
+ // Try to add any woven dynamic imports, since they
+ // could potentially be needed when defining the class.
+ List<BundleRequirement> allWovenReqs =
+ new ArrayList<BundleRequirement>();
+ for (String s : wovenImports)
+ {
+ try
{
- try
- {
- List<BundleRequirement> wovenReqs =
- ManifestParser.parseDynamicImportHeader(
- m_logger, m_revision, s);
- allWovenReqs.addAll(wovenReqs);
- }
- catch (BundleException ex)
- {
- // There should be no exception here
- // since we checked syntax before adding
- // dynamic import strings to list.
- }
- }
- // Add the dynamic requirements.
- if (!allWovenReqs.isEmpty())
+ List<BundleRequirement> wovenReqs =
+ ManifestParser.parseDynamicImportHeader(
+ m_wiring.m_logger, m_wiring.m_revision, s);
+ allWovenReqs.addAll(wovenReqs);
+ }
+ catch (BundleException ex)
{
- // Check for duplicate woven imports.
- // First grab existing woven imports, if any.
- Set<String> filters = new HashSet<String>();
- if (m_wovenReqs != null)
- {
- for (BundleRequirement req : m_wovenReqs)
- {
- filters.add(
- ((BundleRequirementImpl) req)
- .getFilter().toString());
- }
- }
- // Then check new woven imports for duplicates
- // against existing and self.
- int idx = allWovenReqs.size();
- while (idx < allWovenReqs.size())
- {
- BundleRequirement wovenReq = allWovenReqs.get(idx);
- String filter = ((BundleRequirementImpl)
- wovenReq).getFilter().toString();
- if (!filters.contains(filter))
- {
- filters.add(filter);
- idx++;
- }
- else
- {
- allWovenReqs.remove(idx);
- }
- }
- // Merge existing with new imports, if any.
- if (!allWovenReqs.isEmpty())
- {
- if (m_wovenReqs != null)
- {
- allWovenReqs.addAll(0, m_wovenReqs);
- }
- m_wovenReqs = allWovenReqs;
- }
+ // There should be no exception here
+ // since we checked syntax before adding
+ // dynamic import strings to list.
}
}
+ // Add the dynamic requirements.
+ if (!allWovenReqs.isEmpty())
+ {
+ // Check for duplicate woven imports.
+ // First grab existing woven imports, if any.
+ Set<String> filters = new HashSet<String>();
+ if (m_wiring.m_wovenReqs != null)
+ {
+ for (BundleRequirement req : m_wiring.m_wovenReqs)
+ {
+ filters.add(
+ ((BundleRequirementImpl) req)
+ .getFilter().toString());
+ }
+ }
+ // Then check new woven imports for duplicates
+ // against existing and self.
+ int idx = allWovenReqs.size();
+ while (idx < allWovenReqs.size())
+ {
+ BundleRequirement wovenReq = allWovenReqs.get(idx);
+ String filter = ((BundleRequirementImpl)
+ wovenReq).getFilter().toString();
+ if (!filters.contains(filter))
+ {
+ filters.add(filter);
+ idx++;
+ }
+ else
+ {
+ allWovenReqs.remove(idx);
+ }
+ }
+ // Merge existing with new imports, if any.
+ if (!allWovenReqs.isEmpty())
+ {
+ if (m_wiring.m_wovenReqs != null)
+ {
+ allWovenReqs.addAll(0, m_wiring.m_wovenReqs);
+ }
+ m_wiring.m_wovenReqs = allWovenReqs;
+ }
+ }
+ }
- int activationPolicy =
- ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed()
+ int activationPolicy =
+ ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed()
? ((BundleRevisionImpl) getBundle()
.adapt(BundleRevision.class)).getDeclaredActivationPolicy()
: EAGER_ACTIVATION;
- // If the revision is using deferred activation, then if
- // we load this class from this revision we need to activate
- // the bundle before returning the class. We will short
- // circuit the trigger matching if the trigger is already
- // tripped.
- boolean isTriggerClass = m_isActivationTriggered
- ? false : m_revision.isActivationTrigger(pkgName);
- if (!m_isActivationTriggered
- && isTriggerClass
- && (activationPolicy == BundleRevisionImpl.LAZY_ACTIVATION)
- && (getBundle().getState() == Bundle.STARTING))
+ // If the revision is using deferred activation, then if
+ // we load this class from this revision we need to activate
+ // the bundle before returning the class. We will short
+ // circuit the trigger matching if the trigger is already
+ // tripped.
+ boolean isTriggerClass = m_isActivationTriggered
+ ? false : m_wiring.m_revision.isActivationTrigger(pkgName);
+ if (!m_isActivationTriggered
+ && isTriggerClass
+ && (activationPolicy == BundleRevisionImpl.LAZY_ACTIVATION)
+ && (getBundle().getState() == Bundle.STARTING))
+ {
+ List deferredList = (List) m_deferredActivation.get();
+ if (deferredList == null)
{
- List deferredList = (List) m_deferredActivation.get();
- if (deferredList == null)
- {
- deferredList = new ArrayList();
- m_deferredActivation.set(deferredList);
- }
- deferredList.add(new Object[] { name, getBundle() });
+ deferredList = new ArrayList();
+ m_deferredActivation.set(deferredList);
}
- // We need to try to define a Package object for the class
- // before we call defineClass() if we haven't already
- // created it.
- if (pkgName.length() > 0)
+ deferredList.add(new Object[] { name, getBundle() });
+ }
+ // We need to try to define a Package object for the class
+ // before we call defineClass() if we haven't already
+ // created it.
+ if (pkgName.length() > 0)
+ {
+ if (getPackage(pkgName) == null)
{
- if (getPackage(pkgName) == null)
+ Object[] params = definePackage(pkgName);
+ if (params != null)
{
- Object[] params = definePackage(pkgName);
- if (params != null)
- {
- definePackage(
- pkgName,
- (String) params[0],
- (String) params[1],
- (String) params[2],
- (String) params[3],
- (String) params[4],
- (String) params[5],
- null);
- }
- else
- {
- definePackage(pkgName, null, null,
- null, null, null, null, null);
- }
- }
- }
-
- // If we can load the class from a dex file do so
- if (content instanceof JarContent)
- {
- try
- {
- clazz = getDexFileClass((JarContent) content, name, this);
- }
- catch (Exception ex)
- {
- // Looks like we can't
- }
- }
-
- if (clazz == null)
- {
- // If we have a security context, then use it to
- // define the class with it for security purposes,
- // otherwise define the class without a protection domain.
- if (m_revision.getProtectionDomain() != null)
- {
- clazz = defineClass(name, bytes, 0, bytes.length,
- m_revision.getProtectionDomain());
+ definePackage(
+ pkgName,
+ (String) params[0],
+ (String) params[1],
+ (String) params[2],
+ (String) params[3],
+ (String) params[4],
+ (String) params[5],
+ null);
}
else
{
- clazz = defineClass(name, bytes, 0, bytes.length);
+ definePackage(pkgName, null, null,
+ null, null, null, null, null);
}
-
- wovenClass = clazz;
}
+ }
- // At this point if we have a trigger class, then the deferred
- // activation trigger has tripped.
- if (!m_isActivationTriggered && isTriggerClass && (clazz != null))
+ // If we can load the class from a dex file do so
+ if (content instanceof JarContent)
+ {
+ try
{
- m_isActivationTriggered = true;
+ clazz = getDexFileClass((JarContent) content, name, this);
}
+ catch (Exception ex)
+ {
+ // Looks like we can't
+ }
+ }
+
+ if (clazz == null)
+ {
+ // If we have a security context, then use it to
+ // define the class with it for security purposes,
+ // otherwise define the class without a protection domain.
+ if (m_wiring.m_revision.getProtectionDomain() != null)
+ {
+ clazz = defineClass(name, bytes, 0, bytes.length,
+ m_wiring.m_revision.getProtectionDomain());
+ }
+ else
+ {
+ clazz = defineClass(name, bytes, 0, bytes.length);
+ }
+
+ wovenClass = clazz;
+ }
+
+ // At this point if we have a trigger class, then the deferred
+ // activation trigger has tripped.
+ if (!m_isActivationTriggered && isTriggerClass && (clazz != null))
+ {
+ m_isActivationTriggered = true;
}
}
- finally
+ }
+ finally
+ {
+ // If we have a woven class, mark it as complete.
+ // Not exactly clear how we should deal with the
+ // case where the weaving didn't happen because
+ // someone else beat us in defining the class.
+ if (wci != null)
{
- // If we have a woven class, mark it as complete.
- // Not exactly clear how we should deal with the
- // case where the weaving didn't happen because
- // someone else beat us in defining the class.
- if (wci != null)
- {
- wci.complete(wovenClass, wovenBytes, wovenImports);
- }
+ wci.complete(wovenClass, wovenBytes, wovenImports);
+ }
+
+ synchronized (m_classLocks)
+ {
+ m_classLocks.remove(name);
+ m_classLocks.notifyAll();
}
}
@@ -2217,7 +2272,7 @@
}
catch (Throwable ex)
{
- m_logger.log((BundleImpl) (lazy)[1],
+ m_wiring.m_logger.log((BundleImpl) (lazy)[1],
Logger.LOG_WARNING,
"Unable to lazily start bundle.",
ex);
@@ -2232,12 +2287,12 @@
private Object[] definePackage(String pkgName)
{
- String spectitle = (String) m_revision.getHeaders().get("Specification-Title");
- String specversion = (String) m_revision.getHeaders().get("Specification-Version");
- String specvendor = (String) m_revision.getHeaders().get("Specification-Vendor");
- String impltitle = (String) m_revision.getHeaders().get("Implementation-Title");
- String implversion = (String) m_revision.getHeaders().get("Implementation-Version");
- String implvendor = (String) m_revision.getHeaders().get("Implementation-Vendor");
+ String spectitle = (String) m_wiring.m_revision.getHeaders().get("Specification-Title");
+ String specversion = (String) m_wiring.m_revision.getHeaders().get("Specification-Version");
+ String specvendor = (String) m_wiring.m_revision.getHeaders().get("Specification-Vendor");
+ String impltitle = (String) m_wiring.m_revision.getHeaders().get("Implementation-Title");
+ String implversion = (String) m_wiring.m_revision.getHeaders().get("Implementation-Version");
+ String implvendor = (String) m_wiring.m_revision.getHeaders().get("Implementation-Vendor");
if ((spectitle != null)
|| (specversion != null)
|| (specvendor != null)
@@ -2299,8 +2354,8 @@
@Override
public URL getResource(String name)
{
- URL url = BundleWiringImpl.this.getResourceByDelegation(name);
- if (m_useLocalURLs)
+ URL url = m_wiring.getResourceByDelegation(name);
+ if (m_wiring.m_useLocalURLs)
{
url = convertToLocalUrl(url);
}
@@ -2310,7 +2365,7 @@
@Override
protected URL findResource(String name)
{
- return m_revision.getResourceLocal(name);
+ return m_wiring.m_revision.getResourceLocal(name);
}
// The findResources() method should only look at the revision itself, but
@@ -2321,8 +2376,8 @@
@Override
protected Enumeration findResources(String name)
{
- Enumeration urls = BundleWiringImpl.this.getResourcesByDelegation(name);
- if (m_useLocalURLs)
+ Enumeration urls = m_wiring.getResourcesByDelegation(name);
+ if (m_wiring.m_useLocalURLs)
{
urls = new ToLocalUrlEnumeration(urls);
}
@@ -2357,21 +2412,21 @@
// native library.
if (result == null)
{
- List<R4Library> libs = getNativeLibraries();
+ List<R4Library> libs = m_wiring.getNativeLibraries();
for (int libIdx = 0; (libs != null) && (libIdx < libs.size()); libIdx++)
{
- if (libs.get(libIdx).match(m_configMap, name))
+ if (libs.get(libIdx).match(m_wiring.m_configMap, name))
{
// Search bundle content first for native library.
- result = m_revision.getContent().getEntryAsNativeLibrary(
+ result = m_wiring.m_revision.getContent().getEntryAsNativeLibrary(
libs.get(libIdx).getEntryName());
// If not found, then search fragments in order.
for (int i = 0;
- (result == null) && (m_fragmentContents != null)
- && (i < m_fragmentContents.size());
+ (result == null) && (m_wiring.m_fragmentContents != null)
+ && (i < m_wiring.m_fragmentContents.size());
i++)
{
- result = m_fragmentContents.get(i).getEntryAsNativeLibrary(
+ result = m_wiring.m_fragmentContents.get(i).getEntryAsNativeLibrary(
libs.get(libIdx).getEntryName());
}
}
@@ -2394,7 +2449,7 @@
@Override
public String toString()
{
- return BundleWiringImpl.this.toString();
+ return m_wiring.toString();
}
}