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);
}
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;
}
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;
}
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);
}
}
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);
}
Aggregations