Search in sources :

Example 1 with MVELAnalysisResult

use of org.drools.mvel.builder.MVELAnalysisResult in project drools by kiegroup.

the class AsmUtil method rewriteDescr.

private static void rewriteDescr(final RuleBuildContext context, final StringBuilder consequence, final JavaBlockDescr d, final JavaAnalysisResult analysis, final Map<String, Declaration> decls) {
    if (d.getEnd() == 0) {
        // do nothing, it was incorrectly parsed, but this error should be picked up else where
        return;
    }
    boolean typeSafety = context.isTypesafe();
    // we have to analyse in dynamic mode for now, as we cannot safely determine all input vars
    context.setTypesafe(false);
    Map<String, Class<?>> localTypes = d.getInputs();
    if (d.getInScopeLocalVars() != null && !d.getInScopeLocalVars().isEmpty()) {
        localTypes = new HashMap<>(d.getInputs() != null ? d.getInputs() : Collections.emptyMap());
        for (JavaLocalDeclarationDescr local : d.getInScopeLocalVars()) {
            // these are variables declared in the code itself that are in the scope for this expression
            try {
                Class<?> type = context.getDialect("java").getPackageRegistry().getTypeResolver().resolveType(local.getRawType());
                for (JavaLocalDeclarationDescr.IdentifierDescr id : local.getIdentifiers()) {
                    localTypes.put(id.getIdentifier(), type);
                }
            } catch (ClassNotFoundException e) {
                context.addError(new DescrBuildError(context.getRuleDescr(), context.getParentDescr(), null, "Unable to resolve type " + local.getRawType() + ":\n" + e.getMessage()));
            }
        }
    }
    MVELDialect mvel = (MVELDialect) context.getDialect("mvel");
    MVELAnalysisResult mvelAnalysis = (MVELAnalysisResult) mvel.analyzeBlock(context, d.getTargetExpression(), analysis.getBoundIdentifiers(), localTypes, "drools", KnowledgeHelper.class);
    context.setTypesafe(typeSafety);
    if (mvelAnalysis == null) {
        // something bad happened, issue already logged in errors
        return;
    }
    Class<?> ret = mvelAnalysis.getReturnType();
    if (ret == null) {
        // not possible to evaluate expression return value
        context.addError(new DescrBuildError(context.getParentDescr(), context.getRuleDescr(), analysis.getAnalyzedExpr(), "Unable to determine the resulting type of the expression: " + d.getTargetExpression() + "\n"));
        return;
    }
    // adding modify expression
    String retString = ClassUtils.canonicalName(ret);
    String declrString;
    if (d.getTargetExpression().charAt(0) == '(') {
        declrString = d.getTargetExpression().substring(1, d.getTargetExpression().length() - 1).trim();
    } else {
        declrString = d.getTargetExpression();
    }
    String obj = declrString;
    Declaration declr = decls.get(declrString);
    consequence.append("{ ");
    if (declr == null) {
        obj = "__obj__";
        consequence.append(retString);
        consequence.append(" ");
        consequence.append(obj);
        consequence.append(" = ");
        consequence.append(d.getTargetExpression());
        consequence.append("; ");
    }
    if (declr == null || declr.isInternalFact()) {
        consequence.append("org.kie.api.runtime.rule.FactHandle ");
        consequence.append(obj);
        consequence.append("__Handle2__ = drools.getFactHandle(");
        consequence.append(obj);
        consequence.append(");");
    }
    // the following is a hack to preserve line breaks.
    String originalBlock = analysis.getAnalyzedExpr().substring(d.getStart() - 1, d.getEnd());
    switch(d.getType()) {
        case MODIFY:
            rewriteModifyDescr(context, d, originalBlock, consequence, declr, obj);
            break;
        case UPDATE:
            rewriteUpdateDescr(context, d, analysis, consequence, declr, obj);
            break;
        case DELETE:
            rewriteDeleteDescr(context, d, consequence, declr, obj);
            break;
    }
}
Also used : MVELDialect(org.drools.mvel.builder.MVELDialect) DescrBuildError(org.drools.compiler.compiler.DescrBuildError) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) JavaLocalDeclarationDescr(org.drools.compiler.rule.builder.dialect.java.parser.JavaLocalDeclarationDescr) KnowledgeHelper(org.drools.core.spi.KnowledgeHelper) TypeDeclaration(org.drools.core.rule.TypeDeclaration) Declaration(org.drools.core.rule.Declaration)

Example 2 with MVELAnalysisResult

use of org.drools.mvel.builder.MVELAnalysisResult in project drools by kiegroup.

the class MVELConstraintBuilder method analyzeExpression.

private static MVELAnalysisResult analyzeExpression(String expr, ParserConfiguration conf, BoundIdentifiers availableIdentifiers) {
    if (expr.trim().length() <= 0) {
        MVELAnalysisResult result = analyze((Set<String>) Collections.EMPTY_SET, availableIdentifiers);
        result.setMvelVariables(new HashMap<String, Class<?>>());
        result.setTypesafe(true);
        return result;
    }
    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
    MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;
    MVEL.COMPILER_OPT_ALLOW_RESOLVE_INNERCLASSES_WITH_DOTNOTATION = true;
    MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS = true;
    // first compilation is for verification only
    final ParserContext parserContext1 = new ParserContext(conf);
    if (availableIdentifiers.getThisClass() != null) {
        parserContext1.addInput("this", availableIdentifiers.getThisClass());
    }
    if (availableIdentifiers.getOperators() != null) {
        for (Map.Entry<String, EvaluatorWrapper> opEntry : availableIdentifiers.getOperators().entrySet()) {
            parserContext1.addInput(opEntry.getKey(), opEntry.getValue().getClass());
        }
    }
    parserContext1.setStrictTypeEnforcement(false);
    parserContext1.setStrongTyping(false);
    Class<?> returnType;
    try {
        returnType = MVEL.analyze(expr, parserContext1);
    } catch (Exception e) {
        return null;
    }
    Set<String> requiredInputs = new HashSet<>(parserContext1.getInputs().keySet());
    Map<String, Class> variables = parserContext1.getVariables();
    // MVEL includes direct fields of context object in non-strict mode. so we need to strip those
    if (availableIdentifiers.getThisClass() != null) {
        requiredInputs.removeIf(s -> PropertyTools.getFieldOrAccessor(availableIdentifiers.getThisClass(), s) != null);
    }
    // now, set the required input types and compile again
    final ParserContext parserContext2 = new ParserContext(conf);
    parserContext2.setStrictTypeEnforcement(true);
    parserContext2.setStrongTyping(true);
    for (String input : requiredInputs) {
        if ("this".equals(input)) {
            continue;
        }
        if (WM_ARGUMENT.equals(input)) {
            parserContext2.addInput(input, InternalWorkingMemory.class);
            continue;
        }
        Class<?> cls = availableIdentifiers.resolveType(input);
        if (cls == null) {
            if (input.equals("rule")) {
                cls = Rule.class;
            }
        }
        if (cls != null) {
            parserContext2.addInput(input, cls);
        }
    }
    if (availableIdentifiers.getThisClass() != null) {
        parserContext2.addInput("this", availableIdentifiers.getThisClass());
    }
    try {
        returnType = MVEL.analyze(expr, parserContext2);
    } catch (Exception e) {
        return null;
    }
    requiredInputs = new HashSet<>();
    requiredInputs.addAll(parserContext2.getInputs().keySet());
    requiredInputs.addAll(variables.keySet());
    variables = parserContext2.getVariables();
    MVELAnalysisResult result = analyze(requiredInputs, availableIdentifiers);
    result.setReturnType(returnType);
    result.setMvelVariables((Map<String, Class<?>>) (Map) variables);
    result.setTypesafe(true);
    return result;
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) IOException(java.io.IOException) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) ParserContext(org.mvel2.ParserContext) Map(java.util.Map) HashMap(java.util.HashMap) HashSet(java.util.HashSet)

Example 3 with MVELAnalysisResult

use of org.drools.mvel.builder.MVELAnalysisResult in project drools by kiegroup.

the class MVELConstraintBuilder method buildTimerExpression.

@Override
public TimerExpression buildTimerExpression(String expression, RuleBuildContext context) {
    boolean typesafe = context.isTypesafe();
    // pushing consequence LHS into the stack for variable resolution
    context.getDeclarationResolver().pushOnBuildStack(context.getRule().getLhs());
    try {
        // This builder is re-usable in other dialects, so specify by name
        MVELDialect dialect = (MVELDialect) context.getDialect("mvel");
        Map<String, Declaration> decls = context.getDeclarationResolver().getDeclarations(context.getRule());
        MVELAnalysisResult analysis = (MVELAnalysisResult) dialect.analyzeExpression(context, context.getRuleDescr(), expression, new BoundIdentifiers(DeclarationScopeResolver.getDeclarationClasses(decls), context));
        context.setTypesafe(analysis.isTypesafe());
        final BoundIdentifiers usedIdentifiers = analysis.getBoundIdentifiers();
        int i = usedIdentifiers.getDeclrClasses().keySet().size();
        Declaration[] previousDeclarations = new Declaration[i];
        i = 0;
        for (String id : usedIdentifiers.getDeclrClasses().keySet()) {
            previousDeclarations[i++] = decls.get(id);
        }
        Arrays.sort(previousDeclarations, RuleTerminalNode.SortDeclarations.instance);
        MVELCompilationUnit unit = dialect.getMVELCompilationUnit(expression, analysis, previousDeclarations, null, null, context, "drools", KnowledgeHelper.class, false, MVELCompilationUnit.Scope.EXPRESSION);
        MVELObjectExpression expr = new MVELObjectExpression(unit, dialect.getId());
        MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel");
        data.addCompileable(context.getRule(), expr);
        expr.compile(data);
        return expr;
    } catch (final Exception e) {
        AsmUtil.copyErrorLocation(e, context.getRuleDescr());
        context.addError(new DescrBuildError(context.getParentDescr(), context.getRuleDescr(), null, "Unable to build expression : " + e.getMessage() + "'" + expression + "'"));
        return null;
    } finally {
        context.setTypesafe(typesafe);
    }
}
Also used : MVELCompilationUnit(org.drools.mvel.expr.MVELCompilationUnit) MVELDialect(org.drools.mvel.builder.MVELDialect) Constraint(org.drools.core.spi.Constraint) IOException(java.io.IOException) BoundIdentifiers(org.drools.compiler.compiler.BoundIdentifiers) MVELObjectExpression(org.drools.mvel.expr.MVELObjectExpression) DescrBuildError(org.drools.compiler.compiler.DescrBuildError) PatternBuilder.registerDescrBuildError(org.drools.compiler.rule.builder.PatternBuilder.registerDescrBuildError) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) Declaration(org.drools.core.rule.Declaration)

Example 4 with MVELAnalysisResult

use of org.drools.mvel.builder.MVELAnalysisResult in project drools by kiegroup.

the class MVELConstraintBuilder method buildMvelFieldReadAccessor.

@Override
public InternalReadAccessor buildMvelFieldReadAccessor(RuleBuildContext context, BaseDescr descr, Pattern pattern, ObjectType objectType, String fieldName, boolean reportError) {
    InternalReadAccessor reader;
    Dialect dialect = context.getDialect();
    try {
        MVELDialect mvelDialect = (MVELDialect) context.getDialect("mvel");
        context.setDialect(mvelDialect);
        final AnalysisResult analysis = context.getDialect().analyzeExpression(context, descr, fieldName, new BoundIdentifiers(pattern, context, Collections.EMPTY_MAP, objectType));
        if (analysis == null) {
            // something bad happened
            if (reportError) {
                registerDescrBuildError(context, descr, "Unable to analyze expression '" + fieldName + "'");
            }
            return null;
        }
        final BoundIdentifiers usedIdentifiers = analysis.getBoundIdentifiers();
        if (!usedIdentifiers.getGlobals().isEmpty()) {
            // cannot create a read accessors here when using globals
            return null;
        }
        if (!usedIdentifiers.getDeclrClasses().isEmpty()) {
            if (reportError && descr instanceof BindingDescr) {
                registerDescrBuildError(context, descr, "Variables can not be used inside bindings. Variable " + usedIdentifiers.getDeclrClasses().keySet() + " is being used in binding '" + fieldName + "'");
            }
            return null;
        }
        reader = ((MVELKnowledgePackageImpl) context.getPkg()).getClassFieldAccessorStore().getMVELReader(context.getPkg().getName(), objectType.getClassName(), fieldName, context.isTypesafe(), ((MVELAnalysisResult) analysis).getReturnType());
        MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel");
        ((MVELCompileable) reader).compile(data, context.getRule());
        data.addCompileable((MVELCompileable) reader);
    } catch (final Exception e) {
        if (reportError) {
            AsmUtil.copyErrorLocation(e, descr);
            registerDescrBuildError(context, descr, e, "Unable to create reader for '" + fieldName + "':" + e.getMessage());
        }
        // if there was an error, set the reader back to null
        reader = null;
    } finally {
        context.setDialect(dialect);
    }
    return reader;
}
Also used : BindingDescr(org.drools.drl.ast.descr.BindingDescr) MVELCompileable(org.drools.mvel.expr.MVELCompileable) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) InternalReadAccessor(org.drools.core.spi.InternalReadAccessor) MVELDialect(org.drools.mvel.builder.MVELDialect) Dialect(org.drools.compiler.compiler.Dialect) MVELDialect(org.drools.mvel.builder.MVELDialect) AnalysisResult(org.drools.compiler.compiler.AnalysisResult) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) IOException(java.io.IOException) BoundIdentifiers(org.drools.compiler.compiler.BoundIdentifiers)

Example 5 with MVELAnalysisResult

use of org.drools.mvel.builder.MVELAnalysisResult in project drools by kiegroup.

the class MVELConstraintBuilder method buildCompilationUnit.

private MVELCompilationUnit buildCompilationUnit(final RuleBuildContext context, final Declaration[] previousDeclarations, final Declaration[] localDeclarations, final PredicateDescr predicateDescr, final AnalysisResult analysis) {
    if (context.isTypesafe() && analysis instanceof MVELAnalysisResult) {
        Class<?> returnClass = ((MVELAnalysisResult) analysis).getReturnType();
        if (returnClass != Boolean.class && returnClass != Boolean.TYPE) {
            context.addError(new DescrBuildError(context.getParentDescr(), predicateDescr, null, "Predicate '" + predicateDescr.getContent() + "' must be a Boolean expression\n" + predicateDescr.positionAsString()));
        }
    }
    MVELDialect dialect = (MVELDialect) context.getDialect("mvel");
    MVELCompilationUnit unit = null;
    try {
        Map<String, Class<?>> declIds = context.getDeclarationResolver().getDeclarationClasses(context.getRule());
        Pattern p = (Pattern) context.getDeclarationResolver().peekBuildStack();
        if (p.getObjectType() instanceof ClassObjectType) {
            declIds.put("this", ((ClassObjectType) p.getObjectType()).getClassType());
        }
        unit = dialect.getMVELCompilationUnit((String) predicateDescr.getContent(), analysis, previousDeclarations, localDeclarations, null, context, "drools", KnowledgeHelper.class, context.isInXpath(), MVELCompilationUnit.Scope.CONSTRAINT);
    } catch (final Exception e) {
        copyErrorLocation(e, predicateDescr);
        context.addError(new DescrBuildError(context.getParentDescr(), predicateDescr, e, "Unable to build expression for 'inline-eval' : " + e.getMessage() + "'" + predicateDescr.getContent() + "'\n" + e.getMessage()));
    }
    return unit;
}
Also used : Pattern(org.drools.core.rule.Pattern) ClassObjectType(org.drools.core.base.ClassObjectType) MVELCompilationUnit(org.drools.mvel.expr.MVELCompilationUnit) MVELDialect(org.drools.mvel.builder.MVELDialect) IOException(java.io.IOException) DescrBuildError(org.drools.compiler.compiler.DescrBuildError) PatternBuilder.registerDescrBuildError(org.drools.compiler.rule.builder.PatternBuilder.registerDescrBuildError) MVELAnalysisResult(org.drools.mvel.builder.MVELAnalysisResult) KnowledgeHelper(org.drools.core.spi.KnowledgeHelper)

Aggregations

MVELAnalysisResult (org.drools.mvel.builder.MVELAnalysisResult)5 IOException (java.io.IOException)4 MVELDialect (org.drools.mvel.builder.MVELDialect)4 DescrBuildError (org.drools.compiler.compiler.DescrBuildError)3 BoundIdentifiers (org.drools.compiler.compiler.BoundIdentifiers)2 PatternBuilder.registerDescrBuildError (org.drools.compiler.rule.builder.PatternBuilder.registerDescrBuildError)2 Declaration (org.drools.core.rule.Declaration)2 KnowledgeHelper (org.drools.core.spi.KnowledgeHelper)2 MVELCompilationUnit (org.drools.mvel.expr.MVELCompilationUnit)2 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 AnalysisResult (org.drools.compiler.compiler.AnalysisResult)1 Dialect (org.drools.compiler.compiler.Dialect)1 EvaluatorWrapper (org.drools.compiler.rule.builder.EvaluatorWrapper)1 JavaLocalDeclarationDescr (org.drools.compiler.rule.builder.dialect.java.parser.JavaLocalDeclarationDescr)1 ClassObjectType (org.drools.core.base.ClassObjectType)1 Pattern (org.drools.core.rule.Pattern)1 TypeDeclaration (org.drools.core.rule.TypeDeclaration)1 Constraint (org.drools.core.spi.Constraint)1