001: package org.drools.xml;
002:
003: /*
004: *
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.util.Collections;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.drools.lang.descr.AccumulateDescr;
024: import org.drools.lang.descr.AndDescr;
025: import org.drools.lang.descr.AttributeDescr;
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.FieldBindingDescr;
030: import org.drools.lang.descr.FieldConstraintDescr;
031: import org.drools.lang.descr.ForallDescr;
032: import org.drools.lang.descr.FromDescr;
033: import org.drools.lang.descr.FunctionDescr;
034: import org.drools.lang.descr.GlobalDescr;
035: import org.drools.lang.descr.ImportDescr;
036: import org.drools.lang.descr.LiteralRestrictionDescr;
037: import org.drools.lang.descr.NotDescr;
038: import org.drools.lang.descr.OrDescr;
039: import org.drools.lang.descr.PackageDescr;
040: import org.drools.lang.descr.PackageDescrDumper;
041: import org.drools.lang.descr.PatternDescr;
042: import org.drools.lang.descr.PredicateDescr;
043: import org.drools.lang.descr.QualifiedIdentifierRestrictionDescr;
044: import org.drools.lang.descr.QueryDescr;
045: import org.drools.lang.descr.RestrictionConnectiveDescr;
046: import org.drools.lang.descr.ReturnValueRestrictionDescr;
047: import org.drools.lang.descr.RuleDescr;
048: import org.drools.lang.descr.VariableRestrictionDescr;
049: import org.drools.util.ReflectiveVisitor;
050:
051: /**
052: * This utility will take a AST of a rule package, and emit XML.
053: * This can be used in porting from DRL to XML.
054: * @author <a href="mailto:jayaramcs@gmail.com">Author Jayaram C S</a>
055: */
056: public class XmlDumper extends ReflectiveVisitor implements
057: PackageDescrDumper {
058:
059: private StringBuffer xmlDump;
060: private boolean patternContext;
061: private final static String eol = System
062: .getProperty("line.separator");
063: private String template;
064:
065: public synchronized String dump(final PackageDescr packageDescr) {
066: this .xmlDump = new StringBuffer();
067: visitPackageDescr(packageDescr);
068: return this .xmlDump.toString();
069: }
070:
071: public void visitAndDescr(final AndDescr descr) {
072: this .template = new String();
073: if (descr.getDescrs() != Collections.EMPTY_LIST) {
074: if (!this .patternContext)
075: this .template = "<and-conditional-element>"
076: + processDescrList(descr.getDescrs())
077: + "</and-conditional-element>";
078: else
079: this .template = "<and-constraint-connective>"
080: + processDescrList(descr.getDescrs())
081: + "</and-constraint-connective>";
082: }
083: }
084:
085: public void visitAttributeDescr(final AttributeDescr attributeDescr) {
086: this .template = new String();
087: this .template = "<rule-attribute name=\""
088: + attributeDescr.getName() + "\" value=\""
089: + attributeDescr.getValue() + "\" />" + XmlDumper.eol;
090: }
091:
092: public void visitVariableRestrictionDescr(
093: final VariableRestrictionDescr descr) {
094: this .template = new String();
095: this .template = "<variable-restriction evaluator=\""
096: + replaceIllegalChars(descr.getEvaluator())
097: + "\" identifier=\"" + descr.getIdentifier() + "\" />"
098: + XmlDumper.eol;
099: }
100:
101: public void visitPatternDescr(final PatternDescr descr) {
102: this .patternContext = true;
103: this .template = new String();
104: StringBuffer localString = new StringBuffer();
105:
106: if (descr.getDescrs() != Collections.EMPTY_LIST) {
107: if (descr.getIdentifier() != null) {
108: localString.append("<pattern identifier=\""
109: + descr.getIdentifier() + "\" object-type=\""
110: + descr.getObjectType() + "\" >"
111: + XmlDumper.eol
112: + processDescrList(descr.getDescrs())
113: + XmlDumper.eol);
114: } else {
115: localString.append("<pattern object-type=\""
116: + descr.getObjectType() + "\" >"
117: + XmlDumper.eol
118: + processDescrList(descr.getDescrs())
119: + XmlDumper.eol);
120: }
121: } else {
122: if (descr.getIdentifier() != null) {
123: localString.append("<pattern identifier=\""
124: + descr.getIdentifier() + "\" object-type=\""
125: + descr.getObjectType() + "\" >"
126: + XmlDumper.eol);
127: ;
128: } else {
129: localString.append("<pattern object-type=\""
130: + descr.getObjectType() + "\" >"
131: + XmlDumper.eol);
132: }
133: }
134:
135: if (descr.getSource() != null) {
136: visit(descr.getSource());
137: localString.append(this .template);
138: }
139: localString.append("</pattern>" + XmlDumper.eol);
140:
141: this .template = localString.toString();
142:
143: this .patternContext = false;
144: }
145:
146: public void visitFieldConstraintDescr(
147: final FieldConstraintDescr descr) {
148: if (!descr.getRestrictions().isEmpty()) {
149: this .template = "<field-constraint field-name=\""
150: + descr.getFieldName() + "\"> " + XmlDumper.eol
151: + processFieldConstraint(descr.getRestrictions())
152: + XmlDumper.eol + "</field-constraint>";
153: }
154: }
155:
156: public void visitCollectDescr(final CollectDescr descr) {
157: StringBuffer tmpstr = new StringBuffer();
158: tmpstr.append("<from> <collect>");
159: visit(descr.getInputPattern());
160: tmpstr.append(this .template);
161: tmpstr.append(" </collect> </from> ");
162: this .template = tmpstr.toString();
163: }
164:
165: public void visitAccumulateDescr(final AccumulateDescr descr) {
166: String tmpstr = new String();
167: tmpstr += this .template + " <from> <accumulate> ";
168: visit(descr.getInputPattern());
169: tmpstr += this .template;
170:
171: if (descr.isExternalFunction())
172: tmpstr += "<external-function evaluator=\""
173: + descr.getFunctionIdentifier()
174: + "\" expression=\"" + descr.getExpression()
175: + "\"/>";
176: else
177: tmpstr += "<init>" + descr.getInitCode()
178: + "</init><action>" + descr.getActionCode()
179: + "</action><result>" + descr.getResultCode()
180: + "</result>";
181:
182: this .template = tmpstr + " </accumulate> </from> ";
183: }
184:
185: public void visitFromDescr(final FromDescr descr) {
186: String tmpstr = new String();
187: tmpstr += this .template + " <from> <expression> ";
188: tmpstr += descr.getDataSource();
189: this .template = tmpstr + " </expression> </from> ";
190: }
191:
192: public void visitForallDescr(final ForallDescr descr) {
193: this .template = "<forall>"
194: + processDescrList(descr.getDescrs()) + "</forall>";
195: }
196:
197: public void visitEvalDescr(final EvalDescr descr) {
198: this .template = new String();
199: this .template = "<eval>"
200: + replaceIllegalChars((String) descr.getContent())
201: + "</eval>" + XmlDumper.eol;
202: }
203:
204: public void visitExistsDescr(final ExistsDescr descr) {
205: this .template = new String();
206: if (descr.getDescrs() != Collections.EMPTY_LIST) {
207: this .template = "<exists>"
208: + processDescrList(descr.getDescrs()) + "</exists>";
209: } else {
210: this .template = "<exists> </exists>";
211: }
212: }
213:
214: public void visitFieldBindingDescr(final FieldBindingDescr descr) {
215: this .template = new String();
216: this .template = "<field-binding field-name=\""
217: + descr.getFieldName() + "\" identifier=\""
218: + descr.getIdentifier() + "\" />" + XmlDumper.eol;
219: }
220:
221: public void visitFunctionDescr(final FunctionDescr functionDescr) {
222: this .template = new String();
223: final String parameterTemplate = processParameters(
224: functionDescr.getParameterNames(), functionDescr
225: .getParameterTypes());
226:
227: this .template = "<function return-type=\""
228: + functionDescr.getReturnType() + "\" name=\""
229: + functionDescr.getName() + "\">" + XmlDumper.eol
230: + parameterTemplate + "<body>" + XmlDumper.eol
231: + replaceIllegalChars(functionDescr.getText())
232: + XmlDumper.eol + "</body>" + XmlDumper.eol
233: + "</function>" + XmlDumper.eol;
234: }
235:
236: public void visitLiteralRestrictionDescr(
237: final LiteralRestrictionDescr descr) {
238: this .template = new String();
239: this .template = "<literal-restriction evaluator=\""
240: + replaceIllegalChars(descr.getEvaluator())
241: + "\" value=\"" + replaceIllegalChars(descr.getText())
242: + "\" />" + XmlDumper.eol;
243: }
244:
245: public void visitQualifiedIdentifierRestrictionDescr(
246: final QualifiedIdentifierRestrictionDescr descr) {
247: this .template = new String();
248: this .template = "<qualified-identifier-restriction evaluator=\""
249: + replaceIllegalChars(descr.getEvaluator())
250: + "\">"
251: + replaceIllegalChars(descr.getText())
252: + " </qualified-identifier-restriction>"
253: + XmlDumper.eol;
254: }
255:
256: public void visitNotDescr(final NotDescr descr) {
257: this .template = new String();
258: if (descr.getDescrs() != Collections.EMPTY_LIST) {
259: this .template = "<not>"
260: + processDescrList(descr.getDescrs()) + "</not>";
261: } else {
262: this .template = "<not> </not>";
263: }
264:
265: }
266:
267: public void visitOrDescr(final OrDescr descr) {
268: this .template = new String();
269: if (descr.getDescrs() != Collections.EMPTY_LIST) {
270: if (!this .patternContext)
271: this .template = "<or-conditional-element>"
272: + processDescrList(descr.getDescrs())
273: + "</or-conditional-element>";
274: else
275: this .template = "<or-constraint-connective>"
276: + processDescrList(descr.getDescrs())
277: + "</or-constraint-connective>";
278: }
279: }
280:
281: public void visitPackageDescr(final PackageDescr packageDescr) {
282: final String packageName = packageDescr.getName();
283: final String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> "
284: + XmlDumper.eol
285: + " <package name=\""
286: + packageName
287: + "\" "
288: + XmlDumper.eol
289: + "\txmlns=\"http://drools.org/drools-4.0\" "
290: + XmlDumper.eol
291: + "\txmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\" "
292: + XmlDumper.eol
293: + "\txs:schemaLocation=\"http://drools.org/drools-4.0 drools-4.0.xsd\"> "
294: + XmlDumper.eol;
295: appendXmlDump(xmlString);
296: appendXmlDump(processImportsList(packageDescr.getImports()));
297: appendXmlDump(processGlobalsList(packageDescr.getGlobals()));
298: appendXmlDump(processFunctionsList(packageDescr.getFunctions()));
299: appendXmlDump(processRules(packageDescr.getRules()));
300: appendXmlDump("</package>");
301: }
302:
303: public void visitPredicateDescr(final PredicateDescr descr) {
304: this .template = new String();
305: this .template = "<predicate>"
306: + replaceIllegalChars((String) descr.getContent())
307: + "</predicate>" + XmlDumper.eol;
308: }
309:
310: public void visitReturnValueRestrictionDescr(
311: final ReturnValueRestrictionDescr descr) {
312: this .template = new String();
313: this .template = "<return-value-restriction evaluator=\""
314: + replaceIllegalChars(descr.getEvaluator()) + "\" >"
315: + replaceIllegalChars((String) descr.getContent())
316: + "</return-value-restriction>" + XmlDumper.eol;
317: }
318:
319: public void visitQueryDescr(final QueryDescr descr) {
320: this .template = new String();
321: this .template = "<query name=\"" + descr.getName() + "\">"
322: + "<lhs>"
323: + processDescrList(descr.getLhs().getDescrs())
324: + "</lhs>" + "</query>";
325: }
326:
327: private String processRules(final List rules) {
328: String ruleList = "";
329: for (final Iterator iterator = rules.iterator(); iterator
330: .hasNext();) {
331: final RuleDescr ruleDescr = (RuleDescr) iterator.next();
332: String rule = "<rule name=\"" + ruleDescr.getName() + "\">"
333: + XmlDumper.eol;
334: final String attribute = processAttribute(ruleDescr
335: .getAttributes());
336: String lhs = "";
337: if (ruleDescr.getLhs().getDescrs() != Collections.EMPTY_LIST) {
338: lhs = "<lhs>"
339: + processDescrList(ruleDescr.getLhs()
340: .getDescrs()) + "</lhs>";
341: } else {
342:
343: lhs = "<lhs> </lhs>";
344: }
345:
346: final String rhs = "<rhs>"
347: + replaceIllegalChars((String) ruleDescr
348: .getConsequence()) + "</rhs>"
349: + XmlDumper.eol;
350: rule += attribute;
351: rule += lhs;
352: rule += rhs;
353: rule += "</rule>";
354: ruleList += rule;
355: }
356:
357: return ruleList + XmlDumper.eol;
358: }
359:
360: private String processFieldConstraint(final List list) {
361: String descrString = "";
362: for (final Iterator it = list.iterator(); it.hasNext();) {
363: final Object temp = it.next();
364: visit(temp);
365: descrString += this .template;
366: }
367: return descrString;
368: }
369:
370: public void visitRestrictionConnectiveDescr(
371: final RestrictionConnectiveDescr descr) {
372: this .template = new String();
373: final List restrictions = descr.getRestrictions();
374: final String xmlTag = descr.getConnective() == RestrictionConnectiveDescr.OR ? RestrictionConnectiveHandler.OR
375: : RestrictionConnectiveHandler.AND;
376:
377: if (restrictions != Collections.EMPTY_LIST) {
378: this .template = "<" + xmlTag + ">";
379: this .template += processDescrList(restrictions);
380: this .template += "</" + xmlTag + ">";
381: }
382: }
383:
384: private String processDescrList(final List descr) {
385: String descrString = "";
386: for (final Iterator iterator = descr.iterator(); iterator
387: .hasNext();) {
388: visit(iterator.next());
389: descrString += this .template;
390: descrString += XmlDumper.eol;
391: }
392: return descrString + XmlDumper.eol;
393: }
394:
395: private String processFunctionsList(final List functions) {
396: String functionList = "";
397:
398: for (final Iterator iterator = functions.iterator(); iterator
399: .hasNext();) {
400: visit(iterator.next());
401: functionList += this .template;
402: }
403:
404: return functionList + XmlDumper.eol;
405: }
406:
407: private String processAttribute(final List attributes) {
408:
409: String attributeList = "";
410: for (final Iterator iterator = attributes.iterator(); iterator
411: .hasNext();) {
412: final AttributeDescr attributeDescr = (AttributeDescr) iterator
413: .next();
414: visit(attributeDescr);
415: attributeList += this .template;
416: }
417: return attributeList + XmlDumper.eol;
418: }
419:
420: private String processParameters(final List parameterNames,
421: final List parameterTypes) {
422: String paramList = "";
423: int i = 0;
424: for (final Iterator iterator = parameterNames.iterator(); iterator
425: .hasNext(); i++) {
426: final String paramName = (String) iterator.next();
427: final String paramType = (String) parameterTypes.get(i);
428: final String paramTemplate = "<parameter identifier=\""
429: + paramName + "\" type=\"" + paramType + "\" />"
430: + XmlDumper.eol;
431: paramList += paramTemplate;
432: }
433:
434: return paramList + XmlDumper.eol;
435: }
436:
437: private String processGlobalsList(final List globals) {
438: String globalList = "";
439: for (final Iterator iterator = globals.iterator(); iterator
440: .hasNext();) {
441: final GlobalDescr global = (GlobalDescr) iterator.next();
442: final String identifier = global.getIdentifier();
443: final String type = global.getType();
444: final String globalTemplate = "<global identifier=\""
445: + identifier + "\" type=\"" + type + "\" />"
446: + XmlDumper.eol;
447: globalList += globalTemplate;
448: }
449:
450: return globalList + XmlDumper.eol;
451: }
452:
453: private String processImportsList(final List imports) {
454: String importList = "";
455:
456: for (final Iterator iterator = imports.iterator(); iterator
457: .hasNext();) {
458: final String importString = ((ImportDescr) iterator.next())
459: .getTarget();
460: final String importTemplate = "<import name=\""
461: + importString + "\" /> " + XmlDumper.eol;
462: importList += importTemplate;
463: }
464: return importList + XmlDumper.eol;
465: }
466:
467: private void appendXmlDump(final String temp) {
468: this .xmlDump.append(temp);
469: }
470:
471: /**
472: * Replace illegal xml characters with their escaped equivalent
473: * <P>The escaped characters are :
474: * <ul>
475: * <li> <
476: * <li> >
477: * <li> &
478: * </ul>
479: * </p>
480: * @author <a href="mailto:prietor@gmail.com">Author Javier Prieto</a>
481: */
482: private String replaceIllegalChars(final String code) {
483: final StringBuffer sb = new StringBuffer();
484: if (code != null) {
485: final int n = code.length();
486: for (int i = 0; i < n; i++) {
487: final char c = code.charAt(i);
488: switch (c) {
489: case '<':
490: sb.append("<");
491: break;
492: case '>':
493: sb.append(">");
494: break;
495: case '&':
496: sb.append("&");
497: break;
498: default:
499: sb.append(c);
500: break;
501: }
502: }
503: } else {
504: sb.append("null");
505: }
506: return sb.toString();
507: }
508: }
|