public void build( final RuleBuildContext context, final BoundIdentifiers usedIdentifiers, final Declaration[] previousDeclarations, final Declaration[] localDeclarations, final PredicateConstraint predicate, final PredicateDescr predicateDescr, final AnalysisResult analysis) { MVELDialect dialect = (MVELDialect) context.getDialect(context.getDialect().getId()); try { Map<String, Class<?>> declIds = context.getDeclarationResolver().getDeclarationClasses(context.getRule()); Pattern p = (Pattern) context.getBuildStack().peek(); if (p.getObjectType() instanceof ClassObjectType) { declIds.put("this", ((ClassObjectType) p.getObjectType()).getClassType()); } MVELCompilationUnit unit = dialect.getMVELCompilationUnit( (String) predicateDescr.getContent(), analysis, previousDeclarations, localDeclarations, null, context); MVELPredicateExpression expr = new MVELPredicateExpression(unit, context.getDialect().getId()); predicate.setPredicateExpression(expr); MVELDialectRuntimeData data = (MVELDialectRuntimeData) context .getPkg() .getDialectRuntimeRegistry() .getDialectData(context.getDialect().getId()); data.addCompileable(predicate, expr); expr.compile(context.getPackageBuilder().getRootClassLoader()); } catch (final Exception e) { context .getErrors() .add( new DescrBuildError( context.getParentDescr(), predicateDescr, e, "Unable to build expression for 'inline-eval' : " + e.getMessage() + "'" + predicateDescr.getContent() + "'\n" + e.getMessage())); } }
private void attachPattern( final BuildContext context, final BuildUtils utils, final Pattern pattern) throws InvalidPatternException { // Set pattern offset to the appropriate value pattern.setOffset(context.getCurrentPatternOffset()); final List<Constraint> alphaConstraints = new LinkedList<Constraint>(); final List<Constraint> betaConstraints = new LinkedList<Constraint>(); final List<Behavior> behaviors = new LinkedList<Behavior>(); this.createConstraints(context, utils, pattern, alphaConstraints, betaConstraints); // Create BetaConstraints object context.setBetaconstraints(betaConstraints); // set behaviors list behaviors.addAll(pattern.getBehaviors()); context.setBehaviors(behaviors); if (pattern.getSource() != null) { context.setAlphaConstraints(alphaConstraints); final int currentOffset = context.getCurrentPatternOffset(); PatternSource source = pattern.getSource(); ReteooComponentBuilder builder = utils.getBuilderFor(source); builder.build(context, utils, source); // restoring offset context.setCurrentPatternOffset(currentOffset); } if (pattern.getSource() == null || context.getCurrentEntryPoint() != EntryPoint.DEFAULT) { attachAlphaNodes(context, utils, pattern, alphaConstraints); if (context.getCurrentEntryPoint() != EntryPoint.DEFAULT) { context.setObjectSource( (ObjectSource) utils.attachNode( context, new PropagationQueuingNode( context.getNextId(), context.getObjectSource(), context))); // the entry-point specific network nodes are attached, so, set context to default // entry-point context.setCurrentEntryPoint(EntryPoint.DEFAULT); } } // last thing to do is increment the offset, since if the pattern has a source, // offset must be overriden context.incrementCurrentPatternOffset(); }
private void createConstraints( BuildContext context, BuildUtils utils, Pattern pattern, List<Constraint> alphaConstraints, List<Constraint> betaConstraints) { final List<?> constraints = pattern.getConstraints(); // check if cross products for identity patterns should be disabled checkRemoveIdentities(context, pattern, betaConstraints); // checks if this pattern is nested inside a NOT CE final boolean isNegative = isNegative(context); for (final Iterator<?> it = constraints.iterator(); it.hasNext(); ) { final Object object = it.next(); // Check if its a declaration if (object instanceof Declaration) { // nothing to be done continue; } final Constraint constraint = (Constraint) object; if (constraint.getType().equals(Constraint.ConstraintType.ALPHA)) { alphaConstraints.add(constraint); } else if (constraint.getType().equals(Constraint.ConstraintType.BETA)) { betaConstraints.add(constraint); if (isNegative && context.getRuleBase().getConfiguration().getEventProcessingMode() == EventProcessingOption.STREAM && pattern.getObjectType().isEvent() && constraint.isTemporal()) { checkDelaying(context, constraint); } } else { throw new RuntimeDroolsException( "Unknown constraint type: " + constraint.getType() + ". This is a bug. Please contact development team."); } } }
/** * @param context * @param pattern * @param betaConstraints */ private void checkRemoveIdentities( final BuildContext context, final Pattern pattern, final List<Constraint> betaConstraints) { if (context.getRuleBase().getConfiguration().isRemoveIdentities() && pattern.getObjectType().getClass() == ClassObjectType.class) { // Check if this object type exists before // If it does we need stop instance equals cross product final Class<?> thisClass = ((ClassObjectType) pattern.getObjectType()).getClassType(); for (final Iterator<Pattern> it = context.getObjectType().iterator(); it.hasNext(); ) { final Pattern previousPattern = it.next(); final Class<?> previousClass = ((ClassObjectType) previousPattern.getObjectType()).getClassType(); if (thisClass.isAssignableFrom(previousClass)) { betaConstraints.add(new InstanceNotEqualsConstraint(previousPattern)); } } // Must be added after the checking, otherwise it matches against itself context.getObjectType().add(pattern); } }
@Override protected void initDeclaredMask(BuildContext context, LeftTupleSource leftInput) { if (context == null || context.getLastBuiltPatterns() == null) { // only happens during unit tests rightDeclaredMask = Long.MAX_VALUE; super.initDeclaredMask(context, leftInput); return; } if (!(rightInput instanceof RightInputAdapterNode)) { Pattern pattern = context.getLastBuiltPatterns()[0]; // right input pattern ObjectType objectType = pattern.getObjectType(); if (!(objectType instanceof ClassObjectType)) { // InitialFact has no type declaration and cannot be property specific // Only ClassObjectType can use property specific rightDeclaredMask = Long.MAX_VALUE; } Class objectClass = ((ClassObjectType) objectType).getClassType(); if (isPropertyReactive(context, objectClass)) { rightListenedProperties = pattern.getListenedProperties(); List<String> settableProperties = getSettableProperties(context.getRuleBase(), objectClass); rightDeclaredMask = calculatePositiveMask(rightListenedProperties, settableProperties); rightDeclaredMask |= constraints.getListenedPropertyMask(settableProperties); rightNegativeMask = calculateNegativeMask(rightListenedProperties, settableProperties); } else { // if property reactive is not on, then accept all modification propagations rightDeclaredMask = Long.MAX_VALUE; } } else { rightDeclaredMask = Long.MAX_VALUE; // There would have been no right input pattern, so swap current to first, so leftInput can // still work context.setLastBuiltPattern(context.getLastBuiltPatterns()[0]); } super.initDeclaredMask(context, leftInput); }
private void createResultBind( final Pattern pattern, int index, InternalReadAccessor arrayReader, AccumulateFunctionCallDescr fc, AccumulateFunction function) { // bind function result on the result pattern Declaration declr = pattern.addDeclaration(fc.getBind()); Class<?> type = function.getResultType(); // this bit is different, notice its the ArrayElementReader that we wire up to, not the // declaration. ArrayElementReader reader = new ArrayElementReader(arrayReader, index, type); declr.setReadAccessor(reader); }
@Test public void test1() { KnowledgePackage pkg1 = getKnowledgePackage1(); KnowledgePackage pkg2 = getKnowledgePackage1(); KnowledgePackage pkg3 = getKnowledgePackage2(); Rule rule1 = ((KnowledgePackageImp) pkg1).pkg.getRule("rule1"); Rule rule2 = ((KnowledgePackageImp) pkg2).pkg.getRule("rule1"); Rule rule3 = ((KnowledgePackageImp) pkg3).pkg.getRule("rule1"); // test return value Pattern p1 = (Pattern) rule1.getLhs().getChildren().get(0); VariableConstraint rvc1 = (VariableConstraint) p1.getConstraints().get(0); ReturnValueExpression rve1 = ((ReturnValueRestriction) rvc1.getRestriction()).getExpression(); Pattern p2 = (Pattern) rule2.getLhs().getChildren().get(0); VariableConstraint rvc2 = (VariableConstraint) p2.getConstraints().get(0); ReturnValueExpression rve2 = ((ReturnValueRestriction) rvc2.getRestriction()).getExpression(); assertNotSame(rve1, rve2); assertEquals(rve1, rve2); Pattern p3 = (Pattern) rule3.getLhs().getChildren().get(0); VariableConstraint rvc3 = (VariableConstraint) p3.getConstraints().get(0); ReturnValueExpression rve3 = ((ReturnValueRestriction) rvc3.getRestriction()).getExpression(); assertNotSame(rve1, rve3); assertThat(rve1, not(equalTo(rve3))); // test inline eval PredicateConstraint pc1 = (PredicateConstraint) p1.getConstraints().get(1); PredicateExpression pe1 = (PredicateExpression) pc1.getPredicateExpression(); PredicateConstraint pc2 = (PredicateConstraint) p2.getConstraints().get(1); PredicateExpression pe2 = (PredicateExpression) pc2.getPredicateExpression(); assertNotSame(pe1, pe2); assertEquals(pe1, pe2); PredicateConstraint pc3 = (PredicateConstraint) p3.getConstraints().get(1); PredicateExpression pe3 = (PredicateExpression) pc3.getPredicateExpression(); assertNotSame(pe1, pe3); assertThat(pe1, not(equalTo(pe3))); // test eval EvalCondition ec1 = (EvalCondition) rule1.getLhs().getChildren().get(1); EvalExpression ee1 = (EvalExpression) ec1.getEvalExpression(); EvalCondition ec2 = (EvalCondition) rule2.getLhs().getChildren().get(1); EvalExpression ee2 = (EvalExpression) ec2.getEvalExpression(); assertNotSame(ee1, ee2); assertEquals(ee1, ee2); EvalCondition ec3 = (EvalCondition) rule3.getLhs().getChildren().get(1); EvalExpression ee3 = (EvalExpression) ec3.getEvalExpression(); assertNotSame(ee1, ee3); assertThat(ee1, not(equalTo(ee3))); // test consequence assertNotSame(rule1.getConsequence(), rule2.getConsequence()); assertEquals(rule1.getConsequence(), rule2.getConsequence()); assertNotSame(rule1.getConsequence(), rule3.getConsequence()); assertThat(rule1.getConsequence(), not(equalTo(rule3.getConsequence()))); // check LHS equals assertNotSame(rule1.getLhs(), rule2.getLhs()); assertEquals(rule1.getLhs(), rule2.getLhs()); assertNotSame(rule1.getLhs(), rule3.getLhs()); assertThat(rule1.getLhs(), not(equalTo(rule3.getLhs()))); }
@SuppressWarnings("unchecked") @Test public void testSimpleTemplate() throws Exception { TemplateContainer tc = new TemplateContainer() { private Column[] columns = new Column[] { new LongColumn("column1"), new LongColumn("column2"), new StringColumn("column3") }; public Column[] getColumns() { return columns; } public String getHeader() { return null; } public Map<String, RuleTemplate> getTemplates() { Map<String, RuleTemplate> templates = new HashMap<String, RuleTemplate>(); RuleTemplate ruleTemplate = new RuleTemplate("template1", this); ruleTemplate.addColumn("column1 == 10"); ruleTemplate.addColumn("column2 < 5 || > 20"); ruleTemplate.addColumn("column3 == \"xyz\""); templates.put("template1", ruleTemplate); return templates; } public Column getColumn(String name) { return columns[Integer.parseInt(name.substring(6)) - 1]; } }; DefaultTemplateRuleBase ruleBase = new DefaultTemplateRuleBase(tc); Package[] packages = ruleBase.newStatefulSession().getRuleBase().getPackages(); assertEquals(1, packages.length); Map<String, String> globals = packages[0].getGlobals(); assertEquals(DefaultGenerator.class.getName(), globals.get("generator")); Rule[] rules = packages[0].getRules(); assertEquals(1, rules.length); assertEquals("template1", rules[0].getName()); GroupElement lhs = rules[0].getLhs(); // when // r : Row() // column1 : Column(name == "column1") // exists LongCell(row == r, column == column1, value == 10) // column2 : Column(name == "column2") // exists LongCell(row == r, column == column2, value < 5 | > 20) // column3 : Column(name == "column3") // exists StringCell(row == r, column == column3, value == "xyz") assertEquals(7, lhs.getChildren().size()); org.drools.rule.Pattern pattern = (org.drools.rule.Pattern) lhs.getChildren().get(1); assertEquals(1, pattern.getConstraints().size()); Constraint constraint = pattern.getConstraints().get(0); GroupElement exists = (GroupElement) lhs.getChildren().get(2); pattern = (org.drools.rule.Pattern) exists.getChildren().get(0); assertEquals(3, pattern.getConstraints().size()); IndexableConstraint vconstraint = (IndexableConstraint) pattern.getConstraints().get(1); assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass()); assertEquals("column1", vconstraint.getRequiredDeclarations()[0].getIdentifier()); pattern = (org.drools.rule.Pattern) lhs.getChildren().get(3); assertEquals(1, pattern.getConstraints().size()); constraint = pattern.getConstraints().get(0); exists = (GroupElement) lhs.getChildren().get(4); pattern = (org.drools.rule.Pattern) exists.getChildren().get(0); assertEquals(3, pattern.getConstraints().size()); vconstraint = (IndexableConstraint) pattern.getConstraints().get(1); assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass()); assertEquals("column2", vconstraint.getRequiredDeclarations()[0].getIdentifier()); pattern = (org.drools.rule.Pattern) lhs.getChildren().get(5); assertEquals(1, pattern.getConstraints().size()); constraint = pattern.getConstraints().get(0); exists = (GroupElement) lhs.getChildren().get(6); pattern = (org.drools.rule.Pattern) exists.getChildren().get(0); assertEquals(3, pattern.getConstraints().size()); vconstraint = (IndexableConstraint) pattern.getConstraints().get(1); assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass()); assertEquals("column3", vconstraint.getRequiredDeclarations()[0].getIdentifier()); }
public void attachAlphaNodes( final BuildContext context, final BuildUtils utils, final Pattern pattern, List<Constraint> alphaConstraints) throws InvalidPatternException { // Drools Query ObjectTypeNode never has memory, but other ObjectTypeNode/AlphaNoesNodes may (if // not in sequential), // so need to preserve, so we can restore after this node is added. LeftMemory and Terminal // remain the same once set. boolean objectMemory = context.isObjectTypeNodeMemoryEnabled(); boolean alphaMemory = context.isAlphaMemoryAllowed(); ObjectType objectType = pattern.getObjectType(); if (pattern.getObjectType() instanceof ClassObjectType) { // Is this the query node, if so we don't want any memory if (DroolsQuery.class == ((ClassObjectType) pattern.getObjectType()).getClassType()) { context.setTupleMemoryEnabled(false); context.setObjectTypeNodeMemoryEnabled(false); context.setTerminalNodeMemoryEnabled(false); context.setAlphaNodeMemoryAllowed(false); } } context.setObjectSource( (ObjectSource) utils.attachNode( context, new EntryPointNode(context.getNextId(), context.getRuleBase().getRete(), context))); ObjectTypeNode otn = new ObjectTypeNode( context.getNextId(), (EntryPointNode) context.getObjectSource(), objectType, context); if (objectType.isEvent() && EventProcessingOption.STREAM.equals( context.getRuleBase().getConfiguration().getEventProcessingMode())) { long expirationOffset = getExpiratioOffsetForType(context, objectType); if (expirationOffset != -1) { // expiration policy is set, so use it otn.setExpirationOffset(expirationOffset); } else { // otherwise calculate it based on behaviours and temporal constraints for (Behavior behavior : pattern.getBehaviors()) { if (behavior.getExpirationOffset() != -1) { expirationOffset = Math.max(behavior.getExpirationOffset(), expirationOffset); } } long distance = context.getTemporalDistance().getExpirationOffset(pattern); if (distance == -1) { // it means the rules have no temporal constraints, or // the constraints require events to be hold forever. In this // case, we allow type declarations to override the implicit // expiration offset by defining an expiration policy with the // @expires tag otn.setExpirationOffset(expirationOffset); } else { otn.setExpirationOffset(Math.max(distance, expirationOffset)); } } } context.setObjectSource((ObjectSource) utils.attachNode(context, otn)); for (final Iterator<Constraint> it = alphaConstraints.iterator(); it.hasNext(); ) { final AlphaNodeFieldConstraint constraint = (AlphaNodeFieldConstraint) it.next(); context.pushRuleComponent(constraint); context.setObjectSource( (ObjectSource) utils.attachNode( context, new AlphaNode( context.getNextId(), (AlphaNodeFieldConstraint) constraint, context.getObjectSource(), context))); context.popRuleComponent(); } // now restore back to original values context.setObjectTypeNodeMemoryEnabled(objectMemory); context.setAlphaNodeMemoryAllowed(alphaMemory); }
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.getBuildStack().peek(); for (AccumulateFunctionCallDescr func : functions) { // build an external function executor AccumulateFunction function = context.getConfiguration().getAccumulateFunction(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; } // if there is a binding, create the binding if (func.getBind() != null) { if (pattern.getDeclaration(func.getBind()) != null) { context.addError( new DescrBuildError( context.getParentDescr(), accumDescr, null, "Duplicate declaration for variable '" + func.getBind() + "' in the rule '" + context.getRule().getName() + "'")); } else { createResultBind(pattern, index, arrayReader, func, function); } } 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); accumulators[index++] = new MVELAccumulatorFunctionExecutor(unit, function); } return accumulators; }