/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008-2014, 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.data.wfs.internal.v1_1;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.io.IOUtils;
import org.custommonkey.xmlunit.XMLAssert;
import org.geotools.data.Query;
import org.geotools.data.ows.HTTPClient;
import org.geotools.data.ows.HTTPResponse;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.wfs.TestHttpClient;
import org.geotools.data.wfs.TestHttpResponse;
import org.geotools.data.wfs.WFSDataStore;
import org.geotools.data.wfs.internal.WFSClient;
import org.geotools.data.wfs.internal.WFSConfig;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.NameImpl;
import org.geotools.filter.identity.FeatureIdImpl;
import org.geotools.ows.ServiceException;
import org.geotools.test.TestData;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.identity.FeatureId;
import org.xml.sax.SAXException;
public class TinyOwsTest {
private Name typeName = new NameImpl("http://www.tinyows.org/", "comuni_comuni11");
private WFSDataStore getWFSDataStore(HTTPClient httpClient) throws IOException, ServiceException {
URL capabilitiesUrl = new URL("http://127.0.0.1:8888/cgi-bin/tinyows?service=WFS&version=1.1.0&REQUEST=GetCapabilities");
WFSDataStore wfs = new WFSDataStore( new WFSClient(capabilitiesUrl, httpClient, WFSConfig.fromParams(Collections.EMPTY_MAP) ));
return wfs;
}
@Test
public void testGetCapabilities() throws Exception {
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient());
String types[] = wfs.getTypeNames();
assertEquals(1, types.length);
assertEquals(typeName.getLocalPart(), types[0]);
}
AtomicLong reqHandleSeq = new AtomicLong();
public String newRequestHandle() {
StringBuilder handle = new StringBuilder("GeoTools ").append(GeoTools.getVersion())
.append("(").append(GeoTools.getBuildRevision()).append(") WFS ")
.append("1.1.0").append(" DataStore @");
try {
handle.append(InetAddress.getLocalHost().getHostName());
} catch (Exception ignore) {
handle.append("<uknown host>");
}
handle.append('#').append(reqHandleSeq.incrementAndGet());
return handle.toString();
}
private void assertXMLEqual(String expectedXmlResource, String actualXml) throws IOException {
String control = IOUtils.toString(TestData.getResource(this, expectedXmlResource));
control = control.replace("${getfeature.handle}", newRequestHandle());
try {
XMLAssert.assertXMLEqual(control, actualXml);
} catch (SAXException e) {
e.printStackTrace();
throw new IOException(e);
}
}
@Test
public void testGetFirstFeatures() throws Exception {
final String queryXml = "<wfs:Query srsName=\"urn:ogc:def:crs:EPSG::3857\" typeName=\"comuni:comuni11\"/>";
//final String queryXml = "<wfs:Query srsName=\"urn:ogc:def:crs:EPSG::3857\" typeName=\"comuni_comuni11\"/>";
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (stringContains(request,
"<wfs:GetFeature",
"maxFeatures=\"20\"",
"resultType=\"hits\"",
queryXml))
{
assertXMLEqual("tinyows/CountFirstFeaturesRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/CountFirstFeatures.xml"), "text/xml");
}
else if (stringContains(request,
"<wfs:GetFeature",
"maxFeatures=\"20\"",
"resultType=\"results\"",
queryXml))
{
assertXMLEqual("tinyows/GetFirstFeaturesRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFirstFeatures.xml"), "text/xml");
} else {
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
Query query = new Query(typeName.getLocalPart(), Filter.INCLUDE, 20, Query.ALL_NAMES, "my query");
iterate(source.getFeatures(query), 20, true);
}
@Test
public void testGetFeatureByIncludeAndOperatorAndInclude() throws Exception {
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isResultsRequest(request,
"<wfs:GetFeature",
"maxFeatures=\"20\"",
"resultType=\"results\"",
"<ogc:PropertyIsGreaterThan")) {
assertXMLEqual("tinyows/GetFeatureIncludeAndPropertyGreaterThanAndIncludeRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFirstFeatures.xml"), "text/xml");
} else {
postContent.reset();
return super.post(url, postContent, postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Filter and = ff.and(
Arrays.asList(Filter.INCLUDE,
ff.greater(ff.property("gid"), ff.literal(0)),
Filter.INCLUDE));
Query query = new Query(typeName.getLocalPart(), and, 20, Query.ALL_NAMES, "my query");
iterate(source.getFeatures(query), 20, false);
}
@Test
public void testGetFeatureById() throws Exception {
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient());
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Set<FeatureId> fids = new HashSet<FeatureId>();
fids.add(new FeatureIdImpl("comuni11.2671"));
Query query = new Query(typeName.getLocalPart(), ff.id(fids));
iterate(source.getFeatures(query), 1, true);
}
@Test
public void testGetFeaturesByBBox() throws Exception {
final String[] queryTokens = { "<ogc:BBOX>",
"<ogc:PropertyName>the_geom</ogc:PropertyName>",
"<gml:Envelope srsDimension=\"2\" srsName=\"urn:x-ogc:def:crs:EPSG:3857\">",
"<gml:lowerCorner>4623055.0 815134.0</gml:lowerCorner>",
"<gml:upperCorner>4629904.0 820740.0</gml:upperCorner>" };
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isHitsRequest(request, queryTokens)) {
assertXMLEqual("tinyows/CountFeaturesByBBoxRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/CountFeaturesByBBox.xml"), "text/xml");
} else if (isResultsRequest(request, queryTokens)) {
assertXMLEqual("tinyows/GetFeaturesByBBoxRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeaturesByBBox.xml"), "text/xml");
} else {
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
SimpleFeature sf = getSampleSimpleFeature(source);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
PropertyName bboxProperty = ff.property(sf.getDefaultGeometryProperty().getName());
Query query = new Query(typeName.getLocalPart(), ff.bbox(bboxProperty, sf.getBounds()));
iterate(source.getFeatures(query), 6, true);
}
@Test
public void testGetFeaturesByIdAndBBox() throws Exception {
final String[] queryTokens = { "<ogc:BBOX>",
"<ogc:PropertyName>the_geom</ogc:PropertyName>",
"<gml:Envelope srsDimension=\"2\" srsName=\"urn:x-ogc:def:crs:EPSG:3857\">",
"<gml:lowerCorner>4623055.0 815134.0</gml:lowerCorner>",
"<gml:upperCorner>4629904.0 820740.0</gml:upperCorner>" };
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isResultsRequest(request, queryTokens)) {
assertXMLEqual("tinyows/GetFeaturesByBBoxRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeaturesByBBox.xml"), "text/xml");
} else {
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
SimpleFeature sf = getSampleSimpleFeature(source);
Set<FeatureId> fids = new HashSet<FeatureId>();
fids.add(new FeatureIdImpl("comuni11.2671"));
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
PropertyName bboxProperty = ff.property(sf.getDefaultGeometryProperty().getName());
Query query = new Query(typeName.getLocalPart(), ff.and(
ff.id(fids),
ff.bbox(bboxProperty, sf.getBounds())));
iterate(source.getFeatures(query), 1, false);
}
@Test
public void testGetFeaturesByBBoxAndId() throws Exception {
final String[] queryTokens = { "<ogc:BBOX>",
"<ogc:PropertyName>the_geom</ogc:PropertyName>",
"<gml:Envelope srsDimension=\"2\" srsName=\"urn:x-ogc:def:crs:EPSG:3857\">",
"<gml:lowerCorner>4623055.0 815134.0</gml:lowerCorner>",
"<gml:upperCorner>4629904.0 820740.0</gml:upperCorner>" };
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isResultsRequest(request, queryTokens)) {
assertXMLEqual("tinyows/GetFeaturesByBBoxRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeaturesByBBox.xml"), "text/xml");
} else {
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
SimpleFeature sf = getSampleSimpleFeature(source);
Set<FeatureId> fids = new HashSet<FeatureId>();
fids.add(new FeatureIdImpl("comuni11.2671"));
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
PropertyName bboxProperty = ff.property(sf.getDefaultGeometryProperty().getName());
Query query = new Query(typeName.getLocalPart(), ff.and(
ff.bbox(bboxProperty, sf.getBounds()),
ff.id(fids)));
iterate(source.getFeatures(query), 1, false);
}
@Test
public void testGetFeatures() throws Exception {
final String[] idQueryTokens = { "<ogc:FeatureId fid=\"comuni11.2671\"/>" };
final String[] bboxQueryTokens = { "<ogc:BBOX>",
"<ogc:PropertyName>the_geom</ogc:PropertyName>",
"<gml:Envelope srsDimension=\"2\" srsName=\"urn:x-ogc:def:crs:EPSG:3857\">",
"<gml:lowerCorner>4623055.0 815134.0</gml:lowerCorner>",
"<gml:upperCorner>4629904.0 820740.0</gml:upperCorner>" };
WFSDataStore wfs = getWFSDataStore(new TinyOwsMockHttpClient() {
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isHitsRequest(request, idQueryTokens)) {
return new TestHttpResponse(TestData.getResource(this, "tinyows/CountFeatureById.xml"), "text/xml");
} else if (isResultsRequest(request, idQueryTokens)) {
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeatureById.xml"), "text/xml");
} else if (isResultsRequest(request, bboxQueryTokens)) {
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeaturesByBBox.xml"), "text/xml");
} else {
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
});
SimpleFeatureSource source = wfs.getFeatureSource(typeName);
SimpleFeature sf = getSampleSimpleFeature(source);
Set<FeatureId> fids = new HashSet<FeatureId>();
fids.add(new FeatureIdImpl("comuni11.2671"));
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
PropertyName bboxProperty = ff.property(sf.getDefaultGeometryProperty().getName());
Query query = new Query(typeName.getLocalPart(), ff.and(
ff.greater(ff.property("cod_reg"), ff.literal(0)),
ff.and(
ff.bbox(bboxProperty, sf.getBounds()),
ff.id(fids))));
iterate(source.getFeatures(query), 1, true);
//disabled for now: not compliant
/*query = new Query(typeName, ff.and(
ff.bbox(bboxProperty, sf.getBounds()),
ff.or(
ff.bbox(bboxProperty, sf.getBounds()),
ff.id(fids))));
iterate(source.getFeatures(query), 6, true);*/
}
private SimpleFeature getSampleSimpleFeature(SimpleFeatureSource source) throws IOException {
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Set<FeatureId> fids = new HashSet<FeatureId>();
fids.add(new FeatureIdImpl("comuni11.2671"));
Query query = new Query(typeName.getLocalPart(), ff.id(fids));
SimpleFeatureIterator reader = source.getFeatures(query).features();
try {
return reader.next();
} finally {
reader.close();
}
}
private boolean isHitsRequest(String text, String ... tokens) {
return stringContains(text,
"<wfs:GetFeature",
"resultType=\"hits\"",
"<wfs:Query srsName=\"urn:ogc:def:crs:EPSG::3857\" typeName=\"comuni:comuni11\"") &&
stringContains(text, tokens);
}
private boolean isResultsRequest(String text, String ... tokens) {
return stringContains(text,
"<wfs:GetFeature",
"resultType=\"results\"",
"<wfs:Query srsName=\"urn:ogc:def:crs:EPSG::3857\" typeName=\"comuni:comuni11\"") &&
stringContains(text, tokens);
}
private boolean isDescribeFeatureRequest(String text) {
return stringContains(text, "<wfs:DescribeFeatureType");
}
private boolean stringContains(String text, String ... tokens) {
for (String token : tokens) {
if (!text.contains(token)) {
return false;
}
}
return true;
}
private static SimpleFeature iterate(SimpleFeatureCollection features, int expectedSize, boolean getSize) {
int size = -1;
if (getSize) {
size = features.size();
if (size > -1) {
assertEquals(expectedSize, size);
}
}
size = 0;
SimpleFeatureIterator reader = features.features();
SimpleFeature sf = null;
try {
while (reader.hasNext()) {
if (sf == null) {
sf = reader.next();
} else {
reader.next().getIdentifier();
}
size++;
}
} finally {
reader.close();
}
assertEquals(expectedSize, size);
return sf;
}
class TinyOwsMockHttpClient extends TestHttpClient {
@Override
public HTTPResponse get(URL url) throws IOException {
if (url.getQuery().contains("REQUEST=GetCapabilities")) {
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetCapabilities.xml"), "text/xml");
} else {
return super.get(url);
}
}
@Override
public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException {
String query = "<ogc:FeatureId fid=\"comuni11.2671\"/>";
String request = new String(IOUtils.toByteArray(postContent), "UTF-8");
if (isHitsRequest(request, query))
{
assertXMLEqual("tinyows/CountFeatureByIdRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/CountFeatureById.xml"), "text/xml");
}
else if (isResultsRequest(request, query))
{
assertXMLEqual("tinyows/GetFeatureByIdRequest.xml", request);
return new TestHttpResponse(TestData.getResource(this, "tinyows/GetFeatureById.xml"), "text/xml");
}
else if (isDescribeFeatureRequest(request))
{
return new TestHttpResponse(TestData.getResource(this, "tinyows/DescribeFeatureType.xsd"), "text/xml");
}
else
{
return super.post(url, new ByteArrayInputStream(request.getBytes("UTF-8")), postContentType);
}
}
}
}