/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.opengis.filter.capability.ArithmeticOperators; import org.opengis.filter.capability.ComparisonOperators; import org.opengis.filter.capability.FilterCapabilities; import org.opengis.filter.capability.Functions; import org.opengis.filter.capability.GeometryOperand; import org.opengis.filter.capability.Operator; import org.opengis.filter.capability.ScalarCapabilities; import org.opengis.filter.capability.SpatialCapabilities; import org.opengis.filter.capability.SpatialOperators; import org.geotools.filter.capability.ArithmeticOperatorsImpl; import org.geotools.filter.capability.ComparisonOperatorsImpl; import org.geotools.filter.capability.FilterCapabilitiesImpl; import org.geotools.filter.capability.FunctionNameImpl; import org.geotools.filter.capability.FunctionsImpl; import org.geotools.filter.capability.OperatorImpl; import org.geotools.filter.capability.ScalarCapabilitiesImpl; import org.geotools.filter.capability.SpatialCapabiltiesImpl; import org.geotools.filter.capability.SpatialOperatorImpl; import org.geotools.filter.capability.SpatialOperatorsImpl; import org.geotools.filter.visitor.IsFullySupportedFilterVisitor; import org.geotools.filter.visitor.IsSupportedFilterVisitor; import org.geotools.filter.visitor.OperatorNameFilterVisitor; import org.opengis.filter.BinaryComparisonOperator; import org.opengis.filter.Filter; import org.opengis.filter.And; import org.opengis.filter.Id; 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.Add; import org.opengis.filter.expression.Divide; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Multiply; import org.opengis.filter.expression.Subtract; import org.opengis.filter.identity.FeatureId; import org.opengis.filter.spatial.BBOX; 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.SpatialOperator; import org.opengis.filter.spatial.Touches; import org.opengis.filter.spatial.Within; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; /** * Allows for easier interaction with FilterCapabilities. *
* This class provides some out of the box FilterCapabilities constants that * you can quickly use to describe the encoding abilities of your service. *
* This class behaves similar to Citations in that the constants are to * be considered immutable, methods have been provided to assist * in composing your own set of FilterCapabilities. *
* Example:
* Capabilities capabilities = new Capabilities();
* capabilities.addAll( Capabilities.LOGICAL );
* capabilities.addAll( Capabilities.SIMPLE_COMPARISONS );
*
* You can use the Capabilities class at runtime to check
* existing filters to see if they are fully supported:
* if( fullySupports( filter )) {
* // do something
* }
*
* Right now the class gives no indication as to what part of the provided
* filter was in error.
*
* @author Jody Garnett
*
* @source $URL$
*/
public class Capabilities {
private static Map
* This is the same as:
* @param type the Class that indicates the new support.
*/
public void addType( Class type ){
String name = toOperationName( type );
if( name == null ) return;
addName( name );
}
/**
* Adds support for the provided name.
*
* If this is a known name (avaialble as part of opengis interface)
* it will be grouped into:
*
* Examples:
* This method will have no effect if the function is already listed.
*
* Example:
* This method will have no effect if the function is already listed.
*
* Example:
* Is most important for logic filters, as they are the only ones with
* subFilters. The geoapi FilterVisitor and ExpressionVisitors
* allow for the handling of null, even so care should be taken to use
* Filter.INCLUDE and Expression.NIL where you can.
*
* @see IsFullySupportedFilterVisitor
* @param filter the filter to be tested.
* @return true if all sub filters are supported, false otherwise.
*/
public boolean fullySupports(Filter filter) {
if (filter == null) {
return false;
}
if( fullySupportedVisitor == null ){
fullySupportedVisitor = new IsFullySupportedFilterVisitor( contents );
}
return (Boolean) filter.accept( fullySupportedVisitor, null );
}
/**
* Determines if the expression and all its sub expressions is supported.
*
* The Expression visitor used for this work can handle null, even so care
* should be taken to useExpression.NIL where you can.
*
* @see IsFullySupportedFilterVisitor
* @param filter the filter to be tested.
* @return true if all sub filters are supported, false otherwise.
*/
public boolean fullySupports(Expression expression) {
if (expression == null) {
return false;
}
if( fullySupportedVisitor == null ){
fullySupportedVisitor = new IsFullySupportedFilterVisitor( contents );
}
return (Boolean) expression.accept( fullySupportedVisitor, null );
}
/**
* Quickly look at the filter and determine the OperationName
* we need to check for in the FilterCapabilities data structure.
*
* @param filter
* @return Operation name
*/
public String toOperationName( Filter filter ){
if( filter == null ) return null;
return (String) filter.accept( operationNameVisitor, null);
}
/**
* Figure out the OperationName for the provided filterType.
*
* The returned name can be used to check the FilterCapabilities
* to see if it type is supported in this execution context.
*
* This approach is not applicable for Functions.
*
* @param filterType Filter type
* @return Operation name for the provided FilterType
*/
public String toOperationName( Class filterType ){
if( filterType == null ) return null;
String quick = filterNames.get( filterType );
if( quick != null ) {
return quick;
}
// The following is O(N) and slightly wrong in that And.class is not an operator
for( Map.EntryaddName( toOperationName( type ) )
*
*
* This method will have no effect if the operator is already known.
*
*
* @param name FilterCapabilities Operand name such as "BBOX", "Like" or "MUL"
*/
public void addName( String name ){
if( name == null ){
return;
}
else if( spatialNames.containsValue( name )){
SpatialOperatorsImpl operators = contents.getSpatialCapabilities().getSpatialOperators();
if( operators.getOperator( name ) == null ){
SpatialOperatorImpl operator = new SpatialOperatorImpl(name);
// default JTS?
operator.getGeometryOperands().add( GeometryOperand.LineString );
operator.getGeometryOperands().add( GeometryOperand.Point );
operator.getGeometryOperands().add( GeometryOperand.Polygon );
operators.getOperators().add( operator );
}
}
else if( scalarNames.containsValue( name )){
ComparisonOperatorsImpl operators = contents.getScalarCapabilities().getComparisonOperators();
if( operators.getOperator( name ) == null ){
OperatorImpl operator = new OperatorImpl( name );
operators.getOperators().add( operator );
}
}
else if( arithmaticNames.containsValue( name )){
ArithmeticOperatorsImpl operators = contents.getScalarCapabilities().getArithmeticOperators();
operators.setSimpleArithmetic(true);
}
else if( logicalNames.containsValue( name )){
contents.getScalarCapabilities().setLogicalOperators(true);
}
else if( "Id".equals(name)){
contents.getIdCapabilities().setFID(true);
}
else {
FunctionsImpl functions = contents.getScalarCapabilities().getArithmeticOperators().getFunctions();
if( functions.getFunctionName( name ) == null ){
FunctionNameImpl function = new FunctionNameImpl( name, 0 );
functions.getFunctionNames().add( function );
}
}
}
/**
* Will add support for a function with the provided number of arguments
*
* capabilities.addName("Beyond"); // will enabled Beyond Filter
* capabilities.addName("NullCheck"); // will enable PropertyIsNull Filter
* capabilities.addName("SUB"); // will enabled hasSimpleArithmetic
* capabilities.addName("PI"); // add a no argument function called PI()
*
capabilities.addName( "Length", 1 )
*
* @param name
* @param argumentCount
*/
public void addName( String name, int argumentCount ){
FunctionsImpl functions = contents.getScalarCapabilities().getArithmeticOperators().getFunctions();
if( functions.getFunctionName( name ) == null ){
FunctionNameImpl function = new FunctionNameImpl( name, argumentCount );
functions.getFunctionNames().add( function );
}
}
/**
* Document support for the provided function.
* capabilities.addName( "Min", "value1", "value2" )
* @param name
* @param argumentCount
*/
public void addName( String name, String... argumentNames ){
FunctionsImpl functions = contents.getScalarCapabilities().getArithmeticOperators().getFunctions();
if( functions.getFunctionName( name ) == null ){
FunctionNameImpl function = new FunctionNameImpl( name, argumentNames );
functions.getFunctionNames().add( function );
}
}
/**
* Determines if specific filter passed in is supported.
*
* @see IsSupportedFilterVisitor
* @param filter The Filter to be tested.
* @return true if supported, false otherwise.
*/
public boolean supports(Filter filter) {
if (filter == null) {
return false;
}
if( supportedVisitor == null ){
supportedVisitor = new IsSupportedFilterVisitor( contents );
}
return (Boolean) filter.accept( supportedVisitor, null );
}
/**
* Determines if the filter and all its sub filters and expressions are supported.
*