/*
 * ################################################################
 *
 * ProActive: The Java(TM) library for Parallel, Distributed,
 *            Concurrent computing with Security and Mobility
 *
 * Copyright (C) 1997-2005 INRIA/University of Nice-Sophia Antipolis
 * Contact: proactive@objectweb.org
 *
 * 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 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
 *
 *  Initial developer(s):               The ProActive Team
 *                        http://www.inria.fr/oasis/ProActive/contacts.html
 *  Contributor(s):
 *
 * ################################################################
 */
package org.objectweb.proactive.core.exceptions.manager;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;


/*
 * This is the nasty hack to bypass java checked exceptions
 */
/*
 * This interface is the entry-point to the thrower, an object implementing this
 * interface will be built by reflection. By calling the throwException() method
 * on this object, it will be possible to call the ASM generated code.
 */
interface Thrower {
    public void throwException(Throwable t);
}


public class ExceptionThrower {
    private static final String THROWER_CLASS_NAME = "TheActualExceptionThrower";
    private static final String THROWER_CLASS_PACKAGE = ExceptionThrower.class.getPackage()
                                                                              .getName();
    private static final String THROWER_CLASS_FULLNAME = THROWER_CLASS_PACKAGE +
        "." + THROWER_CLASS_NAME;
    private static final String THROWER_METHOD_NAME = "throwException";
    private static Thrower thrower = null;

    /* We load a class given its name and its binary representation */
    private static Class loadClass(String className, byte[] b)
        throws Exception {
        Class clazz = null;
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        Class cls = Class.forName("java.lang.ClassLoader");
        java.lang.reflect.Method method = cls.getDeclaredMethod("defineClass",
                new Class[] { String.class, byte[].class, int.class, int.class });

        /* protected method invocaton */
        method.setAccessible(true);
        try {
            Object[] args = new Object[] {
                    className, b, new Integer(0), new Integer(b.length)
                };
            clazz = (Class) method.invoke(loader, args);
        } finally {
            method.setAccessible(false);
        }
        return clazz;
    }

    /* The first time the mechanism is used, it has to initialize the thrower */
    private static void activate() {
        ClassWriter cw = new ClassWriter(false);
        CodeVisitor cv;

        cw.visit(Constants.V1_2, Constants.ACC_PUBLIC + Constants.ACC_SUPER,
            THROWER_CLASS_FULLNAME.replace('.', '/'), "java/lang/Object",
            new String[] { Thrower.class.getName().replace('.', '/') },
            "AutoGeneratedExceptionThrower.java");

        /* Default constructor */
        cv = cw.visitMethod(Constants.ACC_PUBLIC, "<init>", "()V", null, null);
        cv.visitVarInsn(Constants.ALOAD, 0);
        cv.visitMethodInsn(Constants.INVOKESPECIAL, "java/lang/Object",
            "<init>", "()V");
        cv.visitInsn(Constants.RETURN);
        cv.visitMaxs(1, 1);

        /* throwException() */
        cv = cw.visitMethod(Constants.ACC_PUBLIC, THROWER_METHOD_NAME,
                "(Ljava/lang/Throwable;)V", null, null);
        cv.visitVarInsn(Constants.ALOAD, 1);
        cv.visitInsn(Constants.ATHROW); // No Java checks !!!
        cv.visitMaxs(1, 2);

        cw.visitEnd();

        try {
            Class clazz = loadClass(THROWER_CLASS_FULLNAME, cw.toByteArray());
            thrower = (Thrower) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    synchronized static void throwException(Throwable t) {
        if (thrower == null) {
            activate();
        }

        if (thrower != null) {
            thrower.throwException(t);
        }
    }
}

@@ -1325,111 +1325,145 @@
 ort 
-org.objectweb.asm.ClassWriter;%0Aimport org.objectweb.asm.CodeVisitor;%0Aimport org.objectweb.asm.Constants
+javassist.ClassPool;%0Aimport javassist.CtClass;%0Aimport javassist.CtMethod;%0Aimport javassist.CtNewConstructor;%0Aimport javassist.CtNewMethod
 ;%0A%0A%0A
@@ -2365,16 +2365,767 @@
  null;%0A%0A
+    private static Class loadClassJavassist() %7B%0A        try %7B%0A            CtClass thrower = ClassPool.getDefault().makeClass(THROWER_CLASS_FULLNAME);%0A            thrower.addInterface(ClassPool.getDefault().get(Thrower.class.getName()));%0A            thrower.addConstructor(CtNewConstructor.defaultConstructor(thrower));%0A            CtMethod throwException = CtNewMethod.make(%22%22 +%0A                    %22public void throwException(Throwable t) %7B%22 +%0A                    %22    throw t;%7D%22, thrower);%0A            thrower.addMethod(throwException);%0A            thrower.writeFile();%0A            return loadClass(THROWER_CLASS_FULLNAME, thrower.toBytecode());%0A        %7D catch (Exception e) %7B%0A            e.printStackTrace();%0A        %7D%0A        return null;%0A    %7D%0A%0A
     /* W
@@ -4105,1088 +4105,59 @@
     
-ClassWriter cw = new ClassWriter(false);%0A        CodeVisitor cv;%0A%0A        cw.visit(Constants.V1_2, Constants.ACC_PUBLIC + Constants.ACC_SUPER,%0A            THROWER_CLASS_FULLNAME.replace('.', '/'), %22java/lang/Object%22,%0A            new String%5B%5D %7B Thrower.class.getName().replace('.', '/') %7D,%0A            %22AutoGeneratedExceptionThrower.java%22);%0A%0A        /* Default constructor */%0A        cv = cw.visitMethod(Constants.ACC_PUBLIC, %22%3Cinit%3E%22, %22()V%22, null, null);%0A        cv.visitVarInsn(Constants.ALOAD, 0);%0A        cv.visitMethodInsn(Constants.INVOKESPECIAL, %22java/lang/Object%22,%0A            %22%3Cinit%3E%22, %22()V%22);%0A        cv.visitInsn(Constants.RETURN);%0A        cv.visitMaxs(1, 1);%0A%0A        /* throwException() */%0A        cv = cw.visitMethod(Constants.ACC_PUBLIC, THROWER_METHOD_NAME,%0A                %22(Ljava/lang/Throwable;)V%22, null, null);%0A        cv.visitVarInsn(Constants.ALOAD, 1);%0A        cv.visitInsn(Constants.ATHROW); // No Java checks !!!%0A        cv.visitMaxs(1, 2);%0A%0A        cw.visitEnd();%0A%0A        try %7B%0A            Class clazz = loadClass(THROWER_CLASS_FULLNAME, cw.toByteArray()
+try %7B%0A            Class clazz = loadClassJavassist(
 );%0A 

Use javassist for the exception thrower, and be the first to play with Subversion in 2006 :-)