org.boretti.drools.integration.drools5.DroolsAbstractMethodVisitor.java Source code

Java tutorial

Introduction

Here is the source code for org.boretti.drools.integration.drools5.DroolsAbstractMethodVisitor.java

Source

/*
Drools5 Integration Helper
Copyright (C) 2009  Mathieu Boretti mathieu.boretti@gmail.com
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program 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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
package org.boretti.drools.integration.drools5;

import org.boretti.drools.integration.drools5.annotations.DroolsPostCondition;
import org.boretti.drools.integration.drools5.annotations.DroolsPreCondition;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;

/**
 * @author mbo
 * @since 1.1.0
 */
abstract class DroolsAbstractMethodVisitor extends AdviceAdapter {

    private DroolsClassVisitor visitor;

    private String parent;

    /* (non-Javadoc)
     * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)
     */
    @Override
    public AnnotationVisitor visitAnnotation(String name, boolean arg1) {
        final AnnotationVisitor p = super.visitAnnotation(name, arg1);
        if (Type.getType(name).getClassName().equals(Type.getType(DroolsPreCondition.class).getClassName())) {
            havePreCondition = true;
            return new AnnotationVisitor() {

                @Override
                public void visit(String name, Object value) {
                    if (name.equals("resourceName"))
                        preResourceName = (String) value;
                    else if (name.equals("error"))
                        preError = (Type) value;
                }

                @Override
                public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
                    return this;
                }

                @Override
                public AnnotationVisitor visitArray(String name) {
                    return this;
                }

                @Override
                public void visitEnd() {
                    p.visitEnd();
                }

                @Override
                public void visitEnum(String name, String desc, String value) {
                    if (name.equals("type"))
                        preType = value;
                }

            };
        } else if (Type.getType(name).getClassName()
                .equals(Type.getType(DroolsPostCondition.class).getClassName())) {
            havePostCondition = true;
            return new AnnotationVisitor() {

                @Override
                public void visit(String name, Object value) {
                    if (name.equals("resourceName"))
                        postResourceName = (String) value;
                    else if (name.equals("error"))
                        postError = (Type) value;
                    else if (name.equals("onException"))
                        postOnException = (Boolean) value;
                }

                @Override
                public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
                    return this;
                }

                @Override
                public AnnotationVisitor visitArray(String name) {
                    return this;
                }

                @Override
                public void visitEnd() {
                    p.visitEnd();
                }

                @Override
                public void visitEnum(String name, String desc, String value) {
                    if (name.equals("type"))
                        postType = value;
                }

            };
        }
        return p;
    }

    private boolean havePreCondition = false;

    private String preResourceName = null;

    private String preType = null;

    private Type preError = null;

    private boolean havePostCondition = false;

    private String postResourceName = null;

    private String postType = null;

    private Type postError = null;

    private boolean postOnException = false;

    /* (non-Javadoc)
     * @see org.objectweb.asm.MethodAdapter#visitAnnotationDefault()
     */
    @Override
    public AnnotationVisitor visitAnnotationDefault() {
        return super.visitAnnotationDefault();
    }

    private DroolsGoalExecutionLog droolsGoalExecutionLog;

    private String name;

    private String desc;

    public DroolsAbstractMethodVisitor(MethodVisitor mv, int access, String name, String desc, String parent,
            DroolsClassVisitor visitor, DroolsGoalExecutionLog droolsGoalExecutionLog) {
        super(mv, access, name, desc);
        this.name = name;
        this.desc = desc;
        this.parent = parent;
        this.visitor = visitor;
        this.droolsGoalExecutionLog = droolsGoalExecutionLog;
    }

    /**
     * @return the havePreCondition
     */
    protected boolean isHavePreCondition() {
        return havePreCondition;
    }

    /**
     * @param havePreCondition the havePreCondition to set
     */
    protected void setHavePreCondition(boolean havePreCondition) {
        this.havePreCondition = havePreCondition;
    }

    private void addCondition(boolean preCondition, String type, String resourceName, Type error) {
        droolsGoalExecutionLog.getLogs()
                .add(new DroolsGoalExecutionLog(droolsGoalExecutionLog.getFileName(),
                        droolsGoalExecutionLog.getAction(), "Method instrumentalization for "
                                + ((preCondition) ? "pre" : "post") + "-condition " + name + "/" + desc));
        visitor.setMethodChange(true);
        Type types[] = Type.getArgumentTypes(super.methodDesc);
        //runPreCondition
        this.visitVarInsn(Opcodes.ALOAD, 0);
        this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getObjectType(parent).getInternalName(), "getClass",
                "()Ljava/lang/Class;");
        if (type == null)
            type = "COMPILED";
        this.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(DroolsServiceType.class), type,
                Type.getDescriptor(DroolsServiceType.class));
        this.visitLdcInsn(resourceName);
        this.visitLdcInsn(error);
        this.visitVarInsn(Opcodes.ALOAD, 0);
        this.visitIntInsn(Opcodes.BIPUSH, types.length);
        this.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
        int position = 1;
        for (int i = 0; i < types.length; i++) {
            this.visitInsn(Opcodes.DUP);
            this.visitIntInsn(Opcodes.BIPUSH, i);
            if (types[i].equals(Type.BOOLEAN_TYPE)) {
                this.visitVarInsn(Opcodes.ILOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Boolean.class), "valueOf",
                        "(Z)Ljava/lang/Boolean;");
                position += 1;
            } else if (types[i].equals(Type.BYTE_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Byte");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.ILOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Byte.class), "<init>", "(B)V");
                position += 1;
            } else if (types[i].equals(Type.CHAR_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Character");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.ILOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Character.class), "<init>",
                        "(C)V");
                position += 1;
            } else if (types[i].equals(Type.DOUBLE_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Double");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.DLOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Double.class), "<init>", "(D)V");
                position += 2;
            } else if (types[i].equals(Type.FLOAT_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Float");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.FLOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Float.class), "<init>", "(F)V");
                position += 1;
            } else if (types[i].equals(Type.INT_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Integer");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.ILOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Integer.class), "<init>", "(I)V");
                position += 1;
            } else if (types[i].equals(Type.LONG_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Long");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.LLOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Long.class), "<init>", "(J)V");
                position += 2;
            } else if (types[i].equals(Type.SHORT_TYPE)) {
                this.visitTypeInsn(Opcodes.NEW, "java/lang/Short");
                this.visitInsn(Opcodes.DUP);
                this.visitVarInsn(Opcodes.ILOAD, position);
                this.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Short.class), "<init>", "(S)V");
                position += 1;
            } else {
                this.visitVarInsn(Opcodes.ALOAD, position);
                position += 1;
            }
            this.visitInsn(Opcodes.AASTORE);
        }
        if (preCondition)
            this.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(DroolsProvider.class),
                    "runPreCondition",
                    "(Ljava/lang/Class;Lorg/boretti/drools/integration/drools5/DroolsServiceType;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)V");
        else
            this.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(DroolsProvider.class),
                    "runPostCondition",
                    "(Ljava/lang/Class;Lorg/boretti/drools/integration/drools5/DroolsServiceType;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)V");
    }

    /* (non-Javadoc)
     * @see org.objectweb.asm.commons.AdviceAdapter#onMethodEnter()
     */
    @Override
    protected void onMethodEnter() {
        if (isHavePreCondition())
            addCondition(true, preType, preResourceName, preError);
    }

    /* (non-Javadoc)
     * @see org.objectweb.asm.commons.AdviceAdapter#onMethodExit(int)
     */
    @Override
    protected void onMethodExit(int opcodes) {
        if (isHavePostCondition()) {
            if ((opcodes == Opcodes.ATHROW && postOnException) || opcodes != Opcodes.ATHROW)
                addCondition(false, postType, postResourceName, postError);
        }
    }

    /**
     * @return the havePostCondition
     */
    public boolean isHavePostCondition() {
        return havePostCondition;
    }

    /**
     * @param havePostCondition the havePostCondition to set
     */
    public void setHavePostCondition(boolean havePostCondition) {
        this.havePostCondition = havePostCondition;
    }
}