diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java | 376 |
1 files changed, 0 insertions, 376 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java deleted file mode 100644 index e07f09927..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ide.eclipse.adt.internal.resources.manager; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; - -/** - * ClassLoader able to load class from output of an Eclipse project. - */ -public final class ProjectClassLoader extends ClassLoader { - - private final IJavaProject mJavaProject; - private URLClassLoader mJarClassLoader; - private boolean mInsideJarClassLoader = false; - - public ProjectClassLoader(ClassLoader parentClassLoader, IProject project) { - super(parentClassLoader); - mJavaProject = JavaCore.create(project); - } - - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - // if we are here through a child classloader, throw an exception. - if (mInsideJarClassLoader) { - throw new ClassNotFoundException(name); - } - - // attempt to load the class from the main project - Class<?> clazz = loadFromProject(mJavaProject, name); - - if (clazz != null) { - return clazz; - } - - // attempt to load the class from the jar dependencies - clazz = loadClassFromJar(name); - if (clazz != null) { - return clazz; - } - - // attempt to load the class from the libraries - try { - // get the project info - ProjectState projectState = Sdk.getProjectState(mJavaProject.getProject()); - - // this can happen if the project has no project.properties. - if (projectState != null) { - - List<IProject> libProjects = projectState.getFullLibraryProjects(); - List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects( - libProjects); - - for (IJavaProject javaProject : referencedJavaProjects) { - clazz = loadFromProject(javaProject, name); - - if (clazz != null) { - return clazz; - } - } - } - } catch (CoreException e) { - // log exception? - } - - throw new ClassNotFoundException(name); - } - - /** - * Attempts to load a class from a project output folder. - * @param project the project to load the class from - * @param name the name of the class - * @return a class object if found, null otherwise. - */ - private Class<?> loadFromProject(IJavaProject project, String name) { - try { - // get the project output folder. - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IPath outputLocation = project.getOutputLocation(); - IResource outRes = root.findMember(outputLocation); - if (outRes == null) { - return null; - } - - File outFolder = new File(outRes.getLocation().toOSString()); - - // get the class name segments - String[] segments = name.split("\\."); //$NON-NLS-1$ - - // try to load the class from the bin folder of the project. - File classFile = getFile(outFolder, segments, 0); - if (classFile == null) { - return null; - } - - // load the content of the file and create the class. - FileInputStream fis = new FileInputStream(classFile); - byte[] data = new byte[(int)classFile.length()]; - int read = 0; - try { - read = fis.read(data); - } catch (IOException e) { - data = null; - } - fis.close(); - - if (data != null) { - try { - Class<?> clazz = defineClass(null, data, 0, read); - if (clazz != null) { - return clazz; - } - } catch (UnsupportedClassVersionError e) { - // Attempt to reload on lower version - int maxVersion = 50; // JDK 1.6 - try { - byte[] rewritten = rewriteClass(data, maxVersion, 0); - return defineClass(null, rewritten, 0, rewritten.length); - } catch (UnsupportedClassVersionError e2) { - throw e; // throw *original* exception, not attempt to rewrite - } - } - } - } catch (Exception e) { - // log the exception? - } - - return null; - } - - /** - * Rewrites the given class to the given target class file version. - */ - public static byte[] rewriteClass(byte[] classData, final int maxVersion, final int minVersion) { - assert maxVersion >= minVersion; - ClassWriter classWriter = new ClassWriter(0); - ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) { - @Override - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { - if (version > maxVersion) { - version = maxVersion; - } - if (version < minVersion) { - version = minVersion; - } - super.visit(version, access, name, signature, superName, interfaces); - } - }; - ClassReader reader = new ClassReader(classData); - reader.accept(classVisitor, 0); - return classWriter.toByteArray(); - } - - /** - * Returns the File matching the a certain path from a root {@link File}. - * <p/>The methods checks that the file ends in .class even though the last segment - * does not. - * @param parent the root of the file. - * @param segments the segments containing the path of the file - * @param index the offset at which to start looking into segments. - * @throws FileNotFoundException - */ - private File getFile(File parent, String[] segments, int index) - throws FileNotFoundException { - // reached the end with no match? - if (index == segments.length) { - throw new FileNotFoundException(); - } - - String toMatch = segments[index]; - File[] files = parent.listFiles(); - - // we're at the last segments. we look for a matching <file>.class - if (index == segments.length - 1) { - toMatch = toMatch + ".class"; - - if (files != null) { - for (File file : files) { - if (file.isFile() && file.getName().equals(toMatch)) { - return file; - } - } - } - - // no match? abort. - throw new FileNotFoundException(); - } - - String innerClassName = null; - - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - if (toMatch.equals(file.getName())) { - return getFile(file, segments, index+1); - } - } else if (file.getName().startsWith(toMatch)) { - if (innerClassName == null) { - StringBuilder sb = new StringBuilder(segments[index]); - for (int i = index + 1 ; i < segments.length ; i++) { - sb.append('$'); - sb.append(segments[i]); - } - sb.append(".class"); - - innerClassName = sb.toString(); - } - - if (file.getName().equals(innerClassName)) { - return file; - } - } - } - } - - return null; - } - - /** - * Loads a class from the 3rd party jar present in the project - * - * @return the class loader or null if not found. - */ - private Class<?> loadClassFromJar(String name) { - if (mJarClassLoader == null) { - // get the OS path to all the external jars - URL[] jars = getExternalJars(); - - mJarClassLoader = new URLClassLoader(jars, this /* parent */); - } - - try { - // because a class loader always look in its parent loader first, we need to know - // that we are querying the jar classloader. This will let us know to not query - // it again for classes we don't find, or this would create an infinite loop. - mInsideJarClassLoader = true; - return mJarClassLoader.loadClass(name); - } catch (ClassNotFoundException e) { - // not found? return null. - return null; - } finally { - mInsideJarClassLoader = false; - } - } - - /** - * Returns an array of external jar files used by the project. - * @return an array of OS-specific absolute file paths - */ - private final URL[] getExternalJars() { - // get a java project from it - IJavaProject javaProject = JavaCore.create(mJavaProject.getProject()); - - ArrayList<URL> oslibraryList = new ArrayList<URL>(); - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY || - e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); - } - - handleClassPathEntry(e, oslibraryList); - } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container. - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - e.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container != null && - container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry entry : entries) { - // TODO: Xav -- is this necessary? - if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - entry = JavaCore.getResolvedClasspathEntry(entry); - } - - handleClassPathEntry(entry, oslibraryList); - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", - e.getPath()); - } - } - } - } - - return oslibraryList.toArray(new URL[oslibraryList.size()]); - } - - private void handleClassPathEntry(IClasspathEntry e, ArrayList<URL> oslibraryList) { - // get the IPath - IPath path = e.getPath(); - - // check the name ends with .jar - if (SdkConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) { - boolean local = false; - IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path); - if (resource != null && resource.exists() && - resource.getType() == IResource.FILE) { - local = true; - try { - oslibraryList.add(new File(resource.getLocation().toOSString()) - .toURI().toURL()); - } catch (MalformedURLException mue) { - // pass - } - } - - if (local == false) { - // if the jar path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid file. - String osFullPath = path.toOSString(); - - File f = new File(osFullPath); - if (f.exists()) { - try { - oslibraryList.add(f.toURI().toURL()); - } catch (MalformedURLException mue) { - // pass - } - } - } - } - } -} |