Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/core/runtime/internal/adaptor/ContextFinder.java')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/core/runtime/internal/adaptor/ContextFinder.java175
1 files changed, 175 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/core/runtime/internal/adaptor/ContextFinder.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/core/runtime/internal/adaptor/ContextFinder.java
new file mode 100644
index 000000000..9ecc15b45
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/core/runtime/internal/adaptor/ContextFinder.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2010 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.runtime.internal.adaptor;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import org.eclipse.osgi.framework.adaptor.BundleClassLoader;
+
+public class ContextFinder extends ClassLoader implements PrivilegedAction<List<ClassLoader>> {
+ static final class Finder extends SecurityManager {
+ public Class<?>[] getClassContext() {
+ return super.getClassContext();
+ }
+ }
+
+ //This is used to detect cycle that could be caused while delegating the loading to other classloaders
+ //It keeps track on a thread basis of the set of requested classes and resources
+ private static ThreadLocal<Set<String>> cycleDetector = new ThreadLocal<Set<String>>();
+ static ClassLoader finderClassLoader;
+ static Finder contextFinder;
+ static {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ finderClassLoader = ContextFinder.class.getClassLoader();
+ contextFinder = new Finder();
+ return null;
+ }
+ });
+ }
+
+ private static Class<ContextFinder> THIS = ContextFinder.class;
+
+ private final ClassLoader parentContextClassLoader;
+
+ public ContextFinder(ClassLoader contextClassLoader) {
+ super(contextClassLoader);
+ this.parentContextClassLoader = contextClassLoader != null ? contextClassLoader : new ClassLoader(Object.class.getClassLoader()) {/*boot classloader*/};
+ }
+
+ // Return a list of all classloaders on the stack that are neither the
+ // ContextFinder classloader nor the boot classloader. The last classloader
+ // in the list is either a bundle classloader or the framework's classloader
+ // We assume that the bootclassloader never uses the context classloader to find classes in itself.
+ List<ClassLoader> basicFindClassLoaders() {
+ Class<?>[] stack = contextFinder.getClassContext();
+ List<ClassLoader> result = new ArrayList<ClassLoader>(1);
+ ClassLoader previousLoader = null;
+ for (int i = 1; i < stack.length; i++) {
+ ClassLoader tmp = stack[i].getClassLoader();
+ if (stack[i] != THIS && tmp != null && tmp != this) {
+ if (checkClassLoader(tmp)) {
+ if (previousLoader != tmp) {
+ result.add(tmp);
+ previousLoader = tmp;
+ }
+ }
+ // stop at the framework classloader or the first bundle classloader
+ if (tmp == finderClassLoader || tmp instanceof BundleClassLoader)
+ break;
+ }
+ }
+ return result;
+ }
+
+ // ensures that a classloader does not have the ContextFinder as part of the
+ // parent hierachy. A classloader which has the ContextFinder as a parent must
+ // not be used as a delegate, otherwise we endup in endless recursion.
+ private boolean checkClassLoader(ClassLoader classloader) {
+ if (classloader == null || classloader == getParent())
+ return false;
+ for (ClassLoader parent = classloader.getParent(); parent != null; parent = parent.getParent())
+ if (parent == this)
+ return false;
+ return true;
+ }
+
+ private List<ClassLoader> findClassLoaders() {
+ if (System.getSecurityManager() == null)
+ return basicFindClassLoaders();
+ return AccessController.doPrivileged(this);
+ }
+
+ public List<ClassLoader> run() {
+ return basicFindClassLoaders();
+ }
+
+ //Return whether the request for loading "name" should proceed.
+ //False is returned when a cycle is being detected
+ private boolean startLoading(String name) {
+ Set<String> classesAndResources = cycleDetector.get();
+ if (classesAndResources != null && classesAndResources.contains(name))
+ return false;
+
+ if (classesAndResources == null) {
+ classesAndResources = new HashSet<String>(3);
+ cycleDetector.set(classesAndResources);
+ }
+ classesAndResources.add(name);
+ return true;
+ }
+
+ private void stopLoading(String name) {
+ cycleDetector.get().remove(name);
+ }
+
+ protected Class<?> loadClass(String arg0, boolean arg1) throws ClassNotFoundException {
+ //Shortcut cycle
+ if (startLoading(arg0) == false)
+ throw new ClassNotFoundException(arg0);
+
+ try {
+ List<ClassLoader> toConsult = findClassLoaders();
+ for (Iterator<ClassLoader> loaders = toConsult.iterator(); loaders.hasNext();)
+ try {
+ return loaders.next().loadClass(arg0);
+ } catch (ClassNotFoundException e) {
+ // go to the next class loader
+ }
+ // avoid calling super.loadClass here because it checks the local cache (bug 127963)
+ return parentContextClassLoader.loadClass(arg0);
+ } finally {
+ stopLoading(arg0);
+ }
+ }
+
+ public URL getResource(String arg0) {
+ //Shortcut cycle
+ if (startLoading(arg0) == false)
+ return null;
+ try {
+ List<ClassLoader> toConsult = findClassLoaders();
+ for (Iterator<ClassLoader> loaders = toConsult.iterator(); loaders.hasNext();) {
+ URL result = loaders.next().getResource(arg0);
+ if (result != null)
+ return result;
+ // go to the next class loader
+ }
+ return super.getResource(arg0);
+ } finally {
+ stopLoading(arg0);
+ }
+ }
+
+ protected Enumeration<URL> findResources(String arg0) throws IOException {
+ //Shortcut cycle
+ if (startLoading(arg0) == false) {
+ @SuppressWarnings("unchecked")
+ Enumeration<URL> result = Collections.enumeration(Collections.EMPTY_LIST);
+ return result;
+ }
+ try {
+ List<ClassLoader> toConsult = findClassLoaders();
+ for (Iterator<ClassLoader> loaders = toConsult.iterator(); loaders.hasNext();) {
+ Enumeration<URL> result = loaders.next().getResources(arg0);
+ if (result != null && result.hasMoreElements())
+ return result;
+ // go to the next class loader
+ }
+ return super.findResources(arg0);
+ } finally {
+ stopLoading(arg0);
+ }
+ }
+}

Back to the top