/* * 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.visitor; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import junit.framework.TestCase; import org.geotools.data.DataUtilities; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.function.EnvFunction; import org.geotools.filter.function.math.FilterFunction_random; import org.geotools.filter.visitor.SimplifyingFilterVisitor.FIDValidator; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.And; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.Id; import org.opengis.filter.Or; import org.opengis.filter.PropertyIsEqualTo; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.identity.Identifier; /** * * * @source $URL$ */ public class SimplifyingFilterVisitorTest extends TestCase { FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); Id emptyFid; SimplifyingFilterVisitor simpleVisitor; SimplifyingFilterVisitor complexVisitor; PropertyIsEqualTo property; @Override protected void setUp() throws Exception { emptyFid = ff.id(new HashSet<Identifier>()); property = ff.equal(ff.property("test"), ff.literal("oneTwoThree"), false); // visitor assuming simple features simpleVisitor = new SimplifyingFilterVisitor() { protected boolean isSimpleFeature() { return true; }; }; simpleVisitor.setRangeSimplicationEnabled(true); // one that does not know, and thus assumes complex ones complexVisitor = new SimplifyingFilterVisitor(); } @Override protected void tearDown() throws Exception { EnvFunction.clearLocalValues(); } public void testIncludeAndInclude() { Filter result = (Filter) ff.and(Filter.INCLUDE, Filter.INCLUDE).accept(simpleVisitor, null); assertEquals(Filter.INCLUDE, result); } public void testIncludeAndExclude() { Filter result = (Filter) ff.and(Filter.INCLUDE, Filter.EXCLUDE).accept(simpleVisitor, null); assertEquals(Filter.EXCLUDE, result); } public void testExcludeAndExclude() { Filter result = (Filter) ff.and(Filter.EXCLUDE, Filter.EXCLUDE).accept(simpleVisitor, null); assertEquals(Filter.EXCLUDE, result); } public void testIncludeAndProperty() { Filter result = (Filter) ff.and(Filter.INCLUDE, property).accept(simpleVisitor, null); assertEquals(property, result); } public void testExcludeAndProperty() { Filter result = (Filter) ff.or(Filter.EXCLUDE, property).accept(simpleVisitor, null); assertEquals(property, result); } public void testIncludeOrInclude() { Filter result = (Filter) ff.or(Filter.INCLUDE, Filter.INCLUDE).accept(simpleVisitor, null); assertEquals(Filter.INCLUDE, result); } public void testIncludeOrExclude() { Filter result = (Filter) ff.or(Filter.INCLUDE, Filter.EXCLUDE).accept(simpleVisitor, null); assertEquals(Filter.INCLUDE, result); } public void testExcludeOrExclude() { Filter result = (Filter) ff.or(Filter.EXCLUDE, Filter.EXCLUDE).accept(simpleVisitor, null); assertEquals(Filter.EXCLUDE, result); } public void testIncludeOrProperty() { Filter result = (Filter) ff.or(Filter.INCLUDE, property).accept(simpleVisitor, null); assertEquals(Filter.INCLUDE, result); } public void testExcludeOrProperty() { Filter result = (Filter) ff.or(Filter.EXCLUDE, property).accept(simpleVisitor, null); assertEquals(property, result); } public void testEmptyFid() { Filter result = (Filter) emptyFid.accept(simpleVisitor, null); assertEquals(Filter.EXCLUDE, result); } public void testRecurseAnd() { Filter test = ff.and(Filter.INCLUDE, ff.or(property, Filter.EXCLUDE)); assertEquals(property, test.accept(simpleVisitor, null)); } public void testRecurseOr() { Filter test = ff.or(Filter.EXCLUDE, ff.and(property, Filter.INCLUDE)); assertEquals(property, test.accept(simpleVisitor, null)); } public void testFidValidity() { simpleVisitor.setFIDValidator(new SimplifyingFilterVisitor.FIDValidator() { public boolean isValid(String fid) { return fid.startsWith("pass"); } }); Set<Identifier> ids = new HashSet<Identifier>(); ids.add(ff.featureId("notPass")); Id filter = ff.id(ids); assertEquals(Filter.EXCLUDE, filter.accept(simpleVisitor, null)); ids.add(ff.featureId("pass1")); ids.add(ff.featureId("pass2")); filter = ff.id(ids); Set<Identifier> validIds = new HashSet<Identifier>(); validIds.add(ff.featureId("pass2")); validIds.add(ff.featureId("pass1")); Filter expected = ff.id(validIds); assertEquals(expected, filter.accept(simpleVisitor, null)); } public void testRegExFIDValidator() { FIDValidator validator = new SimplifyingFilterVisitor.RegExFIDValidator("abc\\.\\d+"); simpleVisitor.setFIDValidator(validator); Set<Identifier> ids = new HashSet<Identifier>(); ids.add(ff.featureId("abc..")); ids.add(ff.featureId(".abc.1")); ids.add(ff.featureId("abc.123")); ids.add(ff.featureId("abc.ax")); Id filter = ff.id(ids); Filter result = (Filter) filter.accept(simpleVisitor, null); Filter expected = ff.id(Collections.singleton(ff.featureId("abc.123"))); assertEquals(expected, result); } public void testTypeNameDotNumberValidator() { final String typeName = "states"; FIDValidator validator; validator = new SimplifyingFilterVisitor.TypeNameDotNumberFidValidator(typeName); simpleVisitor.setFIDValidator(validator); Set<Identifier> ids = new HashSet<Identifier>(); ids.add(ff.featureId("_states")); ids.add(ff.featureId("states.abc")); ids.add(ff.featureId("states..")); ids.add(ff.featureId("states.123")); Id filter = ff.id(ids); Filter result = (Filter) filter.accept(simpleVisitor, null); Filter expected = ff.id(Collections.singleton(ff.featureId("states.123"))); assertEquals(expected, result); } public void testNegateEquals() { Filter f = ff.not(ff.equals(ff.property("prop"), ff.literal(10))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.notEqual(ff.property("prop"), ff.literal(10)), result); // not simplified for complex features result = (Filter) f.accept(complexVisitor, null); assertEquals(f, result); } public void testNegateGreater() { Filter f = ff.not(ff.greater(ff.property("prop"), ff.literal(10))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.lessOrEqual(ff.property("prop"), ff.literal(10)), result); // not simplified for complex features result = (Filter) f.accept(complexVisitor, null); assertEquals(f, result); } public void testNegateGreaterOrEqual() { Filter f = ff.not(ff.greaterOrEqual(ff.property("prop"), ff.literal(10))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.less(ff.property("prop"), ff.literal(10)), result); // not simplified for complex features result = (Filter) f.accept(complexVisitor, null); assertEquals(f, result); } public void testNegateLess() { Filter f = ff.not(ff.less(ff.property("prop"), ff.literal(10))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.greaterOrEqual(ff.property("prop"), ff.literal(10)), result); // not simplified for complex features result = (Filter) f.accept(complexVisitor, null); assertEquals(f, result); } public void testNegateLessOrEqual() { Filter f = ff.not(ff.lessOrEqual(ff.property("prop"), ff.literal(10))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.greater(ff.property("prop"), ff.literal(10)), result); // not simplified for complex features result = (Filter) f.accept(complexVisitor, null); assertEquals(f, result); } public void testNegateBetween() { PropertyName prop = ff.property("prop"); Literal l10 = ff.literal(10); Literal l20 = ff.literal(20); Filter f = ff.not(ff.between(prop, l10, l20)); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.or(Arrays.asList((Filter) ff.less(prop, l10), ff.greater(prop, l20))), result); } public void testDoubleNegation() { PropertyIsEqualTo equal = ff.equals(ff.property("prop"), ff.literal(10)); Filter f = ff.not(ff.not(equal)); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(equal, result); } public void testTripleNegation() { PropertyIsEqualTo equal = ff.equals(ff.property("prop"), ff.literal(10)); Filter f = ff.not(ff.not(ff.not(equal))); Filter result = (Filter) f.accept(simpleVisitor, null); assertEquals(ff.notEqual(ff.property("prop"), ff.literal(10)), result); } public void testStableFunction() { EnvFunction.setLocalValue("var", "123"); Function f = ff.function("env", ff.literal("var")); Expression result = (Expression) f.accept(simpleVisitor, null); assertTrue(result instanceof Literal); assertEquals("123", result.evaluate(null, String.class)); } public void testVolatileFunction() { Function f = ff.function("random"); Expression result = (Expression) f.accept(simpleVisitor, null); assertTrue(result instanceof FilterFunction_random); } public void testNestedVolatile() { EnvFunction.setLocalValue("power", 3); Function f = ff.function("pow", ff.function("random"), ff.function("env", ff.literal("power"))); Function result = (Function) f.accept(simpleVisitor, null); // main function not simplified out assertEquals("pow", result.getName()); // first argument not simplified out Function param1 = (Function) result.getParameters().get(0); assertEquals("random", param1.getName()); // second argument simplified out Expression param2 = result.getParameters().get(1); assertTrue(param2 instanceof Literal); assertEquals(Integer.valueOf(3), param2.evaluate(null, Integer.class)); } public void testCompareFunctionNull() { Function f = ff.function("env", ff.literal("var")); PropertyIsEqualTo filter = ff.equal(f, ff.literal("test"), false); Filter simplified = (Filter) filter.accept(simpleVisitor, null); assertEquals(Filter.EXCLUDE, simplified); } public void testCompareConstantFunction() { EnvFunction.setLocalValue("var", "test"); Function f = ff.function("env", ff.literal("var")); PropertyIsEqualTo filter = ff.equal(f, ff.literal("test"), false); Filter simplified = (Filter) filter.accept(simpleVisitor, null); assertEquals(Filter.INCLUDE, simplified); } public void testSimplifyStaticExclude() { assertEquals(Filter.EXCLUDE, simplify(ff.greater(ff.literal(3), ff.literal(5)))); assertEquals(Filter.EXCLUDE, simplify(ff.greaterOrEqual(ff.literal(3), ff.literal(5)))); assertEquals(Filter.EXCLUDE, simplify(ff.less(ff.literal(5), ff.literal(3)))); assertEquals(Filter.EXCLUDE, simplify(ff.lessOrEqual(ff.literal(5), ff.literal(3)))); assertEquals(Filter.EXCLUDE, simplify(ff.equal(ff.literal(5), ff.literal(3), true))); assertEquals(Filter.EXCLUDE, simplify(ff.between(ff.literal(3), ff.literal(1), ff.literal(2)))); } public void testSimplifyStaticInclude() { assertEquals(Filter.INCLUDE, simplify(ff.less(ff.literal(3), ff.literal(5)))); assertEquals(Filter.INCLUDE, simplify(ff.lessOrEqual(ff.literal(3), ff.literal(5)))); assertEquals(Filter.INCLUDE, simplify(ff.greater(ff.literal(5), ff.literal(3)))); assertEquals(Filter.INCLUDE, simplify(ff.greaterOrEqual(ff.literal(5), ff.literal(3)))); assertEquals(Filter.INCLUDE, simplify(ff.equal(ff.literal(5), ff.literal(5), true))); assertEquals(Filter.INCLUDE, simplify(ff.between(ff.literal(3), ff.literal(1), ff.literal(4)))); } private Filter simplify(Filter filter) { return (Filter) filter.accept(new SimplifyingFilterVisitor(), null); } public void testCoalesheNestedAnd() { Filter eq = ff.equal(ff.property("A"), ff.literal("3"), true); Filter gt = ff.greater(ff.property("b"), ff.literal("3")); Filter lt = ff.less(ff.property("c"), ff.literal("5")); And nested = ff.and(Arrays.asList(ff.and(Arrays.asList(eq, gt)), lt)); And simplified = (And) nested.accept(simpleVisitor, null); assertEquals(3, simplified.getChildren().size()); assertEquals(ff.and(Arrays.asList(eq, gt, lt)), simplified); } public void testCoalesheNestedOr() { Filter eq = ff.equal(ff.property("A"), ff.literal("3"), true); Filter gt = ff.greater(ff.property("b"), ff.literal("3")); Filter lt = ff.less(ff.property("c"), ff.literal("5")); Or nested = ff.or(Arrays.asList(ff.or(Arrays.asList(eq, gt)), lt)); Or simplified = (Or) nested.accept(simpleVisitor, null); assertEquals(3, simplified.getChildren().size()); assertEquals(ff.or(Arrays.asList(eq, gt, lt)), simplified); } public void testDualFilterOr() { Or or = ff.or(Arrays.asList(ff.not(ff.equal(ff.property("a"), ff.literal(3), true)), ff.equal(ff.property("a"), ff.literal(3), true))); assertEquals(Filter.INCLUDE, or.accept(simpleVisitor, null)); } public void testDualFilterAnd() { Filter original = ff.and(Arrays.asList(ff.not(ff.equal(ff.property("a"), ff.literal(3), true)), ff.equal(ff.property("a"), ff.literal(3), true))); assertEquals(Filter.EXCLUDE, original.accept(simpleVisitor, null)); } public void testDualFilterNullAnd() { Filter original = ff.and(Arrays.asList(ff.not(ff.isNull(ff.property("a"))), ff.isNull(ff.property("a")))); assertEquals(Filter.EXCLUDE, original.accept(simpleVisitor, null)); } public void testDualFilterNullOr() { Filter original = ff.or(Arrays.asList(ff.not(ff.isNull(ff.property("a"))), ff.isNull(ff.property("a")))); assertEquals(Filter.INCLUDE, original.accept(simpleVisitor, null)); } public void testRepeatedFilter() { Filter f1 = ff.equal(ff.property("a"), ff.literal(3), false); Filter f2 = ff.equal(ff.property("a"), ff.literal(3), false); Filter s1 = (Filter) ff.and(f1, f2).accept(simpleVisitor, null); assertEquals(f1, s1); Filter s2 = (Filter) ff.or(f1, f2).accept(simpleVisitor, null); assertEquals(f1, s2); Filter f3 = ff.greater(ff.property("a"), ff.property("b")); Filter s3 = (Filter) ff.and(Arrays.asList(f1, f2, f3)).accept(simpleVisitor, null); assertEquals(ff.and(Arrays.asList(f1, f3)), s3); Filter s4 = (Filter) ff.and(Arrays.asList(f3, f1, f2)).accept(simpleVisitor, null); assertEquals(ff.and(Arrays.asList(f3, f1)), s4); Filter s5 = (Filter) ff.and(Arrays.asList(f1, f3, f2)).accept(simpleVisitor, null); assertEquals(ff.and(Arrays.asList(f1, f3)), s5); Filter s6 = (Filter) ff.or(Arrays.asList(f1, f2, f3)).accept(simpleVisitor, null); assertEquals(ff.or(Arrays.asList(f1, f3)), s6); Filter s7 = (Filter) ff.or(Arrays.asList(f3, f1, f2)).accept(simpleVisitor, null); assertEquals(ff.or(Arrays.asList(f3, f1)), s7); Filter s8 = (Filter) ff.or(Arrays.asList(f1, f3, f2)).accept(simpleVisitor, null); assertEquals(ff.or(Arrays.asList(f1, f3)), s8); } public void testAndDisjointRanges() throws Exception { testAndDisjointRanges(Integer.class, 10, 5); testAndDisjointRanges(Byte.class, (byte) 10, (byte) 5); testAndDisjointRanges(Long.class, 10l, 5l); testAndDisjointRanges(Float.class, 10f, 5f); testAndDisjointRanges(Double.class, 10d, 5d); testAndDisjointRanges(String.class, "ppp", "bbb"); } private <T> void testAndDisjointRanges(Class<T> type, T max, T min) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); Filter original = ff.and(ff.greater(ff.property("a"), ff.literal(max)), ff.less(ff.property("a"), ff.literal(min))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(original, simplified); visitor.setFeatureType(schema); Filter simplified2 = (Filter) original.accept(visitor, null); assertEquals(Filter.EXCLUDE, simplified2); } public void testOrDisjointRanges() throws Exception { testOrDisjointRanges(Integer.class, 10, 5); testOrDisjointRanges(Byte.class, (byte) 10, (byte) 5); testOrDisjointRanges(Long.class, 10l, 5l); testOrDisjointRanges(Float.class, 10f, 5f); testOrDisjointRanges(Double.class, 10d, 5d); testOrDisjointRanges(String.class, "ppp", "bbb"); } private <T> void testOrDisjointRanges(Class<T> type, T max, T min) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setFeatureType(schema); Filter original = ff.or(ff.greater(ff.property("a"), ff.literal(max)), ff.less(ff.property("a"), ff.literal(min))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(original, simplified); } public void testAndTouchingRanges() throws Exception { testAndTouchingRanges(Integer.class, 10); testAndTouchingRanges(Byte.class, (byte) 10); testAndTouchingRanges(Long.class, 10l); testAndTouchingRanges(Float.class, 10f); testAndTouchingRanges(Double.class, 10d); testAndTouchingRanges(String.class, "ppp"); } private <T> void testAndTouchingRanges(Class<T> type, T value) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); Filter original = ff.and(ff.greaterOrEqual(ff.property("a"), ff.literal(value)), ff.lessOrEqual(ff.property("a"), ff.literal(value))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(ff.equal(ff.property("a"), ff.literal(value), false), simplified); } public void testOrTouchingRanges() throws Exception { testOrTouchingRanges(Integer.class, 10); testOrTouchingRanges(Byte.class, (byte) 10); testOrTouchingRanges(Long.class, 10l); testOrTouchingRanges(Float.class, 10f); testOrTouchingRanges(Double.class, 10d); testOrTouchingRanges(String.class, "ppp"); } private <T> void testOrTouchingRanges(Class<T> type, T value) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); Filter original = ff.or(ff.greaterOrEqual(ff.property("a"), ff.literal(value)), ff.lessOrEqual(ff.property("a"), ff.literal(value))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(Filter.INCLUDE, simplified); } public void testAndOverlappingRanges() throws Exception { testAndOverlappingRanges(Integer.class, 5, 7, 10); testAndOverlappingRanges(Byte.class, (byte) 5, (byte) 7, (byte) 10); testAndOverlappingRanges(Long.class, 5l, 7l, 10l); testAndOverlappingRanges(Float.class, 5f, 7f, 10f); testAndOverlappingRanges(Double.class, 5d, 7d, 10d); testAndOverlappingRanges(String.class, "bbb", "nnn", "ppp"); } private <T> void testAndOverlappingRanges(Class<T> type, T min, T mid, T max) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); // excluding extrema, not possible to turn it into a between filter Filter original = ff.and(Arrays.asList( // (Filter) ff.greater(ff.property("a"), ff.literal(min)), // ff.less(ff.property("a"), ff.literal(max)), // ff.less(ff.property("a"), ff.literal(mid)) )); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(ff.and(ff.greater(ff.property("a"), ff.literal(min)), // ff.less(ff.property("a"), ff.literal(mid))), simplified); } public void testOrOverlappingRanges() throws Exception { testOrOverlappingRanges(Integer.class, 5, 10); testOrOverlappingRanges(Byte.class, (byte) 5, (byte) 10); testOrOverlappingRanges(Long.class, 5l, 10l); testOrOverlappingRanges(Float.class, 5f, 10f); testOrOverlappingRanges(Double.class, 5d, 10d); testOrOverlappingRanges(String.class, "bbb", "ppp"); } private <T> void testOrOverlappingRanges(Class<T> type, T min, T max) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); // excluding extrema, not possible to turn it into a between filter Filter original = ff.or(Arrays.asList( // (Filter) ff.greater(ff.property("a"), ff.literal(min)), // ff.greater(ff.property("a"), ff.literal(max)))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(ff.greater(ff.property("a"), ff.literal(min)), simplified); } public void testAndOverlappingRangesToBetween() throws Exception { testAndOverlappingRangesToBetween(Integer.class, 5, 7, 10); testAndOverlappingRangesToBetween(Byte.class, (byte) 5, (byte) 7, (byte) 10); testAndOverlappingRangesToBetween(Long.class, 5l, 7l, 10l); testAndOverlappingRangesToBetween(Float.class, 5f, 7f, 10f); testAndOverlappingRangesToBetween(Double.class, 5d, 7d, 10d); testAndOverlappingRangesToBetween(String.class, "bbb", "nnn", "ppp"); } private <T> void testAndOverlappingRangesToBetween(Class<T> type, T min, T mid, T max) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); // excluding extrema, not possible to turn it into a between filter Filter original = ff.and(Arrays.asList( // (Filter) ff.greaterOrEqual(ff.property("a"), ff.literal(min)), // ff.less(ff.property("a"), ff.literal(max)), // ff.lessOrEqual(ff.property("a"), ff.literal(mid)))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(ff.between(ff.property("a"), ff.literal(min), ff.literal(mid)), simplified); } public void testOrPseudoBetween() throws Exception { testOrPseudoBetween(Integer.class, 5, 10); testOrPseudoBetween(Byte.class, (byte) 5, (byte) 10); testOrPseudoBetween(Long.class, 5l, 10l); testOrPseudoBetween(Float.class, 5f, 10f); testOrPseudoBetween(Double.class, 5d, 10d); testOrPseudoBetween(String.class, "bbb", "ppp"); } private <T> void testOrPseudoBetween(Class<T> type, T min, T max) throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "a:" + type.getName()); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); // (a > min && a <= max) or (a <= min) Filter original = ff.or(Arrays.asList( // ff.and(ff.greater(ff.property("a"), ff.literal(min)), // ff.lessOrEqual(ff.property("a"), ff.literal(max))), // ff.lessOrEqual(ff.property("a"), ff.literal(min)))); Filter simplified = (Filter) original.accept(visitor, null); assertEquals(ff.lessOrEqual(ff.property("a"), ff.literal(max)), simplified); } public void testRangeExpression() throws Exception { SimpleFeatureType schema = DataUtilities.createType("test", "pop:String"); SimplifyingFilterVisitor visitor = new SimplifyingFilterVisitor(); visitor.setRangeSimplicationEnabled(true); visitor.setFeatureType(schema); Function func = ff.function("parseLong", ff.property("pop")); Filter f1 = ff.less(func, ff.literal(20000)); Filter f2 = ff.between(func, ff.literal(20000), ff.literal(50000)); Filter or = ff.or(f1, f2); Filter simplified = (Filter) or.accept(visitor, null); assertEquals(ff.lessOrEqual(func, ff.literal(50000)), simplified); } }