/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2011, 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.data.complex.filter;
import java.util.List;
import org.geotools.data.complex.FeatureTypeMapping;
import org.geotools.data.complex.filter.XPath.StepList;
import org.geotools.filter.FilterCapabilities;
import org.geotools.filter.visitor.PostPreProcessFilterSplittingVisitor;
import org.opengis.filter.Id;
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.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.Multiply;
import org.opengis.filter.expression.NilExpression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.expression.Subtract;
/**
* @author Niels Charlier (Curtin University of Technology)
*/
public class ComplexFilterSplitter extends PostPreProcessFilterSplittingVisitor {
public class CapabilitiesExpressionVisitor implements ExpressionVisitor {
protected boolean capable = true;
public boolean isCapable(){
return capable;
}
public Object visit(NilExpression expr, Object extraData) {
return null;
}
public Object visit(Add expr, Object extraData) {
visitMathExpression(expr);
return null;
}
public Object visit(Subtract expr, Object extraData) {
visitMathExpression(expr);
return null;
}
public Object visit(Divide expr, Object extraData) {
visitMathExpression(expr);
return null;
}
public Object visit(Multiply expr, Object extraData) {
visitMathExpression(expr);
return null;
}
public Object visit(Function expr, Object extraData) {
for (int i = 0; i < expr.getParameters().size(); i++) {
((Expression)expr.getParameters().get(i)).accept(this, null);
}
capable = capable && fcs.supports(expr.getClass());
return null;
}
public Object visit(Literal expr, Object extraData) {
return null;
}
public Object visit(PropertyName expr, Object extraData) {
return null;
}
private void visitMathExpression(BinaryExpression expression) {
expression.getExpression1().accept(this, null);
expression.getExpression2().accept(this, null);
capable = capable && fcs.supports(expression.getClass());
}
}
private FeatureTypeMapping mappings;
public ComplexFilterSplitter(FilterCapabilities fcs, FeatureTypeMapping mappings) {
super(fcs, null, null);
this.mappings = mappings;
}
public Object visit(Id filter, Object notUsed) {
CapabilitiesExpressionVisitor visitor = new CapabilitiesExpressionVisitor();
mappings.getFeatureIdExpression().accept(visitor, null);
if (visitor.isCapable()) {
super.visit(filter, notUsed);
} else {
postStack.push(filter);
}
return null;
}
public Object visit(PropertyName expression, Object notUsed) {
// break into single steps
StepList exprSteps = XPath.steps(mappings.getTargetFeature(), expression.getPropertyName(), this.mappings.getNamespaces());
if (exprSteps.containsPredicate()) {
postStack.push(expression);
return null;
}
List<Expression> matchingMappings = mappings.findMappingsFor(exprSteps);
if (matchingMappings.isEmpty()) {
postStack.push(expression);
return null;
} else {
for (Expression expr : matchingMappings) {
CapabilitiesExpressionVisitor visitor = new CapabilitiesExpressionVisitor();
expr.accept(visitor, null);
if (!visitor.isCapable()) {
postStack.push(expression);
return null;
}
}
}
return super.visit(expression, notUsed);
}
}