All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.internal.framework.ContextFinder Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2005, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.osgi.internal.framework;

import java.io.IOException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.osgi.internal.loader.BundleLoader;
import org.eclipse.osgi.internal.loader.ModuleClassLoader;

public class ContextFinder extends ClassLoader implements PrivilegedAction> {
	static final class Finder extends SecurityManager {
		@Override
		public Class[] getClassContext() {
			Class[] result = super.getClassContext();
			// note that Android returns null, so handling this by returning empty
			return result == null ? new Class[0] : result;
		}
	}

	//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> cycleDetector = new ThreadLocal<>();
	static ClassLoader finderClassLoader;
	static Finder contextFinder;
	static {
		AccessController.doPrivileged(new PrivilegedAction() {
			@Override
			public Void run() {
				finderClassLoader = ContextFinder.class.getClassLoader();
				contextFinder = new Finder();
				return null;
			}
		});
	}

	private static Class THIS = ContextFinder.class;

	private final ClassLoader parentContextClassLoader;

	public ContextFinder(ClassLoader contextClassLoader, ClassLoader bootLoader) {
		super(contextClassLoader);
		this.parentContextClassLoader = contextClassLoader != null ? contextClassLoader : bootLoader;
	}

	// 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 basicFindClassLoaders() {
		Class[] stack = contextFinder.getClassContext();
		List result = new ArrayList<>(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 ModuleClassLoader)
					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 findClassLoaders() {
		if (System.getSecurityManager() == null)
			return basicFindClassLoaders();
		return AccessController.doPrivileged(this);
	}

	@Override
	public List 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 classesAndResources = cycleDetector.get();
		if (classesAndResources != null && classesAndResources.contains(name))
			return false;

		if (classesAndResources == null) {
			classesAndResources = new HashSet<>(3);
			cycleDetector.set(classesAndResources);
		}
		classesAndResources.add(name);
		return true;
	}

	private void stopLoading(String name) {
		cycleDetector.get().remove(name);
	}

	@Override
	protected Class loadClass(String arg0, boolean arg1) throws ClassNotFoundException {
		//Shortcut cycle
		if (startLoading(arg0) == false)
			throw new ClassNotFoundException(arg0);

		try {
			List toConsult = findClassLoaders();
			for (ClassLoader classLoader : toConsult)
				try {
					return classLoader.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);
		}
	}

	@Override
	public URL getResource(String arg0) {
		//Shortcut cycle
		if (startLoading(arg0) == false)
			return null;
		try {
			List toConsult = findClassLoaders();
			for (ClassLoader classLoader : toConsult) {
				URL result = classLoader.getResource(arg0);
				if (result != null)
					return result;
				// go to the next class loader
			}
			return super.getResource(arg0);
		} finally {
			stopLoading(arg0);
		}
	}

	@Override
	public Enumeration getResources(String arg0) throws IOException {
		//Shortcut cycle
		if (!startLoading(arg0)) {
			return Collections.emptyEnumeration();
		}
		try {
			List toConsult = findClassLoaders();
			Enumeration result = null;
			for (ClassLoader classLoader : toConsult) {
				result = classLoader.getResources(arg0);
				if (result != null && result.hasMoreElements()) {
					// For context finder we do not compound results after this first loader that has resources
					break;
				}
				// no results yet, go to the next class loader
			}
			return BundleLoader.compoundEnumerations(result, super.getResources(arg0));
		} finally {
			stopLoading(arg0);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy