| /******************************************************************************* |
| * Copyright (c) 2016, 2021 Christopher Gerking and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Christopher Gerking - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.m2m.internal.qvt.oml.jdt.runtime.blackbox; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.filesystem.URIUtil; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.emf.common.CommonPlugin; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.launching.IRuntimeClasspathEntry; |
| import org.eclipse.jdt.launching.IRuntimeClasspathEntry2; |
| import org.eclipse.jdt.launching.JavaRuntime; |
| import org.eclipse.m2m.internal.qvt.oml.QvtPlugin; |
| import org.eclipse.pde.core.plugin.IPluginImport; |
| import org.eclipse.pde.core.plugin.IPluginModelBase; |
| import org.eclipse.pde.core.plugin.PluginRegistry; |
| |
| public class ProjectClassLoader extends URLClassLoader { |
| |
| private static Map<IJavaProject, ProjectClassLoader> loadersMap = new HashMap<IJavaProject, ProjectClassLoader>(); |
| |
| ProjectClassLoader(IProject project) throws CoreException, MalformedURLException { |
| this(JavaCore.create(project)); |
| } |
| |
| ProjectClassLoader(IJavaProject javaProject) throws CoreException, MalformedURLException { |
| super(getProjectClassPath(javaProject), getParentClassLoader(javaProject)); |
| |
| loadersMap.put(javaProject, this); |
| } |
| |
| static synchronized boolean isProjectClassLoaderExisting(IJavaProject javaProject) { |
| return loadersMap.containsKey(javaProject); |
| } |
| |
| static synchronized ProjectClassLoader getProjectClassLoader(IProject project) throws CoreException, MalformedURLException { |
| return getProjectClassLoader(JavaCore.create(project)); |
| } |
| |
| static synchronized ProjectClassLoader getProjectClassLoader(IJavaProject javaProject) throws CoreException, MalformedURLException { |
| |
| ProjectClassLoader loader = loadersMap.get(javaProject); |
| |
| if (loader == null) { |
| loader = new ProjectClassLoader(javaProject); |
| } |
| |
| return loader; |
| } |
| |
| static synchronized void resetProjectClassLoader(IJavaProject javaProject) { |
| |
| ProjectClassLoader loader = loadersMap.get(javaProject); |
| |
| if (loader != null) { |
| try { // FIXME Bug 474603#22 |
| Method closeMethod = loader.getClass().getMethod("close"); |
| closeMethod.invoke(loader); |
| } |
| catch (InvocationTargetException e) { |
| Throwable targetException = e.getTargetException(); |
| if (targetException instanceof IOException) { |
| QvtPlugin.error(e); |
| } |
| } |
| catch (Exception e) {} |
| loadersMap.remove(javaProject); |
| } |
| } |
| |
| static synchronized void resetAllProjectClassLoaders() { |
| |
| for(IJavaProject javaProject : loadersMap.keySet()) { |
| resetProjectClassLoader(javaProject); |
| } |
| } |
| |
| @SuppressWarnings("restriction") |
| private static List<String> getRequiredPluginLocations(IRuntimeClasspathEntry classPathEntry) throws CoreException { |
| |
| List<String> requiredPluginLocations = Collections.emptyList(); |
| |
| IPath path = classPathEntry.getPath(); |
| |
| if (path != null && path.equals(org.eclipse.pde.internal.core.PDECore.REQUIRED_PLUGINS_CONTAINER_PATH)) { |
| IRuntimeClasspathEntry[] resolvedEntries = JavaRuntime.resolveRuntimeClasspathEntry(classPathEntry, classPathEntry.getJavaProject()); |
| |
| requiredPluginLocations = new ArrayList<String>(resolvedEntries.length); |
| |
| for (IRuntimeClasspathEntry resolvedEntry : resolvedEntries) { |
| String location = resolvedEntry.getLocation(); |
| requiredPluginLocations.add(location); |
| } |
| } |
| else if (classPathEntry instanceof IRuntimeClasspathEntry2) { |
| IRuntimeClasspathEntry2 compositeEntry = (IRuntimeClasspathEntry2) classPathEntry; |
| IRuntimeClasspathEntry[] nestedEntries = compositeEntry.getRuntimeClasspathEntries(false); |
| |
| requiredPluginLocations = new ArrayList<String>(); |
| |
| for (IRuntimeClasspathEntry nestedEntry : nestedEntries) { |
| requiredPluginLocations.addAll(getRequiredPluginLocations(nestedEntry)); |
| } |
| } |
| |
| return requiredPluginLocations; |
| } |
| |
| private static List<String> getRequiredPluginLocations(IJavaProject javaProject) throws CoreException { |
| |
| List<String> requiredPluginLocations = new ArrayList<String>(); |
| |
| IRuntimeClasspathEntry[] entries = JavaRuntime.computeUnresolvedRuntimeClasspath(javaProject); |
| |
| for (IRuntimeClasspathEntry entry : entries) { |
| requiredPluginLocations.addAll(getRequiredPluginLocations(entry)); |
| } |
| |
| return requiredPluginLocations; |
| } |
| |
| private static URL[] getProjectClassPath(IJavaProject javaProject) throws CoreException, MalformedURLException { |
| List<String> classPathEntries = new ArrayList<String>(Arrays.asList(JavaRuntime.computeDefaultRuntimeClassPath(javaProject))); |
| |
| List<String> requiredPluginLocations = getRequiredPluginLocations(javaProject); |
| |
| for (String pluginLocation : requiredPluginLocations) { |
| URI uri = URIUtil.toURI(pluginLocation); |
| if (!isWorkspaceLocation(uri)) { |
| classPathEntries.remove(pluginLocation); |
| } |
| } |
| |
| List<URL> urlList = new ArrayList<URL>(classPathEntries.size()); |
| |
| for (String entry : classPathEntries) { |
| URL url = new File(entry).toURI().toURL(); |
| urlList.add(url); |
| } |
| |
| return urlList.toArray(new URL[] {}); |
| } |
| |
| private static boolean isWorkspaceLocation(URI uri) throws CoreException { |
| IContainer[] containers = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(uri); |
| |
| for (IContainer container : containers) { |
| IProject project = container.getProject(); |
| |
| if (project != null && project.isOpen()) { |
| if (project.hasNature(JavaCore.NATURE_ID)) { |
| return true; |
| }; |
| } |
| } |
| |
| return false; |
| } |
| |
| @Override |
| protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |
| |
| Class<?> result = findLoadedClass(name); |
| |
| if (result == null) { |
| try { |
| result = findClass(name); |
| } |
| catch(Throwable e) { |
| result = getParent().loadClass(name); |
| } |
| } |
| |
| if (resolve) { |
| resolveClass(result); |
| } |
| |
| return result; |
| } |
| |
| private static ClassLoader getParentClassLoader(IJavaProject javaProject) { |
| |
| ClassLoader root = ProjectClassLoader.class.getClassLoader(); |
| |
| IPluginModelBase pluginModel = PluginRegistry.findModel(javaProject.getProject()); |
| |
| if (pluginModel == null) { |
| return root; |
| } |
| |
| IPluginImport[] imports = pluginModel.getPluginBase().getImports(); |
| final List<IPluginModelBase> importedPlugins = new ArrayList<IPluginModelBase>(imports.length); |
| |
| for(IPluginImport i : imports) { |
| IPluginModelBase importedPlugin = PluginRegistry.findModel(i.getId()); |
| |
| if (importedPlugin != null) { |
| importedPlugins.add(importedPlugin); |
| } |
| } |
| |
| if (importedPlugins.isEmpty()) { |
| return root; |
| } |
| |
| return new ClassLoader() { |
| |
| private Map<String, Class<?>> loadedClasses = new HashMap<String, Class<?>>(); |
| |
| @Override |
| protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |
| |
| if (loadedClasses.containsKey(name)) { |
| Class<?> result = loadedClasses.get(name); |
| |
| if (result == null) { |
| throw new ClassNotFoundException(); |
| } |
| else { |
| return result; |
| } |
| } |
| |
| for(IPluginModelBase importedPlugin : importedPlugins) { |
| if (importedPlugin.getUnderlyingResource() == null) { |
| String pluginId = importedPlugin.getPluginBase().getId(); |
| |
| try { |
| Class<?> result = CommonPlugin.loadClass(pluginId, name); |
| |
| if (resolve) { |
| resolveClass(result); |
| } |
| |
| loadedClasses.put(name, result); |
| return result; |
| } |
| catch (ClassNotFoundException e) { |
| continue; |
| } |
| } |
| } |
| |
| loadedClasses.put(name, null); |
| throw new ClassNotFoundException(); |
| } |
| }; |
| } |
| } |