use of org.drools.core.base.extractors.SelfReferenceClassFieldReader in project drools by kiegroup.
the class ClassFieldAccessorFactory method getClassFieldReader.
public static BaseClassFieldReader getClassFieldReader(Class<?> clazz, String fieldName, CacheEntry cache) {
try {
// if it is a self reference
if (SELF_REFERENCE_FIELD.equals(fieldName)) {
// then just create an instance of the special class field extractor
return new SelfReferenceClassFieldReader(clazz);
} else {
// otherwise, bytecode generate a specific extractor
ClassFieldInspector inspector = getClassFieldInspector(clazz, cache);
Method getterMethod = inspector.getGetterMethods().get(fieldName);
Integer index = inspector.getFieldNames().get(fieldName);
Class<?> fieldType = inspector.getFieldType(fieldName);
if (fieldType == null && fieldName.length() > 1 && Character.isLowerCase(fieldName.charAt(0)) && Character.isUpperCase(fieldName.charAt(1))) {
// it might be that odd case of javabeans naming conventions that does not use lower case first letters if the second is uppercase
String altFieldName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
fieldType = inspector.getFieldType(altFieldName);
if (fieldType != null) {
// it seems it is the corner case indeed.
getterMethod = inspector.getGetterMethods().get(altFieldName);
index = inspector.getFieldNames().get(altFieldName);
}
}
if (fieldType != null && getterMethod != null) {
final String className = ClassFieldAccessorFactory.BASE_PACKAGE + "/" + Type.getInternalName(clazz) + Math.abs(System.identityHashCode(clazz)) + "$" + getterMethod.getName();
// generating byte array to create target class
final byte[] bytes = dumpReader(clazz, className, getterMethod, fieldType);
// use bytes to get a class
ByteArrayClassLoader byteArrayClassLoader = cache.getByteArrayClassLoader();
final Class<?> newClass = byteArrayClassLoader.defineClass(className.replace('/', '.'), bytes, PROTECTION_DOMAIN);
// instantiating target class
final ValueType valueType = ValueType.determineValueType(fieldType);
final Object[] params = { index, fieldType, valueType };
return (BaseClassFieldReader) newClass.getConstructors()[0].newInstance(params);
} else {
// must be a public field
return null;
}
}
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
use of org.drools.core.base.extractors.SelfReferenceClassFieldReader 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.SelfReferenceClassFieldReader 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.SelfReferenceClassFieldReader in project drools by kiegroup.
the class QueryElementBuilder method build.
@SuppressWarnings("unchecked")
public RuleConditionElement build(RuleBuildContext context, BaseDescr descr, QueryImpl query) {
PatternDescr patternDescr = (PatternDescr) descr;
Declaration[] params = query.getParameters();
List<BaseDescr> args = (List<BaseDescr>) patternDescr.getDescrs();
List<Declaration> requiredDeclarations = new ArrayList<Declaration>();
ObjectType argsObjectType = ClassObjectType.ObjectArray_ObjectType;
InternalReadAccessor arrayReader = new SelfReferenceClassFieldReader(Object[].class);
Pattern pattern = new Pattern(context.getNextPatternId(), 0, argsObjectType, null);
if (!StringUtils.isEmpty(patternDescr.getIdentifier())) {
if (query.isAbductive()) {
Declaration declr = context.getDeclarationResolver().getDeclaration(patternDescr.getIdentifier());
if (declr != null && !patternDescr.isUnification()) {
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Duplicate declaration " + patternDescr.getIdentifier() + ", unable to bind abducted value"));
}
} else {
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Query binding is not supported by non-abductive queries : " + patternDescr.getIdentifier()));
}
}
boolean addAbductiveReturnArgument = query.isAbductive() && !StringUtils.isEmpty(patternDescr.getIdentifier()) && args.size() < params.length;
if (addAbductiveReturnArgument) {
ExprConstraintDescr extraDescr = new ExprConstraintDescr(patternDescr.getIdentifier());
extraDescr.setPosition(patternDescr.getConstraint().getDescrs().size());
extraDescr.setType(ExprConstraintDescr.Type.POSITIONAL);
args.add(extraDescr);
}
QueryArgument[] arguments = new QueryArgument[params.length];
// Deal with the constraints, both positional and bindings
for (BaseDescr base : args) {
String expression = null;
boolean isPositional = false;
boolean isBinding = false;
BindingDescr bind = null;
ConstraintConnectiveDescr result = null;
if (base instanceof BindingDescr) {
bind = (BindingDescr) base;
expression = bind.getVariable() + (bind.isUnification() ? " := " : " : ") + bind.getExpression();
isBinding = true;
} else {
if (base instanceof ExprConstraintDescr) {
ExprConstraintDescr ecd = (ExprConstraintDescr) base;
expression = ecd.getExpression();
isPositional = ecd.getType() == ExprConstraintDescr.Type.POSITIONAL;
} else {
expression = base.getText();
}
result = parseExpression(context, patternDescr, expression);
if (result == null) {
// error, can't parse expression.
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Unable to parse constraint: \n" + expression));
continue;
}
isBinding = result.getDescrs().size() == 1 && result.getDescrs().get(0) instanceof BindingDescr;
if (isBinding) {
bind = (BindingDescr) result.getDescrs().get(0);
}
}
if ((!isPositional) && (!isBinding)) {
// error, can't have non binding slots.
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Query's must use positional or bindings, not field constraints:\n" + expression));
} else if (isPositional && isBinding) {
// error, can't have positional binding slots.
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Query's can't use positional bindings:\n" + expression));
} else if (isPositional) {
processPositional(context, query, params, arguments, requiredDeclarations, arrayReader, pattern, base, expression, result);
} else {
// it is binding
processBinding(context, descr, params, arguments, requiredDeclarations, arrayReader, pattern, bind);
}
}
List<Integer> varIndexList = new ArrayList<Integer>();
for (int i = 0; i < arguments.length; i++) {
if (!(arguments[i] instanceof QueryArgument.Declr)) {
if (arguments[i] instanceof QueryArgument.Var) {
varIndexList.add(i);
}
continue;
}
Class actual = ((QueryArgument.Declr) arguments[i]).getArgumentClass();
Declaration formalArgument = query.getParameters()[i];
Class formal = formalArgument.getDeclarationClass();
// input argument require a broader type, while output types require a narrower type, so we check for both.
if (!ClassUtils.isTypeCompatibleWithArgumentType(actual, formal) && !ClassUtils.isTypeCompatibleWithArgumentType(formal, actual)) {
context.addError(new DescrBuildError(context.getParentDescr(), descr, null, "Query is being invoked with known argument of type " + actual + " at position " + i + ", but the expected query argument is of type " + formal));
}
}
return new QueryElement(pattern, query.getName(), arguments, toIntArray(varIndexList), requiredDeclarations.toArray(new Declaration[requiredDeclarations.size()]), !patternDescr.isQuery(), query.isAbductive());
}
use of org.drools.core.base.extractors.SelfReferenceClassFieldReader in project drools by kiegroup.
the class KiePackagesBuilder method buildQueryPattern.
private RuleConditionElement buildQueryPattern(RuleContext ctx, QueryCallPattern queryPattern) {
Pattern pattern = new Pattern(ctx.getNextPatternIndex(), 0, ClassObjectType.ObjectArray_ObjectType, null);
InternalReadAccessor arrayReader = new SelfReferenceClassFieldReader(Object[].class);
QueryArgument[] arguments = new QueryArgument[queryPattern.getArguments().length];
List<Integer> varIndexList = new ArrayList<>();
List<Declaration> requiredDeclarations = new ArrayList<>();
for (int i = 0; i < queryPattern.getArguments().length; i++) {
Argument arg = queryPattern.getArguments()[i];
if (arg instanceof Variable) {
Variable var = ((Variable) arg);
Declaration decl = ctx.getDeclaration(var);
if (decl != null) {
requiredDeclarations.add(decl);
arguments[i] = new QueryArgument.Declr(decl);
} else {
ArrayElementReader reader = new ArrayElementReader(arrayReader, i, arg.getType());
pattern.addDeclaration(var.getName()).setReadAccessor(reader);
arguments[i] = QueryArgument.VAR;
varIndexList.add(i);
}
} else if (arg instanceof Value) {
arguments[i] = new QueryArgument.Literal(((Value) arg).getValue());
} else {
throw new UnsupportedOperationException();
}
}
return new QueryElement(pattern, queryPattern.getQuery().getName(), arguments, varIndexList.stream().mapToInt(i -> i).toArray(), requiredDeclarations.toArray(new Declaration[requiredDeclarations.size()]), queryPattern.isOpen(), // TODO: query.isAbductive() );
false);
}
Aggregations