/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2012-2014, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.cql; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; import java.util.ArrayList; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.Hints; import org.geotoolkit.gui.swing.tree.Trees; import org.geotoolkit.temporal.object.ISODateParser; import org.geotoolkit.temporal.object.TemporalUtilities; import org.opengis.filter.And; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.Or; import org.opengis.filter.expression.Expression; import static org.geotoolkit.cql.CQLParser.*; import org.opengis.filter.expression.PropertyName; /** * * @author Johann Sorel (Geomatys) */ public final class CQL { private static final GeometryFactory GF = new GeometryFactory(); private CQL() {} private static Object compileExpression(String cql) { try { //lexer splits input into tokens final ANTLRInputStream input = new ANTLRInputStream(cql); final TokenStream tokens = new CommonTokenStream(new CQLLexer(input)); //parser generates abstract syntax tree final CQLParser parser = new CQLParser(tokens); final ExpressionContext ctx = parser.expression(); return ctx; } catch (RecognitionException e) { throw new IllegalStateException("Recognition exception is never thrown, only declared."); } } private static Object compileFilter(String cql) { try { //lexer splits input into tokens final ANTLRInputStream input = new ANTLRInputStream(cql); final TokenStream tokens = new CommonTokenStream(new CQLLexer(input)); //parser generates abstract syntax tree final CQLParser parser = new CQLParser(tokens); final FilterContext retfilter = parser.filter(); return retfilter; } catch (RecognitionException e) { throw new IllegalStateException("Recognition exception is never thrown, only declared."); } } private static Object compileFilterOrExpression(String cql) { try { //lexer splits input into tokens final ANTLRInputStream input = new ANTLRInputStream(cql); final TokenStream tokens = new CommonTokenStream(new CQLLexer(input)); //parser generates abstract syntax tree final CQLParser parser = new CQLParser(tokens); final FilterOrExpressionContext retfilter = parser.filterOrExpression(); return retfilter; } catch (RecognitionException e) { throw new IllegalStateException("Recognition exception is never thrown, only declared."); } } public static ParseTree compile(String cql) { final Object obj = compileFilterOrExpression(cql); ParseTree tree = null; if(obj instanceof ParseTree){ tree = (ParseTree)obj; } return tree; } public static Expression parseExpression(String cql) throws CQLException{ return parseExpression(cql, null); } public static Expression parseExpression(String cql, FilterFactory2 factory) throws CQLException{ final Object obj = compileExpression(cql); ParseTree tree = null; Expression result = null; if(obj instanceof ExpressionContext){ tree = (ParseTree)obj; if(factory == null){ factory = (FilterFactory2) FactoryFinder .getFilterFactory(new Hints(Hints.FILTER_FACTORY,FilterFactory2.class)); } result = convertExpression(tree, factory); } return result; } public static Filter parseFilter(String cql) throws CQLException{ return parseFilter(cql, null); } public static Filter parseFilter(String cql, FilterFactory2 factory) throws CQLException{ cql = cql.trim(); //bypass parsing for inclusive filter if(cql.isEmpty() || "*".equals(cql)){ return Filter.INCLUDE; } final Object obj = compileFilter(cql); ParseTree tree = null; Filter result = null; if(obj instanceof FilterContext){ tree = (FilterContext)obj; if(factory == null){ factory = (FilterFactory2) FactoryFinder .getFilterFactory(new Hints(Hints.FILTER_FACTORY,FilterFactory2.class)); } result = convertFilter(tree, factory); } return result; } public static String write(Filter filter){ if(filter == null) return ""; final StringBuilder sb = new StringBuilder(); filter.accept(FilterToCQLVisitor.INSTANCE,sb); return sb.toString(); } public static String write(Expression exp){ if(exp == null) return ""; final StringBuilder sb = new StringBuilder(); exp.accept(FilterToCQLVisitor.INSTANCE,sb); return sb.toString(); } /** * Generate a nice looking tree representation of the tree. */ public static String toString(ParseTree tree){ if(tree == null) return null; final DefaultMutableTreeNode node = explore(tree); return Trees.toString(node); } /** * Create a TreeNode for the given tree. method is recursive. */ private static DefaultMutableTreeNode explore(ParseTree tree){ final DefaultMutableTreeNode node = new DefaultMutableTreeNode(tree); final int nb = tree.getChildCount(); for(int i=0;i<nb;i++){ final DefaultMutableTreeNode n = explore((ParseTree)tree.getChild(i)); node.add(n); } return node; } /** * Convert the given tree in an Expression. */ private static Expression convertExpression(ParseTree tree, FilterFactory2 ff) throws CQLException{ if(tree instanceof ExpressionContext){ //: expression MULT expression //| expression UNARY expression //| expressionTerm if(tree.getChildCount()==3){ final String operand = tree.getChild(1).getText(); final Expression left = convertExpression((ParseTree)tree.getChild(0), ff); final Expression right = convertExpression((ParseTree)tree.getChild(2), ff); if("*".equals(operand)){ return ff.multiply(left,right); }else if("/".equals(operand)){ return ff.divide(left,right); }else if("+".equals(operand)){ return ff.add(left,right); }else if("-".equals(operand)){ return ff.subtract(left,right); } }else{ return convertExpression(tree.getChild(0), ff); } } // else if(tree instanceof ExpressionStringContext){ // //strip start and end ' // final String text = tree.getText(); // return ff.literal(text.substring(1, text.length()-1)); // } else if(tree instanceof ExpressionTermContext){ //: expressionString //| expressionUnary //| PROPERTY_NAME //| DATE //| DURATION_P //| DURATION_T //| NAME (LPAREN expressionFctParam? RPAREN)? //| expressionGeometry //| LPAREN expression RPAREN //: TEXT //| expressionUnary //| PROPERTY_NAME //| DATE //| DURATION_P //| DURATION_T //| expressionGeometry final ExpressionTermContext exp = (ExpressionTermContext) tree; if(exp.getChildCount()==1){ return convertExpression(tree.getChild(0), ff); } // LPAREN expression RPAREN if(exp.expression()!=null){ return convertExpression(exp.expression(), ff); } // NAME (LPAREN expressionFctParam? RPAREN)? if(exp.NAME()!=null){ final String name = exp.NAME().getText(); final ExpressionFctParamContext prm = exp.expressionFctParam(); if(prm==null){ //handle as property name return ff.property(name); } //handle as a function final List<ExpressionContext> params = prm.expression(); final List<Expression> exps = new ArrayList<Expression>(); for(int i=0,n=params.size();i<n;i++){ exps.add(convertExpression(params.get(i), ff)); } return ff.function(name, exps.toArray(new Expression[exps.size()])); } }else if(tree instanceof ExpressionUnaryContext){ //: UNARY? expressionNum ; final ExpressionUnaryContext exp = (ExpressionUnaryContext) tree; return ff.literal(unaryAsNumber(exp)); }else if(tree instanceof ExpressionNumContext){ //: INT | FLOAT ; return convertExpression(tree.getChild(0), ff); }else if(tree instanceof TerminalNode){ final TerminalNode exp = (TerminalNode) tree; final int type = exp.getSymbol().getType(); if(PROPERTY_NAME == type){ //strip start and end " final String text = tree.getText(); return ff.property(text.substring(1, text.length()-1)); }else if(NAME == type){ return ff.property(tree.getText()); }else if(INT == type){ return ff.literal(Integer.valueOf(tree.getText())); }else if(FLOAT == type){ return ff.literal(Double.valueOf(tree.getText())); }else if(DATE == type){ final ISODateParser parser = new ISODateParser(); return ff.literal(parser.parseToDate(tree.getText())); }else if(DURATION_P == type || DURATION_T == type){ return ff.literal(TemporalUtilities.getTimeInMillis(tree.getText())); }else if(TEXT == type){ //strip start and end ' String text = tree.getText(); text = text.replaceAll("\\\\'", "'"); return ff.literal(text.substring(1, text.length()-1)); } }else if(tree instanceof ExpressionGeometryContext){ //: POINT ( EMPTY | coordinateSerie ) //| LINESTRING ( EMPTY | coordinateSerie ) //| POLYGON ( EMPTY | coordinateSeries ) //| MPOINT ( EMPTY | coordinateSerie ) //| MLINESTRING ( EMPTY | coordinateSeries ) //| MPOLYGON ( EMPTY | LPAREN coordinateSeries (COMMA coordinateSeries)* RPAREN ) //| GEOMETRYCOLLECTION ( EMPTY | (LPAREN expressionGeometry (COMMA expressionGeometry)* RPAREN) ) //| ENVELOPE ( EMPTY | (LPAREN expressionUnary COMMA expressionUnary COMMA expressionUnary COMMA expressionUnary RPAREN) ) final ExpressionGeometryContext exp = (ExpressionGeometryContext) tree; final int type = ((TerminalNode)exp.getChild(0)).getSymbol().getType(); if(POINT == type){ final ParseTree st = (ParseTree) tree.getChild(1); final CoordinateSequence cs; if(isEmptyToken(st)){ cs = GF.getCoordinateSequenceFactory().create(new Coordinate[0]); }else{ cs = parseSequence(st); } final Geometry geom = GF.createPoint(cs); return ff.literal(geom); }else if(LINESTRING == type){ final ParseTree st = (ParseTree) tree.getChild(1); final CoordinateSequence cs; if(isEmptyToken(st)){ cs = GF.getCoordinateSequenceFactory().create(new Coordinate[0]); }else{ cs = parseSequence(st); } final Geometry geom = GF.createLineString(cs); return ff.literal(geom); }else if(POLYGON == type){ final ParseTree st = (ParseTree) tree.getChild(1); final Geometry geom; if(isEmptyToken(st)){ geom = GF.createPolygon(GF.createLinearRing(new Coordinate[0]),new LinearRing[0]); }else{ final CoordinateSeriesContext series = (CoordinateSeriesContext) st; final List<CoordinateSerieContext> subs = series.coordinateSerie(); final LinearRing contour = GF.createLinearRing(parseSequence(subs.get(0))); final int n = subs.size(); final LinearRing[] holes = new LinearRing[n-1]; for(int i=1; i<n; i++){ holes[i-1] = GF.createLinearRing(parseSequence(subs.get(i))); } geom = GF.createPolygon(contour,holes); } return ff.literal(geom); }else if(MPOINT == type){ final ParseTree st = (ParseTree) tree.getChild(1); final CoordinateSequence cs; if(isEmptyToken(st)){ cs = GF.getCoordinateSequenceFactory().create(new Coordinate[0]); }else{ cs = parseSequence(st); } final Geometry geom = GF.createMultiPoint(cs); return ff.literal(geom); }else if(MLINESTRING == type){ final ParseTree st = (ParseTree) tree.getChild(1); final Geometry geom; if(isEmptyToken(st)){ geom = GF.createMultiLineString(new LineString[0]); }else{ final CoordinateSeriesContext series = (CoordinateSeriesContext) st; final List<CoordinateSerieContext> subs = series.coordinateSerie(); final int n = subs.size(); final LineString[] strings = new LineString[n]; for(int i=0; i<n; i++){ strings[i] = GF.createLineString(parseSequence(subs.get(i))); } geom = GF.createMultiLineString(strings); } return ff.literal(geom); }else if(MPOLYGON == type){ final ParseTree st = (ParseTree) tree.getChild(1); final Geometry geom; if(isEmptyToken(st)){ geom = GF.createMultiPolygon(new Polygon[0]); }else{ final List<CoordinateSeriesContext> eles = exp.coordinateSeries(); final int n = eles.size(); final Polygon[] polygons = new Polygon[n]; for(int i=0; i<n; i++){ final CoordinateSeriesContext polyTree = eles.get(i); final List<CoordinateSerieContext> subs = polyTree.coordinateSerie(); final LinearRing contour = GF.createLinearRing(parseSequence(subs.get(0))); final int hn = subs.size(); final LinearRing[] holes = new LinearRing[hn-1]; for(int j=1; j<hn; j++){ holes[j-1] = GF.createLinearRing(parseSequence(subs.get(j))); } final Polygon poly = GF.createPolygon(contour,holes); polygons[i] = poly; } geom = GF.createMultiPolygon(polygons); } return ff.literal(geom); }else if(GEOMETRYCOLLECTION == type){ final ParseTree st = (ParseTree) tree.getChild(1); final Geometry geom; if(isEmptyToken(st)){ geom = GF.createGeometryCollection(new Geometry[0]); }else{ final List<ExpressionGeometryContext> eles = exp.expressionGeometry(); final int n = eles.size(); final Geometry[] subs = new Geometry[n]; for(int i=0; i<n; i++){ final ParseTree subTree = eles.get(i); final Geometry sub = (Geometry)convertExpression(subTree, ff).evaluate(null); subs[i] = sub; } geom = GF.createGeometryCollection(subs); } return ff.literal(geom); }else if(ENVELOPE == type){ final ParseTree st = (ParseTree) tree.getChild(1); final Geometry geom; if(isEmptyToken(st)){ geom = GF.createPolygon(GF.createLinearRing(new Coordinate[0]),new LinearRing[0]); }else{ final List<ExpressionUnaryContext> unaries = exp.expressionUnary(); final double west = unaryAsNumber(unaries.get(0)).doubleValue(); final double east = unaryAsNumber(unaries.get(1)).doubleValue(); final double north = unaryAsNumber(unaries.get(2)).doubleValue(); final double south = unaryAsNumber(unaries.get(3)).doubleValue(); final LinearRing contour = GF.createLinearRing(new Coordinate[]{ new Coordinate(west, north), new Coordinate(east, north), new Coordinate(east, south), new Coordinate(west, south), new Coordinate(west, north) }); geom = GF.createPolygon(contour,new LinearRing[0]); } return ff.literal(geom); } return convertExpression(tree.getChild(0), ff); } throw new CQLException("Unreconized expression : type=" + tree.getText()); } private static boolean isEmptyToken(ParseTree tree){ return tree instanceof TerminalNode && ((TerminalNode)tree).getSymbol().getType() == EMPTY; } private static final Number unaryAsNumber(ExpressionUnaryContext tree){ //: UNARY? expressionNum ; final ExpressionUnaryContext exp = (ExpressionUnaryContext) tree; final boolean negate = (exp.UNARY() !=null && exp.UNARY().getSymbol().getText().equals("-")); final ExpressionNumContext num = exp.expressionNum(); if(num.INT()!=null){ int val = Integer.valueOf(num.INT().getText()); return negate ? -val : val; }else{ double val = Double.valueOf(num.FLOAT().getText()); return negate ? -val : val; } } private static CoordinateSequence parseSequence(ParseTree tree){ final CoordinateSerieContext exp = (CoordinateSerieContext) tree; final List<CoordinateContext> lst = exp.coordinate(); final int size = lst.size(); final Coordinate[] coords = new Coordinate[size]; for(int i=0;i<size;i++){ final CoordinateContext cc = lst.get(i); coords[i] = new Coordinate( unaryAsNumber(cc.expressionUnary(0)).doubleValue(), unaryAsNumber(cc.expressionUnary(1)).doubleValue()); } return GF.getCoordinateSequenceFactory().create(coords); } /** * Convert the given tree in a Filter. */ private static Filter convertFilter(ParseTree tree, FilterFactory2 ff) throws CQLException{ if(tree instanceof FilterContext){ //: filter (AND filter)+ //| filter (OR filter)+ //| LPAREN filter RPAREN //| NOT filterTerm //| filterTerm final FilterContext exp = (FilterContext) tree; //| filterTerm if(exp.getChildCount()==1){ return convertFilter(tree.getChild(0), ff); }else if(exp.NOT()!=null){ //| NOT (filterTerm | ( LPAREN filter RPAREN )) if(exp.filterTerm()!=null){ return ff.not(convertFilter(exp.filterTerm(), ff)); }else{ return ff.not(convertFilter(exp.filter(0), ff)); } }else if(!exp.AND().isEmpty()){ //: filter (AND filter)+ final List<Filter> subs = new ArrayList<Filter>(); for(FilterContext f : exp.filter()){ final Filter sub = convertFilter(f, ff); if(sub instanceof And){ subs.addAll(((And)sub).getChildren()); }else{ subs.add(sub); } } return ff.and(subs); }else if(!exp.OR().isEmpty()){ //| filter (OR filter)+ final List<Filter> subs = new ArrayList<Filter>(); for(FilterContext f : exp.filter()){ final Filter sub = convertFilter(f, ff); if(sub instanceof Or){ subs.addAll(((Or)sub).getChildren()); }else{ subs.add(sub); } } return ff.or(subs); }else if(exp.LPAREN()!=null){ //| LPAREN filter RPAREN return convertFilter(exp.filter(0), ff); } }else if(tree instanceof FilterTermContext){ //: expression // ( // COMPARE expression // | NOT? IN LPAREN (expressionFctParam )? RPAREN // | BETWEEN expression AND expression // | NOT? LIKE expression // | NOT? ILIKE expression // | IS NOT? NULL // | AFTER expression // | ANYINTERACTS expression // | BEFORE expression // | BEGINS expression // | BEGUNBY expression // | DURING expression // | ENDEDBY expression // | ENDS expression // | MEETS expression // | METBY expression // | OVERLAPPEDBY expression // | TCONTAINS expression // | TEQUALS expression // | TOVERLAPS expression // ) //| filterGeometry final FilterTermContext exp = (FilterTermContext) tree; final List<ExpressionContext> exps = exp.expression(); if(exp.COMPARE()!=null){ // expression COMPARE expression final String text = exp.COMPARE().getText(); final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); if("=".equals(text)){ return ff.equals(left, right); }else if("<>".equals(text)){ return ff.notEqual(left, right); }else if(">".equals(text)){ return ff.greater(left,right); }else if("<".equals(text)){ return ff.less(left,right); }else if(">=".equals(text)){ return ff.greaterOrEqual(left,right); }else if("<=".equals(text)){ return ff.lessOrEqual(left,right); }else if("<=".equals(text)){ return ff.lessOrEqual(left,right); } }else if(exp.IN()!=null){ // expression NOT? IN LPAREN (expressionFctParam )? RPAREN final Expression val = convertExpression(exps.get(0), ff); final ExpressionFctParamContext prm = exp.expressionFctParam(); final List<ExpressionContext> params = prm.expression(); final List<Expression> subexps = new ArrayList<Expression>(); for(int i=0,n=params.size();i<n;i++){ subexps.add(convertExpression(params.get(i), ff)); } final int size = subexps.size(); final Filter selection; if(size == 0){ selection = Filter.EXCLUDE; }else if(size == 1){ selection = ff.equals(val, subexps.get(0)); }else{ final List<Filter> filters = new ArrayList<Filter>(); for(Expression e : subexps){ filters.add(ff.equals(val, e)); } selection = ff.or(filters); } if(exp.NOT()!=null){ return ff.not(selection); }else{ return selection; } }else if(exp.BETWEEN()!=null){ // expression BETWEEN expression AND expression final Expression exp1 = convertExpression(exps.get(0), ff); final Expression exp2 = convertExpression(exps.get(1), ff); final Expression exp3 = convertExpression(exps.get(2), ff); return ff.between(exp1, exp2, exp3); }else if(exp.LIKE()!=null){ // expression NOT? LIKE expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); if(exp.NOT()!=null){ return ff.not(ff.like(left, right.evaluate(null, String.class), "%", "_", "\\",true)); }else{ return ff.like(left, right.evaluate(null, String.class), "%", "_", "\\",true); } }else if(exp.ILIKE()!=null){ // expression NOT? LIKE expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); if(exp.NOT()!=null){ return ff.not(ff.like(left, right.evaluate(null, String.class), "%", "_", "\\",false)); }else{ return ff.like(left, right.evaluate(null, String.class), "%", "_", "\\",false); } }else if(exp.IS()!=null){ // expression IS NOT? NULL final Expression exp1 = convertExpression(exps.get(0), ff); if(exp.NOT()!=null){ return ff.not(ff.isNull(exp1)); }else{ return ff.isNull(exp1); } }else if(exp.AFTER()!=null){ // expression AFTER expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.after(left, right); }else if(exp.ANYINTERACTS()!=null){ // expression ANYINTERACTS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.anyInteracts(left, right); }else if(exp.BEFORE()!=null){ // expression BEFORE expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.before(left, right); }else if(exp.BEGINS()!=null){ // expression BEGINS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.begins(left, right); }else if(exp.BEGUNBY()!=null){ // expression BEGUNBY expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.begunBy(left, right); }else if(exp.DURING()!=null){ // expression DURING expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.during(left, right); }else if(exp.ENDEDBY()!=null){ // expression ENDEDBY expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.endedBy(left, right); }else if(exp.ENDS()!=null){ // expression ENDS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.ends(left, right); }else if(exp.MEETS()!=null){ // expression MEETS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.meets(left, right); }else if(exp.METBY()!=null){ // expression METBY expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.metBy(left, right); }else if(exp.OVERLAPPEDBY()!=null){ // expression OVERLAPPEDBY expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.overlappedBy(left, right); }else if(exp.TCONTAINS()!=null){ // expression TCONTAINS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.tcontains(left, right); }else if(exp.TEQUALS()!=null){ // expression TEQUALS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.tequals(left, right); }else if(exp.TOVERLAPS()!=null){ // expression TOVERLAPS expression final Expression left = convertExpression(exps.get(0), ff); final Expression right = convertExpression(exps.get(1), ff); return ff.toverlaps(left, right); }else if(exp.filterGeometry()!=null){ //expression filterGeometry return convertFilter(exp.filterGeometry(), ff); } }else if(tree instanceof FilterGeometryContext){ //: BBOX LPAREN (PROPERTY_NAME|NAME) COMMA expressionUnary COMMA expressionUnary COMMA expressionUnary COMMA expressionUnary (COMMA TEXT)? RPAREN //| BEYOND LPAREN expression COMMA expression COMMA expression COMMA expression RPAREN //| CONTAINS LPAREN expression COMMA expression RPAREN //| CROSSES LPAREN expression COMMA expression RPAREN //| DISJOINT LPAREN expression COMMA expression RPAREN //| DWITHIN LPAREN expression COMMA expression COMMA expression COMMA expression RPAREN //| EQUALS LPAREN expression COMMA expression RPAREN //| INTERSECTS LPAREN expression COMMA expression RPAREN //| OVERLAPS LPAREN expression COMMA expression RPAREN //| TOUCHES LPAREN expression COMMA expression RPAREN //| WITHIN LPAREN expression COMMA expression RPAREN final FilterGeometryContext exp = (FilterGeometryContext) tree; final List<ExpressionContext> exps = exp.expression(); if(exp.BBOX()!=null){ final Expression prop = convertExpression(exps.get(0),ff); final double v1 = unaryAsNumber(exp.expressionUnary(0)).doubleValue(); final double v2 = unaryAsNumber(exp.expressionUnary(1)).doubleValue(); final double v3 = unaryAsNumber(exp.expressionUnary(2)).doubleValue(); final double v4 = unaryAsNumber(exp.expressionUnary(3)).doubleValue(); String crs = null; if(exp.TEXT()!=null){ crs = convertExpression(exp.TEXT(),ff).evaluate(null, String.class); } return ff.bbox(prop, v1,v2,v3,v4,crs); }else if(exp.BEYOND()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); final double distance = convertExpression(exps.get(2),ff).evaluate(null, Double.class); final Expression unitExp = convertExpression(exps.get(3),ff); final String unit = (unitExp instanceof PropertyName) ? ((PropertyName)unitExp).getPropertyName() : unitExp.evaluate(null, String.class); return ff.beyond(exp1,exp2,distance,unit); }else if(exp.CONTAINS()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.contains(exp1,exp2); }else if(exp.CROSSES()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.crosses(exp1,exp2); }else if(exp.DISJOINT()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.disjoint(exp1,exp2); }else if(exp.DWITHIN()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); final double distance = convertExpression(exps.get(2),ff).evaluate(null, Double.class); final Expression unitExp = convertExpression(exps.get(3),ff); final String unit = (unitExp instanceof PropertyName) ? ((PropertyName)unitExp).getPropertyName() : unitExp.evaluate(null, String.class); return ff.dwithin(exp1,exp2,distance,unit); }else if(exp.EQUALS()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.equal(exp1,exp2); }else if(exp.INTERSECTS()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.intersects(exp1,exp2); }else if(exp.OVERLAPS()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.overlaps(exp1,exp2); }else if(exp.TOUCHES()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.touches(exp1,exp2); }else if(exp.WITHIN()!=null){ final Expression exp1 = convertExpression(exps.get(0),ff); final Expression exp2 = convertExpression(exps.get(1),ff); return ff.within(exp1,exp2); } } throw new CQLException("Unreconized filter : type=" + tree.getText()); } }