001: package org.drools.rule.builder.dialect.mvel;
002:
003: import java.io.Serializable;
004: import java.lang.reflect.Method;
005: import java.util.ArrayList;
006: import java.util.HashMap;
007: import java.util.Iterator;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.Set;
011: import java.util.Map.Entry;
012:
013: import org.drools.base.ClassFieldExtractorCache;
014: import org.drools.base.TypeResolver;
015: import org.drools.base.mvel.DroolsMVELFactory;
016: import org.drools.base.mvel.DroolsMVELKnowledgeHelper;
017: import org.drools.base.mvel.MVELDebugHandler;
018: import org.drools.commons.jci.readers.MemoryResourceReader;
019: import org.drools.compiler.Dialect;
020: import org.drools.compiler.ImportError;
021: import org.drools.compiler.PackageBuilder;
022: import org.drools.compiler.RuleError;
023: import org.drools.lang.descr.AccumulateDescr;
024: import org.drools.lang.descr.AndDescr;
025: import org.drools.lang.descr.BaseDescr;
026: import org.drools.lang.descr.CollectDescr;
027: import org.drools.lang.descr.EvalDescr;
028: import org.drools.lang.descr.ExistsDescr;
029: import org.drools.lang.descr.ForallDescr;
030: import org.drools.lang.descr.FromDescr;
031: import org.drools.lang.descr.FunctionDescr;
032: import org.drools.lang.descr.NotDescr;
033: import org.drools.lang.descr.OrDescr;
034: import org.drools.lang.descr.PatternDescr;
035: import org.drools.lang.descr.QueryDescr;
036: import org.drools.lang.descr.RuleDescr;
037: import org.drools.rule.Declaration;
038: import org.drools.rule.LineMappings;
039: import org.drools.rule.Package;
040: import org.drools.rule.builder.AccumulateBuilder;
041: import org.drools.rule.builder.CollectBuilder;
042: import org.drools.rule.builder.ConsequenceBuilder;
043: import org.drools.rule.builder.ForallBuilder;
044: import org.drools.rule.builder.FromBuilder;
045: import org.drools.rule.builder.GroupElementBuilder;
046: import org.drools.rule.builder.PatternBuilder;
047: import org.drools.rule.builder.PredicateBuilder;
048: import org.drools.rule.builder.QueryBuilder;
049: import org.drools.rule.builder.ReturnValueBuilder;
050: import org.drools.rule.builder.RuleBuildContext;
051: import org.drools.rule.builder.RuleClassBuilder;
052: import org.drools.rule.builder.RuleConditionBuilder;
053: import org.drools.rule.builder.SalienceBuilder;
054: import org.drools.rule.builder.dialect.java.JavaDialect;
055: import org.drools.rule.builder.dialect.java.JavaFunctionBuilder;
056: import org.drools.spi.DeclarationScopeResolver;
057: import org.drools.spi.KnowledgeHelper;
058: import org.drools.util.StringUtils;
059: import org.mvel.ASTNode;
060: import org.mvel.AbstractParser;
061: import org.mvel.ExpressionCompiler;
062: import org.mvel.ParserContext;
063: import org.mvel.ast.WithNode;
064: import org.mvel.integration.Interceptor;
065: import org.mvel.integration.VariableResolverFactory;
066: import org.mvel.integration.impl.ClassImportResolverFactory;
067: import org.mvel.integration.impl.StaticMethodImportResolverFactory;
068: import org.mvel.optimizers.OptimizerFactory;
069: import org.mvel.util.ParseTools;
070:
071: public class MVELDialect implements Dialect {
072:
073: public final static String ID = "MVELDialect";
074:
075: private final static String EXPRESSION_DIALECT_NAME = "MVEL";
076:
077: private final MVELRuleClassBuilder rule = new MVELRuleClassBuilder();
078:
079: private final PatternBuilder pattern = new PatternBuilder();
080: private final QueryBuilder query = new QueryBuilder();
081: private final MVELAccumulateBuilder accumulate = new MVELAccumulateBuilder();
082: private final SalienceBuilder salience = new MVELSalienceBuilder();
083: private final MVELEvalBuilder eval = new MVELEvalBuilder();
084: private final MVELPredicateBuilder predicate = new MVELPredicateBuilder();
085: private final MVELReturnValueBuilder returnValue = new MVELReturnValueBuilder();
086: private final MVELConsequenceBuilder consequence = new MVELConsequenceBuilder();
087: //private final JavaRuleClassBuilder rule = new JavaRuleClassBuilder();
088: private final MVELFromBuilder from = new MVELFromBuilder();
089: private final JavaFunctionBuilder function = new JavaFunctionBuilder();
090: private final CollectBuilder collect = new CollectBuilder();
091: private final ForallBuilder forall = new ForallBuilder();
092:
093: private Map interceptors;
094:
095: private List results;
096: //private final JavaFunctionBuilder function = new JavaFunctionBuilder();
097:
098: private MemoryResourceReader src;
099:
100: private Package pkg;
101: private MVELDialectConfiguration configuration;
102: private TypeResolver typeResolver;
103: private ClassFieldExtractorCache classFieldExtractorCache;
104: private MVELExprAnalyzer analyzer;
105:
106: private Map imports;
107: private Map packageImports;
108: private StaticMethodImportResolverFactory staticImportFactory;
109: // private ClassImportResolverFactory importFactory;
110:
111: private boolean strictMode;
112:
113: public void addFunction(FunctionDescr functionDescr,
114: TypeResolver typeResolver) {
115: throw new UnsupportedOperationException(
116: "MVEL does not support functions");
117:
118: }
119:
120: // a map of registered builders
121: private Map builders;
122:
123: public MVELDialect() {
124: }
125:
126: public void init(PackageBuilder builder) {
127: AbstractParser.setLanguageLevel(4);
128:
129: this .pkg = builder.getPackage();
130: this .configuration = (MVELDialectConfiguration) builder
131: .getPackageBuilderConfiguration()
132: .getDialectConfiguration("mvel");
133: this .typeResolver = builder.getTypeResolver();
134: this .classFieldExtractorCache = builder
135: .getClassFieldExtractorCache();
136: this .strictMode = this .configuration.isStrict();
137:
138: // we currently default to reflective optimisation
139: OptimizerFactory.setDefaultOptimizer("reflective");
140:
141: this .analyzer = new MVELExprAnalyzer();
142:
143: if (pkg != null) {
144: init(pkg);
145: }
146:
147: this .results = new ArrayList();
148:
149: initBuilder();
150:
151: this .interceptors = new HashMap(1);
152: this .interceptors.put("Modify", new ModifyInterceptor());
153:
154: // this.importFactory = new ClassImportResolverFactory();
155: this .imports = new HashMap();
156: this .packageImports = new HashMap();
157: this .staticImportFactory = new StaticMethodImportResolverFactory();
158: // this.importFactory.setNextFactory( this.staticImportFactory );
159: }
160:
161: public void initBuilder() {
162: // statically adding all builders to the map
163: // but in the future we can move that to a configuration
164: // if we want to
165: this .builders = new HashMap();
166:
167: final GroupElementBuilder gebuilder = new GroupElementBuilder();
168:
169: this .builders.put(AndDescr.class, gebuilder);
170:
171: this .builders.put(OrDescr.class, gebuilder);
172:
173: this .builders.put(NotDescr.class, gebuilder);
174:
175: this .builders.put(ExistsDescr.class, gebuilder);
176:
177: this .builders.put(PatternDescr.class, getPatternBuilder());
178:
179: this .builders.put(FromDescr.class, getFromBuilder());
180:
181: this .builders.put(QueryDescr.class, getQueryBuilder());
182:
183: this .builders
184: .put(AccumulateDescr.class, getAccumulateBuilder());
185:
186: this .builders.put(EvalDescr.class, getEvalBuilder());
187:
188: this .builders.put(CollectDescr.class, this .collect);
189:
190: this .builders.put(ForallDescr.class, this .forall);
191:
192: this .builders.put(FunctionDescr.class, this .function);
193: }
194:
195: public void init(Package pkg) {
196: this .pkg = pkg;
197: this .results = new ArrayList();
198: this .src = new MemoryResourceReader();
199: }
200:
201: public void init(RuleDescr ruleDescr) {
202: //MVEL:test null to Fix failing test on org.drools.rule.builder.dialect.mvel.MVELConsequenceBuilderTest.testImperativeCodeError()
203:
204: // @todo: why is this here, MVEL doesn't compile anything? mdp
205: String pkgName = this .pkg == null ? "" : this .pkg.getName();
206: final String ruleClassName = JavaDialect.getUniqueLegalName(
207: pkgName, ruleDescr.getName(), "mvel", this .src);
208: ruleDescr.setClassName(StringUtils.ucFirst(ruleClassName));
209: ruleDescr.setDialect(this );
210: }
211:
212: public String getExpressionDialectName() {
213: return EXPRESSION_DIALECT_NAME;
214: }
215:
216: public void addRule(RuleBuildContext context) {
217: //MVEL: Compiler change
218: final RuleDescr ruleDescr = context.getRuleDescr();
219:
220: // setup the line mappins for this rule
221: final String name = this .pkg.getName() + "."
222: + StringUtils.ucFirst(ruleDescr.getClassName());
223: final LineMappings mapping = new LineMappings(name);
224: mapping.setStartLine(ruleDescr.getConsequenceLine());
225: mapping.setOffset(ruleDescr.getConsequenceOffset());
226:
227: context.getPkg().getPackageCompilationData().getLineMappings()
228: .put(name, mapping);
229:
230: }
231:
232: public void addImport(String importEntry) {
233: if (importEntry.endsWith("*")) {
234: importEntry = importEntry.substring(0, importEntry
235: .indexOf('*'));
236: this .packageImports.put(importEntry, importEntry);
237: } else {
238: try {
239: Class cls = this .typeResolver.resolveType(importEntry);
240: this .imports.put(ParseTools.getSimpleClassName(cls),
241: cls);
242: } catch (ClassNotFoundException e) {
243: this .results.add(new ImportError(importEntry, 1));
244: }
245: }
246: }
247:
248: public Map getImports() {
249: return this .imports;
250: }
251:
252: public Map getPackgeImports() {
253: return this .packageImports;
254: }
255:
256: public void addStaticImport(String staticImportEntry) {
257: if (staticImportEntry.endsWith("*")) {
258: return;
259: }
260:
261: int index = staticImportEntry.lastIndexOf('.');
262: String className = staticImportEntry.substring(0, index);
263: String methodName = staticImportEntry.substring(0, index + 1);
264:
265: try {
266: Class cls = this .configuration
267: .getPackageBuilderConfiguration().getClassLoader()
268: .loadClass(className);
269: Method[] methods = cls.getDeclaredMethods();
270: for (int i = 0; i < methods.length; i++) {
271: if (methods[i].equals("methodName")) {
272: this .staticImportFactory.createVariable(methodName,
273: methods[i]);
274: this .imports.put(methodName, methods[i]);
275: break;
276: }
277: }
278: } catch (ClassNotFoundException e) {
279: this .results.add(new ImportError(staticImportEntry, -1));
280: }
281: }
282:
283: public StaticMethodImportResolverFactory getStaticMethodImportResolverFactory() {
284: return this .staticImportFactory;
285: }
286:
287: // public ClassImportResolverFactory getClassImportResolverFactory() {
288: // return this.importFactory;
289: // }
290:
291: public boolean isStrictMode() {
292: return strictMode;
293: }
294:
295: public void setStrictMode(boolean strictMode) {
296: this .strictMode = strictMode;
297: }
298:
299: public void compileAll() {
300: }
301:
302: public Dialect.AnalysisResult analyzeExpression(
303: RuleBuildContext context, BaseDescr descr, Object content) {
304: return analyzeExpression(context, descr, content, null);
305: }
306:
307: public Dialect.AnalysisResult analyzeExpression(
308: RuleBuildContext context, BaseDescr descr, Object content,
309: Map localTypes) {
310: Dialect.AnalysisResult result = null;
311: try {
312: result = this .analyzer.analyzeExpression(context,
313: (String) content, new Set[] {
314: context.getDeclarationResolver()
315: .getDeclarations().keySet(),
316: context.getPkg().getGlobals().keySet() },
317: localTypes);
318: } catch (final Exception e) {
319: context
320: .getErrors()
321: .add(
322: new RuleError(context.getRule(), descr,
323: null,
324: "Unable to determine the used declarations"));
325: }
326: return result;
327: }
328:
329: public Dialect.AnalysisResult analyzeBlock(
330: RuleBuildContext context, BaseDescr descr, String text) {
331: return analyzeBlock(context, descr, null, text, null);
332: }
333:
334: public Dialect.AnalysisResult analyzeBlock(
335: RuleBuildContext context, BaseDescr descr,
336: Map interceptors, String text, Map localTypes) {
337: Dialect.AnalysisResult result = null;
338: try {
339: result = this .analyzer.analyzeExpression(context, text,
340: new Set[] {
341: context.getDeclarationResolver()
342: .getDeclarations().keySet(),
343: context.getPkg().getGlobals().keySet() },
344: localTypes);
345: } catch (final Exception e) {
346: context.getErrors().add(
347: new RuleError(context.getRule(), descr, e,
348: "Unable to determine the used declarations.\n"
349: + e.getMessage()));
350: }
351: return result;
352: }
353:
354: public Serializable compile(final String text,
355: final Dialect.AnalysisResult analysis,
356: final Map interceptors, final Map outerDeclarations,
357: final RuleBuildContext context) {
358: final ParserContext parserContext = getParserContext(analysis,
359: outerDeclarations, context);
360:
361: ExpressionCompiler compiler = new ExpressionCompiler(text
362: .trim());
363:
364: if (MVELDebugHandler.isDebugMode()) {
365: compiler.setDebugSymbols(true);
366: }
367:
368: Serializable expr = compiler.compile(parserContext);
369: return expr;
370: }
371:
372: public ParserContext getParserContext(
373: final Dialect.AnalysisResult analysis,
374: final Map outerDeclarations, final RuleBuildContext context) {
375: final ParserContext parserContext = new ParserContext(imports,
376: null, context.getPkg().getName() + "."
377: + context.getRuleDescr().getClassName());
378:
379: for (Iterator it = this .packageImports.values().iterator(); it
380: .hasNext();) {
381: String packageImport = (String) it.next();
382: parserContext.addPackageImport(packageImport);
383: }
384:
385: //this.configuration.get
386:
387: parserContext.setStrictTypeEnforcement(strictMode);
388:
389: if (interceptors != null) {
390: parserContext.setInterceptors(interceptors);
391: }
392: //FIXME: analysis can be null, throws an NPE
393: List list[] = analysis.getBoundIdentifiers();
394: DeclarationScopeResolver resolver = context
395: .getDeclarationResolver();
396: for (Iterator it = list[0].iterator(); it.hasNext();) {
397: String identifier = (String) it.next();
398: Class cls = resolver.getDeclaration(identifier)
399: .getExtractor().getExtractToClass();
400: parserContext.addInput(identifier, cls);
401: }
402:
403: Map globalTypes = context.getPkg().getGlobals();
404: for (Iterator it = list[1].iterator(); it.hasNext();) {
405: String identifier = (String) it.next();
406: parserContext.addInput(identifier, (Class) globalTypes
407: .get(identifier));
408: }
409:
410: Map mvelVars = ((MVELAnalysisResult) analysis)
411: .getMvelVariables();
412: if (mvelVars != null) {
413: for (Iterator it = mvelVars.entrySet().iterator(); it
414: .hasNext();) {
415: Entry entry = (Entry) it.next();
416: parserContext.addInput((String) entry.getKey(),
417: (Class) entry.getValue());
418: }
419: }
420:
421: if (outerDeclarations != null) {
422: for (Iterator it = outerDeclarations.entrySet().iterator(); it
423: .hasNext();) {
424: Entry entry = (Entry) it.next();
425: parserContext.addInput((String) entry.getKey(),
426: ((Declaration) entry.getValue()).getExtractor()
427: .getExtractToClass());
428: }
429: }
430:
431: parserContext.addInput("drools", KnowledgeHelper.class);
432:
433: return parserContext;
434: }
435:
436: public RuleConditionBuilder getBuilder(final Class clazz) {
437: return (RuleConditionBuilder) this .builders.get(clazz);
438: }
439:
440: public Map getBuilders() {
441: return this .builders;
442: }
443:
444: public ClassFieldExtractorCache getClassFieldExtractorCache() {
445: return this .classFieldExtractorCache;
446: }
447:
448: public PatternBuilder getPatternBuilder() {
449: return this .pattern;
450: }
451:
452: public QueryBuilder getQueryBuilder() {
453: return this .query;
454: }
455:
456: public AccumulateBuilder getAccumulateBuilder() {
457: return this .accumulate;
458: }
459:
460: public ConsequenceBuilder getConsequenceBuilder() {
461: return this .consequence;
462: }
463:
464: public RuleConditionBuilder getEvalBuilder() {
465: return this .eval;
466: }
467:
468: public FromBuilder getFromBuilder() {
469: return this .from;
470: }
471:
472: public PredicateBuilder getPredicateBuilder() {
473: return this .predicate;
474: }
475:
476: public PredicateBuilder getExpressionPredicateBuilder() {
477: return this .predicate;
478: }
479:
480: public SalienceBuilder getSalienceBuilder() {
481: return this .salience;
482: }
483:
484: public List getResults() {
485: return results;
486: }
487:
488: public ReturnValueBuilder getReturnValueBuilder() {
489: return this .returnValue;
490: }
491:
492: public RuleClassBuilder getRuleClassBuilder() {
493: return rule;
494: }
495:
496: public TypeResolver getTypeResolver() {
497: return this .typeResolver;
498: }
499:
500: public Map getInterceptors() {
501: return this .interceptors;
502: }
503:
504: public String getId() {
505: return ID;
506: }
507:
508: public static class AssertInterceptor implements Interceptor,
509: Serializable {
510: private static final long serialVersionUID = 400L;
511:
512: public int doBefore(ASTNode node,
513: VariableResolverFactory factory) {
514: return 0;
515: }
516:
517: public int doAfter(Object value, ASTNode node,
518: VariableResolverFactory factory) {
519: ((DroolsMVELFactory) factory).getWorkingMemory().insert(
520: value);
521: return 0;
522: }
523: }
524:
525: public static class ModifyInterceptor implements Interceptor,
526: Serializable {
527: private static final long serialVersionUID = 400L;
528:
529: public int doBefore(ASTNode node,
530: VariableResolverFactory factory) {
531: Object object = ((WithNode) node).getNestedStatement()
532: .getValue(null, factory);
533:
534: DroolsMVELKnowledgeHelper resolver = (DroolsMVELKnowledgeHelper) factory
535: .getVariableResolver("drools");
536: KnowledgeHelper helper = (KnowledgeHelper) resolver
537: .getValue();
538: helper.modifyRetract(object);
539: return 0;
540: }
541:
542: public int doAfter(Object value, ASTNode node,
543: VariableResolverFactory factory) {
544: DroolsMVELKnowledgeHelper resolver = (DroolsMVELKnowledgeHelper) factory
545: .getVariableResolver("drools");
546: KnowledgeHelper helper = (KnowledgeHelper) resolver
547: .getValue();
548: helper.modifyInsert(value);
549: return 0;
550: }
551: }
552: }
|