001: package org.drools.brms.server.util;
002:
003: import org.drools.brms.client.modeldriven.SuggestionCompletionEngine;
004: import org.drools.brms.client.modeldriven.brl.ActionFieldValue;
005: import org.drools.brms.client.modeldriven.brl.ActionInsertFact;
006: import org.drools.brms.client.modeldriven.brl.ActionInsertLogicalFact;
007: import org.drools.brms.client.modeldriven.brl.ActionRetractFact;
008: import org.drools.brms.client.modeldriven.brl.ActionSetField;
009: import org.drools.brms.client.modeldriven.brl.ActionUpdateField;
010: import org.drools.brms.client.modeldriven.brl.CompositeFactPattern;
011: import org.drools.brms.client.modeldriven.brl.CompositeFieldConstraint;
012: import org.drools.brms.client.modeldriven.brl.ConnectiveConstraint;
013: import org.drools.brms.client.modeldriven.brl.DSLSentence;
014: import org.drools.brms.client.modeldriven.brl.FactPattern;
015: import org.drools.brms.client.modeldriven.brl.FieldConstraint;
016: import org.drools.brms.client.modeldriven.brl.IAction;
017: import org.drools.brms.client.modeldriven.brl.IPattern;
018: import org.drools.brms.client.modeldriven.brl.ISingleFieldConstraint;
019: import org.drools.brms.client.modeldriven.brl.RuleAttribute;
020: import org.drools.brms.client.modeldriven.brl.RuleModel;
021: import org.drools.brms.client.modeldriven.brl.SingleFieldConstraint;
022: import org.drools.util.ReflectiveVisitor;
023:
024: /**
025: * This class persists the rule model to DRL and back
026: *
027: * @author etirelli
028: */
029: public class BRDRLPersistence implements BRLPersistence {
030:
031: private static final BRLPersistence INSTANCE = new BRDRLPersistence();
032:
033: private BRDRLPersistence() {
034: }
035:
036: public static BRLPersistence getInstance() {
037: return INSTANCE;
038: }
039:
040: /* (non-Javadoc)
041: * @see org.drools.brms.server.util.BRLPersistence#marshal(org.drools.brms.client.modeldriven.brl.RuleModel)
042: */
043: public String marshal(RuleModel model) {
044: boolean isDSLEnhanced = model.hasDSLSentences();
045:
046: StringBuffer buf = new StringBuffer();
047: buf.append("rule \"" + model.name + "\"\n");
048: this .marshalAttributes(buf, model);
049: buf.append("\twhen\n");
050: this .marshalLHS(buf, model, isDSLEnhanced);
051: buf.append("\tthen\n");
052: this .marshalRHS(buf, model, isDSLEnhanced);
053: buf.append("end\n");
054: return buf.toString();
055: }
056:
057: /* (non-Javadoc)
058: * @see org.drools.brms.server.util.BRLPersistence#unmarshal(java.lang.String)
059: */
060: public RuleModel unmarshal(String str) {
061: throw new UnsupportedOperationException(
062: "Still not possible to convert pure DRL to RuleModel");
063: }
064:
065: /**
066: * Marshal model attributes
067: *
068: * @param buf
069: * @param model
070: */
071: private void marshalAttributes(StringBuffer buf, RuleModel model) {
072: boolean hasDialect = false;
073: for (int i = 0; i < model.attributes.length; i++) {
074: RuleAttribute attr = model.attributes[i];
075:
076: buf.append("\t");
077: buf.append(attr);
078:
079: buf.append("\n");
080: if (attr.attributeName.equals("dialect")) {
081: hasDialect = true;
082: }
083: }
084: //Un comment below for mvel
085: if (!hasDialect) {
086: RuleAttribute attr = new RuleAttribute("dialect", "mvel");
087: buf.append("\t");
088: buf.append(attr);
089: buf.append("\n");
090: }
091: }
092:
093: /**
094: * Marshal LHS patterns
095: *
096: * @param buf
097: * @param model
098: */
099: private void marshalLHS(StringBuffer buf, RuleModel model,
100: boolean isDSLEnhanced) {
101: IPattern[] lhs = model.lhs;
102: LHSPatternVisitor visitor = new LHSPatternVisitor(
103: isDSLEnhanced, buf);
104: for (int i = 0; i < lhs.length; i++) {
105: final IPattern cond = lhs[i];
106: visitor.visit(cond);
107: }
108: }
109:
110: private void marshalRHS(StringBuffer buf, RuleModel model,
111: boolean isDSLEnhanced) {
112: IAction[] rhs = model.rhs;
113: RHSActionVisitor visitor = new RHSActionVisitor(isDSLEnhanced,
114: buf);
115: for (int i = 0; i < rhs.length; i++) {
116: final IAction action = rhs[i];
117: visitor.visit(action);
118: }
119: }
120:
121: public static class LHSPatternVisitor extends ReflectiveVisitor {
122: private StringBuffer buf;
123: private boolean isDSLEnhanced;
124:
125: public LHSPatternVisitor(boolean isDSLEnhanced, StringBuffer b) {
126: this .isDSLEnhanced = isDSLEnhanced;
127: buf = b;
128: }
129:
130: public void visitFactPattern(FactPattern pattern) {
131: buf.append("\t\t");
132: if (isDSLEnhanced) {
133: // adding passthrough markup
134: buf.append(">");
135: }
136: generateFactPattern(pattern);
137: buf.append("\n");
138: }
139:
140: public void visitCompositeFactPattern(
141: CompositeFactPattern pattern) {
142: buf.append("\t\t");
143: if (isDSLEnhanced) {
144: // adding passthrough markup
145: buf.append(">");
146: }
147: if (CompositeFactPattern.COMPOSITE_TYPE_EXISTS
148: .equals(pattern.type)) {
149: buf.append(pattern.type);
150: buf.append(" ");
151: renderSubPattern(pattern);
152: buf.append("\n");
153: } else if (CompositeFactPattern.COMPOSITE_TYPE_NOT
154: .equals(pattern.type)) {
155: buf.append(pattern.type);
156: buf.append(" ");
157: renderSubPattern(pattern);
158: buf.append("\n");
159: } else if (CompositeFactPattern.COMPOSITE_TYPE_OR
160: .equals(pattern.type)) {
161: buf.append("( ");
162: if (pattern.patterns != null) {
163: for (int i = 0; i < pattern.patterns.length; i++) {
164: if (i > 0) {
165: buf.append(" ");
166: buf.append(pattern.type);
167: buf.append(" ");
168: }
169: renderSubPattern(pattern);
170: }
171: }
172: buf.append(" )\n");
173: }
174: }
175:
176: private void renderSubPattern(CompositeFactPattern pattern) {
177: if (pattern.patterns == null
178: || pattern.patterns.length == 0)
179: return;
180: this .generateFactPattern(pattern.patterns[0]);
181: }
182:
183: public void visitDSLSentence(final DSLSentence sentence) {
184: buf.append("\t\t");
185: buf.append(sentence.toString());
186: buf.append("\n");
187: }
188:
189: private void generateFactPattern(FactPattern pattern) {
190: if (pattern.boundName != null) {
191: buf.append(pattern.boundName);
192: buf.append(" : ");
193: }
194: if (pattern.factType != null) {
195: buf.append(pattern.factType);
196: }
197: buf.append("( ");
198:
199: //top level constraints
200: if (pattern.constraintList != null) {
201: generateConstraints(pattern);
202: }
203: buf.append(")");
204: }
205:
206: private void generateConstraints(FactPattern pattern) {
207: for (int i = 0; i < pattern.getFieldConstraints().length; i++) {
208: if (i > 0) {
209: buf.append(", ");
210: }
211: generateConstraint(
212: pattern.constraintList.constraints[i], false);
213: }
214: }
215:
216: /**
217: * Recursively process the nested constraints.
218: * It will only put brackets in for the ones that aren't at top level.
219: * This makes for more readable DRL in the most common cases.
220: */
221: private void generateConstraint(FieldConstraint con,
222: boolean nested) {
223: if (con instanceof CompositeFieldConstraint) {
224: CompositeFieldConstraint cfc = (CompositeFieldConstraint) con;
225: if (nested)
226: buf.append("( ");
227: FieldConstraint[] nestedConstraints = cfc.constraints;
228: for (int i = 0; i < nestedConstraints.length; i++) {
229: generateConstraint(nestedConstraints[i], true);
230: if (i < (nestedConstraints.length - 1)) {
231: //buf.append(" ) ");
232: buf.append(cfc.compositeJunctionType + " ");
233: //buf.append(" ( ");
234: }
235: }
236: if (nested)
237: buf.append(")");
238: } else {
239: generateSingleFieldConstraint((SingleFieldConstraint) con);
240: }
241: }
242:
243: private void generateSingleFieldConstraint(
244: final SingleFieldConstraint constr) {
245: if (constr.constraintValueType == ISingleFieldConstraint.TYPE_PREDICATE) {
246: buf.append("( ");
247: buf.append(constr.value);
248: buf.append(" )");
249: } else {
250: if (constr.fieldBinding != null) {
251: buf.append(constr.fieldBinding);
252: buf.append(" : ");
253: }
254: if ((constr.operator != null && constr.value != null)
255: || constr.fieldBinding != null) {
256: buf.append(constr.fieldName);
257: }
258:
259: addFieldRestriction(buf, constr.constraintValueType,
260: constr.operator, constr.value);
261:
262: //and now do the connectives.
263: if (constr.connectives != null) {
264: for (int j = 0; j < constr.connectives.length; j++) {
265: final ConnectiveConstraint conn = constr.connectives[j];
266: addFieldRestriction(buf,
267: conn.constraintValueType,
268: conn.operator, conn.value);
269: }
270: }
271: }
272: }
273:
274: /**
275: * @param constr
276: * @param constrDescr
277: */
278: private void addFieldRestriction(final StringBuffer buf,
279: final int type, final String operator,
280: final String value) {
281: if (operator == null) {
282: return;
283: }
284:
285: buf.append(" ");
286: buf.append(operator);
287: buf.append(" ");
288: switch (type) {
289: case ISingleFieldConstraint.TYPE_RET_VALUE:
290: buf.append("( ");
291: buf.append(value);
292: buf.append(" )");
293: break;
294: case ISingleFieldConstraint.TYPE_LITERAL:
295: buf.append('"');
296: buf.append(value);
297: buf.append('"');
298: break;
299: default:
300: buf.append(value);
301: }
302: buf.append(" ");
303: }
304:
305: }
306:
307: public static class RHSActionVisitor extends ReflectiveVisitor {
308: private StringBuffer buf;
309: private boolean isDSLEnhanced;
310: private int idx = 0;
311:
312: public RHSActionVisitor(boolean isDSLEnhanced, StringBuffer b) {
313: this .isDSLEnhanced = isDSLEnhanced;
314: buf = b;
315: }
316:
317: public void visitActionInsertFact(final ActionInsertFact action) {
318: this .generateInsertCall(action, false);
319: }
320:
321: public void visitActionInsertLogicalFact(
322: final ActionInsertLogicalFact action) {
323: this .generateInsertCall(action, true);
324: }
325:
326: private void generateInsertCall(final ActionInsertFact action,
327: final boolean isLogic) {
328: buf.append("\t\t");
329: if (isDSLEnhanced) {
330: buf.append(">");
331: }
332: if (action.fieldValues.length == 0) {
333: buf.append("insert( new ");
334: buf.append(action.factType);
335: buf.append("() );\n");
336: } else {
337: buf.append(action.factType);
338: buf.append(" fact");
339: buf.append(idx);
340: buf.append(" = new ");
341: buf.append(action.factType);
342: buf.append("();\n");
343: generateSetMethodCalls("fact" + idx, action.fieldValues);
344: buf.append("\t\t");
345: if (isDSLEnhanced) {
346: buf.append(">");
347: }
348: if (isLogic) {
349: buf.append("insertLogical( fact");
350: } else {
351: buf.append("insert( fact");
352: }
353: buf.append(idx++);
354: buf.append(" );\n");
355: }
356: }
357:
358: public void visitActionUpdateField(
359: final ActionUpdateField action) {
360: this .visitActionSetField(action);
361: buf.append("\t\t");
362: if (isDSLEnhanced) {
363: buf.append(">");
364: }
365: buf.append("update( ");
366: buf.append(action.variable);
367: buf.append(" );\n");
368: }
369:
370: public void visitActionRetractFact(
371: final ActionRetractFact action) {
372: buf.append("\t\t");
373: if (isDSLEnhanced) {
374: buf.append(">");
375: }
376: buf.append("retract( ");
377: buf.append(action.variableName);
378: buf.append(" );\n");
379: }
380:
381: public void visitDSLSentence(final DSLSentence sentence) {
382: buf.append("\t\t");
383: buf.append(sentence.toString());
384: buf.append("\n");
385: }
386:
387: public void visitActionSetField(final ActionSetField action) {
388: this .generateSetMethodCalls(action.variable,
389: action.fieldValues);
390: }
391:
392: private void generateSetMethodCalls(final String variableName,
393: final ActionFieldValue[] fieldValues) {
394: for (int i = 0; i < fieldValues.length; i++) {
395: buf.append("\t\t");
396: if (isDSLEnhanced) {
397: buf.append(">");
398: }
399: buf.append(variableName);
400: buf.append(".set");
401: buf.append(Character.toUpperCase(fieldValues[i].field
402: .charAt(0)));
403: buf.append(fieldValues[i].field.substring(1));
404: buf.append("( ");
405: if (fieldValues[i].isFormula()) {
406: buf.append(fieldValues[i].value.substring(1));
407: } else if (SuggestionCompletionEngine.TYPE_STRING
408: .equals(fieldValues[i].type)) {
409: buf.append("\"");
410: buf.append(fieldValues[i].value);
411: buf.append("\"");
412: } else {
413: buf.append(fieldValues[i].value);
414: }
415: buf.append(" );\n");
416: }
417: }
418:
419: }
420:
421: }
|