use of org.drools.core.base.EvaluatorWrapper in project drools by kiegroup.
the class ASMConditionEvaluatorJitter method jitEvaluator.
public static ConditionEvaluator jitEvaluator(String expression, Condition condition, Declaration[] declarations, EvaluatorWrapper[] operators, ClassLoader classLoader, Tuple tuple) {
ClassGenerator generator = new ClassGenerator(getUniqueClassName(), classLoader).setInterfaces(ConditionEvaluator.class).addStaticField(ACC_PRIVATE | ACC_FINAL, "EXPRESSION", String.class, expression).addField(ACC_PRIVATE | ACC_FINAL, "declarations", Declaration[].class);
generator.addMethod(ACC_PUBLIC, "evaluate", generator.methodDescr(boolean.class, InternalFactHandle.class, InternalWorkingMemory.class, Tuple.class), new EvaluateMethodGenerator(condition, declarations, operators, tuple));
if (operators.length == 0) {
generator.addDefaultConstructor(new ClassGenerator.MethodBody() {
public void body(MethodVisitor mv) {
putFieldInThisFromRegistry("declarations", Declaration[].class, 1);
mv.visitInsn(RETURN);
}
}, Declaration[].class);
return generator.newInstance(Declaration[].class, declarations);
}
generator.addField(ACC_PRIVATE | ACC_FINAL, "operators", EvaluatorWrapper[].class);
generator.addDefaultConstructor(new ClassGenerator.MethodBody() {
public void body(MethodVisitor mv) {
putFieldInThisFromRegistry("declarations", Declaration[].class, 1);
putFieldInThisFromRegistry("operators", EvaluatorWrapper[].class, 2);
mv.visitInsn(RETURN);
}
}, Declaration[].class, EvaluatorWrapper[].class);
return generator.newInstance(Declaration[].class, declarations, EvaluatorWrapper[].class, operators);
}
use of org.drools.core.base.EvaluatorWrapper in project drools by kiegroup.
the class PatternBuilder method getOperators.
protected static EvaluatorWrapper[] getOperators(Map<String, EvaluatorWrapper> operatorMap) {
EvaluatorWrapper[] operators = new EvaluatorWrapper[operatorMap.size()];
int i = 0;
for (Map.Entry<String, EvaluatorWrapper> entry : operatorMap.entrySet()) {
EvaluatorWrapper evaluator = entry.getValue();
evaluator.setBindingName(entry.getKey());
operators[i++] = evaluator;
}
return operators;
}
use of org.drools.core.base.EvaluatorWrapper in project drools by kiegroup.
the class PatternBuilder method buildOperators.
protected static Map<String, EvaluatorWrapper> buildOperators(RuleBuildContext context, Pattern pattern, BaseDescr predicateDescr, Map<String, OperatorDescr> aliases) {
if (aliases.isEmpty()) {
return Collections.emptyMap();
}
Map<String, EvaluatorWrapper> operators = new HashMap<String, EvaluatorWrapper>();
for (Map.Entry<String, OperatorDescr> entry : aliases.entrySet()) {
OperatorDescr op = entry.getValue();
Declaration leftDecl = createDeclarationForOperator(context, pattern, op.getLeftString());
Declaration rightDecl = createDeclarationForOperator(context, pattern, op.getRightString());
Target left = leftDecl != null && leftDecl.isPatternDeclaration() ? Target.HANDLE : Target.FACT;
Target right = rightDecl != null && rightDecl.isPatternDeclaration() ? Target.HANDLE : Target.FACT;
op.setLeftIsHandle(left == Target.HANDLE);
op.setRightIsHandle(right == Target.HANDLE);
Evaluator evaluator = getConstraintBuilder(context).getEvaluator(context, predicateDescr, ValueType.OBJECT_TYPE, op.getOperator(), // the rewrite takes care of negation
false, op.getParametersText(), left, right);
EvaluatorWrapper wrapper = getConstraintBuilder(context).wrapEvaluator(evaluator, leftDecl, rightDecl);
operators.put(entry.getKey(), wrapper);
}
return operators;
}
use of org.drools.core.base.EvaluatorWrapper 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);
}
use of org.drools.core.base.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 = 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;
}
Aggregations