Search in sources :

Example 1 with EvaluatorWrapper

use of org.drools.compiler.rule.builder.EvaluatorWrapper in project drools by kiegroup.

the class MVELDialect method getMVELCompilationUnit.

public static MVELCompilationUnit getMVELCompilationUnit(final String expression, final AnalysisResult analysis, Declaration[] previousDeclarations, Declaration[] localDeclarations, final Map<String, Class<?>> otherInputVariables, final PackageBuildContext context, String contextIndeifier, Class kcontextClass, boolean readLocalsFromTuple, MVELCompilationUnit.Scope scope) {
    Map<String, Class> resolvedInputs = new LinkedHashMap<String, Class>();
    List<String> ids = new ArrayList<String>();
    if (analysis.getBoundIdentifiers().getThisClass() != null || (localDeclarations != null && localDeclarations.length > 0)) {
        Class cls = analysis.getBoundIdentifiers().getThisClass();
        ids.add("this");
        resolvedInputs.put("this", // the only time cls is null is in accumumulate's acc/reverse
        (cls != null) ? cls : Object.class);
    }
    ids.add(contextIndeifier);
    resolvedInputs.put(contextIndeifier, kcontextClass);
    ids.add("kcontext");
    resolvedInputs.put("kcontext", kcontextClass);
    if (scope.hasRule()) {
        ids.add("rule");
        resolvedInputs.put("rule", Rule.class);
    }
    List<String> strList = new ArrayList<String>();
    for (String identifier : analysis.getIdentifiers()) {
        Class<?> type = identifier.equals(WM_ARGUMENT) ? InternalWorkingMemory.class : analysis.getBoundIdentifiers().resolveVarType(identifier);
        if (type != null) {
            strList.add(identifier);
            ids.add(identifier);
            resolvedInputs.put(identifier, type);
        }
    }
    String[] globalIdentifiers = strList.toArray(new String[strList.size()]);
    strList.clear();
    for (String op : analysis.getBoundIdentifiers().getOperators().keySet()) {
        strList.add(op);
        ids.add(op);
        resolvedInputs.put(op, EvaluatorWrapper.class);
    }
    EvaluatorWrapper[] operators = new EvaluatorWrapper[strList.size()];
    for (int i = 0; i < operators.length; i++) {
        operators[i] = analysis.getBoundIdentifiers().getOperators().get(strList.get(i));
    }
    if (previousDeclarations != null) {
        for (Declaration decl : previousDeclarations) {
            if (analysis.getBoundIdentifiers().getDeclrClasses().containsKey(decl.getIdentifier())) {
                ids.add(decl.getIdentifier());
                resolvedInputs.put(decl.getIdentifier(), decl.getDeclarationClass());
            }
        }
    }
    if (localDeclarations != null) {
        for (Declaration decl : localDeclarations) {
            if (analysis.getBoundIdentifiers().getDeclrClasses().containsKey(decl.getIdentifier())) {
                ids.add(decl.getIdentifier());
                resolvedInputs.put(decl.getIdentifier(), decl.getDeclarationClass());
            }
        }
    }
    // "not bound" identifiers could be drools, kcontext and rule
    // but in the case of accumulate it could be vars from the "init" section.
    // String[] otherIdentifiers = otherInputVariables == null ? new String[]{} : new String[otherInputVariables.size()];
    strList = new ArrayList<String>();
    if (otherInputVariables != null) {
        MVELAnalysisResult mvelAnalysis = (MVELAnalysisResult) analysis;
        for (Entry<String, Class<?>> stringClassEntry : otherInputVariables.entrySet()) {
            if ((!analysis.getNotBoundedIdentifiers().contains(stringClassEntry.getKey()) && !mvelAnalysis.getMvelVariables().keySet().contains(stringClassEntry.getKey())) || "rule".equals(stringClassEntry.getKey())) {
                // and rule was already included
                continue;
            }
            ids.add(stringClassEntry.getKey());
            strList.add(stringClassEntry.getKey());
            resolvedInputs.put(stringClassEntry.getKey(), stringClassEntry.getValue());
        }
    }
    String[] otherIdentifiers = strList.toArray(new String[strList.size()]);
    String[] inputIdentifiers = new String[resolvedInputs.size()];
    String[] inputTypes = new String[resolvedInputs.size()];
    int i = 0;
    for (String id : ids) {
        inputIdentifiers[i] = id;
        inputTypes[i++] = resolvedInputs.get(id).getName();
    }
    String name;
    if (context != null && context.getPkg() != null && context.getPkg().getName() != null) {
        if (context instanceof RuleBuildContext) {
            name = context.getPkg().getName() + "." + ((RuleBuildContext) context).getRuleDescr().getClassName();
        } else {
            name = context.getPkg().getName() + ".Unknown";
        }
    } else {
        name = "Unknown";
    }
    return new MVELCompilationUnit(name, expression, globalIdentifiers, operators, previousDeclarations, localDeclarations, otherIdentifiers, inputIdentifiers, inputTypes, ((MVELAnalysisResult) analysis).isTypesafe(), readLocalsFromTuple);
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) RuleBuildContext(org.drools.compiler.rule.builder.RuleBuildContext) ArrayList(java.util.ArrayList) MVELCompilationUnit(org.drools.mvel.expr.MVELCompilationUnit) LinkedHashMap(java.util.LinkedHashMap) Declaration(org.drools.core.rule.Declaration)

Example 2 with EvaluatorWrapper

use of org.drools.compiler.rule.builder.EvaluatorWrapper in project drools by kiegroup.

the class MVELExprAnalyzer method analyzeExpression.

// ------------------------------------------------------------
// Instance methods
// ------------------------------------------------------------
/**
 * Analyze an expression.
 *
 * @param expr
 *            The expression to analyze.
 * @param availableIdentifiers
 *            Total set of declarations available.
 *
 * @return The <code>Set</code> of declarations used by the expression.
 * @throws RecognitionException
 *             If an error occurs in the parser.
 */
@SuppressWarnings("unchecked")
public static MVELAnalysisResult analyzeExpression(final PackageBuildContext context, final String expr, final BoundIdentifiers availableIdentifiers, final Map<String, Class<?>> localTypes, String contextIdentifier, Class kcontextClass) {
    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;
    MVELDialect dialect = (MVELDialect) context.getDialect("mvel");
    ParserConfiguration conf = getMVELDialectRuntimeData(context).getParserConfiguration();
    conf.setClassLoader(context.getKnowledgeBuilder().getRootClassLoader());
    // first compilation is for verification only
    // @todo proper source file name
    final ParserContext parserContext1 = new ParserContext(conf);
    if (localTypes != null) {
        for (Entry entry : localTypes.entrySet()) {
            parserContext1.addInput((String) entry.getKey(), (Class) entry.getValue());
        }
    }
    if (availableIdentifiers.getThisClass() != null) {
        parserContext1.addInput("this", availableIdentifiers.getThisClass());
    }
    if (availableIdentifiers.getOperators() != null) {
        for (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) {
        BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext) context).getRuleDescr() : context.getParentDescr();
        if (e instanceof CompileException && e.getCause() != null && e.getMessage().startsWith("[Error: null]")) {
            // rewrite error message in cause original message is null
            e = new CompileException(e.getCause().toString(), ((CompileException) e).getExpr(), ((CompileException) e).getCursor(), e.getCause());
        }
        AsmUtil.copyErrorLocation(e, context.getParentDescr());
        context.addError(new DescrBuildError(base, context.getParentDescr(), null, "Unable to Analyse Expression " + expr + ":\n" + e.getMessage()));
        return null;
    }
    Set<String> requiredInputs = new HashSet<String>();
    requiredInputs.addAll(parserContext1.getInputs().keySet());
    HashMap<String, Class<?>> variables = (HashMap<String, Class<?>>) ((Map) parserContext1.getVariables());
    if (localTypes != null) {
        for (String str : localTypes.keySet()) {
            // we have to do this due to mvel regressions on detecting true local vars
            variables.remove(str);
        }
    }
    // 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(contextIdentifier) || input.equals("kcontext")) {
                cls = kcontextClass;
            } else if (input.equals("rule")) {
                cls = Rule.class;
            } else if (localTypes != null) {
                cls = localTypes.get(input);
            }
        }
        if (cls != null) {
            parserContext2.addInput(input, cls);
        }
    }
    if (availableIdentifiers.getThisClass() != null) {
        parserContext2.addInput("this", availableIdentifiers.getThisClass());
    }
    boolean typesafe = context.isTypesafe();
    try {
        returnType = MVEL.analyze(expr, parserContext2);
        typesafe = true;
    } catch (Exception e) {
        // is this an error, or can we fall back to non-typesafe mode?
        if (typesafe) {
            BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext) context).getRuleDescr() : context.getParentDescr();
            AsmUtil.copyErrorLocation(e, context.getParentDescr());
            context.addError(new DescrBuildError(base, context.getParentDescr(), null, "Unable to Analyse Expression " + expr + ":\n" + e.getMessage()));
            return null;
        }
    }
    if (typesafe) {
        requiredInputs = new HashSet<String>();
        requiredInputs.addAll(parserContext2.getInputs().keySet());
        requiredInputs.addAll(variables.keySet());
        variables = (HashMap<String, Class<?>>) ((Map) parserContext2.getVariables());
        if (localTypes != null) {
            for (String str : localTypes.keySet()) {
                // we have to do this due to mvel regressions on detecting true local vars
                variables.remove(str);
            }
        }
    }
    MVELAnalysisResult result = analyze(requiredInputs, availableIdentifiers);
    result.setReturnType(returnType);
    result.setMvelVariables(variables);
    result.setTypesafe(typesafe);
    return result;
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) RuleBuildContext(org.drools.compiler.rule.builder.RuleBuildContext) HashMap(java.util.HashMap) CompileException(org.mvel2.CompileException) RecognitionException(org.antlr.runtime.RecognitionException) ParserConfiguration(org.mvel2.ParserConfiguration) Entry(java.util.Map.Entry) DescrBuildError(org.drools.compiler.compiler.DescrBuildError) CompileException(org.mvel2.CompileException) BaseDescr(org.drools.drl.ast.descr.BaseDescr) Rule(org.kie.api.definition.rule.Rule) ParserContext(org.mvel2.ParserContext) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 3 with EvaluatorWrapper

use of org.drools.compiler.rule.builder.EvaluatorWrapper in project drools by kiegroup.

the class MVELExprAnalyzer method analyze.

/**
 * Analyse an expression.
 * @throws RecognitionException
 *             If an error occurs in the parser.
 */
public static MVELAnalysisResult analyze(final Set<String> identifiers, final BoundIdentifiers availableIdentifiers) {
    MVELAnalysisResult result = new MVELAnalysisResult();
    result.setIdentifiers(identifiers);
    final Set<String> notBound = new HashSet<String>(identifiers);
    notBound.remove("this");
    Map<String, Class<?>> usedDecls = new HashMap<String, Class<?>>();
    Map<String, Class<?>> usedGlobals = new HashMap<String, Class<?>>();
    Map<String, EvaluatorWrapper> usedOperators = new HashMap<String, EvaluatorWrapper>();
    for (Entry<String, Class<?>> entry : availableIdentifiers.getDeclrClasses().entrySet()) {
        if (identifiers.contains(entry.getKey())) {
            usedDecls.put(entry.getKey(), entry.getValue());
            notBound.remove(entry.getKey());
        }
    }
    for (String identifier : identifiers) {
        Class<?> type = availableIdentifiers.resolveVarType(identifier);
        if (type != null) {
            usedGlobals.put(identifier, type);
            notBound.remove(identifier);
        }
    }
    for (Map.Entry<String, EvaluatorWrapper> op : availableIdentifiers.getOperators().entrySet()) {
        if (identifiers.contains(op.getKey())) {
            usedOperators.put(op.getKey(), op.getValue());
            notBound.remove(op.getKey());
        }
    }
    BoundIdentifiers boundIdentifiers = new BoundIdentifiers(usedDecls, availableIdentifiers.getContext(), usedOperators, availableIdentifiers.getThisClass());
    boundIdentifiers.setGlobals(usedGlobals);
    result.setBoundIdentifiers(boundIdentifiers);
    result.setNotBoundedIdentifiers(notBound);
    return result;
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) HashMap(java.util.HashMap) BoundIdentifiers(org.drools.compiler.compiler.BoundIdentifiers) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 4 with EvaluatorWrapper

use of org.drools.compiler.rule.builder.EvaluatorWrapper in project drools by kiegroup.

the class MVELCompilationUnit method updateFactory.

private void updateFactory(Object knowledgeHelper, Declaration[] prevDecl, Rule rule, InternalFactHandle rightHandle, Object rightObject, Tuple tuple, Object[] otherVars, ReteEvaluator reteEvaluator, GlobalResolver globals, VariableResolverFactory factory) {
    int varLength = inputIdentifiers.length;
    int i = 0;
    if ("this".equals(inputIdentifiers[0])) {
        factory.getIndexedVariableResolver(i++).setValue(rightObject);
    }
    factory.getIndexedVariableResolver(i++).setValue(knowledgeHelper);
    factory.getIndexedVariableResolver(i++).setValue(knowledgeHelper);
    if (inputIdentifiers.length > i && "rule".equals(inputIdentifiers[i])) {
        factory.getIndexedVariableResolver(i++).setValue(rule);
    }
    if (globalIdentifiers != null) {
        for (String globalIdentifier : globalIdentifiers) {
            if (WM_ARGUMENT.equals(globalIdentifier)) {
                factory.getIndexedVariableResolver(i++).setValue(reteEvaluator);
            } else {
                factory.getIndexedVariableResolver(i++).setValue(globals.resolveGlobal(globalIdentifier));
            }
        }
    }
    InternalFactHandle[] handles = tuple instanceof LeftTuple ? tuple.toFactHandles() : null;
    if (operators.length > 0) {
        for (EvaluatorWrapper operator : operators) {
            // TODO: need to have one operator per working memory
            factory.getIndexedVariableResolver(i++).setValue(operator);
            operator.loadHandles(handles, rightHandle);
        }
    }
    Object[] objs = null;
    if (tuple != null) {
        if (handles == null) {
            objs = tuple.toObjects();
        }
        if (this.previousDeclarations != null && this.previousDeclarations.length > 0) {
            // Consequences with 'or's will have different declaration offsets, so use the one's from the RTN's subrule.
            if (prevDecl == null) {
                // allows the caller to override the member var
                // used for rules, salience and timers so they work with 'or' CEs
                prevDecl = this.previousDeclarations;
            }
            for (Declaration decl : prevDecl) {
                Object o = decl.getValue(reteEvaluator, objs != null ? objs[decl.getObjectIndex()] : handles[decl.getObjectIndex()].getObject());
                factory.getIndexedVariableResolver(i++).setValue(o);
            }
        }
    }
    if (this.localDeclarations != null && this.localDeclarations.length > 0) {
        for (Declaration decl : this.localDeclarations) {
            Object value;
            if (readLocalsFromTuple && tuple != null) {
                value = decl.getValue(reteEvaluator, objs != null ? objs[decl.getObjectIndex()] : handles[decl.getObjectIndex()].getObject());
            } else {
                value = decl.getValue(reteEvaluator, rightObject);
            }
            factory.getIndexedVariableResolver(i++).setValue(value);
        }
    }
    int otherVarsPos = 0;
    if (otherVars != null) {
        otherVarsPos = i;
        for (Object o : otherVars) {
            factory.getIndexedVariableResolver(i++).setValue(o);
        }
    }
    int otherVarsLength = i - otherVarsPos;
    for (i = varLength; i < this.allVarsLength; i++) {
        // null all local vars
        factory.getIndexedVariableResolver(i).setValue(null);
    }
    DroolsVarFactory df = (DroolsVarFactory) factory.getNextFactory();
    df.setOtherVarsPos(otherVarsPos);
    df.setOtherVarsLength(otherVarsLength);
    if (knowledgeHelper instanceof KnowledgeHelper) {
        KnowledgeHelper kh = (KnowledgeHelper) knowledgeHelper;
        df.setKnowledgeHelper(kh);
    }
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) KnowledgeHelper(org.drools.core.spi.KnowledgeHelper) Declaration(org.drools.core.rule.Declaration) InternalFactHandle(org.drools.core.common.InternalFactHandle) LeftTuple(org.drools.core.reteoo.LeftTuple) RuleTerminalNodeLeftTuple(org.drools.core.reteoo.RuleTerminalNodeLeftTuple)

Example 5 with EvaluatorWrapper

use of org.drools.compiler.rule.builder.EvaluatorWrapper in project drools by kiegroup.

the class MVELConditionEvaluator method evaluate.

private boolean evaluate(MvelEvaluator<Boolean> evaluator, InternalFactHandle handle, ReteEvaluator reteEvaluator, Tuple tuple) {
    if (compilationUnit == null) {
        Map<String, Object> vars = valuesAsMap(handle.getObject(), reteEvaluator, tuple, declarations);
        if (operators.length > 0) {
            if (vars == null) {
                vars = new HashMap<>();
            }
            InternalFactHandle[] handles = tuple != null ? tuple.toFactHandles() : new InternalFactHandle[0];
            for (EvaluatorWrapper operator : operators) {
                vars.put(operator.getBindingName(), operator);
                operator.loadHandles(handles, handle);
            }
        }
        return evaluate(evaluator, handle.getObject(), vars);
    }
    VariableResolverFactory factory = compilationUnit.createFactory();
    compilationUnit.updateFactory(handle, tuple, null, reteEvaluator, reteEvaluator.getGlobalResolver(), factory);
    return evaluator.evaluate(handle.getObject(), factory);
}
Also used : EvaluatorWrapper(org.drools.compiler.rule.builder.EvaluatorWrapper) VariableResolverFactory(org.mvel2.integration.VariableResolverFactory) InternalFactHandle(org.drools.core.common.InternalFactHandle)

Aggregations

EvaluatorWrapper (org.drools.compiler.rule.builder.EvaluatorWrapper)10 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 Map (java.util.Map)4 InternalFactHandle (org.drools.core.common.InternalFactHandle)3 ReteEvaluator (org.drools.core.common.ReteEvaluator)3 Declaration (org.drools.core.rule.Declaration)3 MVELCompilationUnit (org.drools.mvel.expr.MVELCompilationUnit)3 IOException (java.io.IOException)2 BoundIdentifiers (org.drools.compiler.compiler.BoundIdentifiers)2 DescrBuildError (org.drools.compiler.compiler.DescrBuildError)2 RuleBuildContext (org.drools.compiler.rule.builder.RuleBuildContext)2 Evaluator (org.drools.core.spi.Evaluator)2 IndexUtil (org.drools.core.util.index.IndexUtil)2 ParserContext (org.mvel2.ParserContext)2 ArrayList (java.util.ArrayList)1 LinkedHashMap (java.util.LinkedHashMap)1 Entry (java.util.Map.Entry)1 RecognitionException (org.antlr.runtime.RecognitionException)1 EvaluatorDefinition (org.drools.compiler.rule.builder.EvaluatorDefinition)1