Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2017-02-28 15:03:45 +0000
committerThomas Watson2017-03-02 20:50:36 +0000
commit64c504c7f56e523b3a70c065bf793acc7c397487 (patch)
treeab116274d3bfc00d447054f407a49652f7f72327 /bundles/org.eclipse.osgi/container
parent6e3d3967c4052a93abc26281fe7809f4abbc5e69 (diff)
downloadrt.equinox.framework-64c504c7f56e523b3a70c065bf793acc7c397487.tar.gz
rt.equinox.framework-64c504c7f56e523b3a70c065bf793acc7c397487.tar.xz
rt.equinox.framework-64c504c7f56e523b3a70c065bf793acc7c397487.zip
Change-Id: I3223216586d1cb5bf399132b26293cf0e787377f Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
Diffstat (limited to 'bundles/org.eclipse.osgi/container')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java7
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java15
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxEventPublisher.java7
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/OSGiFrameworkHooks.java7
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/ClassLoaderHook.java15
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java8
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/EclipseLazyStarter.java7
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java108
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/HookContext.java9
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java30
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WeavingHookConfigurator.java61
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WovenClassImpl.java19
12 files changed, 230 insertions, 63 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
index a65bbe426..a19273b9e 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/BundleContextImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2016 IBM Corporation and others.
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -235,6 +235,11 @@ public class BundleContextImpl implements BundleContext, EventDispatcher<Object,
public String getHookMethodName() {
return "find"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
index db901c525..b81704cc6 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxContainer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2016 IBM Corporation and others.
+ * Copyright (c) 2012, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@ import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.internal.framework.legacy.PackageAdminImpl;
import org.eclipse.osgi.internal.framework.legacy.StartLevelImpl;
+import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.hookregistry.HookRegistry;
import org.eclipse.osgi.internal.location.EquinoxLocations;
import org.eclipse.osgi.internal.log.EquinoxLogServices;
@@ -46,6 +47,7 @@ public class EquinoxContainer implements ThreadFactory, Runnable {
private final Set<String> bootDelegation;
private final String[] bootDelegationStems;
private final boolean bootDelegateAll;
+ private final boolean isProcessClassRecursionSupportedByAll;
private final EquinoxEventPublisher eventPublisher;
private final Object monitor = new Object();
@@ -97,6 +99,13 @@ public class EquinoxContainer implements ThreadFactory, Runnable {
bootDelegateAll = delegateAllValue;
bootDelegation = exactMatch;
bootDelegationStems = stemMatch.isEmpty() ? null : stemMatch.toArray(new String[stemMatch.size()]);
+
+ // Detect if all hooks can support recursive class processing
+ boolean supportRecursion = true;
+ for (ClassLoaderHook hook : equinoxConfig.getHookRegistry().getClassLoaderHooks()) {
+ supportRecursion &= hook.isProcessClassRecursionSupported();
+ }
+ isProcessClassRecursionSupportedByAll = supportRecursion;
}
public Storage getStorage() {
@@ -143,6 +152,10 @@ public class EquinoxContainer implements ThreadFactory, Runnable {
return false;
}
+ public boolean isProcessClassRecursionSupportedByAll() {
+ return isProcessClassRecursionSupportedByAll;
+ }
+
void init() {
eventPublisher.init();
synchronized (this.monitor) {
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxEventPublisher.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxEventPublisher.java
index 232c8de0c..9884a785a 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxEventPublisher.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxEventPublisher.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2016 IBM Corporation and others.
+ * Copyright (c) 2012, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -247,6 +247,11 @@ public class EquinoxEventPublisher {
public String getHookMethodName() {
return "event"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/OSGiFrameworkHooks.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/OSGiFrameworkHooks.java
index 464e9dc20..14a6df5da 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/OSGiFrameworkHooks.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/OSGiFrameworkHooks.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2016 IBM Corporation and others.
+ * Copyright (c) 2012, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -115,6 +115,11 @@ class OSGiFrameworkHooks {
public String getHookMethodName() {
return "filterCollisions"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/ClassLoaderHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/ClassLoaderHook.java
index f921acce7..0f0b02b92 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/ClassLoaderHook.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/ClassLoaderHook.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2013 IBM Corporation and others.
+ * Copyright (c) 2005, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -292,4 +292,17 @@ public abstract class ClassLoaderHook {
return null;
}
+ /**
+ * Returns true if this hook can support invoking
+ * {@link ClassLoaderHook#processClass(String, byte[], ClasspathEntry, BundleEntry, ClasspathManager) processClass}
+ * recursively for the same class name. If false is returned then a class
+ * loading error will occur if recursive class processing is detected.
+ * <p>
+ * This method must return a constant boolean value.
+ * @return true if recursing class processing is supported
+ */
+ public boolean isProcessClassRecursionSupported() {
+ return false;
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
index d936f4ef6..99353e819 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2012 IBM Corporation and others.
+ * Copyright (c) 2006, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -109,4 +109,10 @@ public class DevClassLoadingHook extends ClassLoaderHook implements KeyedElement
public int getKeyHashCode() {
return HASHCODE;
}
+
+ @Override
+ public boolean isProcessClassRecursionSupported() {
+ return true;
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/EclipseLazyStarter.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/EclipseLazyStarter.java
index 7312f8fc0..26edbbac6 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/EclipseLazyStarter.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/EclipseLazyStarter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2016 IBM Corporation and others.
+ * Copyright (c) 2006, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -174,4 +174,9 @@ public class EclipseLazyStarter extends ClassLoaderHook {
return ((includes == null || includes.contains(packageName)) && (excludes == null || !excludes.contains(packageName)));
}
+ @Override
+ public boolean isProcessClassRecursionSupported() {
+ return true;
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
index 8139ded11..10ae89de1 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2016 IBM Corporation and others.
+ * Copyright (c) 2005, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -63,7 +63,7 @@ public class ClasspathManager {
// a Map<String,String> where "libname" is the key and libpath" is the value
private ArrayMap<String, String> loadedLibraries = null;
// used to detect recusive defineClass calls for the same class on the same class loader (bug 345500)
- private ThreadLocal<Collection<String>> currentlyDefining = new ThreadLocal<>();
+ private ThreadLocal<DefineContext> currentDefineContext = new ThreadLocal<>();
/**
* Constructs a classpath manager for the given generation and module class loader
@@ -574,25 +574,20 @@ public class ClasspathManager {
Debug.println(" defining class " + name); //$NON-NLS-1$
}
- Collection<String> current = currentlyDefining.get();
- if (current == null) {
- current = new ArrayList<>(5);
- currentlyDefining.set(current);
- }
- if (current.contains(name))
- return null; // avoid recursive defines (bug 345500)
try {
- current.add(name);
return defineClass(name, classbytes, classpathEntry, entry, hooks);
} catch (Error e) {
if (debug.DEBUG_LOADER)
Debug.println(" error defining class " + name); //$NON-NLS-1$
throw e;
- } finally {
- current.remove(name);
}
}
+ static class DefineContext {
+ Collection<String> currentlyProcessing = new ArrayList<>(5);
+ Collection<String> currentlyDefining = new ArrayList<>(5);
+ }
+
/**
* Defines the specified class. This method will first call all the configured class loader hooks
* {@link ClassLoadingHook#processClass(String, byte[], ClasspathEntry, BundleEntry, ClasspathManager)}
@@ -610,37 +605,90 @@ public class ClasspathManager {
*/
private Class<?> defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, List<ClassLoaderHook> hooks) {
DefineClassResult result = null;
+ boolean recursionDetected = false;
try {
definePackage(name, classpathEntry);
- for (ClassLoaderHook hook : hooks) {
- byte[] modifiedBytes = hook.processClass(name, classbytes, classpathEntry, entry, this);
- if (modifiedBytes != null) {
- // the WeavingHookConfigurator already calls the rejectTransformation method; avoid calling it again.
- if (!(hook instanceof WeavingHookConfigurator)) {
- for (ClassLoaderHook rejectHook : hooks) {
- if (rejectHook.rejectTransformation(name, modifiedBytes, classpathEntry, entry, this)) {
- modifiedBytes = null;
- break;
- }
+ DefineContext context = currentDefineContext.get();
+ if (context == null) {
+ context = new DefineContext();
+ currentDefineContext.set(context);
+ }
+
+ // First call the hooks that do not handle recursion themselves
+ if (!hookRegistry.getContainer().isProcessClassRecursionSupportedByAll()) {
+ // One or more hooks do not support recursive class processing.
+ // We need to detect recursions for this set of hooks.
+ if (context.currentlyProcessing.contains(name)) {
+ // Avoid recursion for the same class name for these hooks
+ recursionDetected = true;
+ // TODO consider thrown a ClassCircularityError here
+ return null;
+ }
+ context.currentlyProcessing.add(name);
+ try {
+
+ for (ClassLoaderHook hook : hooks) {
+ if (!hook.isProcessClassRecursionSupported()) {
+ classbytes = processClass(hook, name, classbytes, classpathEntry, entry, this, hooks);
}
}
- if (modifiedBytes != null) {
- classbytes = modifiedBytes;
- }
+ } finally {
+ context.currentlyProcessing.remove(name);
}
}
- result = classloader.defineClass(name, classbytes, classpathEntry);
- } finally {
- // only pass the newly defined class to the hook
- Class<?> defined = result != null && result.defined ? result.clazz : null;
+
+ // Now call the hooks that do support recursion without the check.
for (ClassLoaderHook hook : hooks) {
- hook.recordClassDefine(name, defined, classbytes, classpathEntry, entry, this);
+ if (hook.isProcessClassRecursionSupported()) {
+ // Note if the hooks don't take protective measures for a recursive class load here
+ // it will result in a stack overflow.
+ classbytes = processClass(hook, name, classbytes, classpathEntry, entry, this, hooks);
+ }
+ }
+
+ if (context.currentlyDefining.contains(name)) {
+ // TODO consider thrown a ClassCircularityError here
+ return null; // avoid recursive defines (bug 345500)
+ }
+ context.currentlyDefining.add(name);
+ try {
+ result = classloader.defineClass(name, classbytes, classpathEntry);
+ } finally {
+ context.currentlyDefining.remove(name);
+ }
+ } finally {
+ // only call hooks if we properly called processClass above
+ if (!recursionDetected) {
+ // only pass the newly defined class to the hook
+ Class<?> defined = result != null && result.defined ? result.clazz : null;
+ for (ClassLoaderHook hook : hooks) {
+ hook.recordClassDefine(name, defined, classbytes, classpathEntry, entry, this);
+ }
}
}
// return either the pre-loaded class or the newly defined class
return result == null ? null : result.clazz;
}
+ private byte[] processClass(ClassLoaderHook hook, String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager classpathManager, List<ClassLoaderHook> hooks) {
+ byte[] modifiedBytes = hook.processClass(name, classbytes, classpathEntry, entry, this);
+ if (modifiedBytes != null) {
+ // the WeavingHookConfigurator already calls the rejectTransformation method; avoid calling it again.
+ if (!(hook instanceof WeavingHookConfigurator)) {
+ for (ClassLoaderHook rejectHook : hooks) {
+ if (rejectHook.rejectTransformation(name, modifiedBytes, classpathEntry, entry, this)) {
+ modifiedBytes = null;
+ break;
+ }
+ }
+ }
+ if (modifiedBytes != null) {
+ classbytes = modifiedBytes;
+ }
+ }
+ return classbytes;
+ }
+
private void definePackage(String name, ClasspathEntry classpathEntry) {
// Define the package if it is not the default package.
int lastIndex = name.lastIndexOf('.');
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/HookContext.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/HookContext.java
index 521917d1b..3bb5528a4 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/HookContext.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/HookContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2012 IBM Corporation and others.
+ * Copyright (c) 2010, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -46,4 +46,11 @@ public interface HookContext {
* @return The hook method name called by this hook context.
*/
public String getHookMethodName();
+
+ /**
+ * Returns true if the given registration should be skipped.
+ * @param hookRegistration the registration to check
+ * @return true if the given registration should be skipped.
+ */
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration);
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
index cc24fe06c..c3ac4d985 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1187,6 +1187,11 @@ public class ServiceRegistry {
public String getHookMethodName() {
return "find"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
@@ -1217,6 +1222,11 @@ public class ServiceRegistry {
public String getHookMethodName() {
return "event"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
@@ -1246,6 +1256,11 @@ public class ServiceRegistry {
public String getHookMethodName() {
return "event"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
@@ -1272,6 +1287,9 @@ public class ServiceRegistry {
* @param hookContext Context to use when calling the hook service.
*/
private void notifyHookPrivileged(BundleContextImpl context, ServiceRegistrationImpl<?> registration, HookContext hookContext) {
+ if (hookContext.skipRegistration(registration)) {
+ return;
+ }
Object hook = registration.getSafeService(context, ServiceConsumer.singletonConsumer);
if (hook == null) { // if the hook is null
return;
@@ -1342,6 +1360,11 @@ public class ServiceRegistry {
public String getHookMethodName() {
return "added"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
@@ -1393,6 +1416,11 @@ public class ServiceRegistry {
public String getHookMethodName() {
return added ? "added" : "removed"; //$NON-NLS-1$ //$NON-NLS-2$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
});
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WeavingHookConfigurator.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WeavingHookConfigurator.java
index e37e2670b..e1f830469 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WeavingHookConfigurator.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WeavingHookConfigurator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2016 IBM Corporation and others.
+ * Copyright (c) 2010, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,10 +22,15 @@ import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.osgi.framework.*;
public class WeavingHookConfigurator extends ClassLoaderHook {
+ static class WovenClassContext {
+ List<WovenClassImpl> wovenClassStack = new ArrayList<>(6);
+ List<String> processClassNameStack = new ArrayList<>(6);
+ }
+
// holds the map of black listed hooks. Use weak map to avoid pinning and simplify cleanup.
private final Map<ServiceRegistration<?>, Boolean> blackList = Collections.synchronizedMap(new WeakHashMap<ServiceRegistration<?>, Boolean>());
// holds the stack of WovenClass objects currently being used to define classes
- private final ThreadLocal<List<WovenClassImpl>> wovenClassStack = new ThreadLocal<>();
+ private final ThreadLocal<WovenClassContext> wovenClassContext = new ThreadLocal<>();
private final EquinoxContainer container;
@@ -45,34 +50,48 @@ public class WeavingHookConfigurator extends ClassLoaderHook {
BundleLoader loader = classLoader.getBundleLoader();
// create a woven class object and add it to the thread local stack
WovenClassImpl wovenClass = new WovenClassImpl(name, classbytes, entry, classpathEntry, loader, container, blackList);
- List<WovenClassImpl> wovenClasses = wovenClassStack.get();
- if (wovenClasses == null) {
- wovenClasses = new ArrayList<>(6);
- wovenClassStack.set(wovenClasses);
+ WovenClassContext context = wovenClassContext.get();
+ if (context == null) {
+ context = new WovenClassContext();
+ wovenClassContext.set(context);
}
- wovenClasses.add(wovenClass);
- // call the weaving hooks
- try {
- return wovenClass.callHooks();
- } catch (Throwable t) {
- ServiceRegistration<?> errorHook = wovenClass.getErrorHook();
- Bundle errorBundle = errorHook != null ? errorHook.getReference().getBundle() : manager.getGeneration().getRevision().getBundle();
- container.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, errorBundle, t);
- // fail hard with a class loading error
- ClassFormatError error = new ClassFormatError("Unexpected error from weaving hook."); //$NON-NLS-1$
- error.initCause(t);
- throw error;
+ context.wovenClassStack.add(wovenClass);
+ // If we detect recursion for the same class name then we will not call the
+ // weaving hooks for the second request to load.
+ // Note that this means the actual bytes that get used to define the class
+ // will not have been woven at all.
+ if (!context.processClassNameStack.contains(name)) {
+ context.processClassNameStack.add(name);
+ // call the weaving hooks
+ try {
+ return wovenClass.callHooks();
+ } catch (Throwable t) {
+ ServiceRegistration<?> errorHook = wovenClass.getErrorHook();
+ Bundle errorBundle = errorHook != null ? errorHook.getReference().getBundle() : manager.getGeneration().getRevision().getBundle();
+ container.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, errorBundle, t);
+ // fail hard with a class loading error
+ ClassFormatError error = new ClassFormatError("Unexpected error from weaving hook."); //$NON-NLS-1$
+ error.initCause(t);
+ throw error;
+ } finally {
+ context.processClassNameStack.remove(name);
+ }
}
+ return null;
}
public void recordClassDefine(String name, Class<?> clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
// here we assume the stack contans a woven class with the same name as the class we are defining.
- List<WovenClassImpl> wovenClasses = wovenClassStack.get();
- if (wovenClasses == null || wovenClasses.size() == 0)
+ WovenClassContext context = wovenClassContext.get();
+ if (context == null || context.wovenClassStack.size() == 0)
return;
- WovenClassImpl wovenClass = wovenClasses.remove(wovenClasses.size() - 1);
+ WovenClassImpl wovenClass = context.wovenClassStack.remove(context.wovenClassStack.size() - 1);
// inform the woven class about the class that was defined.
wovenClass.setWeavingCompleted(clazz);
}
+ @Override
+ public boolean isProcessClassRecursionSupported() {
+ return true;
+ }
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WovenClassImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WovenClassImpl.java
index fbd98bc13..89609baf7 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WovenClassImpl.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/weaving/WovenClassImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2013 IBM Corporation and others.
+ * Copyright (c) 2010, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -147,8 +147,11 @@ public final class WovenClassImpl implements WovenClass, HookContext {
if (error != null)
return; // do not call any other hooks once an error has occurred.
if (hook instanceof WeavingHook) {
- if (blackList.containsKey(hookRegistration))
- return; // black listed hook
+ if (skipRegistration(hookRegistration)) {
+ // Note we double check blacklist here just
+ // in case another thread blacklisted since the first check
+ return;
+ }
if ((hookFlags & FLAG_HOOKCALLED) == 0) {
hookFlags |= FLAG_HOOKCALLED;
// only do this check on the first weaving hook call
@@ -171,6 +174,11 @@ public final class WovenClassImpl implements WovenClass, HookContext {
}
}
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return blackList.containsKey(hookRegistration);
+ }
+
private boolean validBytes(byte[] checkBytes) {
if (checkBytes == null || checkBytes.length < 4)
return false;
@@ -215,6 +223,11 @@ public final class WovenClassImpl implements WovenClass, HookContext {
public String getHookMethodName() {
return "modified"; //$NON-NLS-1$
}
+
+ @Override
+ public boolean skipRegistration(ServiceRegistration<?> hookRegistration) {
+ return false;
+ }
};
if (System.getSecurityManager() == null)
registry.notifyHooksPrivileged(context);

Back to the top