FileDocCategorySizeDatePackage
ProjectClassLoader.javaAPI DocAndroid 1.5 API9632Wed May 06 22:41:10 BST 2009com.android.ide.eclipse.editors.resources.manager

ProjectClassLoader

public final class ProjectClassLoader extends ClassLoader
ClassLoader able to load class from output of an Eclipse project.

Fields Summary
private final org.eclipse.jdt.core.IJavaProject
mJavaProject
private URLClassLoader
mJarClassLoader
private boolean
mInsideJarClassLoader
Constructors Summary
public ProjectClassLoader(ClassLoader parentClassLoader, org.eclipse.core.resources.IProject project)


         
        super(parentClassLoader);
        mJavaProject = JavaCore.create(project);
    
Methods Summary
protected java.lang.ClassfindClass(java.lang.String name)

        try {
            // get the project output folder.
            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
            IPath outputLocation = mJavaProject.getOutputLocation();
            IResource outRes = root.findMember(outputLocation);
            if (outRes == null) {
                throw new ClassNotFoundException(name);
            }

            File outFolder = new File(outRes.getLocation().toOSString());

            // get the class name segments
            String[] segments = name.split("\\."); //$NON-NLS-1$
            
            File classFile = getFile(outFolder, segments, 0);
            if (classFile == null) {
                if (mInsideJarClassLoader == false) {
                    // if no file matching the class name was found, look in the 3rd party jars
                    return loadClassFromJar(name);
                } else {
                    throw new ClassNotFoundException(name);
                }
            }
            
            // 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) {
                Class<?> clazz = defineClass(null, data, 0, read);
                if (clazz != null) {
                    return clazz;
                }
            }
        } catch (Exception e) {
            throw new ClassNotFoundException(e.getMessage());
        }

        throw new ClassNotFoundException(name);
    
private final java.net.URL[]getExternalJars()
Returns an array of external jar files used by the project.

return
an array of OS-specific absolute file paths

        // get a java project from it
        IJavaProject javaProject = JavaCore.create(mJavaProject.getProject());
        
        IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();

        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); 
                    }

                    // get the IPath
                    IPath path = e.getPath();

                    // check the name ends with .jar
                    if (AndroidConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
                        boolean local = false;
                        IResource resource = wsRoot.findMember(path);
                        if (resource != null && resource.exists() &&
                                resource.getType() == IResource.FILE) {
                            local = true;
                            try {
                                oslibraryList.add(
                                        new File(resource.getLocation().toOSString()).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.toURL());
                                } catch (MalformedURLException mue) {
                                    // pass
                                }
                            }
                        }
                    }
                }
            }
        }

        return oslibraryList.toArray(new URL[oslibraryList.size()]);
    
private java.io.FilegetFile(java.io.File parent, java.lang.String[] segments, int index)
Returns the File matching the a certain path from a root {@link File}.

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

        // 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;
    
private java.lang.ClassloadClassFromJar(java.lang.String name)
Loads a class from the 3rd party jar present in the project

throws
ClassNotFoundException

        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);
        } finally {
            mInsideJarClassLoader = false;
        }