/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, 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.filter; import java.awt.Color; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.visitor.DuplicatingFilterVisitor; import org.opengis.filter.And; import org.opengis.filter.ExcludeFilter; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.Id; import org.opengis.filter.IncludeFilter; import org.opengis.filter.Not; import org.opengis.filter.Or; 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.PropertyIsNull; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; import org.opengis.filter.spatial.BBOX; import org.opengis.filter.spatial.Beyond; 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; /** * Utility class for working with Filters & Expression. *
* To get the full benifit you will need to create an instanceof * this Object (supports your own custom FilterFactory!). Additional * methods to help create expressions are available. *
** Example use: *
* Filters filters = new Filters( factory );
* filters.duplicate( origional );
*
* The above example creates a copy of the provided Filter,
* the factory provided will be used when creating the duplicated
* content.
*
* * Expressions form an interesting little semi scripting languge, * intended for queries. A interesting Feature of Filter as a language * is that it is not strongly typed. This utility class many helper * methods that ease the transition from Strongly typed Java to the more * relaxed setting of Expression where most everything can be a string. *
*
* double sum = Filters.number( Object ) + Filters.number( Object );
*
* The above example will support the conversion of many things into a format
* suitable for addition - the complete list is something like:
* * We do our best to be forgiving, any Java class which takes a String as * a constructor can be tried, and toString() assumed to be the inverse. This * lets many things (like URL and Date) function without modification. *
* * @author Jody Garnett, Refractions Research * @since GeoTools 2.2.M3 * @source $URL$ */ public class Filters { /**NOTFOUND
indicates int value was unavailable */
public static final int NOTFOUND = -1;
/**
* Set to true to start throwing exceptions when org.geotools.filter.Filter is used.
*/
private static final boolean STRICT = false;
org.opengis.filter.FilterFactory2 ff;
public Filters(){
this( CommonFactoryFinder.getFilterFactory2(null) );
}
public Filters( org.opengis.filter.FilterFactory2 factory ){
ff = factory;
}
public void setFilterFactory( org.opengis.filter.FilterFactory2 factory ){
ff = factory;
}
/**
* Safe version of FilterFactory *and* that is willing to combine
* filter1 and filter2 correctly in the even either of them is already
* an And filter.
*
* @param ff
* @param filter1
* @param filter2
* @return And
*/
public static Filter and( org.opengis.filter.FilterFactory ff, Filter filter1, Filter filter2 ){
ArrayList* This method handles the case of: *
* Filter objects are mutable, when copying a rich * data structure (like SLD) you will need to duplicate * the Filters referenced therein. *
*/ public Filter duplicate( Filter filter ){ DuplicatingFilterVisitor xerox = new DuplicatingFilterVisitor( ff ); Filter copy = (Filter) filter.accept( xerox, ff ); return copy; } /** * Utility method used to transition to geoapi filter. ** This utility method is designed to help people port their * code quickly, an instanceof check is much preferred. *
* Example:
* BEFORE: filter.getFilterType() == FilterType.GEOMETRY_CONTAINS
* QUICK: Filters.getFilterType( filter ) == FilterType.GEOMETRY_CONTAINS
* AFTER: filter instanceof Contains
*
* @param filter
* @deprecated please use instanceof checks
*/
public static short getFilterType( org.opengis.filter.Filter filter ){
if( filter == org.opengis.filter.Filter.EXCLUDE ) return FilterType.ALL;
if( filter == org.opengis.filter.Filter.INCLUDE ) return FilterType.NONE;
if( filter instanceof org.geotools.filter.Filter){
return ((org.geotools.filter.Filter)filter).getFilterType();
}
if( filter instanceof PropertyIsBetween ) return FilterType.BETWEEN;
if( filter instanceof PropertyIsEqualTo ) return FilterType.COMPARE_EQUALS;
if( filter instanceof PropertyIsGreaterThan ) return FilterType.COMPARE_GREATER_THAN;
if( filter instanceof PropertyIsGreaterThanOrEqualTo ) return FilterType.COMPARE_GREATER_THAN_EQUAL;
if( filter instanceof PropertyIsLessThan) return FilterType.COMPARE_LESS_THAN;
if( filter instanceof PropertyIsLessThanOrEqualTo ) return FilterType.COMPARE_LESS_THAN_EQUAL;
if( filter instanceof PropertyIsNotEqualTo ) return FilterType.COMPARE_NOT_EQUALS;
if( filter instanceof Id ) return FilterType.FID;
if( filter instanceof BBOX ) return FilterType.GEOMETRY_BBOX;
if( filter instanceof Beyond) return FilterType.GEOMETRY_BEYOND;
if( filter instanceof Contains ) return FilterType.GEOMETRY_CONTAINS;
if( filter instanceof Crosses ) return FilterType.GEOMETRY_CROSSES;
if( filter instanceof Disjoint ) return FilterType.GEOMETRY_DISJOINT;
if( filter instanceof DWithin) return FilterType.GEOMETRY_DWITHIN;
if( filter instanceof Equals) return FilterType.GEOMETRY_EQUALS;
if( filter instanceof Intersects) return FilterType.GEOMETRY_INTERSECTS;
if( filter instanceof Overlaps) return FilterType.GEOMETRY_OVERLAPS;
if( filter instanceof Touches) return FilterType.GEOMETRY_TOUCHES;
if( filter instanceof Within) return FilterType.GEOMETRY_WITHIN;
if( filter instanceof PropertyIsLike) return FilterType.LIKE;
if( filter instanceof And) return FilterType.LOGIC_AND;
if( filter instanceof Not) return FilterType.LOGIC_NOT;
if( filter instanceof Or ) return FilterType.LOGIC_OR;
if( filter instanceof PropertyIsNull) return FilterType.NULL;
if( filter instanceof Filter){
return 0;
}
return 0;
}
/**
* Obtain the provided Expression as an integer.
* * This method is quickly used to safely check Literal expressions. * * @param expr * @return int value of first Number, or NOTFOUND */ public static int asInt( Expression expr ) { if( expr == null ) return NOTFOUND; try { Integer number = expr.evaluate( null, Integer.class ); if( number == null ){ return NOTFOUND; } return number; } catch( NullPointerException npe ){ return NOTFOUND; // well that was not unexpected } /* Number number = (Number) asType(expr, Number.class); if (number != null) { return number.intValue(); } //look for a string String string = (String) asType(expr,String.class); if (string != null) { //try parsing into a integer try { return Integer.parseInt(string); } catch(NumberFormatException e) {} } //no dice return NOTFOUND; */ } /** * Obtain the provided Expression as a String. *
* This method only reliably works when the Expression is a Literal. * * @param expr * * @return Expression as a String, or null */ public static String asString(Expression expr) { if( expr == null ) return null; try { return expr.evaluate( null, String.class ); } catch( NullPointerException npe){ // must be a more complicated expression than a literal return null; } } /** * Obtain the provided Expression as a double. * @param expr * @return int value of first Number, or Double.NaN */ public static double asDouble(Expression expr) { if( expr == null ) { return Double.NaN; } try { Double number = expr.evaluate(null, Double.class ); if( number == null ) { return Double.NaN; } return number.doubleValue(); } catch( NullPointerException npe){ // must be a more complicated expression than a literal return Double.NaN; } } /** * Navigate through the expression searching for something that can be a TYPE. *
* This will work even with dynamic expression that would normally require a * feature. It works especially well when the Expression is a Literal * literal (which is usually the case). *
* ** If you have a specific Feature, please do this: *
* Object value = expr.getValue( feature );
* return value instanceof Color ? (Color) value : null;
*
*
*
* @param expr This only really works for down casting literals to a value
* @param Target type
*
* @return expr smunched into indicated type
* @deprecated This is not a good idea; use expr.evaulate( null, TYPE )
*/
public static * This function allows for the non stongly typed Math Opperations * favoured by the Expression standard. *
** Able to hanle: *
* Used to tread softly on the Java typing system, because * Filter/Expression is not strongly typed. Values in in * Expression land are often not the the real Java Objects * we wish they were - it is reall a small, lax, query * language and Java objects need a but of help getting * through. *
*
* A couple notes: *