001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2005, Refractions Research Inc.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.catalog.defaults;
018:
019: import java.util.LinkedList;
020: import java.util.List;
021: import java.util.ListIterator;
022: import java.util.Stack;
023:
024: /**
025: * DOCUMENT ME!
026: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/catalog/defaults/ASTFactory.java $
027: */
028: public class ASTFactory {
029: private ASTFactory() { /* not used */
030: }
031:
032: /**
033: * Creates an AST for the pattern The pattern uses the following
034: * conventions: use " " to surround a phase use + to represent 'AND' use -
035: * to represent 'OR' use ! to represent 'NOT' use ( ) to designate scope
036: *
037: * @param str Search pattern
038: *
039: * @return AST
040: */
041: public static AST parse(String str) {
042: List tokens = tokenize(str);
043: Stack s = new Stack();
044: ListIterator li = tokens.listIterator();
045:
046: // create the ast
047: while (li.hasNext())
048: node(s, li);
049:
050: if (s.size() == 1) {
051: return (AST) s.pop();
052: }
053:
054: if (s.size() > 1) {
055: // assume they are anded ... TODO balance the tree
056: while (s.size() > 1) {
057: AST p1 = (AST) s.pop();
058: AST p2 = (AST) s.pop();
059: s.push(new And(p1, p2));
060: }
061:
062: return (AST) s.pop();
063: }
064:
065: System.err
066: .println("An internal error creating an AST may have occured"); //$NON-NLS-1$
067:
068: return null;
069: }
070:
071: protected static List tokenize(String pattern) {
072: List l = new LinkedList();
073:
074: for (int i = 0; i < pattern.length(); i++) {
075: char c = pattern.charAt(i);
076:
077: switch (c) {
078: case '(':
079: l.add("("); //$NON-NLS-1$
080:
081: break;
082:
083: case ')':
084: l.add(")"); //$NON-NLS-1$
085:
086: break;
087:
088: case '+':
089: l.add("+"); //$NON-NLS-1$
090:
091: break;
092:
093: case '-':
094: l.add("-"); //$NON-NLS-1$
095:
096: break;
097:
098: case '!':
099: l.add("!"); //$NON-NLS-1$
100:
101: break;
102:
103: case '"':
104:
105: // greedy grab
106: int j = pattern.indexOf('"', i + 1);
107: l.add(pattern.substring(i + 1, j));
108: i = j;
109:
110: break;
111:
112: case ' ':
113: case '\t':
114: case '\n':
115:
116: // skip
117: break;
118:
119: case 'A': // ND
120:
121: if ((pattern.charAt(i + 1) == 'N')
122: && (pattern.charAt(i + 2) == 'D')) {
123: // it's a +
124: l.add("+"); //$NON-NLS-1$
125: i += 2;
126: }
127:
128: break;
129:
130: case 'O': // R
131:
132: if (pattern.charAt(i + 1) == 'R') {
133: // it's a +
134: l.add("-"); //$NON-NLS-1$
135: i += 1;
136: }
137:
138: break;
139:
140: case 'N': // OT
141:
142: if ((pattern.charAt(i + 1) == 'O')
143: && (pattern.charAt(i + 2) == 'T')) {
144: // it's a +
145: l.add("!"); //$NON-NLS-1$
146: i += 2;
147: }
148:
149: default:
150: // greedy grab
151: j = i + 1;
152:
153: while ((j < pattern.length())
154: && (pattern.charAt(j) != '"')
155: && (pattern.charAt(j) != '+')
156: && (pattern.charAt(j) != '-')
157: && (pattern.charAt(j) != '!')
158: && (pattern.charAt(j) != '(')
159: && (pattern.charAt(j) != ')')
160: && (pattern.charAt(j) != ' ')
161: && (pattern.charAt(j) != '\t')
162: && (pattern.charAt(j) != '\n'))
163: j++;
164:
165: l.add(pattern.substring(i, j));
166: i = ((i == j) ? j : (j - 1));
167: }
168: }
169:
170: return l;
171: }
172:
173: private static void node(Stack s, ListIterator li) {
174: if (li.hasNext()) {
175: String token = (String) li.next();
176:
177: char c = token.charAt(0);
178:
179: switch (c) {
180: case '(':
181: // child is what we want
182: node(s, li);
183:
184: break;
185:
186: case ')':
187:
188: // ignore this
189: break;
190:
191: case '+':
192:
193: AST prev = (AST) s.pop();
194: node(s, li);
195:
196: AST next = (AST) s.pop();
197: s.push(new And(prev, next));
198:
199: break;
200:
201: case '-':
202: prev = (AST) s.pop();
203: node(s, li);
204: next = (AST) s.pop();
205: s.push(new Or(prev, next));
206:
207: break;
208:
209: case '!':
210: node(s, li);
211: next = (AST) s.pop();
212: s.push(new Not(next));
213:
214: break;
215:
216: default:
217: s.push(new Literal(token));
218: }
219: }
220: }
221:
222: private static class And implements AST {
223: private AST left;
224: private AST right;
225:
226: private And() { /* should not be used */
227: }
228:
229: public And(AST left, AST right) {
230: this .left = left;
231: this .right = right;
232: }
233:
234: /**
235: * TODO summary sentence for accept ...
236: *
237: * @param datum
238: *
239: *
240: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#accept(java.lang.String)
241: */
242: public boolean accept(String datum) {
243: return (left != null) && (right != null)
244: && left.accept(datum) && right.accept(datum);
245: }
246:
247: /**
248: * TODO summary sentence for type ...
249: *
250: *
251: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#type()
252: */
253: public int type() {
254: return AND;
255: }
256:
257: /*
258: * (non-Javadoc)
259: *
260: * @see net.refractions.udig.catalog.util.AST#getLeft()
261: */
262: public AST getLeft() {
263: return left;
264: }
265:
266: /*
267: * (non-Javadoc)
268: *
269: * @see net.refractions.udig.catalog.util.AST#getRight()
270: */
271: public AST getRight() {
272: return right;
273: }
274: }
275:
276: private static class Or implements AST {
277: private AST left;
278: private AST right;
279:
280: private Or() { /* should not be used */
281: }
282:
283: public Or(AST left, AST right) {
284: this .left = left;
285: this .right = right;
286: }
287:
288: /**
289: * TODO summary sentence for accept ...
290: *
291: * @param datum
292: *
293: *
294: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#accept(java.lang.String)
295: */
296: public boolean accept(String datum) {
297: return ((right != null) && right.accept(datum))
298: || ((left != null) && left.accept(datum));
299: }
300:
301: /**
302: * TODO summary sentence for type ...
303: *
304: *
305: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#type()
306: */
307: public int type() {
308: return OR;
309: }
310:
311: /*
312: * (non-Javadoc)
313: *
314: * @see net.refractions.udig.catalog.util.AST#getLeft()
315: */
316: public AST getLeft() {
317: return left;
318: }
319:
320: /*
321: * (non-Javadoc)
322: *
323: * @see net.refractions.udig.catalog.util.AST#getRight()
324: */
325: public AST getRight() {
326: return right;
327: }
328: }
329:
330: private static class Not implements AST {
331: private AST child;
332:
333: private Not() { /* should not be used */
334: }
335:
336: public Not(AST child) {
337: this .child = child;
338: }
339:
340: /**
341: * TODO summary sentence for accept ...
342: *
343: * @param datum
344: *
345: *
346: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#accept(java.lang.String)
347: */
348: public boolean accept(String datum) {
349: return !((child != null) && child.accept(datum));
350: }
351:
352: /**
353: * TODO summary sentence for type ...
354: *
355: *
356: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#type()
357: */
358: public int type() {
359: return NOT;
360: }
361:
362: /*
363: * (non-Javadoc)
364: *
365: * @see net.refractions.udig.catalog.util.AST#getLeft()
366: */
367: public AST getLeft() {
368: return child;
369: }
370:
371: /*
372: * (non-Javadoc)
373: *
374: * @see net.refractions.udig.catalog.util.AST#getRight()
375: */
376: public AST getRight() {
377: return null;
378: }
379: }
380:
381: private static class Literal implements AST {
382: private String value;
383:
384: private Literal() { /* should not be used */
385: }
386:
387: public Literal(String value) {
388: this .value = value;
389: }
390:
391: /**
392: * TODO summary sentence for accept ...
393: *
394: * @param datum
395: *
396: *
397: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#accept(java.lang.String)
398: */
399: public boolean accept(String datum) {
400: // TODO check this
401: return (value != null)
402: && (datum != null)
403: && (datum.toUpperCase()
404: .indexOf(value.toUpperCase()) > -1);
405: }
406:
407: /**
408: * TODO summary sentence for type ...
409: *
410: *
411: * @see net.refractions.udig.catalog.internal.DefaultCatalog.AST#type()
412: */
413: public int type() {
414: return LITERAL;
415: }
416:
417: /*
418: * (non-Javadoc)
419: *
420: * @see net.refractions.udig.catalog.util.AST#getLeft()
421: */
422: public AST getLeft() {
423: return null;
424: }
425:
426: /*
427: * (non-Javadoc)
428: *
429: * @see net.refractions.udig.catalog.util.AST#getRight()
430: */
431: public AST getRight() {
432: return null;
433: }
434:
435: public String toString() {
436: return value;
437: }
438: }
439: }
|