/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2014, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.styling.css.util; import java.util.Date; import java.util.List; import org.geotools.filter.visitor.DefaultFilterVisitor; import org.opengis.filter.BinaryComparisonOperator; import org.opengis.filter.PropertyIsBetween; import org.opengis.filter.PropertyIsEqualTo; import org.opengis.filter.PropertyIsGreaterThan; import org.opengis.filter.PropertyIsGreaterThanOrEqualTo; import org.opengis.filter.PropertyIsLessThan; import org.opengis.filter.PropertyIsLessThanOrEqualTo; import org.opengis.filter.PropertyIsLike; import org.opengis.filter.PropertyIsNotEqualTo; import org.opengis.filter.capability.FunctionName; import org.opengis.filter.expression.Add; import org.opengis.filter.expression.BinaryExpression; import org.opengis.filter.expression.Divide; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.Multiply; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.expression.Subtract; import org.opengis.filter.spatial.Beyond; import org.opengis.filter.spatial.BinarySpatialOperator; import org.opengis.filter.spatial.Contains; import org.opengis.filter.spatial.Crosses; import org.opengis.filter.spatial.DWithin; import org.opengis.filter.spatial.Disjoint; import org.opengis.filter.spatial.Equals; import org.opengis.filter.spatial.Intersects; import org.opengis.filter.spatial.Overlaps; import org.opengis.filter.spatial.Touches; import org.opengis.filter.spatial.Within; import org.opengis.filter.temporal.After; import org.opengis.filter.temporal.AnyInteracts; import org.opengis.filter.temporal.Before; import org.opengis.filter.temporal.Begins; import org.opengis.filter.temporal.BegunBy; import org.opengis.filter.temporal.BinaryTemporalOperator; import org.opengis.filter.temporal.During; import org.opengis.filter.temporal.EndedBy; import org.opengis.filter.temporal.Ends; import org.opengis.filter.temporal.Meets; import org.opengis.filter.temporal.MetBy; import org.opengis.filter.temporal.OverlappedBy; import org.opengis.filter.temporal.TContains; import org.opengis.filter.temporal.TEquals; import org.opengis.filter.temporal.TOverlaps; import org.opengis.parameter.Parameter; import com.vividsolutions.jts.geom.Geometry; /** * Applies duck typing to properties in filters, aggregating the types found in the * {@link TypeAggregator} * * @author Andrea Aime - GeoSolutions */ class FilterTypeVisitor extends DefaultFilterVisitor { TypeAggregator aggregator; public FilterTypeVisitor(TypeAggregator aggregator) { this.aggregator = aggregator; } String getPropertyName(Expression ex) { if (ex instanceof PropertyName) { PropertyName pn = (PropertyName) ex; return pn.getPropertyName(); } return null; } Object getLiteralValue(Expression ex) { if (ex instanceof Literal) { return ex.evaluate(null); } return null; } @Override public Object visit(Add expression, Object data) { visitMathExpression(expression); return super.visit(expression, data); } @Override public Object visit(Multiply expression, Object data) { visitMathExpression(expression); return super.visit(expression, data); } @Override public Object visit(Divide expression, Object data) { visitMathExpression(expression); return super.visit(expression, data); } @Override public Object visit(Subtract expression, Object data) { visitMathExpression(expression); return super.visit(expression, data); } private void visitMathExpression(BinaryExpression expression) { String name = getPropertyName(expression.getExpression1()); if (name != null) { aggregator.addType(name, Double.class); } name = getPropertyName(expression.getExpression2()); if (name != null) { aggregator.addType(name, Double.class); } } @Override public Object visit(Function expression, Object data) { FunctionName name = expression.getFunctionName(); if(name != null && name.getArgumentCount() > 0) { List<Parameter<?>> argumentTypes = name.getArguments(); List<Expression> arguments = expression.getParameters(); for (int i = 0; i < Math.min(arguments.size(), argumentTypes.size()); i++) { Expression ex = arguments.get(i); String propertyName = getPropertyName(ex); Parameter<?> argumentType = argumentTypes.get(i); if (propertyName != null && argumentType != null) { aggregator.addType(propertyName, argumentType.getType()); } } } return super.visit(expression, data); } public Object visit(After after, Object data) { visitTemporalExpression(after); return super.visit(after, data); } public Object visit(AnyInteracts anyInteracts, Object data) { visitTemporalExpression(anyInteracts); return super.visit(anyInteracts, data); } public Object visit(Before before, Object data) { visitTemporalExpression(before); return super.visit(before, data); } public Object visit(Begins begins, Object data) { visitTemporalExpression(begins); return super.visit(begins, data); } public Object visit(BegunBy begunBy, Object data) { visitTemporalExpression(begunBy); return super.visit(begunBy, data); } public Object visit(During during, Object data) { visitTemporalExpression(during); return super.visit(during, data); } public Object visit(EndedBy endedBy, Object data) { visitTemporalExpression(endedBy); return super.visit(endedBy, data); } public Object visit(Ends ends, Object data) { visitTemporalExpression(ends); return super.visit(ends, data); } public Object visit(Meets meets, Object data) { visitTemporalExpression(meets); return super.visit(meets, data); } public Object visit(MetBy metBy, Object data) { visitTemporalExpression(metBy); return super.visit(metBy, data); } public Object visit(OverlappedBy overlappedBy, Object data) { visitTemporalExpression(overlappedBy); return super.visit(overlappedBy, data); } public Object visit(TContains contains, Object data) { visitTemporalExpression(contains); return super.visit(contains, data); } public Object visit(TEquals equals, Object data) { visitTemporalExpression(equals); return super.visit(equals, data); } public Object visit(TOverlaps contains, Object data) { visitTemporalExpression(contains); return super.visit(contains, data); } private void visitTemporalExpression(BinaryTemporalOperator expression) { String name = getPropertyName(expression.getExpression1()); if (name != null) { aggregator.addType(name, Date.class); } name = getPropertyName(expression.getExpression2()); if (name != null) { aggregator.addType(name, Date.class); } } public Object visit(PropertyIsBetween filter, Object data) { String name = getPropertyName(filter.getExpression()); if (name != null) { Object v1 = getLiteralValue(filter.getLowerBoundary()); if (v1 != null) { aggregator.addType(name, v1.getClass()); } Object v2 = getLiteralValue(filter.getUpperBoundary()); if (v2 != null) { aggregator.addType(name, v2.getClass()); } } return super.visit(filter, data); } public Object visit(PropertyIsEqualTo filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } public Object visit(PropertyIsNotEqualTo filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } public Object visit(PropertyIsGreaterThan filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } public Object visit(PropertyIsLessThan filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } public Object visit(PropertyIsLessThanOrEqualTo filter, Object data) { visitBinaryComparison(filter); return super.visit(filter, data); } private void visitBinaryComparison(BinaryComparisonOperator filter) { String name = getPropertyName(filter.getExpression1()); if (name != null) { Object value = getLiteralValue(filter.getExpression2()); if (value != null) { aggregator.addType(name, value.getClass()); } } name = getPropertyName(filter.getExpression2()); if (name != null) { Object value = getLiteralValue(filter.getExpression1()); if (value != null) { aggregator.addType(name, value.getClass()); } } } public Object visit(PropertyIsLike filter, Object data) { String name = getPropertyName(filter.getExpression()); if (name != null) { aggregator.addType(name, String.class); } return null; } public Object visit(Beyond filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Contains filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Crosses filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Disjoint filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(DWithin filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Equals filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Intersects filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Overlaps filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Touches filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } public Object visit(Within filter, Object data) { visitBinarySpatialOperator(filter); return super.visit(filter, data); } private void visitBinarySpatialOperator(BinarySpatialOperator filter) { String name = getPropertyName(filter.getExpression1()); if (name != null) { aggregator.addType(name, Geometry.class); } name = getPropertyName(filter.getExpression2()); if (name != null) { aggregator.addType(name, Geometry.class); } } }