001: package org.drools.rule.builder.dialect.mvel;
002:
003: import java.io.Serializable;
004: import java.util.HashMap;
005: import java.util.Map;
006:
007: import org.drools.base.mvel.DroolsMVELFactory;
008: import org.drools.base.mvel.MVELConsequence;
009: import org.drools.compiler.Dialect;
010: import org.drools.compiler.RuleError;
011: import org.drools.rule.builder.ConsequenceBuilder;
012: import org.drools.rule.builder.RuleBuildContext;
013: import org.mvel.Macro;
014: import org.mvel.MacroProcessor;
015:
016: public class MVELConsequenceBuilder implements ConsequenceBuilder {
017:
018: //private final Interceptor assertInterceptor;
019: //private final Interceptor modifyInterceptor;
020:
021: private final Map macros;
022:
023: public MVELConsequenceBuilder() {
024: macros = new HashMap(4);
025:
026: macros.put("insert", new Macro() {
027: public String doMacro() {
028: return "drools.insert";
029: }
030: });
031:
032: macros.put("modify", new Macro() {
033: public String doMacro() {
034: return "@Modify with";
035: }
036: });
037:
038: macros.put("update", new Macro() {
039: public String doMacro() {
040: return "drools.update";
041: }
042: });
043:
044: macros.put("retract", new Macro() {
045: public String doMacro() {
046: return "drools.retract";
047: }
048: });
049: }
050:
051: public void build(final RuleBuildContext context) {
052: // pushing consequence LHS into the stack for variable resolution
053: context.getBuildStack().push(context.getRule().getLhs());
054:
055: try {
056: MVELDialect dialect = (MVELDialect) context.getDialect();
057:
058: String text = processMacros((String) context.getRuleDescr()
059: .getConsequence());
060:
061: Dialect.AnalysisResult analysis = dialect.analyzeBlock(
062: context, context.getRuleDescr(), dialect
063: .getInterceptors(), text, null);
064:
065: final Serializable expr = dialect.compile(text, analysis,
066: dialect.getInterceptors(), null, context);
067:
068: final DroolsMVELFactory factory = new DroolsMVELFactory(
069: context.getDeclarationResolver().getDeclarations(),
070: null, context.getPkg().getGlobals(), analysis
071: .getBoundIdentifiers());
072:
073: factory.setNextFactory(dialect
074: .getStaticMethodImportResolverFactory());
075:
076: context.getRule().setConsequence(
077: new MVELConsequence(expr, factory));
078: } catch (final Exception e) {
079: context.getErrors().add(
080: new RuleError(context.getRule(), context
081: .getRuleDescr(), null,
082: "Unable to build expression for 'consequence' '"
083: + context.getRuleDescr()
084: .getConsequence() + "'"));
085: }
086: }
087:
088: public String processMacros(String consequence) {
089: MacroProcessor macroProcessor = new MacroProcessor();
090: macroProcessor.setMacros(macros);
091: return macroProcessor.parse(delimitExpressions(consequence));
092: }
093:
094: /**
095: * Allows newlines to demarcate expressions, as per MVEL command line.
096: * If expression spans multiple lines (ie inside an unbalanced bracket) then
097: * it is left alone.
098: * Uses character based iteration which is at least an order of magnitude faster then a single
099: * simple regex.
100: */
101: public static String delimitExpressions(String s) {
102:
103: StringBuffer result = new StringBuffer();
104: char[] cs = s.toCharArray();
105: int brace = 0;
106: int sqre = 0;
107: int crly = 0;
108: char lastNonWhite = ';';
109: for (int i = 0; i < cs.length; i++) {
110: char c = cs[i];
111: switch (c) {
112: case '(':
113: brace++;
114: break;
115: case '{':
116: crly++;
117: break;
118: case '[':
119: sqre++;
120: break;
121: case ')':
122: brace--;
123: break;
124: case '}':
125: crly--;
126: break;
127: case ']':
128: sqre--;
129: break;
130: default:
131: break;
132: }
133: if ((brace == 0 && sqre == 0 && crly == 0)
134: && (c == '\n' || c == '\r')) {
135: if (lastNonWhite != ';') {
136: result.append(';');
137: lastNonWhite = ';';
138: }
139: } else if (!Character.isWhitespace(c)) {
140: lastNonWhite = c;
141: }
142: result.append(c);
143:
144: }
145: return result.toString();
146: }
147:
148: }
|