/* * 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.arcsde.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.NoSuchElementException; import org.geotools.data.DataStore; import org.geotools.data.FeatureReader; import org.geotools.data.FilteringFeatureReader; import org.geotools.data.Query; import org.geotools.data.Transaction; import org.geotools.factory.CommonFactoryFinder; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.opengis.feature.Feature; import org.opengis.feature.IllegalAttributeException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; /** * This test case does not still use the ArcSDEDataStore testing data supplied with in * {@code test-data/import}, so it is excluded in project.xml. * * @author cdillard * @author Gabriel Roldan * * @source $URL$ * http://svn.geotools.org/geotools/trunk/gt/modules/plugin/arcsde/datastore/src/test/java * /org/geotools/arcsde/data/FilterTest.java.fixme $ * @version $Id$ */ public class FilterTest { private static final Comparator<SimpleFeature> FEATURE_COMPARATOR = new Comparator<SimpleFeature>() { public int compare(SimpleFeature f1, SimpleFeature f2) { return f1.getID().compareTo(f2.getID()); } }; private static final GeometryFactory gf = new GeometryFactory(); private static TestData testData; private DataStore dataStore; private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); @BeforeClass public static void oneTimeSetUp() throws Exception { testData = new TestData(); testData.setUp(); final boolean insertTestData = true; testData.createTempTable(insertTestData); } @AfterClass public static void oneTimeTearDown() { boolean cleanTestTable = false; boolean cleanPool = true; testData.tearDown(cleanTestTable, cleanPool); } @Before public void setUp() throws Exception { // facilitates running a single test at a time (eclipse lets you do this // and it's very useful) if (testData == null) { oneTimeSetUp(); } this.dataStore = testData.getDataStore(); } @After public void tearDown() throws Exception { } private static void collectResults(FeatureReader<SimpleFeatureType, SimpleFeature> fr, Collection<SimpleFeature> c) throws NoSuchElementException, IOException, IllegalAttributeException { while (fr.hasNext()) { c.add(fr.next()); } } /** * Are the two collections similar? * * @param c1 * Collection first * @param c2 * Collection second * @return true if they have the same content */ private void assertFeatureListsSimilar(Collection<SimpleFeature> c1, Collection<SimpleFeature> c2) { assertEquals("Actual feature collection was not the expected size", c1.size(), c2.size()); ArrayList<SimpleFeature> al1 = new ArrayList<SimpleFeature>(c1); ArrayList<SimpleFeature> al2 = new ArrayList<SimpleFeature>(c2); Collections.sort(al1, FEATURE_COMPARATOR); Collections.sort(al2, FEATURE_COMPARATOR); int n = c1.size(); for (int i = 0; i < n; i++) { Feature f1 = al1.get(i); Feature f2 = al2.get(i); if (i == 0) { assertEquals("Feature Type", f1.getType(), f2.getType()); } assertEquals("Feature[" + i + "] identifiers Equal", f1.getIdentifier().getID(), f2 .getIdentifier().getID()); if (!f1.equals(f2)) { // go through properties and figure out differneces... for (PropertyDescriptor property : f1.getType().getDescriptors()) { String name = property.getName().getLocalPart(); Object value1 = f1.getProperty(name).getValue(); Object value2 = f2.getProperty(name).getValue(); if (value1 instanceof Calendar) { continue; } if (value1 instanceof Date) { continue; } if (value1 instanceof Geometry) { // jts geometry is not my friend assertTrue("Feature[" + i + "]." + name + " geometry", ((Geometry) value1).equalsTopo((Geometry) value2)); } else { assertEquals("Feature[" + i + "]." + name, value1, value2); } } } } } private static LineString buildSegment(double x1, double y1, double x2, double y2) { Coordinate[] coordArray = new Coordinate[] { new Coordinate(x1, y1), new Coordinate(x2, y2) }; LineString result = gf.createLineString(coordArray); return result; } private static Polygon buildPolygon(double minx, double miny, double maxx, double maxy) { Coordinate[] coordArray = new Coordinate[] { new Coordinate(minx, miny), new Coordinate(minx, maxy), new Coordinate(maxx, maxy), new Coordinate(maxx, miny), new Coordinate(minx, miny) }; Polygon p = gf.createPolygon(gf.createLinearRing(coordArray), new LinearRing[0]); return p; } /** * TODO: resurrect testDisjointFilter */ @Test @Ignore public void testDisjointFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = -179; double maxx = -170; double miny = -90; double maxy = -80; Polygon p = buildPolygon(minx, miny, maxx, maxy); Filter filter = ff.not(ff.isNull(ff.property("SHAPE"))); filter = ff.and(filter, ff.disjoint(ff.property("SHAPE"), ff.literal(p))); runTestWithFilter(ft, filter); } @Test public void testContainsFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6666; double maxx = 106.6677; double miny = -6.1676; double maxy = -6.1672; Polygon p = buildPolygon(minx, miny, maxx, maxy); Filter filter = ff.contains(ff.property("SHAPE"), ff.literal(p)); runTestWithFilter(ft, filter); } @Test public void testBBoxFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6337; double maxx = 106.6381; double miny = -6.1794; double maxy = -6.1727; Filter filter = ff.bbox("SHAPE", minx, miny, maxx, maxy, "EPSG:4326"); runTestWithFilter(ft, filter); } @Test public void testIntersectsFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6337; double maxx = 106.6381; double miny = -6.1794; double maxy = -6.1727; Polygon p = buildPolygon(minx, miny, maxx, maxy); Filter filter = ff.intersects(ff.property("SHAPE"), ff.literal(p)); runTestWithFilter(ft, filter); } @Test public void testOverlapsFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6337; double maxx = 106.6381; double miny = -6.1794; double maxy = -6.1727; Polygon p = buildPolygon(minx, miny, maxx, maxy); Filter filter = ff.overlaps(ff.property("SHAPE"), ff.literal(p)); runTestWithFilter(ft, filter); } @Test public void testWithinFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6337; double maxx = 106.6381; double miny = -6.1794; double maxy = -6.1727; Polygon p = buildPolygon(minx, miny, maxx, maxy); Filter filter = ff.within(ff.property("SHAPE"), ff.literal(p)); runTestWithFilter(ft, filter); } @Test public void testCrossesFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Build the filter double minx = 106.6337; double maxx = 106.6381; double miny = -6.1794; double maxy = -6.1727; LineString ls = buildSegment(minx, miny, maxx, maxy); Filter filter = ff.crosses(ff.property("SHAPE"), ff.literal(ls)); runTestWithFilter(ft, filter); } /** * TODO: resurrect testEqualFilter */ @Test @Ignore public void testEqualFilter() throws Exception { FeatureType ft = this.dataStore.getSchema(testData.getTempTableName()); // Get a geometry for equality comparison Query Query = new Query(testData.getTempTableName()); Query.setPropertyNames(safePropertyNames(ft)); Query.setMaxFeatures(1); FeatureReader<SimpleFeatureType, SimpleFeature> fr = this.dataStore.getFeatureReader(Query, Transaction.AUTO_COMMIT); SimpleFeature feature = fr.next(); fr.close(); Geometry g = (Geometry) feature.getAttribute("SHAPE"); // Build the filter Filter filter = ff.equal(ff.property("SHAPE"), ff.literal(g)); runTestWithFilter(ft, filter); } private void runTestWithFilter(FeatureType ft, Filter filter) throws Exception { System.err.println("****************"); System.err.println("**"); System.err.println("** TESTING FILTER: " + filter); System.err.println("**"); System.err.println("****************"); // First, read using the slow, built-in mechanisms String[] propertyNames = safePropertyNames(ft); Query allQuery = new Query(testData.getTempTableName(), Filter.INCLUDE, propertyNames); System.err.println("Performing slow read..."); long startTime = System.currentTimeMillis(); FeatureReader<SimpleFeatureType, SimpleFeature> fr = this.dataStore.getFeatureReader( allQuery, Transaction.AUTO_COMMIT); FilteringFeatureReader<SimpleFeatureType, SimpleFeature> ffr = new FilteringFeatureReader<SimpleFeatureType, SimpleFeature>( fr, filter); ArrayList<SimpleFeature> slowResults = new ArrayList<SimpleFeature>(); collectResults(ffr, slowResults); ffr.close(); long endTime = System.currentTimeMillis(); System.err.println("Slow read took " + (endTime - startTime) + " milliseconds."); // Now read using DataStore's mechanisms. System.err.println("Performing fast read..."); startTime = System.currentTimeMillis(); Query filteringQuery = new Query(testData.getTempTableName(), filter, safePropertyNames(ft)); fr = this.dataStore.getFeatureReader(filteringQuery, Transaction.AUTO_COMMIT); ArrayList<SimpleFeature> fastResults = new ArrayList<SimpleFeature>(); collectResults(fr, fastResults); fr.close(); endTime = System.currentTimeMillis(); System.err.println("Fast read took " + (endTime - startTime) + " milliseconds."); assertFeatureListsSimilar(slowResults, fastResults); } private String[] safePropertyNames(FeatureType ft) { ArrayList<String> names = new ArrayList<String>(); for (PropertyDescriptor descriptor : ft.getDescriptors()) { Class<?> binding = descriptor.getType().getBinding(); if (Calendar.class.equals(binding)) { continue; } if (Date.class.equals(binding)) { continue; } names.add(descriptor.getName().getLocalPart()); } String[] propertyNames = names.toArray(new String[names.size()]); return propertyNames; } }