001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.filter.text.cql2;
017:
018: import java.io.BufferedReader;
019: import java.io.IOException;
020: import java.io.InputStreamReader;
021: import java.util.List;
022: import javax.xml.transform.TransformerException;
023: import org.opengis.filter.Filter;
024: import org.opengis.filter.FilterFactory;
025: import org.opengis.filter.FilterFactory2;
026: import org.opengis.filter.expression.Expression;
027: import org.geotools.factory.CommonFactoryFinder;
028: import org.geotools.factory.Hints;
029: import org.geotools.filter.FilterTransformer;
030:
031: /**
032: * Utility class to parse <b>CQL</b> predicates and expressions to GeoAPI
033: * {@link Filter}s and {@link Expression}s, respectively.
034: *
035: * <p>
036: * <b>CQL</b> is an acronym for OGC Common Query Language, a query predicate
037: * language whose syntax is similar to a SQL WHERE clause, defined in clause
038: * 6.2.2 of the OGC Catalog Service for Web, version 2.0.1 implementation
039: * specification.
040: * </p>
041: * <p>
042: * This class provides three methods, {@link #toFilter(String)},
043: * {@link #toExpression(String)} and {@link #toFilterList(String)}; and an
044: * overloaded version of each one for the user to provide a
045: * {@link FilterFactory2} implementation to use.
046: * </p>
047: * <p>
048: * <h2>Usage</h2>
049: * Here are some usage examples. Refer to the <a
050: * href="http://docs.codehaus.org/display/GEOTOOLS/CQL+Parser+Design">complete
051: * grammar</a> to see what exactly you can do.
052: *
053: * <pre>
054: * <code>
055: * Filter f1 = CQL.toFilter("ATTR1 < 10 AND ATTR2 < 2 OR ATTR3 > 10");
056: *
057: * Filter f2 = CQL.toFilter("ATTR1 IS NULL");
058: *
059: * Filter f3 = CQL.toFilter("ATTR1 BEFORE 2006-11-30T01:30:00Z");
060: *
061: * Filter f4 = CQL.toFilter("ATTR1 DOES-NOT-EXIST");
062: *
063: * Filter f5 = CQL.toFilter("ATTR1 BETWEEN 10 AND 20");
064: *
065: * Filter f6 = CQL.toFilter("CROSS(ATTR1, LINESTRING(1 2, 10 15))");
066: *
067: * Filter f7 = CQL.toFilter("BBOX(ATTR1, 10,20,30,40)");
068: *
069: * Expression expr1 = CQL.toExpression("attName");
070: *
071: * Expression expr2 = CQL.toExpression("attName * 2");
072: *
073: * Expression expr3 = CQL.toExpression("strConcat(attName, 'suffix')");
074: *
075: * List filters = CQL
076: * .toFilterList("ATTR1 IS NULL|BBOX(ATTR1, 10,20,30,40)|INCLUDE");
077: * </code>
078: * </pre>
079: *
080: * @since 2.4
081: *
082: * @author Mauricio Pazos - Axios Engineering
083: * @author Gabriel Roldan - Axios Engineering
084: *
085: * @version $Id: CQL.java 28745 2008-01-14 12:22:32Z vmpazos $
086: * @source $URL:
087: * http://svn.geotools.org/geotools/trunk/gt/modules/library/cql/src/main/java/org/geotools/filter/text/cql2/CQL.java $
088: */
089: public class CQL {
090: private CQL() {
091: // do nothing, private constructor
092: // to indicate it is a pure utility class
093: }
094:
095: /**
096: * Parses the input string in OGC CQL format into a Filter, using the
097: * systems default FilterFactory implementation.
098: *
099: * @param cqlPredicate
100: * a string containing a query predicate in OGC CQL format.
101: * @return a {@link Filter} equivalent to the constraint specified in
102: * <code>cqlPredicate</code>.
103: */
104: public static Filter toFilter(final String cqlPredicate)
105: throws CQLException {
106: Filter filter = CQL.toFilter(cqlPredicate, null);
107:
108: return filter;
109: }
110:
111: /**
112: * Parses the input string in OGC CQL format into a Filter, using the
113: * provided FilterFactory.
114: *
115: * @param cqlPredicate
116: * a string containing a query predicate in OGC CQL format.
117: * @param filterFactory
118: * the {@link FilterFactory} to use for the creation of the
119: * Filter. If it is null the method finds the default implementation.
120: * @return a {@link Filter} equivalent to the constraint specified in
121: * <code>Predicate</code>.
122: */
123: public static Filter toFilter(final String cqlPredicate,
124: final FilterFactory filterFactory) throws CQLException {
125:
126: FilterFactory ff = filterFactory;
127:
128: if (ff == null) {
129: ff = CommonFactoryFinder.getFilterFactory((Hints) null);
130: }
131:
132: CQLCompiler compiler = new CQLCompiler(cqlPredicate, ff);
133:
134: try {
135: compiler.CompilationUnit();
136: Filter result = compiler.getFilter();
137:
138: return result;
139:
140: } catch (TokenMgrError e) {
141: // note: TokenMgrError is an unchecked exception then the caller cannot
142: // recovery itself if some lexical error happen. This clause catch that
143: // exception an transform it in checked exception.
144: throw new CQLException(e.getMessage(),
145: compiler.getToken(0), e, cqlPredicate);
146:
147: } catch (ParseException e) {
148: throw new CQLException(e.getMessage(),
149: compiler.getToken(0), e, cqlPredicate);
150: }
151:
152: }
153:
154: /**
155: * Parses the input string in OGC CQL format into an Expression, using the
156: * systems default FilterFactory implementation.
157: *
158: * @param cqlExpression
159: * a string containing an OGC CQL expression.
160: * @return a {@link Expression} equivalent to the one specified in
161: * <code>cqlExpression</code>.
162: */
163: public static Expression toExpression(String cqlExpression)
164: throws CQLException {
165: return toExpression(cqlExpression, null);
166: }
167:
168: /**
169: * Parses the input string in OGC CQL format into an Expression, using the
170: * provided FilterFactory.
171: *
172: * @param cqlExpression
173: * a string containing a OGC CQL expression.
174: *
175: * @param filterFactory
176: * the {@link FilterFactory} to use for the creation of the
177: * Expression. If it is null the method finds the default implementation.
178: * @return a {@link Filter} equivalent to the constraint specified in
179: * <code>cqlExpression</code>.
180: */
181: public static Expression toExpression(final String cqlExpression,
182: final FilterFactory filterFactory) throws CQLException {
183: FilterFactory factory = filterFactory;
184:
185: if (factory == null) {
186: factory = CommonFactoryFinder
187: .getFilterFactory((Hints) null);
188: }
189:
190: CQLCompiler c = new CQLCompiler(cqlExpression, factory);
191:
192: try {
193: c.ExpressionCompilationUnit();
194:
195: Expression builtFilter = c.getExpression();
196:
197: return builtFilter;
198: } catch (TokenMgrError e) {
199: // note: TokenMgrError is an unchecked exception then the caller cannot
200: // recovery itself if some lexical error happen. This clause catch that
201: // exception an transform it in checked exception.
202: throw new CQLException(e.getMessage(), c.getToken(0), e,
203: cqlExpression);
204:
205: } catch (ParseException e) {
206: throw new CQLException(e.getMessage(), c.getToken(0), e,
207: cqlExpression);
208: }
209:
210: }
211:
212: /**
213: * Parses the input string, which has to be a list of OGC CQL predicates
214: * separated by <code>|</code> into a <code>List</code> of
215: * <code>Filter</code>s, using the provided FilterFactory.
216: *
217: * @param cqlFilterList
218: * a list of OGC CQL predicates separated by <code>|</code>
219: *
220: * @return a List of {@link Filter}, one for each input CQL statement
221: */
222: public static List toFilterList(final String cqlFilterList)
223: throws CQLException {
224: List filters = CQL.toFilterList(cqlFilterList, null);
225:
226: return filters;
227: }
228:
229: /**
230: * Parses the input string, which has to be a list of OGC CQL predicates
231: * separated by <code>|</code> into a <code>List</code> of
232: * <code>Filter</code>s, using the provided FilterFactory.
233: *
234: * @param cqlSourceFilterList
235: * a list of OGC CQL predicates separated by <code>|</code>
236: *
237: * @param filterFactory
238: * the {@link FilterFactory} to use for the creation of the
239: * Expression. If it is null the method finds the default implementation.
240: * @return a List of {@link Filter}, one for each input CQL statement
241: */
242: public static List toFilterList(final String cqlSourceFilterList,
243: final FilterFactory filterFactory) throws CQLException {
244:
245: FilterFactory factory = filterFactory;
246:
247: if (factory == null) {
248: factory = CommonFactoryFinder
249: .getFilterFactory((Hints) null);
250: }
251:
252: CQLCompiler compiler = new CQLCompiler(cqlSourceFilterList,
253: factory);
254:
255: try {
256: compiler.MultipleCompilationUnit();
257: List results = compiler.getFilterList();
258:
259: return results;
260:
261: } catch (TokenMgrError e) {
262: // note: TokenMgrError is an unchecked exception then the caller cannot
263: // recovery itself if some lexical error happen. This clause catch that
264: // exception an transform it in checked exception.
265: throw new CQLException(e.getMessage(),
266: compiler.getToken(0), e, cqlSourceFilterList);
267:
268: } catch (ParseException e) {
269: throw new CQLException(e.getMessage() + ": "
270: + cqlSourceFilterList, compiler.getToken(0), e,
271: cqlSourceFilterList);
272: }
273: }
274:
275: /**
276: * Interactive filter compiling
277: *
278: * @param args
279: */
280: public static final void main(String[] args) {
281: System.out.println("Expression Tester (\"quit\" to finish)");
282:
283: BufferedReader reader = new BufferedReader(
284: new InputStreamReader(System.in));
285: FilterTransformer filterTransformer = new FilterTransformer();
286: filterTransformer.setIndentation(4);
287:
288: while (true) {
289: System.out.print(">");
290:
291: String line = null;
292:
293: try {
294: line = reader.readLine();
295:
296: if (line.equals("quit")) {
297: System.out.println("Bye!");
298: break;
299: }
300:
301: Object newFilter = CQL.toFilter(line);
302: filterTransformer.transform(newFilter, System.out);
303: System.out.println();
304: } catch (IOException e1) {
305: e1.printStackTrace();
306: } catch (CQLException cqlex) {
307: System.out.println(cqlex.getSyntaxError());
308: } catch (TransformerException e) {
309: e.printStackTrace();
310: }
311: }
312: }
313: }
|