/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * (C) 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; * 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.geotoolkit.filter.visitor; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.Hints; import org.geotoolkit.filter.DefaultLiteral; import org.geotoolkit.filter.binaryspatial.UnreprojectedLooseBBox; import org.geotoolkit.filter.binaryspatial.LooseBBox; import org.opengis.filter.And; import org.opengis.filter.ExcludeFilter; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.FilterVisitor; import org.opengis.filter.Id; import org.opengis.filter.IncludeFilter; import org.opengis.filter.MatchAction; 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.PropertyIsNil; 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.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; 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; 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.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.geometry.BoundingBox; /** * Used to duplication Filters and/or Expressions - returned object is a copy. * <p> * Extra data can be used to provide a {@link FilterFactory2} but this is NOT required. * This class is thread safe. * </ul> * @author Jesse * * @module */ public class DuplicatingFilterVisitor implements FilterVisitor, ExpressionVisitor { protected final FilterFactory2 ff; public DuplicatingFilterVisitor() { this((FilterFactory2) FactoryFinder.getFilterFactory(new Hints(Hints.FILTER_FACTORY, FilterFactory2.class))); } public DuplicatingFilterVisitor(final FilterFactory2 factory) { this.ff = factory; } protected FilterFactory2 getFactory(final Object extraData) { if (extraData instanceof FilterFactory2) { return (FilterFactory2) extraData; } return ff; } @Override public Object visit(final ExcludeFilter filter, final Object extraData) { return filter; } @Override public Object visit(final IncludeFilter filter, final Object extraData) { return filter; } /** * Null safe expression cloning * @param expression * @param extraData * @return */ public Expression visit(final Expression expression, final Object extraData) { if (expression == null) { return null; } return (Expression) expression.accept(this, extraData); } @Override public Object visit(final And filter, final Object extraData) { final List<Filter> children = filter.getChildren(); final List<Filter> newChildren = new ArrayList<Filter>(); for (final Filter child : children) { if (child != null) { newChildren.add((Filter)child.accept(this, extraData)); } } return getFactory(extraData).and(newChildren); } @Override public Object visit(final Id filter, final Object extraData) { return getFactory(extraData).id(filter.getIdentifiers()); } @Override public Object visit(final Not filter, final Object extraData) { return getFactory(extraData).not((Filter) filter.getFilter().accept(this, extraData)); } @Override public Object visit(final Or filter, final Object extraData) { final List<Filter> children = filter.getChildren(); final List<Filter> newChildren = new ArrayList<Filter>(); for (Filter child : children) { if (child != null) { newChildren.add((Filter)child.accept(this, extraData)); } } return getFactory(extraData).or(newChildren); } @Override public Object visit(final PropertyIsBetween filter, final Object extraData) { final Expression expr = visit(filter.getExpression(), extraData); final Expression lower = visit(filter.getLowerBoundary(), extraData); final Expression upper = visit(filter.getUpperBoundary(), extraData); return getFactory(extraData).between(expr, lower, upper); } @Override public Object visit(final PropertyIsEqualTo filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).equal(expr1, expr2, matchCase,matchAction); } @Override public Object visit(final PropertyIsNotEqualTo filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); final boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).notEqual(expr1, expr2, matchCase,matchAction); } @Override public Object visit(final PropertyIsGreaterThan filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); final boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).greater(expr1, expr2,matchCase,matchAction); } @Override public Object visit(final PropertyIsGreaterThanOrEqualTo filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); final boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).greaterOrEqual(expr1, expr2,matchCase,matchAction); } @Override public Object visit(final PropertyIsLessThan filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); final boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).less(expr1, expr2,matchCase,matchAction); } @Override public Object visit(final PropertyIsLessThanOrEqualTo filter, final Object extraData) { final Expression expr1 = visit(filter.getExpression1(), extraData); final Expression expr2 = visit(filter.getExpression2(), extraData); final boolean matchCase = filter.isMatchingCase(); final MatchAction matchAction = filter.getMatchAction(); return getFactory(extraData).lessOrEqual(expr1, expr2,matchCase,matchAction); } @Override public Object visit(final PropertyIsLike filter, final Object extraData) { final Expression expr = visit(filter.getExpression(), extraData); final String pattern = filter.getLiteral(); final String wildcard = filter.getWildCard(); final String singleChar = filter.getSingleChar(); final String escape = filter.getEscape(); final boolean matchCase = filter.isMatchingCase(); return getFactory(extraData).like(expr, pattern, wildcard, singleChar, escape, matchCase); } @Override public Object visit(final PropertyIsNull filter, final Object extraData) { final Expression expr = visit(filter.getExpression(), extraData); return getFactory(extraData).isNull(expr); } @Override public Object visit(final PropertyIsNil filter, Object extraData) { final Expression expr = visit(filter.getExpression(), extraData); return getFactory(extraData).isNil(expr); } @Override public Object visit(final BBOX filter, final Object extraData) { final Expression exp1 = visit(filter.getExpression1(),extraData); final Expression exp2 = filter.getExpression2(); if(!(exp2 instanceof Literal)){ //this value is supposed to hold a BoundingBox throw new IllegalArgumentException("Illegal BBOX filter, " + "second expression should have been a literal with a boundingBox value: \n" + filter); }else{ Literal l = (Literal)visit(exp2,extraData); final Object obj = l.getValue(); if(obj instanceof BoundingBox){ if (filter instanceof UnreprojectedLooseBBox) { return new UnreprojectedLooseBBox((PropertyName)exp1, new DefaultLiteral<BoundingBox>((BoundingBox) obj)); } else if (filter instanceof LooseBBox) { return new LooseBBox((PropertyName)exp1, new DefaultLiteral<BoundingBox>((BoundingBox) obj)); } else { return getFactory(extraData).bbox(exp1, (BoundingBox) obj); } }else{ throw new IllegalArgumentException("Illegal BBOX filter, " + "second expression should have been a literal with a boundingBox value but value was a : \n" + obj.getClass()); } } } @Override public Object visit(final Beyond filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); final double distance = filter.getDistance(); final String units = filter.getDistanceUnits(); return getFactory(extraData).beyond(geometry1, geometry2, distance, units); } @Override public Object visit(final Contains filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).contains(geometry1, geometry2); } @Override public Object visit(final Crosses filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).crosses(geometry1, geometry2); } @Override public Object visit(final Disjoint filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).disjoint(geometry1, geometry2); } @Override public Object visit(final DWithin filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); final double distance = filter.getDistance(); final String units = filter.getDistanceUnits(); return getFactory(extraData).dwithin(geometry1, geometry2, distance, units); } @Override public Object visit(final Equals filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).equal(geometry1, geometry2); } @Override public Object visit(final Intersects filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).intersects(geometry1, geometry2); } @Override public Object visit(final Overlaps filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).overlaps(geometry1, geometry2); } @Override public Object visit(final Touches filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).touches(geometry1, geometry2); } @Override public Object visit(final Within filter, final Object extraData) { final Expression geometry1 = visit(filter.getExpression1(), extraData); final Expression geometry2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).within(geometry1, geometry2); } @Override public Object visit(After filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).after(exp1, exp2); } @Override public Object visit(AnyInteracts filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).anyInteracts(exp1, exp2); } @Override public Object visit(Before filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).before(exp1, exp2); } @Override public Object visit(Begins filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).begins(exp1, exp2); } @Override public Object visit(BegunBy filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).begunBy(exp1, exp2); } @Override public Object visit(During filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).during(exp1, exp2); } @Override public Object visit(EndedBy filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).endedBy(exp1, exp2); } @Override public Object visit(Ends filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).ends(exp1, exp2); } @Override public Object visit(Meets filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).meets(exp1, exp2); } @Override public Object visit(MetBy filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).metBy(exp1, exp2); } @Override public Object visit(OverlappedBy filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).overlappedBy(exp1, exp2); } @Override public Object visit(TContains filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).tcontains(exp1, exp2); } @Override public Object visit(TEquals filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).tequals(exp1, exp2); } @Override public Object visit(TOverlaps filter, Object extraData) { final Expression exp1 = visit(filter.getExpression1(), extraData); final Expression exp2 = visit(filter.getExpression2(), extraData); return getFactory(extraData).toverlaps(exp1, exp2); } @Override public Object visitNullFilter(final Object extraData) { return null; } @Override public Object visit(final NilExpression expression, final Object extraData) { return expression; } @Override public Object visit(final Add expression, final Object extraData) { final Expression expr1 = visit(expression.getExpression1(), extraData); final Expression expr2 = visit(expression.getExpression2(), extraData); return getFactory(extraData).add(expr1, expr2); } @Override public Object visit(final Divide expression, final Object extraData) { final Expression expr1 = visit(expression.getExpression1(), extraData); final Expression expr2 = visit(expression.getExpression2(), extraData); return getFactory(extraData).divide(expr1, expr2); } @Override public Object visit(final Function expression, final Object extraData) { //TODO bug on duplicate interpolate and catorize. //expecting the function to be immutable for now. return expression; // final List<Expression> old = expression.getParameters(); // final Expression[] args = new Expression[old.size()]; // int i = 0; // for (Iterator<Expression> iter = old.iterator(); iter.hasNext(); i++) { // Expression exp = iter.next(); // args[i] = visit(exp, extraData); // } // return getFactory(extraData).function(expression.getName(), args); } @Override public Object visit(final Literal expression, final Object extraData) { return getFactory(extraData).literal(expression.getValue()); } @Override public Object visit(final Multiply expression, final Object extraData) { final Expression expr1 = visit(expression.getExpression1(), extraData); final Expression expr2 = visit(expression.getExpression2(), extraData); return getFactory(extraData).multiply(expr1, expr2); } @Override public Object visit(final PropertyName expression, final Object extraData) { return getFactory(extraData).property(expression.getPropertyName()); } @Override public Object visit(final Subtract expression, final Object extraData) { final Expression expr1 = visit(expression.getExpression1(), extraData); final Expression expr2 = visit(expression.getExpression2(), extraData); return getFactory(extraData).subtract(expr1, expr2); } }