Package org.drools.core.factmodel

Source Code of org.drools.core.factmodel.DefaultEnumClassBuilder

/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.drools.core.factmodel;

import org.mvel2.asm.MethodVisitor;
import org.mvel2.asm.ClassWriter;
import org.mvel2.asm.FieldVisitor;
import org.mvel2.asm.Opcodes;
import org.mvel2.asm.Type;

import java.beans.IntrospectionException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;

import java.util.List;

import static org.drools.core.rule.builder.dialect.asm.ClassGenerator.createClassWriter;

/**
* A builder to dynamically build simple Javabean(TM) classes
*/
public class DefaultEnumClassBuilder implements Opcodes, EnumClassBuilder, Serializable {


    /**
     * Dynamically builds, defines and loads a class based on the given class definition
     *
     * @param classDef the class definition object structure
     *
     * @return the Class instance for the given class definition
     *
     * @throws java.io.IOException
     * @throws java.beans.IntrospectionException
     * @throws java.lang.reflect.InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws ClassNotFoundException
     * @throws IllegalArgumentException
     * @throws SecurityException
     * @throws NoSuchFieldException
     * @throws InstantiationException
     */
    public byte[] buildClass( ClassDefinition classDef, ClassLoader classLoader ) throws IOException,
            IntrospectionException,
            SecurityException,
            IllegalArgumentException,
            ClassNotFoundException,
            NoSuchMethodException,
            IllegalAccessException,
            InvocationTargetException,
            InstantiationException,
            NoSuchFieldException {

        if ( ! ( classDef instanceof EnumClassDefinition ) ) {
            throw new RuntimeException( "FATAL : Trying to create an enum out of a bean class definition  " + classDef );
        }

        EnumClassDefinition edef = (EnumClassDefinition) classDef;

        ClassWriter cw = this.buildClassHeader( classLoader, edef );

        this.buildLiterals(cw,
                edef);

        this.buildFields( cw,
                edef );


        this.buildConstructors( cw,
                edef );

        this.buildGettersAndSetters( cw,
                edef );

        this.buildEqualityMethods( cw,
                edef );

        this.buildToString( cw,
                edef );

        cw.visitEnd();

        byte[] serializedClass = cw.toByteArray();

        return serializedClass;
    }




    protected ClassWriter buildClassHeader(ClassLoader classLoader, EnumClassDefinition classDef) {
        return createClassWriter( classLoader,
                                  ACC_PUBLIC + ACC_FINAL + ACC_SUPER + ACC_ENUM,
                                  BuildUtils.getInternalType( classDef.getClassName() ),
                                  "Ljava/lang/Enum<" + BuildUtils.getTypeDescriptor( classDef.getClassName() ) + ">;",
                                  BuildUtils.getInternalType( classDef.getSuperClass() ),
                                  BuildUtils.getInternalTypes( classDef.getInterfaces() ) );
    }

    protected void buildLiterals(ClassWriter cw, EnumClassDefinition classDef) {
        FieldVisitor fv;
        for ( EnumLiteralDefinition lit : classDef.getEnumLiterals() ) {
            fv = cw.visitField( ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM,
                    lit.getName(),
                    BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    null,
                    null);
            fv.visitEnd();
        }

        {
            fv = cw.visitField( ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
                    "$VALUES",
                    "[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    null,
                    null);
            fv.visitEnd();
        }
    }


    protected void buildFields(ClassWriter cw, EnumClassDefinition classDef) {
        FieldVisitor fv;
        for ( FieldDefinition fld : classDef.getFieldsDefinitions() ) {
            fv = cw.visitField( ACC_PRIVATE + ACC_FINAL,
                    fld.getName(),
                    BuildUtils.getTypeDescriptor( fld.getTypeName() ),
                    null,
                    null);
            fv.visitEnd();
        }

        {
            fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, "$context", "Lorg/mvel2/ParserContext;", null, null);
            fv.visitEnd();
        }
    }


    protected void buildConstructors(ClassWriter cw, EnumClassDefinition classDef) throws IOException, ClassNotFoundException {
        MethodVisitor mv;
        String argTypes = "";
        int size = 0;
        for ( FieldDefinition fld : classDef.getFieldsDefinitions() ) {
            argTypes += BuildUtils.getTypeDescriptor( fld.getTypeName() );
            size += BuildUtils.sizeOf( fld.getTypeName() );
        }


        {
            int ofs = 3;

            mv = cw.visitMethod( ACC_PRIVATE,
                    "<init>",
                    "(Ljava/lang/String;I" + argTypes +")V",
                    "(" + argTypes + ")V",
                    null );
            mv.visitCode();
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitVarInsn( ALOAD, 1 );
            mv.visitVarInsn( ILOAD, 2 );
            mv.visitMethodInsn( INVOKESPECIAL,
                    "java/lang/Enum",
                    "<init>",
                    "(Ljava/lang/String;I)V" );
            for ( FieldDefinition fld : classDef.getFieldsDefinitions() ) {
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitVarInsn( BuildUtils.varType( fld.getTypeName() ), ofs );
                mv.visitFieldInsn( PUTFIELD,
                        BuildUtils.getInternalType( classDef.getName() ),
                        fld.getName(),
                        BuildUtils.getTypeDescriptor( fld.getTypeName() ) );
                ofs += BuildUtils.sizeOf( fld.getTypeName() );
            }
            mv.visitInsn( RETURN );
            mv.visitMaxs( 3, ofs );
            mv.visitEnd();
        }


        {


            mv = cw.visitMethod( ACC_STATIC,
                    "<clinit>",
                    "()V",
                    null,
                    null);
            mv.visitCode();

            int N = classDef.getEnumLiterals().size();

            mv.visitTypeInsn( NEW,
                    BuildUtils.getInternalType( classDef.getClassName() ) );

            for ( int j = 0; j < N; j++ ) {
                EnumLiteralDefinition lit = classDef.getEnumLiterals().get( j );
                mv.visitInsn( DUP );
                mv.visitLdcInsn( lit.getName() );
                BuildUtils.pushInt( mv, j );

                List<String> args = lit.getConstructorArgs();
                for ( int k = 0; k < args.size(); k++ ) {
                    String argType = classDef.getField( k ).getTypeName();

                    mv.visitLdcInsn( args.get( k ) );
                    mv.visitMethodInsn( INVOKESTATIC,
                            "org/mvel2/MVEL",
                            "eval",
                            "(Ljava/lang/String;)Ljava/lang/Object;");

                    if ( BuildUtils.isPrimitive( argType ) ) {
                        mv.visitTypeInsn( CHECKCAST,
                                BuildUtils.getInternalType( BuildUtils.box( argType ) ) );
                        mv.visitMethodInsn( INVOKEVIRTUAL,
                                BuildUtils.getInternalType( BuildUtils.box( argType ) ),
                                BuildUtils.numericMorph( BuildUtils.box( argType ) ),
                                "()" + BuildUtils.getTypeDescriptor( argType ) );
                    } else {
                        mv.visitTypeInsn( CHECKCAST,
                                BuildUtils.getInternalType( argType ) );
                    }
                }

                mv.visitMethodInsn( INVOKESPECIAL,
                        BuildUtils.getInternalType( classDef.getClassName() ),
                        "<init>",
                        "(Ljava/lang/String;I" + argTypes + ")V" );
                mv.visitFieldInsn(PUTSTATIC,
                        BuildUtils.getInternalType(classDef.getClassName()),
                        lit.getName(),
                        BuildUtils.getTypeDescriptor(classDef.getClassName()));
                mv.visitTypeInsn( NEW, BuildUtils.getInternalType( classDef.getClassName() ) );
            }


            BuildUtils.pushInt( mv, N );
            mv.visitTypeInsn( ANEWARRAY, BuildUtils.getInternalType( classDef.getClassName() ));

            for ( int j = 0; j < N; j++ ) {
                EnumLiteralDefinition lit = classDef.getEnumLiterals().get( j );
                mv.visitInsn(DUP);
                BuildUtils.pushInt( mv, j );
                mv.visitFieldInsn( GETSTATIC,
                        BuildUtils.getInternalType( classDef.getClassName() ),
                        lit.getName(),
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ) );
                mv.visitInsn(AASTORE);
            }


            mv.visitFieldInsn( PUTSTATIC,
                    BuildUtils.getInternalType( classDef.getClassName() ),
                    "$VALUES",
                    "[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ));

            mv.visitInsn( RETURN );
            mv.visitMaxs( 4 + size, 0 );
            mv.visitEnd();
        }



        {
            mv = cw.visitMethod( ACC_PUBLIC + ACC_STATIC,
                    "valueOf",
                    "(Ljava/lang/String;)" + BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    null,
                    null );
            mv.visitCode();
            mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( classDef.getClassName() ) ) );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitMethodInsn( INVOKESTATIC,
                    "java/lang/Enum",
                    "valueOf",
                    "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;" );
            mv.visitTypeInsn( CHECKCAST,
                    BuildUtils.getInternalType( classDef.getClassName() ) );
            mv.visitInsn( ARETURN );
            mv.visitMaxs( 2, 1 );
            mv.visitEnd();
        }
    }




    protected void buildGettersAndSetters(ClassWriter cw, EnumClassDefinition classDef) {
        MethodVisitor mv;
        {
            mv = cw.visitMethod( ACC_PUBLIC + ACC_STATIC,
                    "values",
                    "()[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    null,
                    null);
            mv.visitCode();
            mv.visitFieldInsn( GETSTATIC,
                    BuildUtils.getInternalType( classDef.getClassName() ),
                    "$VALUES",
                    "[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ) );
            mv.visitMethodInsn( INVOKEVIRTUAL,
                    "[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    "clone",
                    "()Ljava/lang/Object;" );
            mv.visitTypeInsn( CHECKCAST,
                    "[" + BuildUtils.getTypeDescriptor( classDef.getClassName() ) );
            mv.visitInsn( ARETURN );
            mv.visitMaxs( 1, 0 );
            mv.visitEnd();
        }

        for ( FieldDefinition fld : classDef.getFieldsDefinitions() ) {
            mv = cw.visitMethod( ACC_PUBLIC,
                    BuildUtils.getterName( fld.getName(), fld.getTypeName() ),
                    "()" + BuildUtils.getTypeDescriptor( fld.getTypeName() ),
                    null,
                    null );
            mv.visitCode();
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD,
                    BuildUtils.getInternalType( classDef.getName() ),
                    fld.getName(),
                    BuildUtils.getTypeDescriptor( fld.getTypeName() ) );
            mv.visitInsn( BuildUtils.returnType( fld.getTypeName() ) );
            mv.visitMaxs( BuildUtils.sizeOf( fld.getTypeName() ), 1 );
            mv.visitEnd();


            mv = cw.visitMethod( ACC_PUBLIC,
                    BuildUtils.setterName( fld.getName(), fld.getTypeName() ),
                    "(" + BuildUtils.getTypeDescriptor( fld.getTypeName() ) + ")V",
                    null,
                    null );
            mv.visitCode();
            mv.visitInsn( RETURN );
            mv.visitMaxs( 0, 1 + BuildUtils.sizeOf( fld.getTypeName() ) );
            mv.visitEnd();
        }



        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "get$context", "()Lorg/mvel2/ParserContext;", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, BuildUtils.getInternalType( classDef.getName() ), "$context", "Lorg/mvel2/ParserContext;");
            mv.visitInsn(ARETURN);
            mv.visitMaxs(1, 0);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "set$context", "(Lorg/mvel2/ParserContext;)V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(PUTSTATIC, BuildUtils.getInternalType( classDef.getName() ), "$context", "Lorg/mvel2/ParserContext;");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
    }

    protected void buildToString(ClassWriter cw, EnumClassDefinition classDef) {


    }

    protected void buildEqualityMethods(ClassWriter cw, ClassDefinition classDef) {


    }
}
TOP

Related Classes of org.drools.core.factmodel.DefaultEnumClassBuilder

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.