001: package org.drools.eclipse.editors.completion;
002:
003: import java.io.BufferedReader;
004: import java.io.FileReader;
005: import java.io.IOException;
006: import java.io.Reader;
007: import java.util.ArrayList;
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.Iterator;
011: import java.util.List;
012: import java.util.StringTokenizer;
013:
014: import org.drools.lang.dsl.DSLMapping;
015: import org.drools.lang.dsl.DSLMappingEntry;
016: import org.drools.lang.dsl.DSLMappingEntry.Section;
017:
018: public class DSLTree {
019:
020: public static final String separator = "=";
021: public static final String tab = " ";
022:
023: private Node current = null;
024: private Node last = null;
025: private Node rootCond = null;
026: private Node rootConseq = null;
027: private boolean empty = true;
028: private ArrayList suggestions = new ArrayList();
029: private HashMap objToNL = new HashMap();
030:
031: public DSLTree() {
032: this .rootCond = new Node("root");
033: this .rootConseq = new Node("root");
034: }
035:
036: /**
037: * the method will take the dsl file and build a DSLTree using
038: * the Node class.
039: * @param dslFile
040: */
041: public void buildTree(String dslFile) {
042: buildTree(openDSLFile(dslFile));
043: }
044:
045: /**
046: * the method uses the DSLAdapter to get the contents of the
047: * DSL mapping file.
048: * @param dslcontents
049: */
050: public void buildTree(Reader dslcontents) {
051: buildTree(createBufferedReader(dslcontents));
052: }
053:
054: private void buildTree(BufferedReader breader) {
055: this .rootCond.clearChildren();
056: this .rootConseq.clearChildren();
057: parseFile(breader);
058: try {
059: breader.close();
060: } catch (IOException e) {
061: e.printStackTrace();
062: }
063: this .empty = false;
064: }
065:
066: /**
067: * method will create a BufferedReader to read the file.
068: * @param filename
069: * @return
070: */
071: protected BufferedReader openDSLFile(String filename) {
072: try {
073: FileReader reader = new FileReader(filename);
074: BufferedReader breader = new BufferedReader(reader);
075: return breader;
076: } catch (IOException e) {
077: e.printStackTrace();
078: return null;
079: }
080: }
081:
082: /**
083: * Create a buffered reader for the reader created by the DSLAdapater
084: * @param reader
085: * @return
086: */
087: protected BufferedReader createBufferedReader(Reader reader) {
088: return new BufferedReader(reader);
089: }
090:
091: /**
092: * if the DSL mapping hasn't been loaded, the method will return
093: * true. If the DSL mapping has been loaded, the method returns
094: * false.
095: * @return
096: */
097: public boolean isEmpty() {
098: return this .empty;
099: }
100:
101: /**
102: * method will use the BufferedReader to read the contents of the file.
103: * It calls other methods to parse the line and build the tree.
104: * @param reader
105: */
106: protected void parseFile(BufferedReader reader) {
107: String line = null;
108: try {
109: while ((line = reader.readLine()) != null) {
110: Section section = getSection(line);
111: String nl = stripHeadingAndCode(line);
112: String objname = this .getObjMetadata(nl);
113: nl = this .stripObjMetadata(nl);
114: addEntry(section, nl, objname);
115: }
116: } catch (IOException e) {
117: e.printStackTrace();
118: }
119: }
120:
121: public void buildTree(DSLMapping mapping) {
122: List entries = mapping.getEntries();
123: for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
124: DSLMappingEntry entry = (DSLMappingEntry) iterator.next();
125: Section section = entry.getSection();
126: String nl = entry.getMappingKey();
127: String objname = entry.getMetaData().getMetaData();
128: addEntry(section, nl, objname);
129: }
130: }
131:
132: private void addEntry(Section section, String nl, String objname) {
133: if (!nl.startsWith("-")) {
134: if (objname != null) {
135: this .addObjToNLMap(objname, nl);
136: }
137: String[] tokenz = nl.split("\\s");
138: if (section == DSLMappingEntry.CONDITION
139: || section == DSLMappingEntry.ANY) {
140: addTokens(tokenz, rootCond);
141: }
142: if (section == DSLMappingEntry.CONSEQUENCE
143: || section == DSLMappingEntry.ANY) {
144: addTokens(tokenz, rootConseq);
145: }
146: } else {
147: String res = (String) this .objToNL.get(objname);
148: StringTokenizer tokenz = new StringTokenizer(nl);
149: addTokens(res, tokenz);
150: }
151: }
152:
153: public void addObjToNLMap(String objname, String nl) {
154: if (!objname.startsWith("-")) {
155: this .objToNL.put(objname, nl);
156: }
157: }
158:
159: protected Section getSection(String text) {
160: if (text.startsWith(DSLMappingEntry.CONDITION.getSymbol())) {
161: return DSLMappingEntry.CONDITION;
162: } else if (text.startsWith(DSLMappingEntry.CONSEQUENCE
163: .getSymbol())) {
164: return DSLMappingEntry.CONSEQUENCE;
165: } else if (text.startsWith(DSLMappingEntry.ANY.getSymbol())) {
166: return DSLMappingEntry.ANY;
167: } else if (text.startsWith(DSLMappingEntry.KEYWORD.getSymbol())) {
168: return DSLMappingEntry.KEYWORD;
169: }
170: return null;
171: }
172:
173: /**
174: * method will strip out the when, then, * at the beginning of each
175: * line and the mapped drl expression
176: * @param text
177: * @return
178: */
179: protected String stripHeadingAndCode(String text) {
180: if (text.startsWith(DSLMappingEntry.CONDITION.getSymbol())) {
181: return text.substring(DSLMappingEntry.CONDITION.getSymbol()
182: .length() + 2, text.indexOf("="));
183: } else if (text.startsWith(DSLMappingEntry.CONSEQUENCE
184: .getSymbol())) {
185: return text.substring(DSLMappingEntry.CONSEQUENCE
186: .getSymbol().length() + 2, text.indexOf("="));
187: } else if (text.startsWith(DSLMappingEntry.ANY.getSymbol())) {
188: return text.substring(DSLMappingEntry.ANY.getSymbol()
189: .length() + 2, text.indexOf("="));
190: } else if (text.startsWith("#")) {
191: return "";
192: } else {
193: return text;
194: }
195: }
196:
197: /**
198: * Method will return just the object metadata
199: * @param text
200: * @return
201: */
202: protected String getObjMetadata(String text) {
203: if (text.startsWith("[")) {
204: return text.substring(1, text.lastIndexOf("]"));
205: } else {
206: return "";
207: }
208: }
209:
210: /**
211: * method will strip the metadata from the text string
212: * @param text
213: * @return
214: */
215: protected String stripObjMetadata(String text) {
216: if (text.startsWith("[")) {
217: return text.substring(text.lastIndexOf("]") + 1);
218: } else {
219: return text;
220: }
221: }
222:
223: /**
224: * The method is different than addTokens(StringTokenizer). this method
225: * expects additional metadata. It expects to get an object name or "*"
226: * meaning all. If the metadata is a wildcard all, it will add the
227: * tokens to all the top level nodes that are immediate child of root.
228: * @param metadata
229: * @param tokens
230: */
231: public void addTokens(String metadata, StringTokenizer tokens) {
232: Node mnode = this .rootCond.addToken(metadata);
233: Node thenode = mnode;
234: while (tokens.hasMoreTokens()) {
235: Node newnode = thenode.addToken(tokens.nextToken());
236: thenode = newnode;
237: }
238: }
239:
240: /**
241: * method adds the token to root
242: * @param tokens
243: */
244: public void addTokens(String[] tokens, Node rootNode) {
245: Node thenode = rootNode;
246: for (int i = 0; i < tokens.length; i++) {
247: Node newnode = thenode.addToken(tokens[i]);
248: thenode = newnode;
249: }
250: }
251:
252: /**
253: * the method will tokenize the text and try to find
254: * the node that matches and return the children. the method
255: * will traverse down the network as far as it can and return
256: * the children at that level.
257: * @param text
258: * @return
259: */
260: public Node[] getConditionChildren(String text) {
261: Node thenode = this .rootCond;
262: if (text.length() > 0) {
263: StringTokenizer tokenz = new StringTokenizer(text);
264: this .last = this .current;
265: while (tokenz.hasMoreTokens()) {
266: String strtk = tokenz.nextToken();
267: Node ch = thenode.getChild(strtk);
268: // if a child is found, we set thenode to the child Node
269: if (ch != null) {
270: thenode = ch;
271: } else {
272: break;
273: }
274: }
275: if (thenode != this .rootCond) {
276: this .current = thenode;
277: }
278: }
279: Collection children = thenode.getChildren();
280: Node[] nchild = new Node[children.size()];
281: return (Node[]) children.toArray(nchild);
282: }
283:
284: /**
285: * the method will tokenize the text and try to find
286: * the node that matches and return the children. the method
287: * will traverse down the network as far as it can and return
288: * the children at that level.
289: * @param text
290: * @return
291: */
292: public Node[] getConsequenceChildren(String text) {
293: Node thenode = this .rootConseq;
294: if (text.length() >= 0) {
295: StringTokenizer tokenz = new StringTokenizer(text);
296: this .last = this .current;
297: while (tokenz.hasMoreTokens()) {
298: String strtk = tokenz.nextToken();
299: Node ch = thenode.getChild(strtk);
300: // if a child is found, we set thenode to the child Node
301: if (ch != null) {
302: thenode = ch;
303: } else {
304: break;
305: }
306: }
307: if (thenode != this .rootConseq) {
308: this .current = thenode;
309: }
310: }
311: Collection children = thenode.getChildren();
312: Node[] nchild = new Node[children.size()];
313: return (Node[]) children.toArray(nchild);
314: }
315:
316: /**
317: * the method expects the caller to pass the object
318: * @param obj
319: * @param text
320: * @return
321: */
322: public Node[] getChildren(String obj, String text) {
323: Node thenode = this .rootCond.getChild(obj);
324: if (thenode != null && text.length() > 0) {
325: StringTokenizer tokenz = new StringTokenizer(text);
326: this .last = this .current;
327: while (tokenz.hasMoreTokens()) {
328: String strtk = tokenz.nextToken();
329: Node ch = thenode.getChild(strtk);
330: // if a child is found, we set thenode to the child Node
331: if (ch != null) {
332: thenode = ch;
333: } else {
334: break;
335: }
336: }
337: if (thenode != this .rootCond) {
338: this .current = thenode;
339: }
340: }
341: if (thenode == null) {
342: return null;
343: // thenode = this.rootCond;
344: }
345: Collection children = thenode.getChildren();
346: Node[] nchild = new Node[children.size()];
347: return (Node[]) children.toArray(nchild);
348: }
349:
350: /**
351: * for convienance, the method will return a list of strings
352: * that are children of the last node found. If the editor
353: * wants to generate the children strings, call the method
354: * with true
355: * @param text
356: * @return
357: */
358: public ArrayList getConditionChildrenList(String text,
359: boolean addChildren) {
360: Node[] c = getConditionChildren(text);
361: this .suggestions.clear();
362: for (int idx = 0; idx < c.length; idx++) {
363: this .suggestions.add(c[idx].getToken());
364: if (addChildren) {
365: this .addChildToList(c[idx], c[idx].getToken(),
366: this .suggestions);
367: }
368: }
369: return this .suggestions;
370: }
371:
372: /**
373: * for convienance, the method will return a list of strings
374: * that are children of the last node found. If the editor
375: * wants to generate the children strings, call the method
376: * with true
377: * @param text
378: * @return
379: */
380: public ArrayList getConsequenceChildrenList(String text,
381: boolean addChildren) {
382: Node[] c = getConsequenceChildren(text);
383: this .suggestions.clear();
384: for (int idx = 0; idx < c.length; idx++) {
385: if (addChildren) {
386: this .addChildToList(c[idx], c[idx].getToken(),
387: this .suggestions);
388: } else {
389: this .suggestions.add(c[idx].getToken());
390: }
391: }
392: return this .suggestions;
393: }
394:
395: /**
396: *
397: * @param obj
398: * @param text
399: * @param addChildren
400: * @return
401: */
402: public ArrayList getChildrenList(String obj, String text,
403: boolean addChildren) {
404: Node[] c = getChildren(obj, text);
405: this .suggestions.clear();
406: if (c != null) {
407: for (int idx = 0; idx < c.length; idx++) {
408: if (addChildren) {
409: this .addChildToList(c[idx], c[idx].getToken(),
410: this .suggestions);
411: } else {
412: this .suggestions.add(c[idx].getToken());
413: }
414: }
415: }
416: if (c == null || text.trim().length() == 0) {
417: // in the event the line is zero length after it is trimmed, we also add
418: // the top level nodes
419: Iterator top = this .rootCond.getChildren().iterator();
420: while (top.hasNext()) {
421: Node t = (Node) top.next();
422: if (!this .suggestions.contains(t.getToken())) {
423: if (addChildren) {
424: this .addChildToList(t, t.getToken(),
425: this .suggestions);
426: } else {
427: this .suggestions.add(t.getToken());
428: }
429: }
430: }
431: }
432: return this .suggestions;
433: }
434:
435: /**
436: * method will prepend the parent text to the child and generate
437: * the possible combinations in text format.
438: * @param n
439: * @param prefix
440: * @param list
441: */
442: public void addChildToList(Node n, String prefix, ArrayList list) {
443: if (n.getChildren().size() > 0) {
444: Iterator itr = n.getChildren().iterator();
445: while (itr.hasNext()) {
446: Node child = (Node) itr.next();
447: String text = prefix + " " + child.getToken();
448: // list.add(text);
449: addChildToList(child, text, list);
450: }
451: } else {
452: list.add(prefix);
453: }
454: }
455:
456: public Node getCurrent() {
457: return current;
458: }
459:
460: public void setCurrent(Node current) {
461: this .current = current;
462: }
463:
464: public Node getLast() {
465: return last;
466: }
467:
468: public void setLast(Node last) {
469: this .last = last;
470: }
471:
472: /**
473: * The method will print the DSLTree to System.out in text format.
474: */
475: public void printTree() {
476: System.out.println("ROOT");
477: Iterator itr = this .rootCond.getChildren().iterator();
478: while (itr.hasNext()) {
479: Node n = (Node) itr.next();
480: printNode(n);
481: }
482: }
483:
484: /**
485: * method will print the node and then iterate over the children
486: * @param n
487: */
488: protected void printNode(Node n) {
489: printTabs(n.getDepth());
490: System.out.println("- \"" + n.getToken() + "\"");
491: Iterator itr = n.getChildren().iterator();
492: while (itr.hasNext()) {
493: Node c = (Node) itr.next();
494: printNode(c);
495: }
496: }
497:
498: /**
499: * Method will print n number of tabs
500: * @param count
501: */
502: protected void printTabs(int count) {
503: for (int idx = 0; idx < count; idx++) {
504: System.out.print(tab);
505: }
506: }
507: }
|