[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();
+			}
+		};
+	}
 }