[573752] Exclude required plugins from URLClassLoader
diff --git a/plugins/org.eclipse.m2m.qvt.oml.runtime.jdt/src/org/eclipse/m2m/internal/qvt/oml/jdt/runtime/blackbox/ProjectClassLoader.java b/plugins/org.eclipse.m2m.qvt.oml.runtime.jdt/src/org/eclipse/m2m/internal/qvt/oml/jdt/runtime/blackbox/ProjectClassLoader.java
index 84c8f91..d60459a 100644
--- a/plugins/org.eclipse.m2m.qvt.oml.runtime.jdt/src/org/eclipse/m2m/internal/qvt/oml/jdt/runtime/blackbox/ProjectClassLoader.java
+++ b/plugins/org.eclipse.m2m.qvt.oml.runtime.jdt/src/org/eclipse/m2m/internal/qvt/oml/jdt/runtime/blackbox/ProjectClassLoader.java
@@ -10,25 +10,37 @@
*******************************************************************************/
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.core.runtime.Path;
+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 {
@@ -39,8 +51,8 @@
}
ProjectClassLoader(IJavaProject javaProject) throws CoreException, MalformedURLException {
- super(getProjectClassPath(javaProject), ProjectClassLoader.class.getClassLoader());
-
+ super(getProjectClassPath(javaProject), getParentClassLoader(javaProject));
+
loadersMap.put(javaProject, this);
}
@@ -89,17 +101,176 @@
resetProjectClassLoader(javaProject);
}
}
-
- private static URL[] getProjectClassPath(IJavaProject javaProject) throws CoreException, MalformedURLException {
- String[] classPathEntries = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);
+
+ @SuppressWarnings("restriction")
+ private static List<String> getRequiredPluginLocations(IRuntimeClasspathEntry classPathEntry) throws CoreException {
- List<URL> urlList = new ArrayList<URL>();
+ 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) {
- IPath path = new Path(entry);
- URL url = path.toFile().toURI().toURL();
- urlList.add(url);
+ 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();
+ }
+ };
+ }
}