@SuppressWarnings("unchecked") public RuleConditionElement build( final RuleBuildContext context, final BaseDescr descr, final Pattern prefixPattern) { try { final AccumulateDescr accumDescr = (AccumulateDescr) descr; if (!accumDescr.hasValidInput()) { return null; } final RuleConditionBuilder builder = (RuleConditionBuilder) context.getDialect().getBuilder(accumDescr.getInput().getClass()); Declaration[] previousDeclarations = (Declaration[]) context .getDeclarationResolver() .getDeclarations(context.getRule()) .values() .toArray( new Declaration [context .getDeclarationResolver() .getDeclarations(context.getRule()) .size()]); // create source CE final RuleConditionElement source = builder.build(context, accumDescr.getInput()); if (source == null) { return null; } MVELDialect dialect = (MVELDialect) context.getDialect(); final Declaration[] sourceDeclArr = (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]); Accumulator accumulator = null; Declaration[] declarations = null; if (accumDescr.isExternalFunction()) { // build an external function executor AccumulateFunction function = context.getConfiguration().getAccumulateFunction(accumDescr.getFunctionIdentifier()); if (function == null) { context .getErrors() .add( new DescrBuildError( accumDescr, context.getRuleDescr(), null, "Unknown accumulate function: '" + accumDescr.getFunctionIdentifier() + "' on rule '" + context.getRuleDescr().getName() + "'. All accumulate functions must be registered before building a resource.")); return null; } Map<String, Class<?>> declarationsMap = context.getDeclarationResolver().getDeclarationClasses(context.getRule()); final Dialect.AnalysisResult analysis = dialect.analyzeExpression( context, accumDescr, accumDescr.getExpression(), new Map[] {declarationsMap, context.getPackageBuilder().getGlobals()}); MVELCompilationUnit unit = dialect.getMVELCompilationUnit( (String) accumDescr.getExpression(), analysis, previousDeclarations, (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]), null, context); accumulator = new MVELAccumulatorFunctionExecutor(unit, function); } else { // it is a custom accumulate Map<String, Class<?>> declarationsMap = context.getDeclarationResolver().getDeclarationClasses(context.getRule()); final MVELAnalysisResult initCodeAnalysis = (MVELAnalysisResult) dialect.analyzeBlock( context, accumDescr, accumDescr.getInitCode(), new Map[] {declarationsMap, context.getPackageBuilder().getGlobals()}); final MVELAnalysisResult actionCodeAnalysis = (MVELAnalysisResult) dialect.analyzeBlock( context, accumDescr, null, accumDescr.getActionCode(), new Map[] {declarationsMap, context.getPackageBuilder().getGlobals()}, initCodeAnalysis.getMvelVariables()); final MVELAnalysisResult resultCodeAnalysis = (MVELAnalysisResult) dialect.analyzeExpression( context, accumDescr, accumDescr.getResultCode(), new Map[] {declarationsMap, context.getPackageBuilder().getGlobals()}, initCodeAnalysis.getMvelVariables()); Dialect.AnalysisResult reverseCodeAnalysis = null; if (accumDescr.getReverseCode() != null) { reverseCodeAnalysis = dialect.analyzeBlock( context, accumDescr, null, accumDescr.getActionCode(), new Map[] {declarationsMap, context.getPackageBuilder().getGlobals()}, initCodeAnalysis.getMvelVariables()); } MVELCompilationUnit initUnit = dialect.getMVELCompilationUnit( (String) accumDescr.getInitCode(), initCodeAnalysis, previousDeclarations, (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]), null, context); MVELCompilationUnit actionUnit = dialect.getMVELCompilationUnit( (String) accumDescr.getActionCode(), actionCodeAnalysis, previousDeclarations, (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]), initCodeAnalysis.getMvelVariables(), context); MVELCompilationUnit reverseUnit = null; if (accumDescr.getReverseCode() != null) { reverseUnit = dialect.getMVELCompilationUnit( (String) accumDescr.getReverseCode(), reverseCodeAnalysis, previousDeclarations, (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]), initCodeAnalysis.getMvelVariables(), context); } MVELCompilationUnit resultUnit = dialect.getMVELCompilationUnit( (String) accumDescr.getResultCode(), resultCodeAnalysis, previousDeclarations, (Declaration[]) source .getOuterDeclarations() .values() .toArray(new Declaration[source.getOuterDeclarations().size()]), initCodeAnalysis.getMvelVariables(), context); if (reverseUnit != null) { Set<String> shadow = new HashSet<String>(source.getOuterDeclarations().keySet()); shadow.retainAll(reverseCodeAnalysis.getNotBoundedIdentifiers()); shadow.addAll(reverseCodeAnalysis.getBoundIdentifiers()[0]); String[] shadowVars = (String[]) shadow.toArray(new String[shadow.size()]); actionUnit.setShadowIdentifiers(shadowVars); reverseUnit.setShadowIdentifiers(shadowVars); } accumulator = new MVELAccumulator(initUnit, actionUnit, reverseUnit, resultUnit); } final Accumulate accumulate = new Accumulate(source, declarations, sourceDeclArr, new Accumulator[] {accumulator}); MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel"); data.addCompileable(accumulate, (MVELCompileable) accumulator); ((MVELCompileable) accumulator).compile(context.getPackageBuilder().getRootClassLoader()); return accumulate; } catch (Exception e) { context .getErrors() .add( new DescrBuildError( context.getParentDescr(), descr, e, "Unable to build expression for 'accumulate' : " + e.getMessage())); return null; } }
public void execute(Map<String, Object> context, List<String[]> args) { BuildContext buildContext = (BuildContext) context.get("BuildContext"); if (args.size() >= 1) { // The first argument list is the node parameters String[] a = args.get(0); String name = a[0]; String leftInput = a[1]; String rightInput = a[2]; String sourceType = a[3]; String expr = a[4]; LeftTupleSource leftTupleSource; if ("mock".equals(leftInput)) { leftTupleSource = Mockito.mock(LeftTupleSource.class); } else { leftTupleSource = (LeftTupleSource) context.get(leftInput); } ObjectSource rightObjectSource; if ("mock".equals(rightInput)) { rightObjectSource = Mockito.mock(ObjectSource.class); } else { rightObjectSource = (ObjectSource) context.get(rightInput); } Pattern sourcePattern; Pattern resultPattern; try { sourcePattern = reteTesterHelper.getPattern(0, sourceType); // we always use the accumulate function "sum", so return type is always Number resultPattern = reteTesterHelper.getPattern(buildContext.getNextId(), Number.class.getName()); } catch (Exception e) { throw new IllegalArgumentException( "Not possible to process arguments: " + Arrays.toString(a)); } BetaConstraints betaSourceConstraints = new EmptyBetaConstraints(); AlphaNodeFieldConstraint[] alphaResultConstraint = new AlphaNodeFieldConstraint[0]; // the following arguments are constraints for (int i = 1; i < args.size(); i++) { a = args.get(i); String type = a[0]; String fieldName = a[1]; String operator = a[2]; String val = a[3]; if ("source".equals(type)) { Declaration declr = (Declaration) context.get(val); try { BetaNodeFieldConstraint sourceBetaConstraint = this.reteTesterHelper.getBoundVariableConstraint( sourcePattern, fieldName, declr, operator); betaSourceConstraints = new SingleBetaConstraints( sourceBetaConstraint, buildContext.getRuleBase().getConfiguration()); } catch (IntrospectionException e) { throw new IllegalArgumentException(); } } else if ("result".equals(type)) { alphaResultConstraint = new AlphaNodeFieldConstraint[1]; try { alphaResultConstraint[0] = this.reteTesterHelper.getLiteralConstraint(resultPattern, fieldName, operator, val); } catch (IntrospectionException e) { throw new IllegalArgumentException( "Unable to configure alpha constraint: " + Arrays.toString(a), e); } } } NodeTestCase testCase = (NodeTestCase) context.get("TestCase"); List<String> classImports = new ArrayList<String>(); List<String> pkgImports = new ArrayList<String>(); for (String imp : testCase.getImports()) { if (imp.endsWith(".*")) { pkgImports.add(imp.substring(0, imp.lastIndexOf('.'))); } else { classImports.add(imp); } } // build an external function executor MVELCompilationUnit compilationUnit = new MVELCompilationUnit( name, expr, pkgImports.toArray(new String[0]), // pkg imports classImports.toArray(new String[0]), // imported classes new String[] {}, // imported methods new String[] {}, // imported fields new String[] {}, // global identifiers new Declaration[] {}, // previous declarations new Declaration[] {(Declaration) context.get(expr)}, // local declarations new String[] {}, // other identifiers new String[] {}, // input identifiers new String[] {}, // input types 4, false); AccumulateFunction accFunction = new SumAccumulateFunction(); Accumulator accumulator = new MVELAccumulatorFunctionExecutor(compilationUnit, accFunction); ((MVELCompileable) accumulator).compile(Thread.currentThread().getContextClassLoader()); Accumulate accumulate = new Accumulate( sourcePattern, new Declaration[] {}, // required declaration new Declaration[] {}, // inner declarations new Accumulator[] {accumulator}); AccumulateNode accNode = new AccumulateNode( buildContext.getNextId(), leftTupleSource, rightObjectSource, alphaResultConstraint, betaSourceConstraints, new EmptyBetaConstraints(), new Behavior[] {}, accumulate, false, buildContext); accNode.attach(); context.put(name, accNode); } else { StringBuilder msgBuilder = new StringBuilder(); msgBuilder.append("Can not parse AccumulateNode step arguments: \n"); for (String[] arg : args) { msgBuilder.append(" "); msgBuilder.append(Arrays.toString(arg)); msgBuilder.append("\n"); } throw new IllegalArgumentException(msgBuilder.toString()); } }
@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 = context.getDeclarationResolver().getDeclarationClasses(decls); declarationClasses.putAll( context.getDeclarationResolver().getDeclarationClasses(sourceOuterDeclr)); BoundIdentifiers boundIds = new BoundIdentifiers(declarationClasses, context.getPackageBuilder().getGlobals()); boundIds.setDeclarations(mergedDecl); Accumulator[] accumulators = null; final boolean readLocalsFromTuple = PackageBuilderUtil.isReadLocalsFromTuple(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, source, dialect, decls, sourceOuterDeclr, boundIds, readLocalsFromTuple); } final Accumulate accumulate = new Accumulate(source, null, accumulators, accumDescr.isMultiFunction()); MVELDialectRuntimeData data = (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData("mvel"); int index = 0; for (Accumulator accumulator : accumulators) { data.addCompileable(accumulate.new Wirer(index++), (MVELCompileable) accumulator); ((MVELCompileable) accumulator).compile(data); } return accumulate; } catch (Exception e) { 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); } }