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