protected void initDeclaredMask(BuildContext context, LeftTupleSource leftInput) { if (context == null || context.getLastBuiltPatterns() == null) { // only happens during unit tests leftDeclaredMask = AllSetBitMask.get(); return; } if (leftInput.getType() != NodeTypeEnums.LeftInputAdapterNode) { // BetaNode's not after LIANode are not relevant for left mask property specific, so don't // block anything. leftDeclaredMask = AllSetBitMask.get(); return; } Pattern pattern = context.getLastBuiltPatterns()[1]; // left input pattern ObjectType objectType = pattern == null || this.getType() == NodeTypeEnums.AccumulateNode ? ((LeftInputAdapterNode) leftInput) .getParentObjectSource() .getObjectTypeNode() .getObjectType() : pattern.getObjectType(); if (!(objectType instanceof ClassObjectType)) { // Only ClassObjectType can use property specific leftDeclaredMask = AllSetBitMask.get(); return; } Class objectClass = ((ClassWireable) objectType).getClassType(); if (isPropertyReactive(context, objectClass)) { // TODO: at the moment if pattern is null (e.g. for eval node) we cannot calculate the mask, // so we leave it to 0 if (pattern != null) { List<String> leftListenedProperties = pattern.getListenedProperties(); List<String> settableProperties = getSettableProperties(context.getKnowledgeBase(), objectClass); leftDeclaredMask = calculatePositiveMask(leftListenedProperties, settableProperties); leftNegativeMask = calculateNegativeMask(leftListenedProperties, settableProperties); setLeftListenedProperties(leftListenedProperties); } } else { // if property specific is not on, then accept all modification propagations leftDeclaredMask = AllSetBitMask.get(); } }
public AlphaNodeFieldConstraint getLiteralConstraint( final Pattern pattern, final String fieldName, final String evaluatorString, final String value) throws IntrospectionException { final Class<?> clazz = ((ClassObjectType) pattern.getObjectType()).getClassType(); final InternalReadAccessor extractor = store.getReader(clazz, fieldName, getClass().getClassLoader()); FieldValue fieldValue = FieldFactory.getInstance().getFieldValue(value, extractor.getValueType(), null); return new MvelConstraintTestUtil(fieldName + evaluatorString + value, fieldValue, extractor); }
/* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ @Before public void setUp() throws Exception { kBase = (InternalKnowledgeBase) KnowledgeBaseFactory.newKnowledgeBase(); listener1 = new TestRuleBaseListener("(listener-1) "); listener2 = new TestRuleBaseListener("(listener-2) "); kBase.addEventListener(listener1); kBase.addEventListener(listener2); final RuleImpl rule1 = new RuleImpl("test1"); final ClassObjectType cheeseObjectType = new ClassObjectType(Cheese.class); final Pattern pattern = new Pattern(0, cheeseObjectType); ClassFieldAccessorStore store = new ClassFieldAccessorStore(); store.setClassFieldAccessorCache( new ClassFieldAccessorCache(Thread.currentThread().getContextClassLoader())); store.setEagerWire(true); final ClassFieldReader extractor = store.getReader(Cheese.class, "type"); final FieldValue field = FieldFactory.getInstance().getFieldValue("cheddar"); final MvelConstraint constraint = new MvelConstraintTestUtil("type == \"cheddar\"", field, extractor); pattern.addConstraint(constraint); rule1.addPattern(pattern); rule1.setConsequence( new Consequence() { private static final long serialVersionUID = 510l; public void evaluate( final KnowledgeHelper knowledgeHelper, final WorkingMemory workingMemory) throws Exception {} public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {} public void writeExternal(ObjectOutput out) throws IOException {} public String getName() { return "default"; } }); final RuleImpl rule2 = new RuleImpl("test2"); final ClassObjectType cheeseObjectType2 = new ClassObjectType(Cheese.class); final Pattern pattern2 = new Pattern(0, cheeseObjectType2); final FieldValue field2 = FieldFactory.getInstance().getFieldValue("stilton"); final MvelConstraint constraint2 = new MvelConstraintTestUtil("type == \"stilton\"", field, extractor); pattern2.addConstraint(constraint2); rule2.addPattern(pattern2); rule2.setConsequence( new Consequence() { private static final long serialVersionUID = 510l; public void evaluate( final KnowledgeHelper knowledgeHelper, final WorkingMemory workingMemory) throws Exception {} public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {} public void writeExternal(ObjectOutput out) throws IOException {} public String getName() { return "default"; } }); pkg = new KnowledgePackageImpl("org.drools.test1"); pkg.addRule(rule1); pkg.addRule(rule2); }
private void processPositional( RuleBuildContext context, Query query, Declaration[] params, List<Integer> declrIndexes, List<Integer> varIndexes, List<Object> arguments, List<Declaration> requiredDeclarations, InternalReadAccessor arrayReader, Pattern pattern, BaseDescr base, String expression, ConstraintConnectiveDescr result) { int position = ((ExprConstraintDescr) base).getPosition(); if (position >= arguments.size()) { context.addError( new DescrBuildError( context.getParentDescr(), base, null, "Unable to parse query '" + query.getName() + "', as postion " + (position - 1) + " for expression '" + expression + "' does not exist on query size " + arguments.size())); return; } if (isVariable(expression)) { // is this already bound? Declaration declr = context.getDeclarationResolver().getDeclaration(query, expression); if (declr != null) { // it exists, so it's an input arguments.set(position, declr); declrIndexes.add(position); requiredDeclarations.add(declr); } else { // it doesn't exist, so it's an output arguments.set(position, Variable.v); varIndexes.add(position); declr = pattern.addDeclaration(expression); // this bit is different, notice its the ArrayElementReader that we wire up to, not the // declaration. ArrayElementReader reader = new ArrayElementReader( arrayReader, position, params[position].getExtractor().getExtractToClass()); declr.setReadAccessor(reader); } } else { // it's an expression and thus an input MVELDumper.MVELDumperContext mvelCtx = new MVELDumper.MVELDumperContext(); String rewrittenExpr = context.getCompilerFactory().getExpressionProcessor().dump(result, mvelCtx); arguments.set(position, MVEL.eval(rewrittenExpr)); // for now we just work with literals } }
@SuppressWarnings("unchecked") private void processBinding( RuleBuildContext context, BaseDescr descr, Declaration[] params, List<Integer> declrIndexes, List<Integer> varIndexes, List<Object> arguments, List<Declaration> requiredDeclarations, InternalReadAccessor arrayReader, Pattern pattern, BindingDescr bind, ConstraintConnectiveDescr result) { Declaration declr = context.getDeclarationResolver().getDeclaration(context.getRule(), bind.getVariable()); if (declr != null) { // check right maps to a slot, otherwise we can't reverse this and should error int pos = getPos(bind.getExpression(), params); if (pos >= 0) { // slot exist, reverse and continue String slot = bind.getExpression(); String var = bind.getVariable(); bind.setVariable(slot); bind.setExpression(var); } else { // else error, we cannot find the slot to unify against } } // left does not already exist, is it a slot? int pos = getPos(bind.getVariable(), params); if (pos >= 0) { // it's an input on a slot, is the input using bindings? declr = context.getDeclarationResolver().getDeclaration(context.getRule(), bind.getExpression()); if (declr != null) { arguments.set(pos, declr); declrIndexes.add(pos); requiredDeclarations.add(declr); } else { // it must be a literal/expression // it's an expression and thus an input DrlExprParser parser = new DrlExprParser(context.getConfiguration().getLanguageLevel()); ConstraintConnectiveDescr bresult = parser.parse(bind.getExpression()); if (parser.hasErrors()) { for (DroolsParserException error : parser.getErrors()) { context.addError( new DescrBuildError( context.getParentDescr(), descr, null, "Unable to parser pattern expression:\n" + error.getMessage())); } return; } MVELDumper.MVELDumperContext mvelCtx = new MVELDumper.MVELDumperContext(); String expr = context.getCompilerFactory().getExpressionProcessor().dump(bresult, mvelCtx); try { Object o = MVEL.eval(expr); arguments.set(pos, o); // for now we just work with literals } catch (Exception e) { context.addError( new DescrBuildError( context.getParentDescr(), descr, null, "Unable to compile expression:\n" + expr)); } } } else { // this is creating a new output binding // we know it doesn't exist, as we already checked for left == var declr = pattern.addDeclaration(bind.getVariable()); pos = getPos(bind.getExpression(), params); if (pos < 0) { // error this must be a binding on a slot context.addError( new DescrBuildError( context.getParentDescr(), descr, null, "named argument does not exist:\n" + bind.getExpression())); return; } // this bit is different, notice its the ArrayElementReader that we wire up to, not the // declaration. ArrayElementReader reader = new ArrayElementReader(arrayReader, pos, params[pos].getExtractor().getExtractToClass()); // Should the reader be registered like the others? Probably yes... // PatternBuilder.registerReadAccessor( ); declr.setReadAccessor(reader); varIndexes.add(pos); arguments.set(pos, Variable.v); } }
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, "this"); 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 .getKnowledgeBuilder() .getPackage() .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(context.getRule(), func.getBind()); Constraint c = new MvelConstraint( Collections.singletonList(context.getPkg().getName()), accumDescr.isMultiFunction() ? "this[ " + index + " ] == " + func.getBind() : "this == " + func.getBind(), new Declaration[] {inner}, null, IndexUtil.ConstraintType.EQUAL, context .getDeclarationResolver() .getDeclaration(context.getRule(), func.getBind()), accumDescr.isMultiFunction() ? new ArrayElementReader(arrayReader, index, function.getResultType()) : new SelfReferenceClassFieldReader(function.getResultType(), "this"), 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(), "this")); } } } index++; } return accumulators; }
@Test public void testSimpleExpression() throws Exception { PackageDescr pkgDescr = new PackageDescr("pkg1"); KnowledgeBuilderImpl pkgBuilder = new KnowledgeBuilderImpl(); pkgBuilder.addPackage(pkgDescr); InternalKnowledgePackage pkg = pkgBuilder.getPackageRegistry("pkg1").getPackage(); final RuleDescr ruleDescr = new RuleDescr("rule 1"); ruleDescr.setNamespace("pkg1"); ruleDescr.setConsequence("modify (cheese) {price = 5 };\nretract (cheese)"); DialectCompiletimeRegistry dialectRegistry = pkgBuilder.getPackageRegistry(pkg.getName()).getDialectCompiletimeRegistry(); MVELDialect mvelDialect = (MVELDialect) dialectRegistry.getDialect("mvel"); final InstrumentedBuildContent context = new InstrumentedBuildContent(pkgBuilder, ruleDescr, dialectRegistry, pkg, mvelDialect); final InstrumentedDeclarationScopeResolver declarationResolver = new InstrumentedDeclarationScopeResolver(); final ObjectType cheeseObjeectType = new ClassObjectType(Cheese.class); final Pattern pattern = new Pattern(0, cheeseObjeectType, "cheese"); final GroupElement subrule = new GroupElement(GroupElement.AND); subrule.addChild(pattern); final Map<String, Declaration> map = new HashMap<String, Declaration>(); map.put("cheese", pattern.getDeclaration()); declarationResolver.setDeclarations(map); context.setDeclarationResolver(declarationResolver); final MVELConsequenceBuilder builder = new MVELConsequenceBuilder(); builder.build(context, RuleImpl.DEFAULT_CONSEQUENCE_NAME); InternalKnowledgeBase kBase = (InternalKnowledgeBase) KnowledgeBaseFactory.newKnowledgeBase(); PropagationContextFactory pctxFactory = kBase.getConfiguration().getComponentFactory().getPropagationContextFactory(); kBase.addPackage(pkg); StatefulKnowledgeSessionImpl ksession = (StatefulKnowledgeSessionImpl) kBase.newStatefulKnowledgeSession(); final Cheese cheddar = new Cheese("cheddar", 10); final InternalFactHandle f0 = (InternalFactHandle) ksession.insert(cheddar); final LeftTupleImpl tuple = new LeftTupleImpl(f0, null, true); f0.removeLeftTuple(tuple); final AgendaItem item = new AgendaItemImpl( 0, tuple, 10, pctxFactory.createPropagationContext(1, 1, null, tuple, null), new RuleTerminalNode( 0, new CompositeObjectSinkAdapterTest.MockBetaNode(), context.getRule(), subrule, 0, new BuildContext(kBase, null)), null); final DefaultKnowledgeHelper kbHelper = new DefaultKnowledgeHelper(ksession); kbHelper.setActivation(item); ((MVELConsequence) context.getRule().getConsequence()) .compile( (MVELDialectRuntimeData) pkgBuilder .getPackageRegistry(pkg.getName()) .getDialectRuntimeRegistry() .getDialectData("mvel")); context.getRule().getConsequence().evaluate(kbHelper, ksession); assertEquals(5, cheddar.getPrice()); }