private void replaceDeclarations( DeclarationScopeResolver resolver, Pattern pattern, Constraint constraint) { Declaration[] decl = constraint.getRequiredDeclarations(); for (Declaration aDecl : decl) { Declaration resolved = resolver.getDeclaration(null, aDecl.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 if (resolved.getPattern() != pattern) { ((MvelConstraint) constraint).unsetUnification(); } } if (resolved != null && resolved != aDecl && resolved.getPattern() != pattern) { constraint.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); constraint.replaceDeclaration(aDecl, resolved); } } } }
private void processEvalCondition(DeclarationScopeResolver resolver, EvalCondition element) { Declaration[] decl = element.getRequiredDeclarations(); for (Declaration aDecl : decl) { Declaration resolved = resolver.getDeclaration(null, aDecl.getIdentifier()); if (resolved != null && resolved != aDecl) { element.replaceDeclaration(aDecl, resolved); } } }
private void replaceDeclarations(DeclarationScopeResolver resolver, Accumulate accumulate) { Declaration[] decl = accumulate.getRequiredDeclarations(); for (Declaration aDecl : decl) { Declaration resolved = resolver.getDeclaration(null, aDecl.getIdentifier()); if (resolved != null && resolved != aDecl) { accumulate.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); accumulate.replaceDeclaration(aDecl, resolved); } } } }
/** recurse through the rule condition elements updating the declaration objecs */ private void processElement( final DeclarationScopeResolver resolver, final Stack<RuleConditionElement> contextStack, final RuleConditionElement element) { if (element instanceof Pattern) { Pattern pattern = (Pattern) element; for (RuleConditionElement ruleConditionElement : pattern.getNestedElements()) { processElement(resolver, contextStack, ruleConditionElement); } for (Constraint constraint : pattern.getConstraints()) { if (constraint instanceof Declaration) { continue; } replaceDeclarations(resolver, pattern, constraint); } } else if (element instanceof EvalCondition) { processEvalCondition(resolver, (EvalCondition) element); } else if (element instanceof Accumulate) { for (RuleConditionElement rce : element.getNestedElements()) { processElement(resolver, contextStack, rce); } Accumulate accumulate = (Accumulate) element; replaceDeclarations(resolver, accumulate); accumulate.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 = asList(qe.getVariableIndexes()); for (int i = 0; i < qe.getArguments().length; i++) { if (!(qe.getArguments()[i] instanceof QueryArgument.Declr)) { continue; } Declaration declr = ((QueryArgument.Declr) qe.getArguments()[i]).getDeclaration(); Declaration resolved = resolver.getDeclaration(null, declr.getIdentifier()); if (resolved != declr && resolved.getPattern() != pattern) { qe.getArguments()[i] = new QueryArgument.Declr(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), i, resolved.getDeclarationClass()); declr.setReadAccessor(reader); varIndexes.add(i); } } qe.setVariableIndexes(toIntArray(varIndexes)); } else if (element instanceof ConditionalBranch) { processBranch(resolver, (ConditionalBranch) element); } else { contextStack.push(element); for (RuleConditionElement ruleConditionElement : element.getNestedElements()) { processElement(resolver, contextStack, ruleConditionElement); } contextStack.pop(); } }
@SuppressWarnings("unchecked") public RuleConditionElement build( final RuleBuildContext context, final BaseDescr descr, final Pattern prefixPattern) { boolean typesafe = context.isTypesafe(); try { final AccumulateDescr accumDescr = (AccumulateDescr) descr; if (!accumDescr.hasValidInput()) { return null; } final RuleConditionBuilder builder = (RuleConditionBuilder) context.getDialect().getBuilder(accumDescr.getInput().getClass()); // create source CE final RuleConditionElement source = builder.build(context, accumDescr.getInput()); if (source == null) { return null; } MVELDialect dialect = (MVELDialect) context.getDialect(); Map<String, Declaration> decls = context.getDeclarationResolver().getDeclarations(context.getRule()); Map<String, Declaration> sourceOuterDeclr = source.getOuterDeclarations(); Map<String, Declaration> mergedDecl = new HashMap(decls); mergedDecl.putAll(sourceOuterDeclr); Map<String, Class<?>> declarationClasses = DeclarationScopeResolver.getDeclarationClasses(decls); declarationClasses.putAll(DeclarationScopeResolver.getDeclarationClasses(sourceOuterDeclr)); BoundIdentifiers boundIds = new BoundIdentifiers(declarationClasses, context.getKnowledgeBuilder().getGlobals()); boundIds.setDeclarations(mergedDecl); Accumulator[] accumulators; final boolean readLocalsFromTuple = PackageBuilderUtil.isReadLocalsFromTuple(context, accumDescr, source); if (accumDescr.isExternalFunction()) { // uses accumulate functions accumulators = buildExternalFunctions( context, accumDescr, dialect, decls, sourceOuterDeclr, boundIds, readLocalsFromTuple); } else { // it is a custom accumulate accumulators = buildCustomAccumulate( context, accumDescr, dialect, decls, sourceOuterDeclr, boundIds, readLocalsFromTuple); } List<Declaration> requiredDeclarations = new ArrayList<Declaration>(); for (Accumulator acc : accumulators) { MvelAccumulator mvelAcc = (MvelAccumulator) acc; Collections.addAll(requiredDeclarations, mvelAcc.getRequiredDeclarations()); } MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel"); Accumulate accumulate; if (accumDescr.isMultiFunction()) { accumulate = new MultiAccumulate( source, requiredDeclarations.toArray(new Declaration[requiredDeclarations.size()]), accumulators); int index = 0; for (Accumulator accumulator : accumulators) { data.addCompileable( ((MultiAccumulate) accumulate).new Wirer(index++), (MVELCompileable) accumulator); ((MVELCompileable) accumulator).compile(data, context.getRule()); } } else { accumulate = new SingleAccumulate( source, requiredDeclarations.toArray(new Declaration[requiredDeclarations.size()]), accumulators[0]); data.addCompileable( ((SingleAccumulate) accumulate).new Wirer(), (MVELCompileable) accumulators[0]); ((MVELCompileable) accumulators[0]).compile(data, context.getRule()); } return accumulate; } catch (Exception e) { DialectUtil.copyErrorLocation(e, descr); context.addError( new DescrBuildError( context.getParentDescr(), descr, e, "Unable to build expression for 'accumulate' : " + e.getMessage())); return null; } finally { context.setTypesafe(typesafe); } }
public void build(final RuleBuildContext context, String consequenceName) { // pushing consequence LHS into the stack for variable resolution context.getBuildStack().push(context.getRule().getLhs()); try { MVELDialect dialect = (MVELDialect) context.getDialect(context.getDialect().getId()); final RuleDescr ruleDescr = context.getRuleDescr(); String text = (Rule.DEFAULT_CONSEQUENCE_NAME.equals(consequenceName)) ? (String) ruleDescr.getConsequence() : (String) ruleDescr.getNamedConsequences().get(consequenceName); text = processMacros(text); Map<String, Declaration> decls = context.getDeclarationResolver().getDeclarations(context.getRule()); AnalysisResult analysis = dialect.analyzeBlock( context, context.getRuleDescr(), dialect.getInterceptors(), text, new BoundIdentifiers( DeclarationScopeResolver.getDeclarationClasses(decls), context.getPackageBuilder().getGlobals(), null, KnowledgeHelper.class), null, "drools", KnowledgeHelper.class); if (analysis == null) { // something bad happened, issue already logged in errors return; } final BoundIdentifiers usedIdentifiers = analysis.getBoundIdentifiers(); final Declaration[] declarations = new Declaration[usedIdentifiers.getDeclrClasses().size()]; String[] declrStr = new String[declarations.length]; int j = 0; for (String str : usedIdentifiers.getDeclrClasses().keySet()) { declrStr[j] = str; declarations[j++] = decls.get(str); } Arrays.sort(declarations, SortDeclarations.instance); for (int i = 0; i < declrStr.length; i++) { declrStr[i] = declarations[i].getIdentifier(); } context.getRule().setRequiredDeclarationsForConsequence(consequenceName, declrStr); MVELCompilationUnit unit = dialect.getMVELCompilationUnit( text, analysis, declarations, null, null, context, "drools", KnowledgeHelper.class, false); MVELConsequence expr = new MVELConsequence(unit, dialect.getId()); if (Rule.DEFAULT_CONSEQUENCE_NAME.equals(consequenceName)) { context.getRule().setConsequence(expr); } else { context.getRule().addNamedConsequence(consequenceName, expr); } MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel"); data.addCompileable(context.getRule(), expr); expr.compile(data); } catch (final Exception e) { copyErrorLocation(e, context.getRuleDescr()); context.addError( new DescrBuildError( context.getParentDescr(), context.getRuleDescr(), null, "Unable to build expression for 'consequence': " + e.getMessage() + " '" + context.getRuleDescr().getConsequence() + "'")); } }