Package org.drools.compiler.builder.impl

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

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.EnumDeclarationDescr;
import org.drools.compiler.lang.descr.ImportDescr;
import org.drools.compiler.lang.descr.PackageDescr;
import org.drools.compiler.lang.descr.TypeDeclarationDescr;
import org.drools.core.factmodel.ClassDefinition;
import org.drools.core.factmodel.FieldDefinition;
import org.drools.core.factmodel.traits.Thing;
import org.drools.core.factmodel.traits.Trait;
import org.drools.core.factmodel.traits.TraitFactory;
import org.drools.core.factmodel.traits.Traitable;
import org.drools.core.rule.TypeDeclaration;
import org.drools.core.util.ClassUtils;
import org.drools.core.util.asm.ClassFieldInspector;
import org.kie.api.io.Resource;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
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 TypeDeclarationBuilder {

    protected final KnowledgeBuilderImpl kbuilder;

    protected final Set<String> generatedTypes                = new HashSet<String>();

    protected TypeDeclarationCache classDeclarationExtractor;
    protected TypeDeclarationNameResolver typeDeclarationNameResolver;
    protected TypeDeclarationFactory typeDeclarationFactory;
    protected ClassDefinitionFactory classDefinitionFactory;
    protected TypeDeclarationConfigurator typeDeclarationConfigurator;
    protected DeclaredClassBuilder declaredClassBuilder;

    TypeDeclarationBuilder(KnowledgeBuilderImpl kbuilder) {
        this.kbuilder = kbuilder;
        this.classDeclarationExtractor = new TypeDeclarationCache( kbuilder );
        this.typeDeclarationNameResolver = new TypeDeclarationNameResolver( kbuilder );
        this.typeDeclarationFactory = new TypeDeclarationFactory( kbuilder );
        this.classDefinitionFactory = new ClassDefinitionFactory( kbuilder );
        this.typeDeclarationConfigurator = new TypeDeclarationConfigurator( kbuilder );
        this.declaredClassBuilder = new DeclaredClassBuilder( kbuilder );
    }

    public TypeDeclaration getAndRegisterTypeDeclaration( Class<?> cls, String packageName ) {
        return classDeclarationExtractor.getAndRegisterTypeDeclaration( cls, packageName );
    }

    public TypeDeclaration getTypeDeclaration( Class<?> cls ) {
        return classDeclarationExtractor.getTypeDeclaration( cls );
    }

    public void removeTypesGeneratedFromResource( Resource resource ) {
        classDeclarationExtractor.removeTypesGeneratedFromResource( resource );
    }

    void registerGeneratedType(AbstractClassTypeDeclarationDescr typeDescr) {
        String fullName = typeDescr.getType().getFullName();
        generatedTypes.add(fullName);
    }



    /**********************************************************************************************************************************************************************
        1) Process the TypeDeclaration Descriptors
         Resolve names
         Normalize field descriptors
    **********************************************************************************************************************************************************************/



    public void processTypeDeclarations( Collection<? extends PackageDescr> packageDescrs,
                                         Collection<AbstractClassTypeDeclarationDescr> unsortedDescrs,
                                         List<TypeDefinition> unresolvedTypes,
                                         Map<String,AbstractClassTypeDeclarationDescr> unprocesseableDescrs ) {

        // init package to ensure type resolvers are available
        for ( PackageDescr packageDescr : packageDescrs ) {
            if ( kbuilder.getPackageRegistry( packageDescr.getName() ) == null ) {
                kbuilder.createPackageRegistry( packageDescr );
            }
        }

        setResourcesInDescriptors( packageDescrs );

        // ensure all names are fully qualified before continuing
        typeDeclarationNameResolver.resolveTypes( packageDescrs, unsortedDescrs, unresolvedTypes, unprocesseableDescrs );

        // create "implicit" packages
        for ( PackageDescr packageDescr : packageDescrs ) {
            normalizeForeignPackages( packageDescr );
        }

        // now sort declarations by mutual dependencies
        ClassHierarchyManager classHierarchyManager = new ClassHierarchyManager( unsortedDescrs, kbuilder );

        for ( AbstractClassTypeDeclarationDescr typeDescr : classHierarchyManager.getSortedDescriptors() ) {
            PackageRegistry pkgRegistry = kbuilder.getPackageRegistry( typeDescr.getNamespace() );
            createBean( typeDescr, pkgRegistry, classHierarchyManager, unresolvedTypes, unprocesseableDescrs );
        }

        for ( AbstractClassTypeDeclarationDescr typeDescr : classHierarchyManager.getSortedDescriptors() ) {
            if ( ! unprocesseableDescrs.containsKey( typeDescr.getType().getFullName() ) ) {
                PackageRegistry pkgRegistry = kbuilder.getPackageRegistry( typeDescr.getNamespace() );
                typeDeclarationConfigurator.wireFieldAccessors( pkgRegistry,
                                                                typeDescr,
                                                                pkgRegistry.getPackage().getTypeDeclaration( typeDescr.getType().getName() ) );
            }
        }
    }

    protected void setResourcesInDescriptors( Collection<? extends PackageDescr> packageDescrs ) {
        for ( PackageDescr packageDescr : packageDescrs ) {
            for ( AbstractClassTypeDeclarationDescr typeDescr : packageDescr.getClassAndEnumDeclarationDescrs() ) {
                if ( typeDescr.getResource() == null ) {
                    typeDescr.setResource( kbuilder.getCurrentResource() );
                }
            }
        }
    }

    protected void createBean( AbstractClassTypeDeclarationDescr typeDescr,
                             PackageRegistry pkgRegistry,
                             ClassHierarchyManager hierarchyManager,
                             List<TypeDefinition> unresolvedTypes,
                             Map<String,AbstractClassTypeDeclarationDescr> unprocesseableDescrs ) {

        //descriptor needs fields inherited from superclass
        if ( typeDescr instanceof TypeDeclarationDescr ) {
            hierarchyManager.inheritFields( pkgRegistry, typeDescr, hierarchyManager.getSortedDescriptors(), unresolvedTypes, unprocesseableDescrs );
        }

        TypeDeclaration type = typeDeclarationFactory.processTypeDeclaration( pkgRegistry,
                                                                              typeDescr,
                                                                              unresolvedTypes,
                                                                              unprocesseableDescrs );
        boolean success = ! kbuilder.hasErrors();

        try {
            // the type declaration is generated in any case (to be used by subclasses, if any)
            // the actual class will be generated only if needed
            ClassDefinition def = null;
            if ( success ) {
                def = classDefinitionFactory.generateDeclaredBean( typeDescr,
                                                                   type,
                                                                   pkgRegistry,
                                                                   unresolvedTypes,
                                                                   unprocesseableDescrs );

                // now use the definition to compare redeclarations, if any
                // this has to be done after the classDef has been generated
                if ( ! type.isNovel() ) {
                    typeDeclarationFactory.checkRedeclaration( typeDescr, type, pkgRegistry );
                }

            }
            success = ( def != null ) && ( ! kbuilder.hasErrors() );

            if ( success ) {
                updateTraitInformation( typeDescr, type, def, pkgRegistry );
            }
            success = ! kbuilder.hasErrors();

            if ( success ) {
                declaredClassBuilder.generateBeanFromDefinition( typeDescr,
                                                                 type,
                                                                 pkgRegistry,
                                                                 def );
            }
            success = ! kbuilder.hasErrors();

            if ( success ) {
                Class<?> clazz = pkgRegistry.getTypeResolver().resolveType( typeDescr.getType().getFullName() );
                type.setTypeClass( clazz );
                type.setValid( true );
            } else {
                unprocesseableDescrs.put( typeDescr.getType().getFullName(), typeDescr );
                type.setValid( false );
            }

            typeDeclarationConfigurator.finalize( type, typeDescr, pkgRegistry, kbuilder.getPackageRegistry(), hierarchyManager );

        } catch ( final ClassNotFoundException e ) {
            unprocesseableDescrs.put( typeDescr.getType().getFullName(), typeDescr );
            kbuilder.addBuilderResult(new TypeDeclarationError( typeDescr,
                                                                "Class '" + type.getTypeClassName() +
                                                                "' not found for type declaration of '" +
                                                                type.getTypeName() + "'" ) );
        }

        if ( ! success  ) {
            unresolvedTypes.add( new TypeDefinition( type, typeDescr ) );
        } else {
            registerGeneratedType( typeDescr );
        }
    }



    protected void normalizeForeignPackages( PackageDescr packageDescr ) {
        Map<String, PackageDescr> foreignPackages = null;

        for ( AbstractClassTypeDeclarationDescr typeDescr : packageDescr.getClassAndEnumDeclarationDescrs() ) {
            if ( kbuilder.filterAccepts(typeDescr.getNamespace(), typeDescr.getTypeName()) ) {

                if ( ! typeDescr.getNamespace().equals( packageDescr.getNamespace() ) ) {
                    // If the type declaration is for a different namespace, process that separately.
                    PackageDescr altDescr;

                    if ( foreignPackages == null ) {
                        foreignPackages = new HashMap<String, PackageDescr>(  );
                    }

                    if ( foreignPackages.containsKey( typeDescr.getNamespace() ) ) {
                        altDescr = foreignPackages.get( typeDescr.getNamespace() );
                    } else {
                        altDescr = new PackageDescr(typeDescr.getNamespace());
                        foreignPackages.put( typeDescr.getNamespace(), altDescr );
                    }

                    if (typeDescr instanceof TypeDeclarationDescr) {
                        altDescr.addTypeDeclaration((TypeDeclarationDescr) typeDescr);
                    } else if (typeDescr instanceof EnumDeclarationDescr) {
                        altDescr.addEnumDeclaration((EnumDeclarationDescr) typeDescr);
                    }

                    for (ImportDescr imp : packageDescr.getImports()) {
                        altDescr.addImport(imp);
                    }
                    if (!kbuilder.getPackageRegistry().containsKey(altDescr.getNamespace())) {
                        kbuilder.createPackageRegistry( altDescr );
                    }
                }
            }
        }
    }


    protected void updateTraitInformation( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type, ClassDefinition def, PackageRegistry pkgRegistry ) {
        if ( typeDescr.getAnnotation( Traitable.class.getSimpleName() ) != null
             || ( ! type.getKind().equals( TypeDeclaration.Kind.TRAIT ) &&
                  kbuilder.getPackageRegistry().containsKey( def.getSuperClass() ) &&
                  kbuilder.getPackageRegistry( def.getSuperClass() ).getTraitRegistry().getTraitables().containsKey( def.getSuperClass() )
        )) {
            // traitable
            if ( type.isNovel() ) {
                try {
                    PackageRegistry reg = kbuilder.getPackageRegistry( typeDescr.getNamespace() );
                    String availableName = typeDescr.getType().getFullName();
                    Class<?> resolvedType = reg.getTypeResolver().resolveType( availableName );
                    updateTraitDefinition( type,
                                           resolvedType,
                                           false );
                } catch ( ClassNotFoundException cnfe ) {
                    // we already know the class exists
                }
            }
            pkgRegistry.getTraitRegistry().addTraitable( def );
        } else if (type.getKind().equals(TypeDeclaration.Kind.TRAIT)
                   || typeDescr.getAnnotation(Trait.class.getSimpleName()) != null) {
            // trait
            if ( ! type.isNovel() ) {
                try {
                    PackageRegistry reg = kbuilder.getPackageRegistry(typeDescr.getNamespace());
                    String availableName = typeDescr.getType().getFullName();
                    Class<?> resolvedType = reg.getTypeResolver().resolveType(availableName);
                    if (!Thing.class.isAssignableFrom(resolvedType)) {
                        updateTraitDefinition( type,
                                               resolvedType,
                                               false );

                        String target = typeDescr.getTypeName() + TraitFactory.SUFFIX;
                        TypeDeclarationDescr tempDescr = new TypeDeclarationDescr();
                        tempDescr.setNamespace(typeDescr.getNamespace());
                        tempDescr.setFields(typeDescr.getFields());
                        tempDescr.setType(target,
                                          typeDescr.getNamespace());
                        tempDescr.addSuperType(typeDescr.getType());
                        TypeDeclaration tempDeclr = new TypeDeclaration(target);
                        tempDeclr.setKind(TypeDeclaration.Kind.TRAIT);
                        tempDeclr.setTypesafe(type.isTypesafe());
                        tempDeclr.setNovel(true);
                        tempDeclr.setTypeClassName(tempDescr.getType().getFullName());
                        tempDeclr.setResource(type.getResource());

                        ClassDefinition tempDef = new ClassDefinition(target);
                        tempDef.setClassName(tempDescr.getType().getFullName());
                        tempDef.setTraitable(false);
                        for ( FieldDefinition fld : def.getFieldsDefinitions() ) {
                            tempDef.addField(fld);
                        }
                        tempDef.setInterfaces(def.getInterfaces());
                        tempDef.setSuperClass(def.getClassName());
                        tempDef.setDefinedClass(resolvedType);
                        tempDef.setAbstrakt(true);
                        tempDeclr.setTypeClassDef(tempDef);

                        type.setKind(TypeDeclaration.Kind.CLASS);

                        declaredClassBuilder.generateBeanFromDefinition( tempDescr,
                                                                         tempDeclr,
                                                                         pkgRegistry,
                                                                         tempDef );
                        try {
                            Class<?> clazz = pkgRegistry.getTypeResolver().resolveType(tempDescr.getType().getFullName());
                            tempDeclr.setTypeClass(clazz);

                            pkgRegistry.getTraitRegistry().addTrait( tempDef.getClassName().replace( TraitFactory.SUFFIX,
                                                                                                     ""),
                                                                     tempDef );

                        } catch (ClassNotFoundException cnfe) {
                            kbuilder.addBuilderResult(new TypeDeclarationError( typeDescr,
                                                                                "Internal Trait extension Class '" + target +
                                                                                "' could not be generated correctly'" ) );
                        } finally {
                            pkgRegistry.getPackage().addTypeDeclaration(tempDeclr);
                        }

                    } else {
                        updateTraitDefinition( type,
                                               resolvedType,
                                               true );
                        pkgRegistry.getTraitRegistry().addTrait( def );
                    }
                } catch (ClassNotFoundException cnfe) {
                    // we already know the class exists
                }
            } else {
                if ( def.getClassName().endsWith( TraitFactory.SUFFIX ) ) {
                    pkgRegistry.getTraitRegistry().addTrait( def.getClassName().replace( TraitFactory.SUFFIX,
                                                                                         ""),
                                                             def );
                } else {
                    pkgRegistry.getTraitRegistry().addTrait( def );
                }
            }
        }
    }

    protected void updateTraitDefinition( TypeDeclaration type,
                                          Class concrete,
                                          boolean asTrait ) {
        classDefinitionFactory.populateDefinitionFromClass( type.getTypeClassDef(), concrete, asTrait );
    }

}
TOP

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

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.