Package alt.jiapi.util

Source Code of alt.jiapi.util.InstrumentingClassLoader

/*
* Copyright (C) 2001 Mika Riekkinen, Joni Suominen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package alt.jiapi.util;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.log4j.Category;

import alt.jiapi.InstrumentationContext;
import alt.jiapi.Runtime;
import alt.jiapi.reflect.JiapiClass;
import alt.jiapi.JiapiException;

/**
* A sample ClassLoader which can be used when instrumenting Java
* applications. It knows how to load classes from CLASSPATH.
* <p>
* NOTE: Should the jar files found from jre/lib/ext
* (System.getProperty("java.ext.dirs")) also be added to search path?
*
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.5 $ $Date: 2004/08/04 08:58:04 $
*/
public class InstrumentingClassLoader extends URLClassLoader {
    private static Category log = Runtime.getLogCategory(InstrumentingClassLoader.class);

    protected Map classes;
    protected InstrumentationContext ctx;

    /**
     * Creates a new InstrumentingClassloader.
     */
    public static ClassLoader createClassLoader() {
        return createClassLoader((InstrumentationContext)null);
    }

    /**
     * Creates a new InstrumentingClassloader.
     */
    public static ClassLoader createClassLoader(InstrumentationContextProvider icp) throws JiapiException {
        return createClassLoader(icp.getInstrumentationContext());
    }

    /**
     * Creates a new InstrumentingClassloader.
     */
    public static ClassLoader createClassLoader(InstrumentationContextProvider icp, ClassLoader parent) throws JiapiException {
        return createClassLoader(icp.getInstrumentationContext(), parent);
    }

    /**
     * Creates a new InstrumentingClassloader.
     */
    public static ClassLoader createClassLoader(InstrumentationContext ctx) {
        return createClassLoader(ctx, getSystemClassLoader());
    }

    /**
     * Creates a new InstrumentingClassloader.
     */
    public static ClassLoader createClassLoader(InstrumentationContext ctx,
                                                ClassLoader parent) {
        URL urls[] = getClassPathUrls();
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkCreateClassLoader();
        }

//   System.out.println("Creating class loader with context " + ctx.getClass().getName() + ", " + ctx + ", parent: " + parent);

        return new InstrumentingClassLoader(ctx, urls, parent);
    }

    protected InstrumentingClassLoader(InstrumentationContext ctx, URL[] urls,
                                       ClassLoader parent) {
        super(urls, parent);
        this.ctx = ctx;

        classes = Collections.synchronizedMap(new HashMap());
    }

    protected synchronized Class loadClass(String className, boolean resolve)
        throws ClassNotFoundException {
        //System.out.println("Loading " + className);

        Class cl = null;
        JiapiClass jiapiClass = null;
        log.debug("loadClass(" + className + ")");
//         System.out.println("loadClass(" + className + ")");

        // Core Java classes and Jiapi classes are delegated to parent
        // class loader.
        if (className.startsWith("java.") || className.startsWith("javax.") ||
            className.startsWith("sun.") || className.startsWith("alt.jiapi.")) {
//       System.out.println("getParent().loadClass(" + className + ")" +
//     getParent());
            return getParent().loadClass(className);
        }

        if ((cl = (Class) classes.get(className)) == null) {
            log.debug("cache miss: " + className);
            // Check if we have permission to access the package.
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                int i = className.lastIndexOf('.');
                if (i != -1) {
                    sm.checkPackageAccess(className.substring(0, i));
                }
            }

            if (ctx == null) {
                return bootstrap(className);
            }
           
            // Locate the class as a resource.
            String path = className.replace('.', '/').concat(".class");
            URL location = super.findResource(path);

            if (location == null) {
                // Delagate to parent.

                return getParent().loadClass(className);
            }

            try {
                jiapiClass = ctx.getLoader().loadClass(className, location);
            }
            catch(java.io.IOException ioe) {
                throw new ClassNotFoundException(className);
            }

            ctx.instrument(jiapiClass);

            byte[] bytes = jiapiClass.getByteCode();

            if (System.getProperty("dump") != null) {
                try {
                    jiapiClass.dump(new java.io.FileOutputStream(jiapiClass.getName() + ".dump"));
                }
                catch(Throwable t) {
                }
            }

            if (bytes != null) {
                CodeSource cs = createCodeSource(location);
                cl = defineClass(className, bytes, 0, bytes.length, cs);
            }

            log.debug(cl + " was loaded with " + cl.getClassLoader());

            // Should we cache this or not.
            // Could there be a case, where we want to instrument
            // a class differently each time.
            // debug on, debug off...
            classes.put(className, cl);
        }

        if (resolve) {
            resolveClass(cl);
        }

        return cl;
    }

    /**
     * Form a CodeSource for loaded class.
     *
     * @param location a location where the class was loaded from
     */
    protected CodeSource createCodeSource(URL location) {
        Certificate []certs = null;
        if (location.getProtocol().equals("jar")) {
            try {
                JarURLConnection jarConnection =
                    (JarURLConnection) location.openConnection();

                certs = jarConnection.getCertificates();
                location = jarConnection.getJarFileURL();
            } catch (IOException ioe) {
                ioe.printStackTrace();
                throw new RuntimeException(ioe.getMessage());
            }
        }
       
        return new CodeSource(location, certs);
    }


    /**
     * Creates an array of URLs which are used for seaching classes.
     */
    private static URL []getClassPathUrls() {
        String string = System.getProperty("java.class.path");
        List urls = new ArrayList();
        if (string != null) {
            StringTokenizer st = new StringTokenizer(string,
                                                     File.pathSeparator);
           
            while (st.hasMoreTokens()) {
                try {
                    urls.add((new File(st.nextToken())).toURL());
                } catch (IOException ioe) {
                    // Don't mind... CLASSPATH is supplied by user
                    // and can easily contain spelling mistakes etc.
                }
            }
        }

        return ((URL []) urls.toArray(new URL[0]));
    }

    /**
     * Set the context for the ClassLoader.
     *
     * @param ctx an InstrumentationContext to be used
     */
    public void setContext(InstrumentationContext ctx) {
        this.ctx = ctx;
    }

    // should be private:
    public Class bootstrap(String className) throws ClassNotFoundException {
        String s = className.replace('.', '/') + ".class";
       
        return findClass(s);
    }

    // This method is used only for bootstrapping the class.
    byte [] byteBuffer = new byte[65000];
    public Class findClass(String name) throws ClassNotFoundException {
        log.debug("findClass(" + name + ")");
        Class c = null;
        //Class c = findClass(name);
        try {
            URL url = findResource(name);
            if (url == null) {
                throw new ClassNotFoundException(name);
            }

            java.io.InputStream is = url.openStream();
            int count = 0;
            while (is.available() > 0) {
                int elemsRead = is.read(byteBuffer, count, is.available());
                if (elemsRead == -1) {
                    break;
                }
                count += elemsRead;
            }

            c = defineClass(name.substring(0, name.lastIndexOf('.')),
                            byteBuffer, 0, count);
        }
        catch (java.io.IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException(name);
        }

        classes.put(c.getName(), c);
        return c;
    }
}
TOP

Related Classes of alt.jiapi.util.InstrumentingClassLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.