/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2016, Open Source Geospatial Foundation (OSGeo) * (C) 2005, David Zwiers * * 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.wfs.online; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.URL; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.data.FeatureReader; import org.geotools.data.Query; import org.geotools.data.ResourceInfo; import org.geotools.data.Transaction; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.wfs.WFSDataStore; import org.geotools.data.wfs.WFSDataStoreFactory; import org.geotools.data.wfs.WFSTestData; import org.geotools.factory.CommonFactoryFinder; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.CRS.AxisOrder; import org.geotools.util.logging.Logging; import org.junit.Before; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.FilterVisitor; import org.opengis.filter.Id; import org.opengis.filter.expression.Expression; import org.opengis.filter.spatial.BBOX; import org.opengis.geometry.BoundingBox; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * * * @source $URL$ */ public abstract class AbstractWfsDataStoreOnlineTest { private static final Logger LOGGER = Logging.getLogger("org.geotools.wfs.v_1_1_0.data.test"); protected static final FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); private final String SERVER_URL; protected Boolean serviceAvailable = null; /** * The DataStore under test, static so we create it only once */ protected WFSDataStore wfs = null; protected final WFSTestData.TestDataType testType; protected final String defaultGeometryName; protected String axisOrder; private final int featureCount; /** * The filter used for the count test, may be null if {@link #testFeatureSourceGetCountFilter()} and * {@link #testFeatureSourceGetFeatures()} are not expected to be run */ private final Id fidFilter; /** * The filter used for the filter test, may be null if {@link #testFeatureSourceGetFeaturesFilter()} is * not expected to run. */ private final Filter spatialFilter; private final Class geometryType; public AbstractWfsDataStoreOnlineTest(String serverURL, WFSTestData.TestDataType testType, String defaultGeometryName, Class geometryType, int featureCount, Id fidFilter, Filter spatialFilter, String axisOrder) { this.SERVER_URL = serverURL; this.testType = testType; this.defaultGeometryName = defaultGeometryName; this.featureCount = featureCount; this.fidFilter = fidFilter; this.geometryType = geometryType; this.axisOrder = axisOrder; this.spatialFilter = spatialFilter; } @Before public void setUp() throws IOException { if (serviceAvailable == null) { // check for service availability only once URL url = new URL(SERVER_URL); serviceAvailable = Boolean.FALSE; InputStream stream = null; try { stream = url.openStream(); serviceAvailable = Boolean.TRUE; } catch (Throwable t) { LOGGER.log(Level.WARNING, "The test server is not available: " + SERVER_URL + ". " + getClass().getSimpleName() + " test disabled "); url = null; return; } finally { if (stream != null) try { stream.close(); } catch (IOException e) { // whatever } } } if (wfs == null && serviceAvailable.booleanValue()) { LOGGER.info("Creating test datastore for " + SERVER_URL); Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put(WFSDataStoreFactory.URL.key, SERVER_URL); params.put(WFSDataStoreFactory.GML_COMPATIBLE_TYPENAMES.key, true); params.put(WFSDataStoreFactory.AXIS_ORDER.key, axisOrder); WFSDataStoreFactory dataStoreFactory = new WFSDataStoreFactory(); wfs = dataStoreFactory.createDataStore(params); LOGGER.fine("WFS datastore created"); } } @Test public void testFeatureSourceInfo() throws IOException, NoSuchAuthorityCodeException, FactoryException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); ResourceInfo info = featureSource.getInfo(); assertNotNull(info.getCRS()); ReferencedEnvelope bounds = info.getBounds(); assertSame(info.getCRS(), bounds.getCoordinateReferenceSystem()); assertEquals(testType.FEATURETYPENAME, info.getName()); } @Test public void testFeatureSourceGetBounds() throws IOException, NoSuchAuthorityCodeException, FactoryException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); ReferencedEnvelope infoBounds = featureSource.getInfo().getBounds(); ReferencedEnvelope bounds = featureSource.getBounds(); assertEquals(infoBounds, bounds); Query query = new Query(featureSource.getInfo().getName()); CoordinateReferenceSystem queryCrs = CRS.decode("EPSG:23030"); query.setCoordinateSystem(queryCrs); bounds = featureSource.getBounds(query); assertNotNull(bounds); assertSame("the bounds were not reprojected", queryCrs, bounds.getCoordinateReferenceSystem()); final String geometryName = featureSource.getSchema().getGeometryDescriptor() .getLocalName(); query.setFilter(ff.bbox(geometryName, -180, -90, 180, 90, "EPSG:4326")); bounds = featureSource.getBounds(query); assertNull(bounds); // too expensive to calculate } @Test public void testFeatureSourceGetCountAll() throws IOException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); assertEquals(featureCount, featureSource.getCount(Query.ALL)); } /** * Performs a FeatureSource.getCount(Query) with the constructor provided fid filter if the filter is not null. * * @throws IOException */ @Test public void testFeatureSourceGetCountFilter() throws IOException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } if (featureCount >= 0) { //server doesn't support feature count anyway, skip if (fidFilter == null) { LOGGER.info("Ignoring testFeatureSourceGetCountFilter " + "since the subclass didn't provide a fid filter"); return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); Query query = new Query(featureSource.getInfo().getName()); query.setFilter(fidFilter); assertEquals(1, featureSource.getCount(query)); } } @Test public void testFeatureSourceGetFeatures() throws IOException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } if (fidFilter == null) { LOGGER.info("Ignoring testFeatureSourceGetCountFilter " + "since the subclass didn't provide a fid filter"); return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); SimpleFeatureCollection features; features = featureSource.getFeatures(); assertNotNull(features); SimpleFeatureType schema = features.getSchema(); assertNotNull(schema); SimpleFeatureIterator iterator = features.features(); assertNotNull(iterator); try { assertTrue(iterator.hasNext()); SimpleFeature next = iterator.next(); assertNotNull(next); assertNotNull(next.getDefaultGeometry()); } finally { iterator.close(); } } @Test public void testFeatureSourceGetFeaturesFilter() throws IOException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } if (spatialFilter == null) { LOGGER.info("Ignoring testFeatureSourceGetCountFilter " + "since the subclass didn't provide a spatial filter"); return; } SimpleFeatureSource featureSource; featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); assertNotNull(featureSource); Query query = new Query(testType.FEATURETYPENAME); query.setFilter(spatialFilter); SimpleFeatureCollection features; features = featureSource.getFeatures(query); assertNotNull(features); SimpleFeatureType schema = features.getSchema(); assertNotNull(schema); SimpleFeatureIterator iterator = features.features(); assertNotNull(iterator); try { assertTrue(iterator.hasNext()); SimpleFeature next = iterator.next(); assertNotNull(next); assertNotNull(next.getDefaultGeometry()); assertFalse(iterator.hasNext()); } finally { iterator.close(); } } @Test public void testTypes() throws IOException, NoSuchElementException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } assertTrue(wfs instanceof WFSDataStore); String types[] = wfs.getTypeNames(); List<String> typeNames = Arrays.asList(types); assertTrue(typeNames.contains(testType.FEATURETYPENAME)); for (int i = 0; i < types.length; i++) { String typeName = types[i]; SimpleFeatureType type = wfs.getSchema(typeName); type.getTypeName(); type.getName().getNamespaceURI(); SimpleFeatureSource source = wfs.getFeatureSource(typeName); source.getBounds(); SimpleFeatureCollection features = source.getFeatures(); features.getBounds(); features.getSchema(); Query query = new Query(typeName, Filter.INCLUDE, 20, Query.ALL_NAMES, "work already"); features = source.getFeatures(query); features.size(); SimpleFeatureIterator iterator = features.features(); try { while (iterator.hasNext()) { iterator.next(); } } finally { iterator.close(); } } SimpleFeatureType schema = wfs.getSchema(testType.FEATURETYPENAME); assertNotNull(schema); GeometryDescriptor geometryDescriptor = schema.getGeometryDescriptor(); assertNotNull(geometryDescriptor); assertEquals(defaultGeometryName, geometryDescriptor.getLocalName()); assertEquals(geometryType, geometryDescriptor.getType().getBinding()); CoordinateReferenceSystem crs = geometryDescriptor.getCoordinateReferenceSystem(); assertNotNull(crs); } @Test public void testSingleType() throws IOException, NoSuchElementException { if (Boolean.FALSE.equals(serviceAvailable)) { return; } SimpleFeatureType type = wfs.getSchema(testType.FEATURETYPENAME); type.getTypeName(); type.getName().getNamespaceURI(); SimpleFeatureSource source = wfs.getFeatureSource(testType.FEATURETYPENAME); source.getBounds(); SimpleFeatureCollection features = source.getFeatures(); features.getBounds(); features.getSchema(); Query query = new Query(testType.FEATURETYPENAME, Filter.INCLUDE, 20, Query.ALL_NAMES, "work already"); features = source.getFeatures(query); features.size(); SimpleFeatureIterator iterator = features.features(); try { while (iterator.hasNext()) { iterator.next(); } } finally { iterator.close(); } } /** * {@link BBOX} support? */ @Test public void testDataStoreSupportsPlainBBOXInterface() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } final SimpleFeatureType ft = wfs.getSchema(testType.FEATURETYPENAME); SimpleFeatureSource featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); final ReferencedEnvelope bounds = featureSource.getBounds(); String srsName = CRS.toSRS(bounds.getCoordinateReferenceSystem()); final BBOX bbox = ff.bbox("the_geom", bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY(), srsName); /** * This one does not implement the deprecated geotools filter interfaces */ final BBOX strictBBox = new BBOX() { @Override public boolean evaluate(Object object) { return bbox.evaluate(object); } @Override public Object accept(FilterVisitor visitor, Object extraData) { return bbox.accept(visitor, extraData); } @Override public Expression getExpression2() { return bbox.getExpression2(); } @Override public Expression getExpression1() { return bbox.getExpression1(); } @Override public String getSRS() { return bbox.getSRS(); } @Override public String getPropertyName() { return bbox.getPropertyName(); } @Override public double getMinY() { return bbox.getMinY(); } @Override public double getMinX() { return bbox.getMinX(); } @Override public double getMaxY() { return bbox.getMaxY(); } @Override public double getMaxX() { return bbox.getMaxX(); } @Override public MatchAction getMatchAction() { return MatchAction.ANY; } @Override public BoundingBox getBounds() { return bbox.getBounds(); } }; final Query query = new Query(ft.getTypeName()); query.setPropertyNames(new String[] { "the_geom" }); query.setFilter(strictBBox); FeatureReader<SimpleFeatureType, SimpleFeature> reader; reader = wfs.getFeatureReader(query, Transaction.AUTO_COMMIT); assertNotNull(reader); reader = wfs.getFeatureReader(query, Transaction.AUTO_COMMIT); assertNotNull(reader); } @Test public void testDataStoreHandlesAxisFlipping() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } final SimpleFeatureType ft = wfs.getSchema(testType.FEATURETYPENAME); final SimpleFeatureSource featureSource = wfs.getFeatureSource(testType.FEATURETYPENAME); final ReferencedEnvelope bounds = featureSource.getBounds(); CoordinateReferenceSystem wgs84LonLat = CRS.decode("EPSG:4326", true); CoordinateReferenceSystem wgs84LatLon = CRS.decode("EPSG:4326", false); assertEquals(AxisOrder.EAST_NORTH, CRS.getAxisOrder(wgs84LonLat)); assertEquals(AxisOrder.NORTH_EAST, CRS.getAxisOrder(wgs84LatLon)); ReferencedEnvelope lonLat = bounds.transform(wgs84LonLat, true); ReferencedEnvelope latLon = bounds.transform(wgs84LatLon, true); final BBOX lonLatFilter = ff.bbox("the_geom", lonLat.getMinimum(0), lonLat.getMinimum(1), lonLat.getMaximum(0), lonLat.getMaximum(1), null); final BBOX latLonFiler = ff.bbox("the_geom", latLon.getMinimum(0), latLon.getMinimum(1), latLon.getMaximum(0), latLon.getMaximum(1), null); final Query query = new Query(ft.getTypeName()); query.setPropertyNames(new String[] { "the_geom" }); query.setFilter(lonLatFilter); query.setCoordinateSystem(wgs84LonLat); final int expectedCount = wfs.getFeatureSource(query.getTypeName()).getFeatures().size(); FeatureReader<SimpleFeatureType, SimpleFeature> reader; reader = wfs.getFeatureReader(query, Transaction.AUTO_COMMIT); try { assertTrue(reader.hasNext()); int count = 0; while (reader.hasNext()) { reader.next(); count++; } assertEquals(expectedCount, count); } finally { reader.close(); } query.setFilter(latLonFiler); query.setCoordinateSystem(wgs84LatLon); reader = wfs.getFeatureReader(query, Transaction.AUTO_COMMIT); try { assertTrue(reader.hasNext()); int count = 0; while (reader.hasNext()) { reader.next(); count++; } assertEquals(expectedCount, count); } finally { reader.close(); } } public void XtestFeatureType() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } WFSOnlineTestSupport.doFeatureType(wfs, testType.FEATURETYPENAME); } @Test public void testFeatureReader() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } WFSOnlineTestSupport.doFeatureReader(wfs, testType.FEATURETYPENAME); } @Test public void testFeatureReaderWithQuery() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } WFSOnlineTestSupport.doFeatureReaderWithQuery(wfs, testType.FEATURETYPENAME); } @Test public void testFeatureReaderWithFilterBBox() throws Exception { if (Boolean.FALSE.equals(serviceAvailable)) { return; } ReferencedEnvelope bbox = wfs.getFeatureSource(testType.FEATURETYPENAME).getBounds(); WFSOnlineTestSupport.doFeatureReaderWithBBox(wfs, testType.FEATURETYPENAME, bbox); } }