Package org.drools.rule.builder.dialect.mvel

Source Code of org.drools.rule.builder.dialect.mvel.MVELDialect

package org.drools.rule.builder.dialect.mvel;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.drools.base.ClassFieldExtractorCache;
import org.drools.base.ModifyInterceptor;
import org.drools.base.TypeResolver;
import org.drools.base.mvel.MVELDebugHandler;
import org.drools.commons.jci.readers.MemoryResourceReader;
import org.drools.compiler.Dialect;
import org.drools.compiler.ImportError;
import org.drools.compiler.PackageBuilder;
import org.drools.compiler.RuleError;
import org.drools.lang.descr.AccumulateDescr;
import org.drools.lang.descr.AndDescr;
import org.drools.lang.descr.BaseDescr;
import org.drools.lang.descr.CollectDescr;
import org.drools.lang.descr.EvalDescr;
import org.drools.lang.descr.ExistsDescr;
import org.drools.lang.descr.ForallDescr;
import org.drools.lang.descr.FromDescr;
import org.drools.lang.descr.FunctionDescr;
import org.drools.lang.descr.NotDescr;
import org.drools.lang.descr.OrDescr;
import org.drools.lang.descr.PatternDescr;
import org.drools.lang.descr.QueryDescr;
import org.drools.lang.descr.RuleDescr;
import org.drools.rule.Declaration;
import org.drools.rule.LineMappings;
import org.drools.rule.Package;
import org.drools.rule.builder.AccumulateBuilder;
import org.drools.rule.builder.CollectBuilder;
import org.drools.rule.builder.ConsequenceBuilder;
import org.drools.rule.builder.ForallBuilder;
import org.drools.rule.builder.FromBuilder;
import org.drools.rule.builder.GroupElementBuilder;
import org.drools.rule.builder.PatternBuilder;
import org.drools.rule.builder.PredicateBuilder;
import org.drools.rule.builder.QueryBuilder;
import org.drools.rule.builder.ReturnValueBuilder;
import org.drools.rule.builder.RuleBuildContext;
import org.drools.rule.builder.RuleClassBuilder;
import org.drools.rule.builder.RuleConditionBuilder;
import org.drools.rule.builder.SalienceBuilder;
import org.drools.rule.builder.dialect.java.JavaDialect;
import org.drools.rule.builder.dialect.java.JavaFunctionBuilder;
import org.drools.spi.DeclarationScopeResolver;
import org.drools.spi.KnowledgeHelper;
import org.drools.util.StringUtils;
import org.mvel.AbstractParser;
import org.mvel.ExpressionCompiler;
import org.mvel.MVEL;
import org.mvel.ParserContext;
import org.mvel.optimizers.OptimizerFactory;
import org.mvel.util.ParseTools;

public class MVELDialect
    implements
    Dialect {

    public final static String                ID             = "mvel";

    private final static String               EXPRESSION_DIALECT_NAME = "MVEL";

    private final MVELRuleClassBuilder        rule                    = new MVELRuleClassBuilder();

    private final PatternBuilder              pattern                 = new PatternBuilder();
    private final QueryBuilder                query                   = new QueryBuilder();
    private final MVELAccumulateBuilder       accumulate              = new MVELAccumulateBuilder();
    private final SalienceBuilder             salience                = new MVELSalienceBuilder();
    private final MVELEvalBuilder             eval                    = new MVELEvalBuilder();
    private final MVELPredicateBuilder        predicate               = new MVELPredicateBuilder();
    private final MVELReturnValueBuilder      returnValue             = new MVELReturnValueBuilder();
    private final MVELConsequenceBuilder      consequence             = new MVELConsequenceBuilder();
    //private final JavaRuleClassBuilder            rule        = new JavaRuleClassBuilder();
    private final MVELFromBuilder             from                    = new MVELFromBuilder();
    private final JavaFunctionBuilder         function                = new JavaFunctionBuilder();
    private final CollectBuilder              collect                 = new CollectBuilder();
    private final ForallBuilder               forall                  = new ForallBuilder();

    private Map                               interceptors;

    private List                              results;
    //private final JavaFunctionBuilder             function    = new JavaFunctionBuilder();

    private MemoryResourceReader                    src;

    private Package                           pkg;
    private MVELDialectConfiguration          configuration;
    private TypeResolver                      typeResolver;
    private ClassFieldExtractorCache          classFieldExtractorCache;
    private MVELExprAnalyzer                  analyzer;

    private Map                               imports;
    private Map                               packageImports;

    private boolean                           strictMode;
   
    private static Boolean                           languageSet = new Boolean( false );

    public void addFunction(FunctionDescr functionDescr,
                            TypeResolver typeResolver) {
        throw new UnsupportedOperationException( "MVEL does not support functions" );

    }

    // a map of registered builders
    private Map builders;

    public MVELDialect() {
    }
   
    public static void setLanguageLevel(int level) {
        synchronized ( languageSet ) {
            // this synchronisation is needed as setLanguageLevel is now thread safe
            // and we do not want ot be calling this while something else is being parsed.
            // the flag ensures it is just called once and no more.
            if ( languageSet.booleanValue() == false ) {
                languageSet = new Boolean( true );
                AbstractParser.setLanguageLevel( level );
            }
        }
    }

    public void init(PackageBuilder builder) {
        setLanguageLevel( 4 );
        this.pkg = builder.getPackage();
        this.configuration = (MVELDialectConfiguration) builder.getPackageBuilderConfiguration().getDialectConfiguration( "mvel" );
        this.typeResolver = builder.getTypeResolver();
        this.classFieldExtractorCache = builder.getClassFieldExtractorCache();
        this.strictMode = this.configuration.isStrict();

        // we currently default to reflective optimisation
        OptimizerFactory.setDefaultOptimizer("reflective");
       
        MVEL.setThreadSafe( true );

        this.analyzer = new MVELExprAnalyzer();
        this.imports = new HashMap();
        this.packageImports = new HashMap();

        this.interceptors = new HashMap( 1 );
        this.interceptors.put( "Modify",
                               new ModifyInterceptor() );

        this.results = new ArrayList();

        if ( pkg != null ) {
            init( pkg );
        }

        initBuilder();
    }

    public void initBuilder() {
        // statically adding all builders to the map
        // but in the future we can move that to a configuration
        // if we want to
        this.builders = new HashMap();

        final GroupElementBuilder gebuilder = new GroupElementBuilder();

        this.builders.put( AndDescr.class,
                           gebuilder );

        this.builders.put( OrDescr.class,
                           gebuilder );

        this.builders.put( NotDescr.class,
                           gebuilder );

        this.builders.put( ExistsDescr.class,
                           gebuilder );

        this.builders.put( PatternDescr.class,
                           getPatternBuilder() );

        this.builders.put( FromDescr.class,
                           getFromBuilder() );

        this.builders.put( QueryDescr.class,
                           getQueryBuilder() );

        this.builders.put( AccumulateDescr.class,
                           getAccumulateBuilder() );

        this.builders.put( EvalDescr.class,
                           getEvalBuilder() );

        this.builders.put( CollectDescr.class,
                           this.collect );

        this.builders.put( ForallDescr.class,
                           this.forall );

        this.builders.put( FunctionDescr.class,
                           this.function );
   }

    public void init(Package pkg) {
        this.pkg = pkg;
        this.results = new ArrayList();
        this.src = new MemoryResourceReader();
        if( this.pkg != null ) {
            this.addImport( this.pkg.getName()+".*" );
        }
    }

    public void init(RuleDescr ruleDescr) {
        //MVEL:test null to Fix failing test on org.drools.rule.builder.dialect.mvel.MVELConsequenceBuilderTest.testImperativeCodeError()

        // @todo: why is this here, MVEL doesn't compile anything? mdp
        String pkgName = this.pkg == null? "": this.pkg.getName();
        final String ruleClassName = JavaDialect.getUniqueLegalName( pkgName,
                                       ruleDescr.getName(),
                                       "mvel",
                                       this.src );
        ruleDescr.setClassName( StringUtils.ucFirst( ruleClassName ) );
        ruleDescr.setDialect( this );
    }

    public String getExpressionDialectName() {
        return EXPRESSION_DIALECT_NAME;
    }

    public void addRule(RuleBuildContext context) {
      //MVEL: Compiler change
        final RuleDescr ruleDescr = context.getRuleDescr();

        // setup the line mappins for this rule
        final String name = this.pkg.getName() + "." + StringUtils.ucFirst( ruleDescr.getClassName() );
        final LineMappings mapping = new LineMappings( name );
        mapping.setStartLine( ruleDescr.getConsequenceLine() );
        mapping.setOffset( ruleDescr.getConsequenceOffset() );

        context.getPkg().getPackageCompilationData().getLineMappings().put( name, mapping );

    }

    public void addImport(String importEntry) {
        if ( importEntry.endsWith( ".*" ) ) {
            importEntry = importEntry.substring( 0, importEntry.length()-);
            this.packageImports.put( importEntry, importEntry );
        } else {
            try {
                Class cls = this.typeResolver.resolveType( importEntry );
                this.imports.put( ParseTools.getSimpleClassName( cls ), cls );
            } catch ( ClassNotFoundException e ) {
                this.results.add( new ImportError( importEntry, 1 ) );
            }
        }
    }

    public Map getImports() {
        return this.imports;
    }

    public Map getPackgeImports() {
        return this.packageImports;
    }

    public void addStaticImport(String staticImportEntry) {
        if ( staticImportEntry.endsWith( "*" ) ) {
            return;
        }

        int index = staticImportEntry.lastIndexOf( '.' );
        String className = staticImportEntry.substring( 0,
                                                        index );
        String methodName = staticImportEntry.substring( index + 1 );

        try {
            Class cls = this.pkg.getPackageCompilationData().getClassLoader().loadClass( className );
            Method[] methods = cls.getDeclaredMethods();
            for ( int i = 0; i < methods.length; i++ ) {
                if ( methods[i].getName().equals( methodName ) ) {
                    this.imports.put( methodName, methods[i] );
                    break;
                }
            }
        } catch ( ClassNotFoundException e ) {
            this.results.add( new ImportError( staticImportEntry, -1 ) );
        }
    }

    public boolean isStrictMode() {
        return strictMode;
    }

    public void setStrictMode(boolean strictMode) {
        this.strictMode = strictMode;
    }

    public void compileAll() {
    }

    public Dialect.AnalysisResult analyzeExpression(RuleBuildContext context,
                                                    BaseDescr descr,
                                                    Object content) {
        return analyzeExpression( context,
                                  descr,
                                  content,
                                  null );
    }

    public Dialect.AnalysisResult analyzeExpression(RuleBuildContext context,
                                                    BaseDescr descr,
                                                    Object content,
                                                    Map localTypes) {
        Dialect.AnalysisResult result = null;
        try {
            result = this.analyzer.analyzeExpression( context,
                                                      (String) content,
                                                      new Set[]{context.getDeclarationResolver().getDeclarations().keySet(), context.getPkg().getGlobals().keySet()},
                                                      localTypes );
        } catch ( final Exception e ) {
            context.getErrors().add( new RuleError( context.getRule(),
                                                    descr,
                                                    null,
                                                    "Unable to determine the used declarations.\n" + e.getMessage()) );
        }
        return result;
    }

    public Dialect.AnalysisResult analyzeBlock(RuleBuildContext context,
                                               BaseDescr descr,
                                               String text) {
        return analyzeBlock( context,
                             descr,
                             null,
                             text,
                             null );
    }

    public Dialect.AnalysisResult analyzeBlock(RuleBuildContext context,
                                               BaseDescr descr,
                                               Map interceptors,
                                               String text,
                                               Map localTypes) {
        Dialect.AnalysisResult result = null;
        try {
            result = this.analyzer.analyzeExpression( context,
                                                      text,
                                                      new Set[]{context.getDeclarationResolver().getDeclarations().keySet(), context.getPkg().getGlobals().keySet()},
                                                      localTypes );
        } catch ( final Exception e ) {
            context.getErrors().add( new RuleError( context.getRule(),
                                                    descr,
                                                    e,
                                                    "Unable to determine the used declarations.\n" + e.getMessage()) );
        }
        return result;
    }

    public Serializable compile(final String text,
                                final Dialect.AnalysisResult analysis,
                                final Map interceptors,
                                final Map outerDeclarations,
                                final RuleBuildContext context) {
        final ParserContext parserContext = getParserContext(analysis, outerDeclarations, context );

        ExpressionCompiler compiler = new ExpressionCompiler( text.trim() );

        if (MVELDebugHandler.isDebugMode()) {
          System.out.println("Source before MVEL Compilation:\n"+text.trim());
            compiler.setDebugSymbols( true );
        }

        Serializable expr = compiler.compile( parserContext );
        return expr;
    }

    public ParserContext getParserContext(final Dialect.AnalysisResult analysis, final Map outerDeclarations, final RuleBuildContext context) {
        final ParserContext parserContext = new ParserContext( this.imports,
                                                               null,
                                                               context.getPkg().getName()+"."+context.getRuleDescr().getClassName() );

        for ( Iterator it = this.packageImports.values().iterator(); it.hasNext(); ) {
            String packageImport = ( String ) it.next();
            parserContext.addPackageImport( packageImport );
        }

        parserContext.setStrictTypeEnforcement( strictMode );

        if ( interceptors != null ) {
            parserContext.setInterceptors( interceptors );
        }
        //FIXME: analysis can be null, throws an NPE
        List list[] = analysis.getBoundIdentifiers();
        DeclarationScopeResolver resolver = context.getDeclarationResolver();
        for ( Iterator it = list[0].iterator(); it.hasNext(); ) {
            String identifier = (String) it.next();
            Class cls = resolver.getDeclaration( identifier ).getExtractor().getExtractToClass();
            parserContext.addInput( identifier,
                                    cls );
        }

        Map globalTypes = context.getPkg().getGlobals();
        for ( Iterator it = list[1].iterator(); it.hasNext(); ) {
            String identifier = (String) it.next();
            parserContext.addInput( identifier,
                                    (Class) globalTypes.get( identifier ) );
        }

        Map mvelVars = ((MVELAnalysisResult) analysis).getMvelVariables();
        if ( mvelVars != null ) {
            for ( Iterator it = mvelVars.entrySet().iterator(); it.hasNext(); ) {
                Entry entry = (Entry) it.next();
                parserContext.addInput( (String) entry.getKey(),
                                        (Class) entry.getValue() );
            }
        }

        if ( outerDeclarations != null ) {
            for ( Iterator it = outerDeclarations.entrySet().iterator(); it.hasNext(); ) {
                Entry entry = (Entry) it.next();
                parserContext.addInput( (String) entry.getKey(),
                                        ((Declaration) entry.getValue()).getExtractor().getExtractToClass() );
            }
        }

        parserContext.addInput( "drools",
                                KnowledgeHelper.class );

        return parserContext;
    }

    public RuleConditionBuilder getBuilder(final Class clazz) {
        return (RuleConditionBuilder) this.builders.get( clazz );
    }

    public Map getBuilders() {
        return this.builders;
    }

    public ClassFieldExtractorCache getClassFieldExtractorCache() {
        return this.classFieldExtractorCache;
    }

    public PatternBuilder getPatternBuilder() {
        return this.pattern;
    }

    public QueryBuilder getQueryBuilder() {
        return this.query;
    }

    public AccumulateBuilder getAccumulateBuilder() {
        return this.accumulate;
    }

    public ConsequenceBuilder getConsequenceBuilder() {
        return this.consequence;
    }

    public RuleConditionBuilder getEvalBuilder() {
        return this.eval;
    }

    public FromBuilder getFromBuilder() {
        return this.from;
    }

    public PredicateBuilder getPredicateBuilder() {
        return this.predicate;
    }

    public PredicateBuilder getExpressionPredicateBuilder() {
        return this.predicate;
    }

    public SalienceBuilder getSalienceBuilder() {
        return this.salience;
    }

    public List getResults() {
        return results;
    }

    public ReturnValueBuilder getReturnValueBuilder() {
        return this.returnValue;
    }

    public RuleClassBuilder getRuleClassBuilder() {
        return rule;
    }

    public TypeResolver getTypeResolver() {
        return this.typeResolver;
    }

    public Map getInterceptors() {
        return this.interceptors;
    }

    public String getId() {
        return ID;
    }



}
TOP

Related Classes of org.drools.rule.builder.dialect.mvel.MVELDialect

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.