/**************************************************************************************
 * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved.                 *
 * http://aspectwerkz.codehaus.org                                                    *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the QPL license       *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package org.codehaus.aspectwerkz.hook.impl;

import sun.misc.Resource;
import sun.misc.URLClassPath;

import java.net.URLClassLoader;
import java.net.URL;
import java.io.IOException;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper;

/**
 * Very basic classloader that do online weaving.
 *
 * This classloader can be used thru several means
 * <ul>
 *  <li>as a URLClassLoader in a custom development</li>
 *  <li>as a <i>MainClass</i> to allow on the fly weaving (without support for classloader hierarchy)</li>
 * </ul>
 * It can also be used for debugging step by step in any IDE
 *
 * @todo rewrite based on SUN src (definePackage missing)
 *
 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
 */
public class WeavingClassLoader extends URLClassLoader {

    public WeavingClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    protected Class findClass(String name) throws ClassNotFoundException {
        String path = name.replace('.', '/').concat(".class");
        Resource res = new URLClassPath(getURLs()).getResource(path, false);
        if (res != null) {
            //definePackage(name.substring(0, name.lastIndexOf(".")), null, null);
            try {
                byte[] b = res.getBytes();
                byte[] transformed = ClassPreProcessorHelper.defineClass0Pre(this, name, b, 0, b.length, null);
                return defineClass(name, transformed, 0, transformed.length);
            }
            catch (IOException e) {
                throw new ClassNotFoundException(e.getMessage());
            }
        }
        else {
            throw new ClassNotFoundException(name);
        }
    }

    public static void main(String args[]) throws Exception {
        String path = System.getProperty("java.class.path");
        ArrayList paths = new ArrayList();
        StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
        while (st.hasMoreTokens()) {
            paths.add((new File(st.nextToken())).getCanonicalFile().toURL());
        }

        //System.setProperty("aspectwerkz.transform.verbose", "yes");
        //System.setProperty("aspectwerkz.transform.dump", "*");
        //System.setProperty("aspectwerkz.definition.file", "...");
        //@todo check child of extension classloader instead of boot classloader
        ClassLoader cl = new WeavingClassLoader((URL[])paths.toArray(new URL[]{}), ClassLoader.getSystemClassLoader().getParent());

        Thread.currentThread().setContextClassLoader(cl);
        String s = args[0];
        String args1[] = new String[args.length - 1];
        if (args1.length > 0)
            System.arraycopy(args, 1, args1, 0, args.length - 1);
        Class class1 = cl.loadClass(s);
        Method method = class1.getMethod("main", new Class[]{String[].class});
        method.invoke(null, new Object[]{args1});
    }

}
