/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008 - 2009, 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.ogc.xml;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBElement;
import org.geotoolkit.ogc.xml.v100.BinaryOperatorType;
import org.geotoolkit.ogc.xml.v100.FunctionType;
import org.geotoolkit.ogc.xml.v100.LiteralType;
import org.geotoolkit.ogc.xml.v100.PropertyNameType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.MatchAction;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.identity.Identifier;
/**
* Transform OGC v1.0 jaxb xml in GT classes.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class OGC100toGTTransformer {
protected final FilterFactory2 filterFactory;
public OGC100toGTTransformer(final FilterFactory2 factory){
this.filterFactory = factory;
}
/**
* Transform a SLD filter v1.0 in GT filter.
*/
public Filter visitFilter(final org.geotoolkit.ogc.xml.v100.FilterType ft){
if(ft == null) {return null;}
if(ft.getComparisonOps() != null){
final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.ComparisonOpsType> jax = ft.getComparisonOps();
return visitComparisonOp(jax);
}else if(ft.getLogicOps() != null){
final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.LogicOpsType> jax = ft.getLogicOps();
return visitLogicOp(jax);
}else if(ft.getSpatialOps() != null){
final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.SpatialOpsType> jax = ft.getSpatialOps();
return visitSpatialOp(jax);
}else if(ft.getFeatureId() != null && !ft.getFeatureId().isEmpty()){
return visitIds(ft.getFeatureId());
}else{
//this case should not happen but if so, we consider it's an ALL features filter
return Filter.INCLUDE;
}
}
/**
* Transform a SLD spatial Filter v1.0 in GT filter.
*/
public Filter visitSpatialOp(final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.SpatialOpsType> jax) {
final org.geotoolkit.ogc.xml.v100.SpatialOpsType ops = jax.getValue();
final String OpName = jax.getName().getLocalPart();
if (ops instanceof org.geotoolkit.ogc.xml.v100.BinarySpatialOpType) {
final org.geotoolkit.ogc.xml.v100.BinarySpatialOpType binary = (org.geotoolkit.ogc.xml.v100.BinarySpatialOpType) ops;
final JAXBElement<? extends org.geotoolkit.gml.xml.v212.AbstractGeometryType> geom = binary.getGeometry();
final org.geotoolkit.ogc.xml.v100.PropertyNameType pnt = binary.getPropertyName();
final Expression left = filterFactory.property(pnt.getContent());
final Expression right = visit(geom);
if (OGCJAXBStatics.FILTER_SPATIAL_CONTAINS.equalsIgnoreCase(OpName)) {
return filterFactory.contains(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_CROSSES.equalsIgnoreCase(OpName)) {
return filterFactory.crosses(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_DISJOINT.equalsIgnoreCase(OpName)) {
return filterFactory.disjoint(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_EQUALS.equalsIgnoreCase(OpName)) {
return filterFactory.equal(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_INTERSECTS.equalsIgnoreCase(OpName)) {
return filterFactory.intersects(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_OVERLAPS.equalsIgnoreCase(OpName)) {
return filterFactory.overlaps(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_TOUCHES.equalsIgnoreCase(OpName)) {
return filterFactory.touches(left,right);
} else if (OGCJAXBStatics.FILTER_SPATIAL_WITHIN.equalsIgnoreCase(OpName)) {
return filterFactory.within(left,right);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.DistanceBufferType) {
final org.geotoolkit.ogc.xml.v100.DistanceBufferType dstOp = (org.geotoolkit.ogc.xml.v100.DistanceBufferType) ops;
final org.geotoolkit.ogc.xml.v100.DistanceType dt = dstOp.getDistance();
final JAXBElement<? extends org.geotoolkit.gml.xml.v212.AbstractGeometryType> geom = dstOp.getGeometry();
final org.geotoolkit.ogc.xml.v100.PropertyNameType pnt = dstOp.getPropertyName();
final Expression geom1 = filterFactory.property(pnt.getContent());
final Expression geom2 = visit(geom);
final double distance = Double.valueOf(dt.getContent());
final String units = dt.getUnits();
if (OGCJAXBStatics.FILTER_SPATIAL_DWITHIN.equalsIgnoreCase(OpName)) {
return filterFactory.dwithin(geom1, geom2, distance, units);
} else if (OGCJAXBStatics.FILTER_SPATIAL_BEYOND.equalsIgnoreCase(OpName)) {
return filterFactory.beyond(geom1, geom2, distance, units);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.BBOXType) {
final org.geotoolkit.ogc.xml.v100.BBOXType binary = (org.geotoolkit.ogc.xml.v100.BBOXType) ops;
final org.geotoolkit.gml.xml.v212.BoxType box = binary.getBox();
final org.geotoolkit.ogc.xml.v100.PropertyNameType pnt = binary.getPropertyName();
final Expression geom = filterFactory.property(pnt.getContent());
final double minx = box.getCoord().get(0).getX().doubleValue();
final double maxx = box.getCoord().get(1).getX().doubleValue();
final double miny = box.getCoord().get(0).getY().doubleValue();
final double maxy = box.getCoord().get(1).getY().doubleValue();
final String srs = box.getSrsName();
if (OGCJAXBStatics.FILTER_SPATIAL_BBOX.equalsIgnoreCase(OpName)) {
return filterFactory.bbox(geom, minx, miny, maxx, maxy, srs);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
}
throw new IllegalArgumentException("Unknowed filter element" + jax);
}
/**
* Transform a SLD logic Filter v1.0 in GT filter.
*/
public Filter visitLogicOp(final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.LogicOpsType> jax) {
final org.geotoolkit.ogc.xml.v100.LogicOpsType ops = jax.getValue();
final String OpName = jax.getName().getLocalPart();
if (ops instanceof org.geotoolkit.ogc.xml.v100.UnaryLogicOpType) {
final org.geotoolkit.ogc.xml.v100.UnaryLogicOpType unary = (org.geotoolkit.ogc.xml.v100.UnaryLogicOpType) ops;
if (OGCJAXBStatics.FILTER_LOGIC_NOT.equalsIgnoreCase(OpName)) {
Filter filter = null;
if(unary.getComparisonOps() != null) {filter = visitComparisonOp(unary.getComparisonOps());}
else if(unary.getLogicOps() != null) {filter = visitLogicOp(unary.getLogicOps());}
else if(unary.getSpatialOps() != null) {filter = visitSpatialOp(unary.getSpatialOps());}
if(filter == null){
throw new IllegalArgumentException("Invalide filter element" + unary);
}
return filterFactory.not(filter);
}
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.BinaryLogicOpType) {
final org.geotoolkit.ogc.xml.v100.BinaryLogicOpType binary = (org.geotoolkit.ogc.xml.v100.BinaryLogicOpType) ops;
if (OGCJAXBStatics.FILTER_LOGIC_AND.equalsIgnoreCase(OpName)) {
final List<Filter> filters = new ArrayList<Filter>();
for(final JAXBElement<?> ele : binary.getComparisonOpsOrSpatialOpsOrLogicOps()){
final Object obj = ele.getValue();
if(obj instanceof org.geotoolkit.ogc.xml.v100.ComparisonOpsType){
filters.add(visitComparisonOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.ComparisonOpsType>) ele ));
}else if(obj instanceof org.geotoolkit.ogc.xml.v100.SpatialOpsType){
filters.add(visitSpatialOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.SpatialOpsType>) ele ));
}else if(obj instanceof org.geotoolkit.ogc.xml.v100.LogicOpsType){
filters.add(visitLogicOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.LogicOpsType>) ele ));
}
}
return filterFactory.and(filters);
} else if (OGCJAXBStatics.FILTER_LOGIC_OR.equalsIgnoreCase(OpName)) {
final List<Filter> filters = new ArrayList<Filter>();
for(final JAXBElement<?> ele : binary.getComparisonOpsOrSpatialOpsOrLogicOps()){
final Object obj = ele.getValue();
if(obj instanceof org.geotoolkit.ogc.xml.v100.ComparisonOpsType){
filters.add(visitComparisonOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.ComparisonOpsType>) ele ));
}else if(obj instanceof org.geotoolkit.ogc.xml.v100.SpatialOpsType){
filters.add(visitSpatialOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.SpatialOpsType>) ele ));
}else if(obj instanceof org.geotoolkit.ogc.xml.v100.LogicOpsType){
filters.add(visitLogicOp( (JAXBElement<? extends org.geotoolkit.ogc.xml.v100.LogicOpsType>) ele ));
}
}
return filterFactory.or(filters);
}
}
throw new IllegalArgumentException("Unknowed filter element" + jax);
}
/**
* Transform a SLD comparison Filter v1.0 in GT filter.
*/
public Filter visitComparisonOp(final JAXBElement<? extends org.geotoolkit.ogc.xml.v100.ComparisonOpsType> jax){
final org.geotoolkit.ogc.xml.v100.ComparisonOpsType ops = jax.getValue();
final String OpName = jax.getName().getLocalPart();
if (ops instanceof org.geotoolkit.ogc.xml.v100.BinaryComparisonOpType) {
final org.geotoolkit.ogc.xml.v100.BinaryComparisonOpType binary = (org.geotoolkit.ogc.xml.v100.BinaryComparisonOpType) ops;
final Expression left = visitExpression(binary.getExpression().get(0));
final Expression right = visitExpression(binary.getExpression().get(1));
if (OGCJAXBStatics.FILTER_COMPARISON_ISEQUAL.equalsIgnoreCase(OpName)) {
return filterFactory.equals(left,right);
} else if (OGCJAXBStatics.FILTER_COMPARISON_ISNOTEQUAL.equalsIgnoreCase(OpName)) {
return filterFactory.notEqual(left, right, false, MatchAction.ANY);
} else if (OGCJAXBStatics.FILTER_COMPARISON_ISLESS.equalsIgnoreCase(OpName)) {
return filterFactory.less(left, right);
} else if (OGCJAXBStatics.FILTER_COMPARISON_ISGREATER.equalsIgnoreCase(OpName)) {
return filterFactory.greater(left, right);
} else if (OGCJAXBStatics.FILTER_COMPARISON_ISLESSOREQUAL.equalsIgnoreCase(OpName)) {
return filterFactory.lessOrEqual(left, right);
} else if (OGCJAXBStatics.FILTER_COMPARISON_ISGREATEROREQUAL.equalsIgnoreCase(OpName)) {
return filterFactory.greaterOrEqual(left, right);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.PropertyIsLikeType) {
final org.geotoolkit.ogc.xml.v100.PropertyIsLikeType property = (org.geotoolkit.ogc.xml.v100.PropertyIsLikeType) ops;
final Expression expr = filterFactory.property(property.getPropertyName().getContent());
final String pattern = visitExpression(property.getLiteral()).toString();
final String wild = property.getWildCard();
final String single = property.getSingleChar();
final String escape = property.getEscape();
if (OGCJAXBStatics.FILTER_COMPARISON_ISLIKE.equalsIgnoreCase(OpName)) {
return filterFactory.like(expr, pattern, wild, single, escape);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.PropertyIsBetweenType) {
final org.geotoolkit.ogc.xml.v100.PropertyIsBetweenType property = (org.geotoolkit.ogc.xml.v100.PropertyIsBetweenType) ops;
final Expression lower = visitExpression( property.getLowerBoundary().getExpression() );
final Expression upper = visitExpression( property.getUpperBoundary().getExpression() );
final Expression expr = visitExpression( property.getExpression() );
if (OGCJAXBStatics.FILTER_COMPARISON_ISBETWEEN.equalsIgnoreCase(OpName)) {
return filterFactory.between(expr, lower, upper);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
} else if (ops instanceof org.geotoolkit.ogc.xml.v100.PropertyIsNullType) {
final org.geotoolkit.ogc.xml.v100.PropertyIsNullType property = (org.geotoolkit.ogc.xml.v100.PropertyIsNullType) ops;
Expression expr = null;
if(property.getPropertyName() != null){
expr = filterFactory.property(property.getPropertyName().getContent());
}else if(property.getLiteral() != null){
expr = visitExpression(property.getLiteral());
}
if (OGCJAXBStatics.FILTER_COMPARISON_ISNULL.equalsIgnoreCase(OpName)) {
return filterFactory.isNull(expr);
}
throw new IllegalArgumentException("Illegal filter element" + OpName + " : " + ops);
}
throw new IllegalArgumentException("Unknowed filter element" + jax);
}
/**
* Transform a SLD IDS Filter v1.0 in GT filter.
*/
public Filter visitIds(final List<org.geotoolkit.ogc.xml.v100.FeatureIdType> lst){
final Set<Identifier> ids = new HashSet<Identifier>();
for(final org.geotoolkit.ogc.xml.v100.FeatureIdType id : lst){
ids.add( filterFactory.gmlObjectId(id.getFid()) );
}
return filterFactory.id(ids);
}
public Expression visit(final JAXBElement<? extends org.geotoolkit.gml.xml.v212.AbstractGeometryType> ele){
throw new UnsupportedOperationException("not supported yet, need GML");
}
public PropertyName visitPropertyName(final PropertyNameType pnt){
return filterFactory.property(pnt.getContent());
}
/**
* Transform a JaxBelement in Expression.
*/
public Expression visitExpression(final JAXBElement<?> jax){
// JAXBElementFunctionType> ---NS
// JAXBElementExpressionType> ---k
// JAXBElementLiteralType> ---k
// JAXBElementBinaryOperatorType> ---k
// JAXBElementBinaryOperatorType> ---k
// JAXBElementBinaryOperatorType> ---k
// JAXBElementPropertyNameType> ---k
// JAXBElementBinaryOperatorType> ---k
final String expName = jax.getName().getLocalPart();
final Object obj = jax.getValue();
if(obj instanceof LiteralType){
return visitExpression( (LiteralType)obj );
}else if(obj instanceof BinaryOperatorType){
final BinaryOperatorType bot = (BinaryOperatorType) obj;
final Expression left = visitExpression(bot.getExpression().get(0));
final Expression right = visitExpression(bot.getExpression().get(1));
if(OGCJAXBStatics.EXPRESSION_ADD.equalsIgnoreCase(expName)){
return filterFactory.add(left, right);
}else if(OGCJAXBStatics.EXPRESSION_DIV.equalsIgnoreCase(expName)){
return filterFactory.divide(left, right);
}else if(OGCJAXBStatics.EXPRESSION_MUL.equalsIgnoreCase(expName)){
return filterFactory.multiply(left, right);
}else if(OGCJAXBStatics.EXPRESSION_SUB.equalsIgnoreCase(expName)){
return filterFactory.subtract(left, right);
}
throw new IllegalArgumentException("Unknowed expression element : Name > " + expName +" JAXB > " + jax + " OBJECT >" + obj);
}else if(obj instanceof PropertyNameType){
return visitPropertyName((PropertyNameType) obj);
}else if(obj instanceof FunctionType){
final FunctionType ft = (FunctionType) obj;
final Expression[] exps = new Expression[ft.getExpression().size()];
int i=0;
for(final JAXBElement<?> ele : ft.getExpression()){
exps[i] = visitExpression(ele);
i++;
}
return filterFactory.function(ft.getName(), exps);
}
throw new IllegalArgumentException("Unknowed expression element : Name > " + expName +" JAXB > " + jax + " OBJECT >" + obj);
}
/**
* Transform a literalType in Expression.
*/
public Expression visitExpression(final LiteralType type){
final List<Object> content = type.getContent();
for(Object obj : content){
if(obj != null && !obj.toString().trim().isEmpty()){
//try to convert it to a number
try{
obj = Double.valueOf(obj.toString().trim());
}catch(NumberFormatException ex){
}
return filterFactory.literal(obj);
}
}
return filterFactory.literal("");
}
}