Package org.drools.compiler.builder.impl

Source Code of org.drools.compiler.builder.impl.ClassDefinitionFactory

package org.drools.compiler.builder.impl;

import org.drools.compiler.compiler.PackageRegistry;
import org.drools.compiler.compiler.TypeDeclarationError;
import org.drools.compiler.lang.descr.AbstractClassTypeDeclarationDescr;
import org.drools.compiler.lang.descr.AnnotationDescr;
import org.drools.compiler.lang.descr.EnumDeclarationDescr;
import org.drools.compiler.lang.descr.EnumLiteralDescr;
import org.drools.compiler.lang.descr.PatternDescr;
import org.drools.compiler.lang.descr.QualifiedName;
import org.drools.compiler.lang.descr.TypeDeclarationDescr;
import org.drools.compiler.lang.descr.TypeFieldDescr;
import org.drools.compiler.rule.builder.util.AnnotationFactory;
import org.drools.core.base.TypeResolver;
import org.drools.core.factmodel.AnnotationDefinition;
import org.drools.core.factmodel.ClassDefinition;
import org.drools.core.factmodel.EnumClassDefinition;
import org.drools.core.factmodel.EnumLiteralDefinition;
import org.drools.core.factmodel.FieldDefinition;
import org.drools.core.factmodel.traits.Thing;
import org.drools.core.factmodel.traits.Traitable;
import org.drools.core.factmodel.traits.TraitableBean;
import org.drools.core.rule.TypeDeclaration;
import org.drools.core.util.ClassUtils;
import org.drools.core.util.asm.ClassFieldInspector;
import org.kie.api.definition.type.Key;
import org.kie.api.definition.type.Position;

import java.io.Externalizable;
import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ClassDefinitionFactory {

    protected KnowledgeBuilderImpl kbuilder;

    public ClassDefinitionFactory( KnowledgeBuilderImpl kbuilder ) {
        this.kbuilder = kbuilder;
    }



    /**
     * Generates a bean, and adds it to the composite class loader that
     * everything is using.
     */
    public ClassDefinition generateDeclaredBean( AbstractClassTypeDeclarationDescr typeDescr,
                                                 TypeDeclaration type,
                                                 PackageRegistry pkgRegistry,
                                                 List<TypeDefinition> unresolvedTypeDefinitions,
                                                 Map<String,AbstractClassTypeDeclarationDescr> unprocesseableDescrs ) {

        ClassDefinition def = createClassDefinition( typeDescr, type );

        boolean success = true;
        success &= wireAnnotationDefs( typeDescr, type, def, pkgRegistry.getTypeResolver() );
        success &= wireEnumLiteralDefs( typeDescr, type, def );
        success &= wireFields( typeDescr, type, def, pkgRegistry, unresolvedTypeDefinitions );

        if ( ! success ) {
            unprocesseableDescrs.put( typeDescr.getType().getFullName(), typeDescr );
        }
        // attach the class definition, it will be completed later
        type.setTypeClassDef( def );

        return def;
    }

    protected ClassDefinition createClassDefinition( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type ) {
        // extracts type, supertype and interfaces
        String fullName = typeDescr.getType().getFullName();

        if ( type.getKind().equals( TypeDeclaration.Kind.CLASS ) ) {
            TypeDeclarationDescr tdescr = (TypeDeclarationDescr) typeDescr;
            if (tdescr.getSuperTypes().size() > 1) {
                kbuilder.addBuilderResult(new TypeDeclarationError( typeDescr, "Declared class " + fullName + "  - has more than one supertype;" ) );
                return null;
            } else if ( tdescr.getSuperTypes().isEmpty() ) {
                tdescr.addSuperType("java.lang.Object");
            }
        }

        Traitable traitableAnn = typeDescr.getTypedAnnotation(Traitable.class);
        boolean traitable = traitableAnn != null;

        String[] fullSuperTypes = new String[typeDescr.getSuperTypes().size() + 1];
        int j = 0;
        for (QualifiedName qname : typeDescr.getSuperTypes()) {
            fullSuperTypes[j++] = qname.getFullName();
        }
        fullSuperTypes[j] = Thing.class.getName();

        List<String> interfaceList = new ArrayList<String>();
        interfaceList.add(traitable ? Externalizable.class.getName() : Serializable.class.getName());
        if (traitable) {
            interfaceList.add(TraitableBean.class.getName());
        }
        String[] interfaces = interfaceList.toArray(new String[interfaceList.size()]);

        // prepares a class definition
        ClassDefinition def;
        switch ( type.getKind() ) {
            case TRAIT:
                def = new ClassDefinition( fullName,
                                           Object.class.getName(),
                                           fullSuperTypes );
                break;
            case ENUM:
                def = new EnumClassDefinition( fullName,
                                               fullSuperTypes[0],
                                               null );
                break;
            case CLASS:
            default:
                def = new ClassDefinition( fullName,
                                           fullSuperTypes[0],
                                           interfaces );
                def.setTraitable( traitable, traitableAnn != null && traitableAnn.logical() );
        }

        return def;
    }

    protected boolean wireAnnotationDefs( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type, ClassDefinition def, TypeResolver resolver ) {
        for ( AnnotationDescr annotationDescr : typeDescr.getAnnotations() ) {
            Class annotation = null;
            try {
                annotation = annotationDescr.getFullyQualifiedName() != null ? resolver.resolveType(annotationDescr.getFullyQualifiedName()) : null;
            } catch (ClassNotFoundException e) {
                continue;
            }

            if ( annotation != null && annotation.isAnnotation() ) {
                try {
                    AnnotationDefinition annotationDefinition = AnnotationDefinition.build( annotation,
                                                                                            annotationDescr.getValueMap(),
                                                                                            resolver );
                    def.addAnnotation(annotationDefinition);
                } catch (NoSuchMethodException nsme) {
                    kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr,
                                                                       "Annotated type " + typeDescr.getType().getFullName() +
                                                                       "  - undefined property in @annotation " +
                                                                       annotationDescr.getName() + ": " +
                                                                       nsme.getMessage() + ";"));
                }
            }
            if (annotation == null || annotation.getCanonicalName().startsWith("org.kie.api.definition.type")) {
                def.addMetaData(annotationDescr.getName(), annotationDescr.getSingleValue());
            }
        }
        return true;
    }

    protected boolean wireEnumLiteralDefs( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type, ClassDefinition def ) {
        // add enum literals, if appropriate
        if ( type.getKind() == TypeDeclaration.Kind.ENUM ) {
            for (EnumLiteralDescr lit : ((EnumDeclarationDescr) typeDescr).getLiterals()) {
                ( (EnumClassDefinition) def ).addLiteral(
                        new EnumLiteralDefinition( lit.getName(), lit.getConstructorArgs() )
                );
            }
        }
        return true;
    }

    protected boolean wireFields( AbstractClassTypeDeclarationDescr typeDescr,
                                  TypeDeclaration type,
                                  ClassDefinition def,
                                  PackageRegistry pkgRegistry,
                                  List<TypeDefinition> unresolvedTypeDefinitions ) {
        // fields definitions are created. will be used by subclasses, if any.
        // Fields are SORTED in the process
        if ( ! typeDescr.getFields().isEmpty() ) {
            if ( unresolvedTypeDefinitions != null && ! unresolvedTypeDefinitions.isEmpty() ) {
                for ( TypeFieldDescr fld : typeDescr.getFields().values() ) {
                    if ( unresolvedTypeDefinitions != null ) {
                        for ( TypeDefinition typeDef : unresolvedTypeDefinitions ) {
                            if ( fld.getPattern().getObjectType().equals( typeDef.getTypeClassName() ) ) {
                                return false;
                            }
                        }
                    }
                }
            }

            List<FieldDefinition> fieldDefs = sortFields( typeDescr.getFields(), pkgRegistry.getTypeResolver(), kbuilder );
            int i = 0;
            for (FieldDefinition fieldDef : fieldDefs) {
                fieldDef.setIndex( i++ );
                def.addField( fieldDef );
            }
        }
        return true;
    }

    private static List<FieldDefinition> sortFields( Map<String, TypeFieldDescr> fields,
                                                     TypeResolver typeResolver,
                                                     KnowledgeBuilderImpl kbuilder ) {
        List<FieldDefinition> fieldDefs = new ArrayList<FieldDefinition>(fields.size());
        int maxDeclaredPos = 0;
        BitSet occupiedPositions = new BitSet(fields.size());

        for (TypeFieldDescr field : fields.values()) {
            String typeName = field.getPattern().getObjectType();
            String typeNameKey = typeName;
            String fullFieldType = kbuilder != null ?
                                   TypeDeclarationUtils.toBuildableType( typeNameKey, kbuilder.getRootClassLoader() ) :
                                   typeNameKey;

            FieldDefinition fieldDef = new FieldDefinition( field.getFieldName(), fullFieldType );
            fieldDefs.add(fieldDef);

            fieldDef.setInherited( field.isInherited() );
            fieldDef.setRecursivefield.isRecursive() );
            fieldDef.setInitExpr( TypeDeclarationUtils.rewriteInitExprWithImports( field.getInitExpr(), typeResolver ) );

            if (field.getIndex() >= 0) {
                int pos = field.getIndex();
                occupiedPositions.set(pos);
                maxDeclaredPos = Math.max(maxDeclaredPos, pos);
                fieldDef.addMetaData("position", pos);
            } else {
                Position position = field.getTypedAnnotation(Position.class);
                if (position != null) {
                    int pos = position.value();
                    field.setIndex(pos);
                    occupiedPositions.set(pos);
                    maxDeclaredPos = Math.max(maxDeclaredPos, pos);
                    fieldDef.addMetaData("position", pos);
                }
            }

            if (field.hasAnnotation(Key.class)) {
                fieldDef.setKey( true );
                fieldDef.addMetaData("key", null);
            }

            if (typeResolver != null) {
                for (AnnotationDescr annotationDescr : field.getAnnotations()) {
                    if (annotationDescr.getFullyQualifiedName() == null) {
                        if (annotationDescr.isStrict()) {
                            kbuilder.addBuilderResult( new TypeDeclarationError( field,
                                                                                 "Unknown annotation @" + annotationDescr.getName() + " on field " + field.getFieldName() ) );
                        } else {
                            continue;
                        }
                    }
                    Annotation annotation = AnnotationFactory.buildAnnotation(typeResolver, annotationDescr);
                    if (annotation != null) {
                        try {
                            AnnotationDefinition annotationDefinition = AnnotationDefinition.build( annotation.annotationType(),
                                                                                                    field.getAnnotation(annotationDescr.getFullyQualifiedName()).getValueMap(),
                                                                                                    typeResolver );
                            fieldDef.addAnnotation( annotationDefinition );
                        } catch ( Exception e ) {
                            kbuilder.addBuilderResult( new TypeDeclarationError( field,
                                                                                 "Annotated field " + field.getFieldName() +
                                                                                 "  - undefined property in @annotation " +
                                                                                 annotationDescr.getName() + ": " + e.getMessage() + ";" ) );
                        }
                    } else {
                        if (annotationDescr.isStrict()) {
                            kbuilder.addBuilderResult(new TypeDeclarationError(field,
                                                                               "Unknown annotation @" + annotationDescr.getName() + " on field " + field.getFieldName()));
                        }
                    }
                }
            }

            fieldDef.setDeclIndex(field.getIndex());
        }

        int curr = 0;
        for (FieldDefinition fieldDef : fieldDefs) {
            if (fieldDef.getDeclIndex() < 0) {
                int freePos = occupiedPositions.nextClearBit(0);
                if (freePos < maxDeclaredPos) {
                    occupiedPositions.set(freePos);
                } else {
                    freePos = maxDeclaredPos + 1;
                }
                fieldDef.setPriority(freePos * 256 + curr++);
            } else {
                fieldDef.setPriority(fieldDef.getDeclIndex() * 256 + curr++);
            }
        }

        Collections.sort(fieldDefs);
        return fieldDefs;
    }

    public static void populateDefinitionFromClass( ClassDefinition def, Class<?> concrete, boolean asTrait ) {
        try {
            def.setClassName( concrete.getName() );
            if ( concrete.getSuperclass() != null ) {
                def.setSuperClass( concrete.getSuperclass().getName() );
            }

            ClassFieldInspector inspector = new ClassFieldInspector(concrete);
            Map<String, Method> methods = inspector.getGetterMethods();
            Map<String, Method> setters = inspector.getSetterMethods();
            int j = 0;
            Map<String,TypeFieldDescr> fields = new HashMap<String,TypeFieldDescr>();
            for ( String fieldName : methods.keySet() ) {
                if ( asTrait && ( "core".equals(fieldName) || "fields".equals(fieldName) ) ) {
                    continue;
                }
                if ( !inspector.isNonGetter( fieldName ) && setters.keySet().contains( fieldName ) ) {

                    Position position = null;
                    if ( ! concrete.isInterface() ) {
                        try {
                            Field fld = concrete.getDeclaredField( fieldName );
                            position = fld.getAnnotation( Position.class );
                        } catch ( NoSuchFieldException nsfe ) {
                            // @Position can only annotate fields. This x means that a getter/setter pair was found with no field
                        }
                    }

                    Class ret = methods.get( fieldName ).getReturnType();
                    TypeFieldDescr field = new TypeFieldDescr(  );
                    field.setFieldName( fieldName );
                    field.setPattern( new PatternDescr( ret.getName() ) );
                    field.setIndex( position != null ? position.value() : -1 );
                    fields.put( fieldName, field );
                }
            }
            if ( ! fields.isEmpty() ) {
                List<FieldDefinition> fieldDefs = sortFields( fields, null, null );
                int i = 0;
                for (FieldDefinition fieldDef : fieldDefs) {
                    fieldDef.setIndex( i++ );
                    def.addField( fieldDef );
                }
            }

            Set<String> interfaces = new HashSet<String>();
            Collections.addAll( interfaces, def.getInterfaces() );
            for ( Class iKlass : ClassUtils.getAllImplementedInterfaceNames( concrete ) ) {
                interfaces.add(iKlass.getName());
            }
            def.setInterfaces( interfaces.toArray( new String[ interfaces.size() ] ) );

            def.setDefinedClass( concrete );
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
TOP

Related Classes of org.drools.compiler.builder.impl.ClassDefinitionFactory

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.