Search in sources :

Example 21 with MVEL

use of org.mvel2.MVEL in project drools by kiegroup.

the class MVELConsequence method evaluate.

@Override
public void evaluate(KnowledgeHelper knowledgeHelper, WorkingMemory workingMemory) throws Exception {
    // same as lambda consequence...
    Tuple tuple = knowledgeHelper.getTuple();
    Declaration[] declarations = ((RuleTerminalNode) knowledgeHelper.getMatch().getTuple().getTupleSink()).getRequiredDeclarations();
    Variable[] vars = consequence.getVariables();
    // ...but the facts are association of Variable and its value, preserving order.
    Map<Variable, Object> facts = new LinkedHashMap<>();
    int declrCounter = 0;
    for (Variable var : vars) {
        if (var.isFact()) {
            Declaration declaration = declarations[declrCounter++];
            InternalFactHandle fh = tuple.get(declaration);
            facts.put(var, declaration.getValue((InternalWorkingMemory) workingMemory, fh.getObject()));
        } else {
            facts.put(var, workingMemory.getGlobal(var.getName()));
        }
    }
    ScriptBlock scriptBlock = null;
    try {
        scriptBlock = (ScriptBlock) consequence.getBlock();
    } catch (ClassCastException e) {
        throw new RuntimeException("I tried to access a ScriptBlock but it was not. So something is thinking is a MVEL consequence but did not set the MVEL script textual representation", e);
    }
    String originalRHS = scriptBlock.getScript();
    String name = context.getRule().getPackageName() + "." + context.getRule().getName();
    String expression = MVELConsequenceBuilder.processMacros(originalRHS);
    String[] globalIdentifiers = new String[] {};
    String[] default_inputIdentifiers = new String[] { "this", "drools", "kcontext", "rule" };
    String[] inputIdentifiers = Stream.concat(Arrays.asList(default_inputIdentifiers).stream(), facts.entrySet().stream().map(kv -> kv.getKey().getName())).collect(Collectors.toList()).toArray(new String[] {});
    String[] default_inputTypes = new String[] { "org.drools.core.spi.KnowledgeHelper", "org.drools.core.spi.KnowledgeHelper", "org.drools.core.spi.KnowledgeHelper", "org.kie.api.definition.rule.Rule" };
    String[] inputTypes = Stream.concat(Arrays.asList(default_inputTypes).stream(), facts.entrySet().stream().map(kv -> kv.getKey().getType().getName())).collect(Collectors.toList()).toArray(new String[] {});
    // ^^ please notice about inputTypes, it is to use the Class.getName(), because is later used by the Classloader internally in MVEL to load the class,
    // do NOT replace with getCanonicalName() otherwise inner classes will not be loaded correctly.
    int languageLevel = 4;
    boolean strictMode = true;
    boolean readLocalsFromTuple = false;
    EvaluatorWrapper[] operators = new EvaluatorWrapper[] {};
    Declaration[] previousDeclarations = new Declaration[] {};
    Declaration[] localDeclarations = new Declaration[] {};
    String[] otherIdentifiers = new String[] {};
    MVELCompilationUnit cu = new MVELCompilationUnit(name, expression, globalIdentifiers, operators, previousDeclarations, localDeclarations, otherIdentifiers, inputIdentifiers, inputTypes, languageLevel, strictMode, readLocalsFromTuple);
    // TODO unfortunately the MVELDialectRuntimeData would be the one of compile time
    // the one from runtime is not helpful, in fact the dialect registry for runtime is empty:
    // MVELDialectRuntimeData runtimeData = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel");
    MVELDialectRuntimeData runtimeData = new MVELDialectRuntimeData();
    // this classloader will be used by the CompilationUnit to load the imports.
    runtimeData.onAdd(null, Thread.currentThread().getContextClassLoader());
    runtimeData.addPackageImport(context.getPkg().getName());
    runtimeData.addPackageImport("java.lang");
    // therefore we assume for the ScriptBlock all available KBPackages are the default available and imported for the scope of the Script itself.
    for (KiePackage kp : context.getKnowledgePackages()) {
        if (!kp.getName().equals(context.getPkg().getName())) {
            runtimeData.addPackageImport(kp.getName());
        }
    }
    // sometimes here it was passed as a 2nd argument a String?? similar to `rule R in file file.drl`
    Serializable cuResult = cu.getCompiledExpression(runtimeData);
    ExecutableStatement compiledExpression = (ExecutableStatement) cuResult;
    // TODO the part above up to the ExecutableStatement compiledExpression should be cached.
    Map<String, Object> mvelContext = new HashMap<>();
    mvelContext.put("this", knowledgeHelper);
    mvelContext.put("drools", knowledgeHelper);
    mvelContext.put("kcontext", knowledgeHelper);
    mvelContext.put("rule", knowledgeHelper.getRule());
    for (Entry<Variable, Object> kv : facts.entrySet()) {
        mvelContext.put(kv.getKey().getName(), kv.getValue());
    }
    CachingMapVariableResolverFactory cachingFactory = new CachingMapVariableResolverFactory(mvelContext);
    VariableResolverFactory factory = cu.getFactory(knowledgeHelper, ((AgendaItem) knowledgeHelper.getMatch()).getTerminalNode().getRequiredDeclarations(), knowledgeHelper.getRule(), knowledgeHelper.getTuple(), null, (InternalWorkingMemory) workingMemory, workingMemory.getGlobalResolver());
    cachingFactory.setNextFactory(factory);
    MVEL.executeExpression(compiledExpression, knowledgeHelper, cachingFactory);
}
Also used : ScriptBlock(org.drools.model.functions.ScriptBlock) AgendaItem(org.drools.core.common.AgendaItem) ExecutableStatement(org.mvel2.compiler.ExecutableStatement) Arrays(java.util.Arrays) RuleTerminalNode(org.drools.core.reteoo.RuleTerminalNode) InternalFactHandle(org.drools.core.common.InternalFactHandle) HashMap(java.util.HashMap) RuleContext(org.drools.modelcompiler.RuleContext) LinkedHashMap(java.util.LinkedHashMap) MVELConsequenceBuilder(org.drools.compiler.rule.builder.dialect.mvel.MVELConsequenceBuilder) Map(java.util.Map) Declaration(org.drools.core.rule.Declaration) KnowledgeHelper(org.drools.core.spi.KnowledgeHelper) KiePackage(org.kie.api.definition.KiePackage) WorkingMemory(org.drools.core.WorkingMemory) Variable(org.drools.model.Variable) InternalWorkingMemory(org.drools.core.common.InternalWorkingMemory) VariableResolverFactory(org.mvel2.integration.VariableResolverFactory) Consequence(org.drools.core.spi.Consequence) MVELDialectRuntimeData(org.drools.core.rule.MVELDialectRuntimeData) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) MVELCompilationUnit(org.drools.core.base.mvel.MVELCompilationUnit) CachingMapVariableResolverFactory(org.mvel2.integration.impl.CachingMapVariableResolverFactory) Stream(java.util.stream.Stream) RuleImpl(org.drools.core.definitions.rule.impl.RuleImpl) Tuple(org.drools.core.spi.Tuple) ScriptBlock(org.drools.model.functions.ScriptBlock) Entry(java.util.Map.Entry) MVEL(org.mvel2.MVEL) EvaluatorWrapper(org.drools.core.base.EvaluatorWrapper) Serializable(java.io.Serializable) Variable(org.drools.model.Variable) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) MVELCompilationUnit(org.drools.core.base.mvel.MVELCompilationUnit) AgendaItem(org.drools.core.common.AgendaItem) LinkedHashMap(java.util.LinkedHashMap) InternalWorkingMemory(org.drools.core.common.InternalWorkingMemory) MVELDialectRuntimeData(org.drools.core.rule.MVELDialectRuntimeData) KiePackage(org.kie.api.definition.KiePackage) CachingMapVariableResolverFactory(org.mvel2.integration.impl.CachingMapVariableResolverFactory) Declaration(org.drools.core.rule.Declaration) InternalFactHandle(org.drools.core.common.InternalFactHandle) RuleTerminalNode(org.drools.core.reteoo.RuleTerminalNode) ExecutableStatement(org.mvel2.compiler.ExecutableStatement) EvaluatorWrapper(org.drools.core.base.EvaluatorWrapper) VariableResolverFactory(org.mvel2.integration.VariableResolverFactory) CachingMapVariableResolverFactory(org.mvel2.integration.impl.CachingMapVariableResolverFactory) Tuple(org.drools.core.spi.Tuple)

Example 22 with MVEL

use of org.mvel2.MVEL 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 = context.getMVELDialectRuntimeData().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);
    parserContext1.setInterceptors(dialect.getInterceptors());
    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());
        }
        DialectUtil.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);
    parserContext2.setInterceptors(dialect.getInterceptors());
    for (String input : requiredInputs) {
        if ("this".equals(input)) {
            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();
            DialectUtil.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.core.base.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.compiler.lang.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 23 with MVEL

use of org.mvel2.MVEL in project drools by kiegroup.

the class MVELExprAnalyzer method getExpressionType.

public static Class<?> getExpressionType(PackageBuildContext context, Map<String, Class<?>> declCls, RuleConditionElement source, String expression) {
    MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel");
    ParserConfiguration conf = data.getParserConfiguration();
    conf.setClassLoader(context.getKnowledgeBuilder().getRootClassLoader());
    ParserContext pctx = new ParserContext(conf);
    pctx.setStrongTyping(true);
    pctx.setStrictTypeEnforcement(true);
    for (Map.Entry<String, Class<?>> entry : declCls.entrySet()) {
        pctx.addInput(entry.getKey(), entry.getValue());
    }
    for (Declaration decl : source.getOuterDeclarations().values()) {
        pctx.addInput(decl.getBindingName(), decl.getDeclarationClass());
    }
    try {
        return MVEL.analyze(expression, pctx);
    } catch (Exception e) {
        log.warn("Unable to parse expression: " + expression, e);
    }
    return null;
}
Also used : MVELDialectRuntimeData(org.drools.core.rule.MVELDialectRuntimeData) Declaration(org.drools.core.rule.Declaration) ParserContext(org.mvel2.ParserContext) HashMap(java.util.HashMap) Map(java.util.Map) CompileException(org.mvel2.CompileException) RecognitionException(org.antlr.runtime.RecognitionException) ParserConfiguration(org.mvel2.ParserConfiguration)

Example 24 with MVEL

use of org.mvel2.MVEL in project drools by kiegroup.

the class MVELAccumulator method init.

/* (non-Javadoc)
     * @see org.kie.spi.Accumulator#init(java.lang.Object, org.kie.spi.Tuple, org.kie.rule.Declaration[], org.kie.WorkingMemory)
     */
public void init(Object workingMemoryContext, Object context, Tuple tuple, Declaration[] declarations, WorkingMemory workingMemory) throws Exception {
    Object[] localVars = new Object[initUnit.getOtherIdentifiers().length];
    MVELAccumulatorFactoryContext factoryContext = (MVELAccumulatorFactoryContext) workingMemoryContext;
    VariableResolverFactory factory = factoryContext.getInitFactory();
    initUnit.updateFactory(null, tuple, localVars, (InternalWorkingMemory) workingMemory, workingMemory.getGlobalResolver(), factory);
    InternalKnowledgePackage pkg = workingMemory.getKnowledgeBase().getPackage("MAIN");
    if (pkg != null) {
        MVELDialectRuntimeData data = (MVELDialectRuntimeData) pkg.getDialectRuntimeRegistry().getDialectData("mvel");
        factory.setNextFactory(data.getFunctionFactory());
    }
    MVELSafeHelper.getEvaluator().executeExpression(this.init, null, factory);
    DroolsVarFactory df = (DroolsVarFactory) factory.getNextFactory();
    if (localVars.length > 0) {
        for (int i = 0; i < df.getOtherVarsLength(); i++) {
            localVars[i] = factory.getIndexedVariableResolver(df.getOtherVarsPos() + i).getValue();
        }
    }
    ((MVELAccumulatorContext) context).setVariables(localVars);
}
Also used : MVELDialectRuntimeData(org.drools.core.rule.MVELDialectRuntimeData) VariableResolverFactory(org.mvel2.integration.VariableResolverFactory) DroolsVarFactory(org.drools.core.base.mvel.MVELCompilationUnit.DroolsVarFactory) InternalKnowledgePackage(org.drools.core.definitions.InternalKnowledgePackage)

Example 25 with MVEL

use of org.mvel2.MVEL in project drools by kiegroup.

the class ActivationPropertyHandler method getProperty.

public Object getProperty(String name, Object obj, VariableResolverFactory variableFactory) {
    AgendaItem item = (AgendaItem) obj;
    if ("rule".equals(name)) {
        return item.getRule();
    } else if ("active".equals(name)) {
        return item.isQueued();
    } else if ("objects".equals(name)) {
        return item.getObjects();
    } else if ("factHandles".equals(name)) {
        return item.getFactHandles();
    } else if ("declarationIds".equals(name)) {
        return item.getDeclarationIds();
    } else if ("this".equals(name)) {
        return item;
    }
    // FIXME hack as MVEL seems to be ignoring indexed variables
    VariableResolver vr = variableFactory.getNextFactory().getVariableResolver(name);
    if (vr != null) {
        return vr.getValue();
    }
    Declaration declr = item.getTerminalNode().getSubRule().getOuterDeclarations().get(name);
    if (declr != null) {
        return declr.getValue(null, item.getTuple().get(declr).getObject());
    } else {
        return item.getRule().getMetaData(name);
    }
}
Also used : Declaration(org.drools.core.rule.Declaration) VariableResolver(org.mvel2.integration.VariableResolver) AgendaItem(org.drools.core.common.AgendaItem)

Aggregations

ParserContext (org.mvel2.ParserContext)7 MVELDialectRuntimeData (org.drools.core.rule.MVELDialectRuntimeData)6 Test (org.junit.Test)6 ParserConfiguration (org.mvel2.ParserConfiguration)6 HashMap (java.util.HashMap)5 KieServices (org.kie.api.KieServices)5 KieFileSystem (org.kie.api.builder.KieFileSystem)5 ReleaseId (org.kie.api.builder.ReleaseId)5 KieContainer (org.kie.api.runtime.KieContainer)5 PropertyAccessException (org.mvel2.PropertyAccessException)5 Map (java.util.Map)4 KieSession (org.kie.api.runtime.KieSession)4 CompileException (org.mvel2.CompileException)4 Declaration (org.drools.core.rule.Declaration)3 Serializable (java.io.Serializable)2 HashSet (java.util.HashSet)2 List (java.util.List)2 Entry (java.util.Map.Entry)2 RecognitionException (org.antlr.runtime.RecognitionException)2 DroolsParserException (org.drools.compiler.compiler.DroolsParserException)2