All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jingle.util.dydelegation.DelegationCreator Maven / Gradle / Ivy

package org.jingle.util.dydelegation;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.bcel.Constants;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BranchInstruction;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.INSTANCEOF;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;

/**
 * 
 * Delegation Creator
 *
 *
 * @author JianLu
 * @version 1.0 2004-10-29
 * @since 1.0
 */
public class DelegationCreator implements Constants {
    static final String DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME = "org.jingle.util.dydelegation.DelegationInvocationHandler";

    static long num = 0;

    private InstructionFactory _factory;

    private ConstantPoolGen _cp;

    private ClassGen _cg;

    private String className;

    private String targetName;

    private Method[] methods;
    
    private Constructor[] constructors;
    
    protected Class[] classes;

    protected Class[] sourceClasses;

    protected Class[] interfaces;
    
    /**
     * Constructor
     * @param targetClassName The name of the generated delegation class. If it is null, a system generated name will provided.
     * @param sourceClasses The classes to be delegated
     */
    public DelegationCreator(String targetClassName, Class[] sourceClasses) {
        this.sourceClasses = sourceClasses;
        analyseSourceClasses();
        validate();
        this.className = this.classes[0].getName();
        this.targetName = getTargetName(targetClassName, this.classes[0], this.interfaces);
        String[] interfaceNames = new String[interfaces.length];
        for (int i = 1; i <= interfaces.length; i++) {
            interfaceNames[i - 1] = interfaces[i - 1].getName();
        }
        this._cg = new ClassGen(targetName, this.className,
                    this.targetName + ".java", ACC_PUBLIC | ACC_SUPER,
                    interfaceNames);
        this._cp = this._cg.getConstantPool();
        this._factory = new InstructionFactory(this._cg, this._cp);
    }

    /**
     * Constructor
     * @param classes The classes to be delegated
     */
    public DelegationCreator(Class[] classes) {
        this(null, classes);
    }

    /**
     * Analyse the sourceClasses. Divide it into classes and interfaces
     *
     */
    private void analyseSourceClasses() {
        if (sourceClasses != null) {
            List interfaceList = new ArrayList();
            List classList = new ArrayList();
            for (int i = 1; i <= sourceClasses.length; i++) {
                if (sourceClasses[i - 1] == null)
                    throw new NullPointerException();
                if (sourceClasses[i - 1].isInterface()) {
                    if (!interfaceList.contains(sourceClasses[i - 1]))
                        interfaceList.add(sourceClasses[i - 1]);
                }
                else
                    classList.add(sourceClasses[i - 1]);
            }
            if (classList.size() == 0)
                classList.add(Object.class);
            if (!interfaceList.contains(Delegation.class))
                interfaceList.add(Delegation.class);
            classes = (Class[])classList.toArray(new Class[0]);
            interfaces = (Class[])interfaceList.toArray(new Class[0]);
        }
    }
    /**
     * Get the name of the generated delegation class.
     * @param targetClassName The name provided by the creator
     * @param clazz The class to be delegated
     * @param interfaces The interfaces to be delegated
     * @return Name of the generated delegation class.
     */
    protected static synchronized String getTargetName(String targetClassName,
            Class clazz, Class[] interfaces) {
        if (targetClassName == null) {
            String name = null;
            String classFullName = clazz.getName();
            if (classFullName.startsWith("java.")) {
                String className = classFullName.substring(classFullName.lastIndexOf('.') + 1);
                if (className.equals("Object"))
                    className = null;
                for (int i = 1; i <= interfaces.length; i++) {
                    Package pac = interfaces[i - 1].getPackage();
                    if (pac != null) {
	                    if (!pac.getName().startsWith("java.")) {
	                        if (className == null)
	                            name = pac.getName() + "." + "Delegation";
	                        else
	                            name = pac.getName() + "." + className + "_Delegation";
	                        break;
	                    }
                    }
                }
            }
            else
                name = clazz.getName() + "_Delegation";
            return name + "_" + (num++);
        }
        else {
            if (targetClassName.startsWith("java.")) {
                throw new IllegalArgumentException("Delegation class name can not start with java.");
            }
            return targetClassName;
        }
    }

    /**
     * Validate the arguments pass to creator
     */
    protected void validate() {
        if (classes == null)
            throw new NullPointerException();
        if (classes.length != 1)
            throw new IllegalArgumentException(
            "Can not generate delegation for more than one class");
        if (Delegation.class.isAssignableFrom(classes[0]))
            throw new IllegalArgumentException(
                    "Can not generate delegation for Delegation class");
        int modifier = classes[0].getModifiers();
        if (Modifier.isFinal(modifier))
            throw new IllegalArgumentException(
                    "Can not generate delegation for final class");
        try {
            Constructor[] allConstructors = classes[0].getDeclaredConstructors();
            List constructorList = new ArrayList();
            for(int i = 1; i <= allConstructors.length; i++) {
                modifier = allConstructors[i - 1].getModifiers();
                if (Modifier.isPublic(modifier) || Modifier.isProtected(modifier)) {
                    constructorList.add(allConstructors[i - 1]);
                }
            }
            constructors = (Constructor[]) constructorList.toArray(new Constructor[0]);
            if (constructors.length == 0)
                throw new Exception();
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "The class to be delegated should have a public/protected constructor");
        }
    }

    /**
     * Create delegation class
     * @return Delegation class
     */
    public Class create() {
        try {
            return create(null);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.toString());
        }
    }

    /**
     * Create delegation class
     * @param out Output the delegation class to this stream
     * @return Delegation class
     * @throws IOException If output the class to output stream failed
     */
    public Class create(OutputStream out) throws IOException {
        Class newClass = null;
        getMethods();
        createFields();

        createStaticBlock();
        createConstructors();
        createGetHandler();
        createSetHandler();
        createGetActualObject();
        createGetDelegatedObject();
        
        for (int i = 1; i <= methods.length; i++) {
            createMethod(methods[i - 1], i - 1);
        }
        if (out != null)
            _cg.getJavaClass().dump(out);
//        Repository.addClass(_cg.getJavaClass());
//        Verifier.main(new String[] { targetName });
//        Class2HTML c2h = new Class2HTML(_cg.getJavaClass(), "c:/temp/code-gen/");
        ClassLoader loader = new DelegationClassLoader(Delegation.class.getClassLoader(),
                _cg.getJavaClass().getBytes());
        try {
            newClass = Class.forName(targetName, true, loader);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return newClass;
    }

    /**
     * get All methods to be delegated
     *
     */
    protected void getMethods() {
        Method[] allMethods = classes[0].getMethods();
        allMethods = combineMethods(allMethods, getHierachyAbstractProtectedMethods(classes[0]));
        for (int i = 1; i <= interfaces.length; i++) {
            if (!interfaces[i - 1].equals(Delegation.class))
                allMethods = combineMethods(allMethods, interfaces[i -1].getMethods());
        }
        List qualifiedMethods = new ArrayList();
        for (int i = 1; i <= allMethods.length; i++) {
            if (allMethods[i - 1].getDeclaringClass() == Object.class) {
                String name = allMethods[i - 1].getName();
                if (name.equals("toString") || name.equals("hashCode")
                        || name.equals("equals"))
                    qualifiedMethods.add(allMethods[i - 1]);
            } else {
                int modifier = allMethods[i - 1].getModifiers();
                if (!Modifier.isStatic(modifier) && !Modifier.isFinal(modifier))
                    qualifiedMethods.add(allMethods[i - 1]);
            }
        }
        methods = (Method[]) qualifiedMethods.toArray(new Method[0]);

    }

    private void createFields() {
        FieldGen field;

        field = new FieldGen(0, new ObjectType(className), "bean", _cp);
        _cg.addField(field.getField());

        field = new FieldGen(0, new ObjectType(
                DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME), "handler", _cp);
        _cg.addField(field.getField());

        for (int i = 1; i <= methods.length; i++) {
            field = new FieldGen(ACC_STATIC, new ObjectType(
                    "java.lang.reflect.Method"), "m" + (i - 1), _cp);
            _cg.addField(field.getField());
        }
    }

    private void createStaticBlock() {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_STATIC, Type.VOID, Type.NO_ARGS,
                new String[] {}, "", targetName, il, _cp);
        InstructionHandle[] start_pc = new InstructionHandle[methods.length + 1];
        InstructionHandle[] end_pc = new InstructionHandle[methods.length];
        InstructionHandle[] handler_pc = new InstructionHandle[methods.length];
        BranchInstruction[] goto_pc = new BranchInstruction[methods.length];

        for (int i = 1; i <= methods.length; i++) {
            InstructionHandle ih = il.append(InstructionConstants.ACONST_NULL);
            il.append(_factory.createFieldAccess(targetName, "m" + (i - 1),
                    new ObjectType("java.lang.reflect.Method"),
                    Constants.PUTSTATIC));
        }

        for (int i = 1; i <= methods.length; i++) {
            start_pc[i - 1] = genForName(il, methods[i - 1].getDeclaringClass().getName());
            genGetMethod(il, methods[i - 1]);
            il.append(_factory.createFieldAccess(targetName, "m" + (i - 1),
                    new ObjectType("java.lang.reflect.Method"),
                    Constants.PUTSTATIC));
            genExHandler(il, end_pc, handler_pc, goto_pc, i - 1);
        }

        start_pc[methods.length] = il.append(InstructionFactory
                .createReturn(Type.VOID));
        for (int i = 1; i <= methods.length; i++)
            goto_pc[i - 1].setTarget(start_pc[i]);
        for (int i = 1; i <= methods.length; i++) {
            method.addExceptionHandler(start_pc[i - 1], end_pc[i - 1],
                    handler_pc[i - 1], new ObjectType("java.lang.Exception"));
        }
        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
    }

    private void createConstructors() {
        for(int i = 1; i <= constructors.length; i++) {
            InstructionList il = new InstructionList();
            Class[] paraClass = constructors[i - 1].getParameterTypes();
            Class[] exceptClass = constructors[i - 1].getExceptionTypes();
            Type[] paraTypes = new Type[paraClass.length + 1];
            String[] paraNames = new String[paraClass.length + 1];
            int stackIndex = 0;
            
            //method definition
            paraTypes[0] = Type.OBJECT;
            paraNames[0] = "arg0";
            for (int t = 1; t <= paraClass.length; t++) {
                paraTypes[t] = getType(paraClass[t - 1]);
                paraNames[t] = "arg" + t;
            }
            MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID,
                    paraTypes, paraNames, "", targetName, il, _cp);
            for (int t = 1; t <= exceptClass.length; t++) {
                method.addException(exceptClass[t - 1].getName());
            }

            il.append(InstructionFactory.createLoad(Type.OBJECT, stackIndex));
            stackIndex = stackIndex + getTypeSize(Type.OBJECT); //Index of first argument
            stackIndex = stackIndex + getTypeSize(Type.OBJECT); //Index of second argument
            for (int t = 1; t <= paraClass.length; t++) {
                if (paraClass[t - 1].isPrimitive())
                    il.append(InstructionFactory.createLoad(
                            getEqualType(paraClass[t - 1]), stackIndex));
                else {
                    il.append(InstructionFactory.createLoad(Type.OBJECT, stackIndex));
                }
                stackIndex = stackIndex + getTypeSize(paraTypes[t]);
            }
            Type[] superParaTypes = new Type[paraClass.length];
            System.arraycopy(paraTypes, 1, superParaTypes, 0, paraClass.length);
            il.append(_factory.createInvoke(className, "", Type.VOID,
                    superParaTypes, Constants.INVOKESPECIAL));

            il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
            il.append(InstructionConstants.ACONST_NULL);
            il.append(_factory.createFieldAccess(targetName, "handler",
                    new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                    Constants.PUTFIELD));
            il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
            il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
            il.append(_factory.createCheckCast(new ObjectType(className)));
            il.append(_factory.createFieldAccess(targetName, "bean",
                    new ObjectType(className), Constants.PUTFIELD));
            il.append(InstructionFactory.createReturn(Type.VOID));
            method.setMaxStack();
            method.setMaxLocals();
            _cg.addMethod(method.getMethod());
            il.dispose();
        }
    }

    private void createGetHandler() {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, new ObjectType(
                DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME), Type.NO_ARGS,
                new String[] {}, "_getInvocationHandler", targetName, il, _cp);

        InstructionHandle ih_0 = il.append(InstructionFactory.createLoad(
                Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        InstructionHandle ih_4 = il.append(InstructionFactory
                .createReturn(Type.OBJECT));
        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
    }

    private void createSetHandler() {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID,
                new Type[] { new ObjectType(
                        DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME) },
                new String[] { "arg0" }, "_setInvocationHandler", targetName,
                il, _cp);

        InstructionHandle ih_0 = il.append(InstructionFactory.createLoad(
                Type.OBJECT, 0));
        il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.PUTFIELD));
        InstructionHandle ih_5 = il.append(InstructionFactory
                .createReturn(Type.VOID));
        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
    }

    private InstructionHandle genForName(InstructionList il, Class clazz) {
        if (clazz.isPrimitive())
            return il.append(_factory.createFieldAccess(
                    getWrapperClassName(clazz), "TYPE", new ObjectType(
                            "java.lang.Class"), Constants.GETSTATIC));
        else {
            InstructionHandle ih = il.append(new PUSH(_cp,
                    getWrapperClassName(clazz)));
            il.append(_factory.createInvoke("java.lang.Class", "forName",
                    new ObjectType("java.lang.Class"),
                    new Type[] { Type.STRING }, Constants.INVOKESTATIC));
            return ih;
        }
    }

    private InstructionHandle genForName(InstructionList il, String className) {
        InstructionHandle ih = il.append(new PUSH(_cp, className));
        il.append(_factory.createInvoke("java.lang.Class", "forName",
                new ObjectType("java.lang.Class"), new Type[] { Type.STRING },
                Constants.INVOKESTATIC));
        return ih;
    }

    /**
     * Get the given class's wrapper class name
     * @param clazz The class to be wrapped
     * @return The class name of the wrapper class. If the class is primitive class, return its wrapper class, else return itself.
     */
    protected static String getWrapperClassName(Class clazz) {
        if (clazz == Boolean.TYPE)
            return Boolean.class.getName();
        if (clazz == Character.TYPE)
            return Character.class.getName();
        if (clazz == Byte.TYPE)
            return Byte.class.getName();
        if (clazz == Short.TYPE)
            return Short.class.getName();
        if (clazz == Integer.TYPE)
            return Integer.class.getName();
        if (clazz == Long.TYPE)
            return Long.class.getName();
        if (clazz == Float.TYPE)
            return Float.class.getName();
        if (clazz == Double.TYPE)
            return Double.class.getName();
        return clazz.getName();
    }

    /**
     * Get the method name of wrapper class which is used to change a wrapper object to its primitive value
     * @param clazz The primitive class
     * @return The method name
     */
    protected static String getWrapperClassMethod(Class clazz) {
        if (clazz == Boolean.TYPE)
            return "booleanValue";
        if (clazz == Character.TYPE)
            return "charValue";
        if (clazz == Byte.TYPE)
            return "byteValue";
        if (clazz == Short.TYPE)
            return "shortValue";
        if (clazz == Integer.TYPE)
            return "intValue";
        if (clazz == Long.TYPE)
            return "longValue";
        if (clazz == Float.TYPE)
            return "floatValue";
        if (clazz == Double.TYPE)
            return "doubleValue";
        return null;
    }

    private void genSetInitValue(InstructionList il, Class clazz,
            float value, int index) {
        if (clazz == Boolean.TYPE) {
            il.append(new PUSH(_cp, (int) value));
            il.append(InstructionFactory.createStore(Type.INT, index));
        } else if (clazz == Character.TYPE) {
            il.append(new PUSH(_cp, (int) value));
            il.append(InstructionFactory.createStore(Type.INT, index));
        } else if (clazz == Byte.TYPE) {
            il.append(new PUSH(_cp, (int) value));
            il.append(InstructionFactory.createStore(Type.INT, index));
        } else if (clazz == Short.TYPE) {
            il.append(new PUSH(_cp, (int) value));
            il.append(InstructionFactory.createStore(Type.INT, index));
        } else if (clazz == Integer.TYPE) {
            il.append(new PUSH(_cp, (int) value));
            il.append(InstructionFactory.createStore(Type.INT, index));
        } else if (clazz == Long.TYPE) {
            il.append(new PUSH(_cp, (long) value));
            il.append(InstructionFactory.createStore(Type.LONG, index));
        } else if (clazz == Float.TYPE) {
            il.append(new PUSH(_cp, value));
            il.append(InstructionFactory.createStore(Type.FLOAT, index));
        } else if (clazz == Double.TYPE) {
            il.append(new PUSH(_cp, (double) value));
            il.append(InstructionFactory.createStore(Type.DOUBLE, index));
        } else if (clazz == void.class) {
        } else {
            il.append(InstructionConstants.ACONST_NULL);
            il.append(InstructionFactory.createStore(Type.OBJECT, index));
        }
    }

    private void genGetMethod(InstructionList il, Method method) {
        il.append(new PUSH(_cp, method.getName()));
        Class[] params = method.getParameterTypes();
        il.append(new PUSH(_cp, params.length));
        il.append(_factory.createNewArray(new ObjectType("java.lang.Class"),
                (short) 1));
        for (int i = 1; i <= params.length; i++) {
            il.append(InstructionConstants.DUP);
            il.append(new PUSH(_cp, i - 1));
            genForName(il, params[i - 1]);
            il.append(InstructionConstants.AASTORE);
        }
        il.append(_factory.createInvoke("java.lang.Class", "getMethod",
                new ObjectType("java.lang.reflect.Method"), new Type[] {
                        Type.STRING,
                        new ArrayType(new ObjectType("java.lang.Class"), 1) },
                Constants.INVOKEVIRTUAL));
    }

    private void genExHandler(InstructionList il, InstructionHandle[] end_pc,
            InstructionHandle[] handler_pc, BranchInstruction[] goto_pc,
            int index) {
        goto_pc[index] = InstructionFactory.createBranchInstruction(
                Constants.GOTO, null);
        end_pc[index] = il.append(goto_pc[index]);
        handler_pc[index] = il.append(InstructionFactory.createStore(
                Type.OBJECT, 0));

    }

    private void createMethod(Method m, int index) {
        InstructionList il = new InstructionList();
        Class[] paraClass = m.getParameterTypes();
        Class[] exceptClass = m.getExceptionTypes();
        boolean[] defaultExceptCatch = getDefaultExceptCatch(exceptClass);
        Type[] paraTypes = new Type[paraClass.length];
        String[] paraNames = new String[paraClass.length];
        Class returnClass = m.getReturnType();
        Type returnType = getType(returnClass);
        InstructionHandle start_pc, end_pc;
        InstructionHandle[] handler_pc = new InstructionHandle[exceptClass.length];
        BranchInstruction goto_1 = null, goto_2 = null, goto_3 = null;
        String m_name = "m" + index;

        boolean skipOriginalCall = Modifier.isAbstract(m.getModifiers());
        
        //method definition
        for (int i = 1; i <= paraClass.length; i++) {
            paraTypes[i - 1] = getType(paraClass[i - 1]);
            paraNames[i - 1] = "arg" + (i - 1);
        }
        int goonIndex = getTypeSize(paraTypes) + 1;
        int retIndex = (returnClass == void.class) ? -1 : goonIndex + getTypeSize(Type.BOOLEAN);
        int throwableIndex = (retIndex == -1) ? goonIndex + getTypeSize(Type.BOOLEAN) : retIndex
                + getTypeSize(returnType);
        int exceptIndex = throwableIndex + getTypeSize(Type.OBJECT);

        MethodGen method = new MethodGen(getAccessFlag(m), returnType, paraTypes,
                paraNames, m.getName(), targetName, il, _cp);
        for (int i = 1; i <= exceptClass.length; i++) {
            method.addException(exceptClass[i - 1].getName());
        }
        //declare the local vars (goon and ret)
        genSetInitValue(il, Boolean.TYPE, 1, goonIndex);
        genSetInitValue(il, returnClass, 0, retIndex);
        genSetInitValue(il, Throwable.class, 0, throwableIndex);

        //if handler != null
        start_pc = il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        BranchInstruction ifnull_1 = InstructionFactory
                .createBranchInstruction(Constants.IFNULL, null);
        il.append(ifnull_1);

        //goon = handler.invokeBefore(bean, m0, new Object[] {...});
        InstructionHandle ih_11 = il.append(InstructionFactory.createLoad(
                Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "bean",
                new ObjectType(className), Constants.GETFIELD));
        il.append(_factory
                .createFieldAccess(targetName, m_name, new ObjectType(
                        "java.lang.reflect.Method"), Constants.GETSTATIC));
        genMethodArgumentArray(il, paraClass);
        il.append(_factory.createInvoke(
                DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME, "invokeBefore",
                Type.BOOLEAN, new Type[] { Type.OBJECT,
                        new ObjectType("java.lang.reflect.Method"),
                        new ArrayType(Type.OBJECT, 1) },
                Constants.INVOKEINTERFACE));
        il.append(InstructionFactory.createStore(Type.INT, goonIndex));

        //if (goon)
        InstructionHandle beyond_ifnull_1 = il.append(InstructionFactory
                .createLoad(Type.INT, goonIndex));
        BranchInstruction ifeq = InstructionFactory.createBranchInstruction(
                Constants.IFEQ, null);
        il.append(ifeq);
	
        InstructionHandle sub_start_pc = null;
        if (!skipOriginalCall) {
	        //ret = bean.doMethod(...);
	        sub_start_pc = il.append(InstructionFactory
	                .createLoad(Type.OBJECT, 0));
	        il.append(_factory.createFieldAccess(targetName, "bean",
	                new ObjectType(className), Constants.GETFIELD));
	        int stackIndex = getTypeSize(Type.OBJECT);
	        for (int i = 1; i <= paraClass.length; i++) {
	            if (paraClass[i - 1].isPrimitive())
	                il.append(InstructionFactory.createLoad(
	                        getEqualType(paraClass[i - 1]), stackIndex));
	            else {
	                //if equals, call bean.equals(getActualObject(obj))
	                if (m.getName().equals("equals") && (paraClass.length == 1) && (paraClass[0] == Object.class)) {
	        	        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
	        	        il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
	        	        il.append(_factory.createInvoke(targetName, "getActualObject", Type.OBJECT, new Type[] { Type.OBJECT }, Constants.INVOKESPECIAL));
	                } else
	                    il.append(InstructionFactory.createLoad(Type.OBJECT, stackIndex));
	            }
	            stackIndex = stackIndex + getTypeSize(paraTypes[i - 1]);
	        }
	        il.append(_factory.createInvoke(/* className */m.getDeclaringClass()
	                .getName(), m.getName(), returnType, paraTypes,
	                Constants.INVOKEVIRTUAL));
	        if (returnClass != void.class) {
	            if (returnClass.isPrimitive())
	                il.append(InstructionFactory.createStore(
	                        getEqualType(returnClass), retIndex));
	            else
	                il
	                        .append(InstructionFactory.createStore(Type.OBJECT,
	                                retIndex));
	        }
        } else {
            sub_start_pc = il.append(InstructionConstants.ACONST_NULL);
            il.append(InstructionFactory.createStore(Type.OBJECT, throwableIndex));
        }
            
        goto_1 = InstructionFactory.createBranchInstruction(Constants.GOTO,
                null);
        InstructionHandle sub_end_pc = il.append(goto_1);
        InstructionHandle sub_handler_pc = il.append(InstructionFactory
                .createStore(Type.OBJECT, exceptIndex));
        il.append(InstructionFactory.createLoad(Type.OBJECT, exceptIndex));
        il.append(InstructionFactory.createStore(Type.OBJECT, throwableIndex));
        //exception close
        method.addExceptionHandler(sub_start_pc, sub_end_pc, sub_handler_pc,
                new ObjectType("java.lang.Throwable"));
        
        //if (handler != null)
        InstructionHandle beyond_ifeq = il.append(InstructionFactory
                .createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        BranchInstruction ifnull_2 = InstructionFactory
                .createBranchInstruction(Constants.IFNULL, null);
        il.append(ifnull_2);

        //if (t != null)
        //    ret = ((Integer)handler.invokeAfter(bean, m4, new Object[] {...}, t)).intValue();
        il.append(InstructionFactory.createLoad(Type.OBJECT, throwableIndex));
        BranchInstruction ifnull_1_5 = InstructionFactory
                .createBranchInstruction(Constants.IFNULL, null);
        il.append(ifnull_1_5);

        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "bean",
                new ObjectType(className), Constants.GETFIELD));
        il.append(_factory
                .createFieldAccess(targetName, m_name, new ObjectType(
                        "java.lang.reflect.Method"), Constants.GETSTATIC));
        genMethodArgumentArray(il, paraClass);
        il.append(InstructionFactory.createLoad(Type.OBJECT, throwableIndex));
        il.append(_factory.createInvoke(
                DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME,
                "invokeAfterException", Type.OBJECT, new Type[] { Type.OBJECT,
                        new ObjectType("java.lang.reflect.Method"),
                        new ArrayType(Type.OBJECT, 1), new ObjectType("java.lang.Throwable") },
                Constants.INVOKEINTERFACE));
        if (returnClass != void.class) {
            if (returnClass.isPrimitive()) {
                String wrapperName = getWrapperClassName(returnClass);
                String wrapperMethodName = getWrapperClassMethod(returnClass);
                il
                        .append(_factory.createCheckCast(new ObjectType(
                                wrapperName)));
                il.append(_factory.createInvoke(wrapperName, wrapperMethodName,
                        returnType, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
                il.append(InstructionFactory.createStore(
                        getEqualType(returnClass), retIndex));
            } else {
                il.append(_factory.createCheckCast((ReferenceType) returnType));
                il
                        .append(InstructionFactory.createStore(Type.OBJECT,
                                retIndex));
            }
        } else {
            il.append(InstructionConstants.POP);
        }
        goto_2 = InstructionFactory.createBranchInstruction(Constants.GOTO,
                null);
        il.append(goto_2);

        //else
        //    ret = ((Integer)handler.invokeAfter(bean, m4, new Object[] {...}, new
        //          Integer(ret))).intValue();
        InstructionHandle else_ih = il.append(InstructionFactory.createLoad(
                Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "handler",
                new ObjectType(DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME),
                Constants.GETFIELD));
        il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "bean",
                new ObjectType(className), Constants.GETFIELD));
        il.append(_factory
                .createFieldAccess(targetName, m_name, new ObjectType(
                        "java.lang.reflect.Method"), Constants.GETSTATIC));
        genMethodArgumentArray(il, paraClass);
        if (returnClass == void.class) {
            il.append(InstructionConstants.ACONST_NULL);
            il.append(_factory.createInvoke(
                    DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME,
                    "invokeAfter", Type.OBJECT, new Type[] { Type.OBJECT,
                            new ObjectType("java.lang.reflect.Method"),
                            new ArrayType(Type.OBJECT, 1), Type.OBJECT },
                    Constants.INVOKEINTERFACE));
        } else if (returnClass.isPrimitive()) {
            String wrapperName = getWrapperClassName(returnClass);
            String wrapperMethodName = getWrapperClassMethod(returnClass);
            il.append(_factory.createNew(wrapperName));
            il.append(InstructionConstants.DUP);
            il.append(InstructionFactory.createLoad(getEqualType(returnClass),
                    retIndex));
            il.append(_factory.createInvoke(wrapperName, "", Type.VOID,
                    new Type[] { returnType }, Constants.INVOKESPECIAL));
            il.append(_factory.createInvoke(
                    DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME,
                    "invokeAfter", Type.OBJECT, new Type[] { Type.OBJECT,
                            new ObjectType("java.lang.reflect.Method"),
                            new ArrayType(Type.OBJECT, 1), Type.OBJECT },
                    Constants.INVOKEINTERFACE));
            il.append(_factory.createCheckCast(new ObjectType(wrapperName)));
            il.append(_factory.createInvoke(wrapperName, wrapperMethodName,
                    returnType, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
            il.append(InstructionFactory.createStore(getEqualType(returnClass),
                    retIndex));
        } else {
            il.append(InstructionFactory.createLoad(Type.OBJECT, retIndex));
            il.append(_factory.createInvoke(
                    DELEGATION_INVOCATION_HANDLER_INTERFACE_NAME,
                    "invokeAfter", Type.OBJECT, new Type[] { Type.OBJECT,
                            new ObjectType("java.lang.reflect.Method"),
                            new ArrayType(Type.OBJECT, 1), Type.OBJECT },
                    Constants.INVOKEINTERFACE));
            il.append(_factory.createCheckCast((ReferenceType) returnType));
            il.append(InstructionFactory.createStore(Type.OBJECT, retIndex));
        }

        //return ret;
        InstructionHandle beyond_ifnull_2 = null;
        end_pc = null;
        if (returnClass == void.class) {
            il.append(InstructionConstants.POP);
            goto_3 = InstructionFactory.createBranchInstruction(Constants.GOTO,
                    null);
            end_pc = il.append(goto_3);
        } else if (returnClass.isPrimitive()) {
            beyond_ifnull_2 = il.append(InstructionFactory.createLoad(
                    returnType, retIndex));
            end_pc = il.append(InstructionFactory.createReturn(returnType));
        } else {
            beyond_ifnull_2 = il.append(InstructionFactory.createLoad(
                    Type.OBJECT, retIndex));
            end_pc = il.append(InstructionFactory.createReturn(Type.OBJECT));
        }

        //exception handling
        for (int i = 1; i <= exceptClass.length; i++) {
            handler_pc[i - 1] = il.append(InstructionFactory.createStore(
                    Type.OBJECT, exceptIndex));
            il.append(InstructionFactory.createLoad(Type.OBJECT, exceptIndex));
            il.append(InstructionConstants.ATHROW);
        }
        InstructionHandle runtime_pc = null;
        if (defaultExceptCatch[0]) {
            runtime_pc = il.append(InstructionFactory.createStore(Type.OBJECT,
                    exceptIndex));
            il.append(InstructionFactory.createLoad(Type.OBJECT, exceptIndex));
            il.append(InstructionConstants.ATHROW);
        }
        InstructionHandle error_pc = null;
        if (defaultExceptCatch[1]) {
            error_pc = il.append(InstructionFactory.createStore(Type.OBJECT,
                    exceptIndex));
            il.append(InstructionFactory.createLoad(Type.OBJECT, exceptIndex));
            il.append(InstructionConstants.ATHROW);
        }
        InstructionHandle throwable_pc = null;
        if (defaultExceptCatch[2]) {
            throwable_pc = il.append(InstructionFactory.createStore(
                    Type.OBJECT, exceptIndex));
            il
                    .append(_factory
                            .createNew("java.lang.reflect.UndeclaredThrowableException"));
            il.append(InstructionConstants.DUP);
            il.append(InstructionFactory.createLoad(Type.OBJECT, exceptIndex));
            il.append(_factory.createInvoke(
                    "java.lang.reflect.UndeclaredThrowableException", "",
                    Type.VOID, new Type[] { new ObjectType(
                            "java.lang.Throwable") }, Constants.INVOKESPECIAL));
            il.append(InstructionConstants.ATHROW);
        }

        if (returnClass == void.class) {
            beyond_ifnull_2 = il.append(InstructionFactory
                    .createReturn(Type.VOID));
        }

        //if statment close
        ifnull_1.setTarget(beyond_ifnull_1);
        ifeq.setTarget(beyond_ifeq);
        ifnull_1_5.setTarget(else_ih);
        ifnull_2.setTarget(beyond_ifnull_2);

        goto_1.setTarget(beyond_ifeq);
        goto_2.setTarget(beyond_ifnull_2);
        if (returnClass == void.class) {
            goto_3.setTarget(beyond_ifnull_2);
        }

        //exception close
//        method.addExceptionHandler(sub_start_pc, sub_end_pc, sub_handler_pc,
//                new ObjectType("java.lang.Throwable"));
        for (int i = 1; i <= exceptClass.length; i++) {
            method.addExceptionHandler(start_pc, end_pc, handler_pc[i - 1],
                    (ObjectType) getType(exceptClass[i - 1]));
        }
        if (defaultExceptCatch[0])
            method.addExceptionHandler(start_pc, end_pc, runtime_pc,
                    new ObjectType("java.lang.RuntimeException"));
        if (defaultExceptCatch[1])
            method.addExceptionHandler(start_pc, end_pc, error_pc,
                    new ObjectType("java.lang.Error"));
        if (defaultExceptCatch[2])
            method.addExceptionHandler(start_pc, end_pc, throwable_pc,
                    new ObjectType("java.lang.Throwable"));

        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
    }

    private boolean[] getDefaultExceptCatch(Class[] exceptClasses) {
        boolean[] ret = new boolean[] { true, true, true };
        for (int i = 1; i <= exceptClasses.length; i++) {
            if (exceptClasses[i - 1].equals(RuntimeException.class)) {
                ret[0] = false;
            } else if (exceptClasses[i - 1].equals(Error.class)) {
                ret[1] = false;
            } else if (exceptClasses[i - 1].equals(Throwable.class)) {
                ret[2] = false;
                ret[1] = false;
                ret[0] = false;
                break;
            }
        }
        return ret;
    }

    /**
     * Get the size of the Type
     * @param type BCEL Type
     * @return Type size
     */
    protected static int getTypeSize(Type type) {
        if ((type == Type.LONG) || (type == Type.DOUBLE))
            return 2;
        if (type == Type.VOID)
            return 0;
        return 1;
    }

    /**
     * Get the size of the Type array
     * @param types Type array
     * @return Size of type array
     */
    protected static int getTypeSize(Type[] types) {
        int ret = 0;
        for (int i = 1; i <= types.length; i++) {
            ret = ret + getTypeSize(types[i - 1]);
        }
        return ret;
    }

    /**
     * Change class to BCEL Type
     * @param clazz Java class
     * @return BCEL Type
     */
    protected static Type getType(Class clazz) {
        if (clazz == Boolean.TYPE)
            return Type.BOOLEAN;
        if (clazz == Character.TYPE)
            return Type.CHAR;
        if (clazz == Byte.TYPE)
            return Type.BYTE;
        if (clazz == Short.TYPE)
            return Type.SHORT;
        if (clazz == Integer.TYPE)
            return Type.INT;
        if (clazz == Long.TYPE)
            return Type.LONG;
        if (clazz == Float.TYPE)
            return Type.FLOAT;
        if (clazz == Double.TYPE)
            return Type.DOUBLE;
        if (clazz == void.class)
            return Type.VOID;
        if (clazz.isArray())
            return getArrayType(clazz);
        return new ObjectType(clazz.getName());
    }

    /**
     * Get the array type for a specific class
     * @param clazz Java class
     * @return BCEL Array type
     */
    protected static Type getArrayType(Class clazz) {
        Class componentClass = clazz;
        int dim = 0;
        while (componentClass.isArray()) {
            dim++;
            componentClass = componentClass.getComponentType();
        }
        return new ArrayType(getType(componentClass), dim);
    }

    /**
     * Get a specific class's equal type
     * @param clazz Java class
     * @return BCEL Type
     */
    protected static Type getEqualType(Class clazz) {
        if (clazz == Boolean.TYPE)
            return Type.INT;
        if (clazz == Character.TYPE)
            return Type.INT;
        if (clazz == Byte.TYPE)
            return Type.INT;
        if (clazz == Short.TYPE)
            return Type.INT;
        if (clazz == Integer.TYPE)
            return Type.INT;
        if (clazz == Long.TYPE)
            return Type.LONG;
        if (clazz == Float.TYPE)
            return Type.FLOAT;
        if (clazz == Double.TYPE)
            return Type.DOUBLE;
        if (clazz == void.class)
            return Type.VOID;
        return new ObjectType(clazz.getName());
    }

    private void genMethodArgumentArray(InstructionList il, Class[] paraClass) {
        il.append(new PUSH(_cp, paraClass.length));
        il.append(_factory.createNewArray(Type.OBJECT, (short) 1));
        int pos = 1;
        for (int i = 1; i <= paraClass.length; i++) {
            Type type = getType(paraClass[i - 1]);
            il.append(InstructionConstants.DUP);
            il.append(new PUSH(_cp, i - 1));
            if (paraClass[i - 1].isPrimitive()) {
                String wrapperName = getWrapperClassName(paraClass[i - 1]);
                il.append(_factory.createNew(wrapperName));
                il.append(InstructionConstants.DUP);
                il.append(InstructionFactory.createLoad(type, pos));
                il.append(_factory
                        .createInvoke(wrapperName, "", Type.VOID,
                                new Type[] { type }, Constants.INVOKESPECIAL));
            } else {
                il.append(InstructionFactory.createLoad(Type.OBJECT, pos));
            }
            il.append(InstructionConstants.AASTORE);
            pos = pos + getTypeSize(type);
        }
    }
    
    private static Method[] combineMethods(Method[] array1, Method[] array2) {
        List methods = new ArrayList();
        for (int i = 1; i <= array1.length; i++) {
            methods.add(array1[i - 1]);
        }
        for (int i = 1; i <= array2.length; i++) {
            boolean find = false;
            for (int j = 1; j <= array1.length; j++) {
                if (equals(array1[j - 1], array2[i - 1])) {
                    find = true;
                    break;
                }
            }
            if (!find)
                methods.add(array2[i - 1]);
        }
        return (Method[])methods.toArray(new Method[0]);
    }
    
    private static Method[] getHierachyAbstractProtectedMethods(Class clazz) {
        List ret = new ArrayList();
        List superLink = new ArrayList();
        while (clazz != null) {
            superLink.add(0, clazz);
            clazz = clazz.getSuperclass();
        }
        
        for (int i = 1; i <= superLink.size(); i++) {
            getAbstractProtectedMethods((Class)superLink.get(i - 1), ret);
        }
        return (Method[]) ret.toArray(new Method[0]);
    }

    private static void getAbstractProtectedMethods(Class clazz, List abMethods) {
        Method[] methods = clazz.getDeclaredMethods();
        for (int i = 1; i <= methods.length; i++) {
            int modifier = methods[i - 1].getModifiers();
            if (Modifier.isAbstract(modifier) && Modifier.isProtected(modifier))
                abMethods.add(methods[i - 1]);
            else if (!Modifier.isAbstract(modifier) && !Modifier.isStatic(modifier) && !Modifier.isPrivate(modifier)) {
                Iterator it = abMethods.iterator();
                while(it.hasNext()) {
                    Method m = (Method)it.next();
                    if (equals(methods[i - 1], m)) {
                        it.remove();
                        break;
                    }
                }
            }
        }
    }

    private static boolean equals(Method m1, Method m2) {
        if (m1.getName().equals(m2.getName()) && Arrays.equals(m1.getParameterTypes(), m2.getParameterTypes()))
            return true;
        return false;
    }
    
    private void createGetActualObject() {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PRIVATE, Type.OBJECT, new Type[] { Type.OBJECT }, new String[] { "arg0" }, "getActualObject", targetName, il, _cp);

        InstructionHandle ih_0 = il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
        il.append(new INSTANCEOF(_cp.addClass(new ObjectType("org.jingle.util.dydelegation.Delegation"))));
            BranchInstruction ifeq_4 = InstructionFactory.createBranchInstruction(Constants.IFEQ, null);
        il.append(ifeq_4);
        InstructionHandle ih_7 = il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
        il.append(_factory.createCheckCast(new ObjectType("org.jingle.util.dydelegation.Delegation")));
        il.append(_factory.createInvoke("org.jingle.util.dydelegation.Delegation", "_getDelegatedObject", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEINTERFACE));
        il.append(InstructionFactory.createReturn(Type.OBJECT));
        InstructionHandle ih_17 = il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
        InstructionHandle ih_18 = il.append(InstructionFactory.createReturn(Type.OBJECT));
        ifeq_4.setTarget(ih_17);
        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
      }

    private void createGetDelegatedObject() {
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(ACC_PUBLIC, Type.OBJECT, Type.NO_ARGS, new String[] {  }, "_getDelegatedObject", targetName, il, _cp);

        InstructionHandle ih_0 = il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createFieldAccess(targetName, "bean", new ObjectType(className), Constants.GETFIELD));
        InstructionHandle ih_4 = il.append(InstructionFactory.createReturn(Type.OBJECT));
        method.setMaxStack();
        method.setMaxLocals();
        _cg.addMethod(method.getMethod());
        il.dispose();
    }
    
    private static short getAccessFlag(Method m) {
        int modifier = m.getModifiers();
        if (Modifier.isPublic(modifier))
            return ACC_PUBLIC;
        else if (Modifier.isProtected(modifier))
            return ACC_PROTECTED;
        else
            return ACC_PRIVATE;
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy