use of org.drools.core.base.extractors.ArrayElementReader in project drools by kiegroup.
the class KiePackagesBuilder method buildAccumulate.
private Accumulate buildAccumulate(RuleContext ctx, AccumulatePattern accPattern, RuleConditionElement source, Pattern pattern, List<String> usedVariableName, Binding binding) {
AccumulateFunction[] accFunctions = accPattern.getAccumulateFunctions();
Accumulate accumulate;
if (accFunctions.length == 1) {
final Class<?> functionClass = accFunctions[0].getFunctionClass();
final Accumulator accumulator = createAccumulator(usedVariableName, binding, functionClass);
final Variable boundVar = accPattern.getBoundVariables()[0];
final Declaration declaration = new Declaration(boundVar.getName(), getReadAcessor(JAVA_CLASS_OBJECT_TYPE), pattern, true);
pattern.addDeclaration(declaration);
Declaration[] bindingDeclaration = binding != null ? new Declaration[0] : new Declaration[] { ctx.getPattern(accFunctions[0].getSource()).getDeclaration() };
accumulate = new SingleAccumulate(source, bindingDeclaration, accumulator);
} else {
InternalReadAccessor reader = new SelfReferenceClassFieldReader(Object[].class);
Accumulator[] accumulators = new Accumulator[accFunctions.length];
for (int i = 0; i < accFunctions.length; i++) {
final Class<?> functionClass = accFunctions[i].getFunctionClass();
final Accumulator accumulator = createAccumulator(usedVariableName, binding, functionClass);
Variable boundVar = accPattern.getBoundVariables()[i];
pattern.addDeclaration(new Declaration(boundVar.getName(), new ArrayElementReader(reader, i, boundVar.getType()), pattern, true));
accumulators[i] = accumulator;
}
accumulate = new MultiAccumulate(source, new Declaration[0], accumulators);
}
for (Variable boundVar : accPattern.getBoundVariables()) {
ctx.addAccumulateSource(boundVar, accumulate);
}
return accumulate;
}
use of org.drools.core.base.extractors.ArrayElementReader in project drools by kiegroup.
the class MVELAccumulateBuilder method buildExternalFunctions.
private Accumulator[] buildExternalFunctions(final RuleBuildContext context, final AccumulateDescr accumDescr, MVELDialect dialect, Map<String, Declaration> decls, Map<String, Declaration> sourceOuterDeclr, BoundIdentifiers boundIds, boolean readLocalsFromTuple) {
Accumulator[] accumulators;
List<AccumulateFunctionCallDescr> functions = accumDescr.getFunctions();
accumulators = new Accumulator[functions.size()];
// creating the custom array reader
InternalReadAccessor arrayReader = new SelfReferenceClassFieldReader(Object[].class);
int index = 0;
Pattern pattern = (Pattern) context.getDeclarationResolver().peekBuildStack();
for (AccumulateFunctionCallDescr func : functions) {
// build an external function executor
AccumulateFunction function = context.getConfiguration().getAccumulateFunction(func.getFunction());
if (function == null) {
// might have been imported in the package
function = context.getPkg().getAccumulateFunctions().get(func.getFunction());
}
if (function == null) {
context.addError(new DescrBuildError(accumDescr, context.getRuleDescr(), null, "Unknown accumulate function: '" + func.getFunction() + "' on rule '" + context.getRuleDescr().getName() + "'. All accumulate functions must be registered before building a resource."));
return null;
}
final AnalysisResult analysis = dialect.analyzeExpression(context, accumDescr, func.getParams().length > 0 ? func.getParams()[0] : "\"\"", boundIds);
MVELCompilationUnit unit = dialect.getMVELCompilationUnit(func.getParams().length > 0 ? func.getParams()[0] : "\"\"", analysis, getUsedDeclarations(decls, analysis), getUsedDeclarations(sourceOuterDeclr, analysis), null, context, "drools", KnowledgeHelper.class, readLocalsFromTuple, MVELCompilationUnit.Scope.CONSTRAINT);
accumulators[index] = new MVELAccumulatorFunctionExecutor(unit, function);
// if there is a binding, create the binding
if (func.getBind() != null) {
if (context.getDeclarationResolver().isDuplicated(context.getRule(), func.getBind(), function.getResultType().getName())) {
if (!func.isUnification()) {
context.addError(new DescrBuildError(context.getParentDescr(), accumDescr, null, "Duplicate declaration for variable '" + func.getBind() + "' in the rule '" + context.getRule().getName() + "'"));
} else {
Declaration inner = context.getDeclarationResolver().getDeclaration(func.getBind());
Constraint c = new MvelConstraint(Collections.singletonList(context.getPkg().getName()), accumDescr.isMultiFunction() ? "this[ " + index + " ] == " + func.getBind() : "this == " + func.getBind(), new Declaration[] { inner }, null, null, IndexUtil.ConstraintType.EQUAL, context.getDeclarationResolver().getDeclaration(func.getBind()), accumDescr.isMultiFunction() ? new ArrayElementReader(arrayReader, index, function.getResultType()) : new SelfReferenceClassFieldReader(function.getResultType()), true);
((MutableTypeConstraint) c).setType(Constraint.ConstraintType.BETA);
pattern.addConstraint(c);
index++;
}
} else {
Declaration declr = pattern.addDeclaration(func.getBind());
if (accumDescr.isMultiFunction()) {
declr.setReadAccessor(new ArrayElementReader(arrayReader, index, function.getResultType()));
} else {
declr.setReadAccessor(new SelfReferenceClassFieldReader(function.getResultType()));
}
}
}
index++;
}
return accumulators;
}
use of org.drools.core.base.extractors.ArrayElementReader in project drools by kiegroup.
the class QueryBuilder method build.
public Pattern build(final RuleBuildContext context, final QueryDescr queryDescr) {
ObjectType queryObjectType = ClassObjectType.DroolsQuery_ObjectType;
final Pattern pattern = new Pattern(context.getNextPatternId(), // offset is 0 by default
0, queryObjectType, null);
final InternalReadAccessor extractor = PatternBuilder.getFieldReadAccessor(context, queryDescr, pattern, "name", null, true);
final QueryNameConstraint constraint = new QueryNameConstraint(extractor, queryDescr.getName());
PatternBuilder.registerReadAccessor(context, queryObjectType, "name", constraint);
// adds appropriate constraint to the pattern
pattern.addConstraint(constraint);
ObjectType argsObjectType = ClassObjectType.DroolsQuery_ObjectType;
InternalReadAccessor arrayExtractor = PatternBuilder.getFieldReadAccessor(context, queryDescr, null, argsObjectType, "elements", null, true);
QueryImpl query = ((QueryImpl) context.getRule());
String[] params;
String[] types;
int numParams = queryDescr.getParameters().length;
if (query.isAbductive()) {
params = Arrays.copyOf(queryDescr.getParameters(), queryDescr.getParameters().length + 1);
types = Arrays.copyOf(queryDescr.getParameterTypes(), queryDescr.getParameterTypes().length + 1);
} else {
params = queryDescr.getParameters();
types = queryDescr.getParameterTypes();
}
Declaration[] declarations = new Declaration[params.length];
Class<?> abductionReturnKlass = null;
if (query.isAbductive()) {
Abductive abductive = queryDescr.getTypedAnnotation(Abductive.class);
abductionReturnKlass = abductive.target();
params[numParams] = "";
types[numParams] = abductionReturnKlass.getName();
}
int i = 0;
try {
for (i = 0; i < params.length; i++) {
Declaration declr = pattern.addDeclaration(params[i]);
// this bit is different, notice its the ArrayElementReader that we wire up to, not the declaration.
ArrayElementReader reader = new ArrayElementReader(arrayExtractor, i, context.getDialect().getTypeResolver().resolveType(types[i]));
PatternBuilder.registerReadAccessor(context, argsObjectType, "elements", reader);
declr.setReadAccessor(reader);
declarations[i] = declr;
}
query.setParameters(declarations);
} catch (ClassNotFoundException e) {
context.addError(new DescrBuildError(context.getParentDescr(), queryDescr, e, "Unable to resolve type '" + types[i] + " for parameter" + params[i]));
}
context.setPrefixPattern(pattern);
if (query.isAbductive()) {
String returnName = "";
try {
AnnotationDescr ann = queryDescr.getAnnotation(Abductive.class);
Object[] argsVal = ((Object[]) ann.getValue("args"));
String[] args = argsVal != null ? Arrays.copyOf(argsVal, argsVal.length, String[].class) : null;
returnName = types[numParams];
ObjectType objectType = new ClassObjectType(abductionReturnKlass, false);
objectType = context.getPkg().getClassFieldAccessorStore().wireObjectType(objectType, (AbductiveQuery) query);
((AbductiveQuery) query).setReturnType(objectType, params, args, declarations);
} catch (NoSuchMethodException e) {
context.addError(new DescrBuildError(context.getParentDescr(), queryDescr, e, "Unable to resolve abducible constructor for type : " + returnName + " with types " + Arrays.toString(types)));
} catch (IllegalArgumentException e) {
context.addError(new DescrBuildError(context.getParentDescr(), queryDescr, e, e.getMessage()));
}
}
return pattern;
}
use of org.drools.core.base.extractors.ArrayElementReader in project drools by kiegroup.
the class KiePackagesBuilder method buildAccumulate.
private Accumulate buildAccumulate(RuleContext ctx, AccumulatePattern accPattern, RuleConditionElement source, Pattern pattern, Set<String> usedVariableName, Collection<Binding> bindings) {
boolean isGroupBy = accPattern instanceof GroupByPattern;
AccumulateFunction[] accFunctions = accPattern.getAccumulateFunctions();
Declaration groupByDeclaration = null;
Class selfType = (isGroupBy || accFunctions.length > 1) ? Object[].class : accFunctions[0].getResult().getType();
InternalReadAccessor selfReader = new SelfReferenceClassFieldReader(selfType);
int arrayIndexOffset = 0;
if (isGroupBy) {
if (accFunctions.length == 0) {
// In this situation the result is anonymous, but it still uses element position 0.
// For this reason the i used to populate hte array index must be offset by 1.
accFunctions = new AccumulateFunction[] { new AccumulateFunction(null, CountAccumulateFunction::new) };
arrayIndexOffset = 1;
}
// GroupBy key is always the last element in the result array
Variable groupVar = ((GroupByPattern<?, ?>) accPattern).getVarKey();
groupByDeclaration = new Declaration(groupVar.getName(), new ArrayElementReader(selfReader, accFunctions.length, groupVar.getType()), pattern, true);
pattern.addDeclaration(groupByDeclaration);
}
Accumulate accumulate;
Accumulator[] accumulators = new Accumulator[accFunctions.length];
List<Declaration> requiredDeclarationList = new ArrayList<>();
for (int i = 0; i < accFunctions.length; i++) {
Variable boundVar = processFunctions(ctx, accPattern, source, pattern, usedVariableName, bindings, isGroupBy, accFunctions[i], selfReader, accumulators, requiredDeclarationList, arrayIndexOffset, i);
if (isGroupBy) {
ctx.addGroupByDeclaration(((GroupByPattern) accPattern).getVarKey(), groupByDeclaration);
}
}
if (accFunctions.length == 1) {
accumulate = new SingleAccumulate(source, requiredDeclarationList.toArray(new Declaration[requiredDeclarationList.size()]), accumulators[0]);
} else {
if (source instanceof Pattern) {
requiredDeclarationList.forEach(((Pattern) source)::addDeclaration);
}
accumulate = new MultiAccumulate(source, new Declaration[0], accumulators, // if this is a groupby +1 for the key
accumulators.length + ((isGroupBy) ? 1 : 0));
}
if (isGroupBy) {
GroupByPatternImpl groupBy = (GroupByPatternImpl) accPattern;
Declaration[] groupingDeclarations = new Declaration[groupBy.getVars().length];
for (int i = 0; i < groupBy.getVars().length; i++) {
groupingDeclarations[i] = ctx.getDeclaration(groupBy.getVars()[i]);
}
accumulate = new LambdaGroupByAccumulate(accumulate, groupingDeclarations, groupBy.getGroupingFunction());
}
for (Variable boundVar : accPattern.getBoundVariables()) {
ctx.addAccumulateSource(boundVar, accumulate);
}
return accumulate;
}
use of org.drools.core.base.extractors.ArrayElementReader in project drools by kiegroup.
the class JavaAccumulateBuilder method buildExternalFunctionCall.
private Accumulate buildExternalFunctionCall(RuleBuildContext context, AccumulateDescr accumDescr, RuleConditionElement source, Map<String, Declaration> declsInScope, Map<String, Class<?>> declCls, boolean readLocalsFromTuple) {
// list of functions to build
final List<AccumulateFunctionCallDescr> funcCalls = accumDescr.getFunctions();
// list of available source declarations
final Declaration[] sourceDeclArr = source.getOuterDeclarations().values().toArray(new Declaration[source.getOuterDeclarations().size()]);
Arrays.sort(sourceDeclArr, RuleTerminalNode.SortDeclarations.instance);
// set of required previous declarations
Set<Declaration> requiredDecl = new HashSet<Declaration>();
Pattern pattern = (Pattern) context.getDeclarationResolver().peekBuildStack();
if (accumDescr.isMultiFunction()) {
// the accumulator array
Accumulator[] accumulators = new Accumulator[funcCalls.size()];
// creating the custom array reader
InternalReadAccessor reader = new SelfReferenceClassFieldReader(Object[].class);
int index = 0;
for (AccumulateFunctionCallDescr fc : funcCalls) {
AccumulateFunction function = getAccumulateFunction(context, accumDescr, fc, source, declCls);
if (function == null) {
return null;
}
bindReaderToDeclaration(context, accumDescr, pattern, fc, new ArrayElementReader(reader, index, function.getResultType()), function.getResultType(), index);
accumulators[index++] = buildAccumulator(context, accumDescr, declsInScope, declCls, readLocalsFromTuple, sourceDeclArr, requiredDecl, fc, function);
}
return new MultiAccumulate(source, requiredDecl.toArray(new Declaration[requiredDecl.size()]), accumulators, accumulators.length);
} else {
AccumulateFunctionCallDescr fc = accumDescr.getFunctions().get(0);
AccumulateFunction function = getAccumulateFunction(context, accumDescr, fc, source, declCls);
if (function == null) {
return null;
}
Class<?> returnType = function.getResultType();
if (!pattern.isCompatibleWithAccumulateReturnType(returnType)) {
context.addError(new DescrBuildError(accumDescr, context.getRuleDescr(), null, "Pattern of type: '" + pattern.getObjectType() + "' on rule '" + context.getRuleDescr().getName() + "' is not compatible with type " + returnType.getCanonicalName() + " returned by accumulate function."));
return null;
}
bindReaderToDeclaration(context, accumDescr, pattern, fc, new SelfReferenceClassFieldReader(function.getResultType()), function.getResultType(), -1);
Accumulator accumulator = buildAccumulator(context, accumDescr, declsInScope, declCls, readLocalsFromTuple, sourceDeclArr, requiredDecl, fc, function);
return new SingleAccumulate(source, requiredDecl.toArray(new Declaration[requiredDecl.size()]), accumulator);
}
}
Aggregations