/** * recurse through the rule condition elements updating the declaration objecs * * @param resolver * @param contextStack * @param element */ private void processElement( final DeclarationScopeResolver resolver, final Stack contextStack, final RuleConditionElement element) { if (element instanceof Pattern) { Pattern pattern = (Pattern) element; for (Iterator it = pattern.getNestedElements().iterator(); it.hasNext(); ) { processElement(resolver, contextStack, (RuleConditionElement) it.next()); } for (Constraint next : pattern.getConstraints()) { if (next instanceof Declaration) { continue; } Constraint constraint = (Constraint) next; Declaration[] decl = constraint.getRequiredDeclarations(); for (int i = 0; i < decl.length; i++) { Declaration resolved = resolver.getDeclaration(null, decl[i].getIdentifier()); if (constraint instanceof MvelConstraint && ((MvelConstraint) constraint).isUnification()) { if (ClassObjectType.DroolsQuery_ObjectType.isAssignableFrom( resolved.getPattern().getObjectType())) { Declaration redeclaredDeclr = new Declaration( resolved.getIdentifier(), ((MvelConstraint) constraint).getFieldExtractor(), pattern, false); pattern.addDeclaration(redeclaredDeclr); } else { ((MvelConstraint) constraint).unsetUnification(); } } if (resolved != null && resolved != decl[i] && resolved.getPattern() != pattern) { constraint.replaceDeclaration(decl[i], resolved); } else if (resolved == null) { // it is probably an implicit declaration, so find the corresponding pattern Pattern old = decl[i].getPattern(); Pattern current = resolver.findPatternByIndex(old.getIndex()); if (current != null && old != current) { resolved = new Declaration(decl[i].getIdentifier(), decl[i].getExtractor(), current); constraint.replaceDeclaration(decl[i], resolved); } } } } } else if (element instanceof EvalCondition) { Declaration[] decl = ((EvalCondition) element).getRequiredDeclarations(); for (Declaration aDecl : decl) { Declaration resolved = resolver.getDeclaration(null, aDecl.getIdentifier()); if (resolved != null && resolved != aDecl) { ((EvalCondition) element).replaceDeclaration(aDecl, resolved); } } } else if (element instanceof Accumulate) { for (RuleConditionElement rce : element.getNestedElements()) { processElement(resolver, contextStack, rce); } ((Accumulate) element).resetInnerDeclarationCache(); } else if (element instanceof From) { DataProvider provider = ((From) element).getDataProvider(); Declaration[] decl = provider.getRequiredDeclarations(); for (Declaration aDecl : decl) { Declaration resolved = resolver.getDeclaration(null, aDecl.getIdentifier()); if (resolved != null && resolved != aDecl) { provider.replaceDeclaration(aDecl, resolved); } else if (resolved == null) { // it is probably an implicit declaration, so find the corresponding pattern Pattern old = aDecl.getPattern(); Pattern current = resolver.findPatternByIndex(old.getIndex()); if (current != null && old != current) { resolved = new Declaration(aDecl.getIdentifier(), aDecl.getExtractor(), current); provider.replaceDeclaration(aDecl, resolved); } } } } else if (element instanceof QueryElement) { QueryElement qe = (QueryElement) element; Pattern pattern = qe.getResultPattern(); for (Entry<String, Declaration> entry : pattern.getInnerDeclarations().entrySet()) { Declaration resolved = resolver.getDeclaration(null, entry.getValue().getIdentifier()); if (resolved != null && resolved != entry.getValue() && resolved.getPattern() != pattern) { entry.setValue(resolved); } } List<Integer> varIndexes = ArrayUtils.asList(qe.getVariableIndexes()); for (int i = 0; i < qe.getDeclIndexes().length; i++) { Declaration declr = (Declaration) qe.getArgTemplate()[qe.getDeclIndexes()[i]]; Declaration resolved = resolver.getDeclaration(null, declr.getIdentifier()); if (resolved != null && resolved != declr && resolved.getPattern() != pattern) { qe.getArgTemplate()[qe.getDeclIndexes()[i]] = resolved; } if (ClassObjectType.DroolsQuery_ObjectType.isAssignableFrom( resolved.getPattern().getObjectType())) { // if the resolved still points to DroolsQuery, we know this is the first unification // pattern, so redeclare it as the visible Declaration declr = pattern.addDeclaration(declr.getIdentifier()); // this bit is different, notice its the ArrayElementReader that we wire up to, not the // declaration. ArrayElementReader reader = new ArrayElementReader( new SelfReferenceClassFieldReader(Object[].class, "this"), qe.getDeclIndexes()[i], resolved.getExtractor().getExtractToClass()); declr.setReadAccessor(reader); varIndexes.add(qe.getDeclIndexes()[i]); } } qe.setVariableIndexes(ArrayUtils.toIntArray(varIndexes)); } else { contextStack.push(element); for (RuleConditionElement ruleConditionElement : element.getNestedElements()) { processElement(resolver, contextStack, ruleConditionElement); } contextStack.pop(); } }
public void wire(Object object) { setAccumulator((Accumulator) object); for (Accumulate clone : this.cloned) { clone.wire(object); } }
public void modifyLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); BetaMemory bm = memory.betaMemory; // Add and remove to make sure we are in the right bucket and at the end // this is needed to fix for indexing and deterministic iteration bm.getLeftTupleMemory().removeAdd(leftTuple); this.constraints.updateFromTuple(bm.getContext(), workingMemory, leftTuple); LeftTuple childLeftTuple = getFirstMatch(leftTuple, accctx, false); RightTupleMemory rightMemory = bm.getRightTupleMemory(); FastIterator rightIt = getRightIterator(rightMemory); RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt); // first check our index (for indexed nodes only) hasn't changed and we are returning the same // bucket // if rightTuple is null, we assume there was a bucket change and that bucket is empty if (childLeftTuple != null && rightMemory.isIndexed() && !rightIt.isFullIterator() && (rightTuple == null || (rightTuple.getMemory() != childLeftTuple.getRightParent().getMemory()))) { // our index has changed, so delete all the previous matchings removePreviousMatchesForLeftTuple(leftTuple, workingMemory, memory, accctx); childLeftTuple = null; // null so the next check will attempt matches for new bucket } // we can't do anything if RightTupleMemory is empty if (rightTuple != null) { if (childLeftTuple == null) { // either we are indexed and changed buckets or // we had no children before, but there is a bucket to potentially match, so try as normal // assert for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) { final InternalFactHandle handle = rightTuple.getFactHandle(); if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) { // add a new match addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true); } } } else { boolean isDirty = false; // in the same bucket, so iterate and compare for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) { final InternalFactHandle handle = rightTuple.getFactHandle(); if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) { if (childLeftTuple == null || childLeftTuple.getRightParent() != rightTuple) { // add a new match addMatch( leftTuple, rightTuple, childLeftTuple, null, workingMemory, memory, accctx, true); } else { // we must re-add this to ensure deterministic iteration LeftTuple temp = childLeftTuple.getLeftParentNext(); childLeftTuple.reAddRight(); childLeftTuple = temp; } } else if (childLeftTuple != null && childLeftTuple.getRightParent() == rightTuple) { LeftTuple temp = childLeftTuple.getLeftParentNext(); // remove the match removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, false); childLeftTuple = temp; // the next line means that when a match is removed from the current leftTuple // and the accumulate does not support the reverse operation, then the whole // result is dirty (since removeMatch above is not recalculating the total) // and we need to do this later isDirty = !accumulate.supportsReverse(); } // else do nothing, was false before and false now. } if (isDirty) { reaccumulateForLeftTuple(leftTuple, workingMemory, memory, accctx); } } } this.constraints.resetTuple(memory.betaMemory.getContext()); if (accctx.getAction() == null) { evaluateResultConstraints( ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accctx, true); } // else evaluation is already scheduled, so do nothing }