package org.geomajas.gwt2.plugin.wfs.server.command; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import junit.framework.Assert; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.geomajas.geometry.Bbox; import org.geomajas.geometry.Coordinate; import org.geomajas.geometry.Geometry; import org.geomajas.geometry.service.BboxService; import org.geomajas.geometry.service.GeometryService; import org.geomajas.geometry.service.WktService; import org.geomajas.global.GeomajasException; import org.geomajas.gwt2.client.map.attribute.AttributeDescriptorImpl; import org.geomajas.gwt2.client.map.attribute.GeometryAttributeTypeImpl; import org.geomajas.gwt2.client.map.attribute.GeometryType; import org.geomajas.gwt2.client.map.attribute.PrimitiveAttributeTypeImpl; import org.geomajas.gwt2.client.map.attribute.PrimitiveType; import org.geomajas.gwt2.client.map.feature.query.Criterion; import org.geomajas.gwt2.plugin.wfs.server.command.dto.WfsGetFeatureRequest; import org.geomajas.gwt2.plugin.wfs.server.command.dto.WfsGetFeatureResponse; import org.geomajas.gwt2.plugin.wfs.server.dto.WfsVersionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.AttributeCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.BboxCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.DWithinCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.DoubleAttributeCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.FidCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.FullTextCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.GeometryCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.IntegerAttributeCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.LogicalCriterionDto; import org.geomajas.gwt2.plugin.wfs.server.dto.query.StringAttributeCriterionDto; import org.geomajas.layer.feature.Feature; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureSource; import org.geotools.data.Query; import org.geotools.data.collection.CollectionFeatureSource; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.filter.text.ecql.ECQL; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.opengis.feature.Property; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.io.WKTReader; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/org/geomajas/spring/geomajasContext.xml", "commandContext.xml" }) public class WfsGetFeatureCommandTest { private static final String WFS_BASE_URL = "http://apps.geomajas.org/geoserver/demo_world/ows?version=1.1.0"; private static final String LAYER = "demo_world:simplified_country_borders"; private Server server; @Autowired private WfsGetFeatureCommand command; private WfsServlet servlet; private SimpleFeatureSource featureSource; private SimpleFeature f1; private SimpleFeature f2; private SimpleFeature f3; private int port; @Before public void before() throws Exception { server = new Server(0); servlet = new WfsServlet(); ServletContextHandler servletContextHandler = new ServletContextHandler(); servletContextHandler.setContextPath("/"); servletContextHandler.addServlet(new ServletHolder(servlet),"/wfs/*"); server.setHandler(servletContextHandler); server.start(); port = server.getConnectors()[0].getLocalPort(); servlet.setPort(port); StringBuilder sb = new StringBuilder(); sb.append("myGeom:Point,"); sb.append("myInt:Integer,"); sb.append("myDouble:Double,"); sb.append("myDate:Date,"); sb.append("myBigDecimal:java.math.BigDecimal,"); sb.append("myString:String,"); sb.append("anotherString:String"); SimpleFeatureType schema = DataUtilities.createType("testdata", sb.toString()); f1 = DataUtilities.createFeature(schema, "fid1=POINT(1 1)|1|1.0|2014-01-01 02:24:56am|11111111.1111|a|cef"); f2 = DataUtilities.createFeature(schema, "fid2=POINT(2 2)|2|2.0|2014-02-02 02:24:56am|22222222.2222|aa|ceef"); f3 = DataUtilities.createFeature(schema, "fid3=POINT(3 3)|3|3.0|2014-03-03 02:24:56am|33333333.3333|ab|c"); featureSource = new CollectionFeatureSource(DataUtilities.collection(new SimpleFeature[] { f1, f2, f3 })); } @Test public void integrationTest() throws Exception { WfsGetFeatureRequest request = new WfsGetFeatureRequest(); request.setBaseUrl("http://127.0.0.1:"+port+"/wfs"); request.setTypeName("dov-pub-bodem:Bodemassociatiekaart"); request.setCriterion(new FidCriterionDto(new String[] { "Bodemassociatiekaart.1", "Bodemassociatiekaart.2" })); request.setCrs("EPSG:31370"); WfsGetFeatureResponse response = new WfsGetFeatureResponse(); command.execute(request, response); Assert.assertEquals(2, response.getFeatureCollection().size()); Assert.assertNotNull(servlet.getLastFilter()); Assert.assertEquals(ECQL.toFilter("IN('Bodemassociatiekaart.1', 'Bodemassociatiekaart.2')"), servlet.getLastFilter()); } @Test public void testGetCountries() throws Exception { WfsGetFeatureResponse response = command.getEmptyCommandResponse(); Assert.assertNotNull(response); Bbox bounds = new Bbox(-180, -90, 360, 180); Geometry geometry = GeometryService.toPolygon(bounds); WfsGetFeatureRequest request = new WfsGetFeatureRequest(); request.setBaseUrl(WFS_BASE_URL); request.setTypeName(LAYER); request.setCriterion(new GeometryCriterionDto("the_geom",GeometryCriterionDto.INTERSECTS,geometry)); request.setCrs("EPSG:4326"); request.setMaxCoordsPerFeature(100); request.setMaxFeatures(100); command.execute(request, response); Assert.assertNotNull(response.getFeatureCollection()); Assert.assertTrue(response.getFeatureCollection().getFeatures().size() > 0); } @Test public void EQCriterion() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", "=", new Integer(1)), 3, 0, null); Assert.assertEquals(1, ff.size()); assertEquals(f1, ff.get(0)); } @Test public void LTCriterion() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", "<", new Integer(3)), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f1, ff.get(0)); assertEquals(f2, ff.get(1)); } @Test public void GTCriterion() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", ">", new Integer(1)), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f2, ff.get(0)); assertEquals(f3, ff.get(1)); } @Test public void LTEQCriterion() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", "<=", new Integer(2)), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f1, ff.get(0)); assertEquals(f2, ff.get(1)); } @Test public void GTEQCriterion() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", ">=", new Integer(2)), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f2, ff.get(0)); assertEquals(f3, ff.get(1)); } @Test public void LikeCriterion() throws Exception { // single char List<Feature> ff = queryFeatures(featureSource, new StringAttributeCriterionDto("myString", "like", "a?"), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f2, ff.get(0)); assertEquals(f3, ff.get(1)); // wildcard ff = queryFeatures(featureSource, new StringAttributeCriterionDto("myString", "like", "*a"), 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f1, ff.get(0)); assertEquals(f2, ff.get(1)); // exact ff = queryFeatures(featureSource, new StringAttributeCriterionDto("myString", "like", "ab"), 3, 0, null); Assert.assertEquals(1, ff.size()); assertEquals(f3, ff.get(0)); // case insensitive (if supported by the datastore, but WFS 1.0.0 does not support it !!!) ff = queryFeatures(featureSource, new StringAttributeCriterionDto("myString", "like", "AB"), 3, 0, null); Assert.assertEquals(1, ff.size()); assertEquals(f3, ff.get(0)); } @Test public void FullTextCriterion() throws Exception { // a List<Feature> ff = queryFeatures(featureSource, new FullTextCriterionDto("a"), 3, 0, null); Assert.assertEquals(3, ff.size()); // aa ff = queryFeatures(featureSource, new FullTextCriterionDto("aa"), 3, 0, null); Assert.assertEquals(1, ff.size()); // e ff = queryFeatures(featureSource, new FullTextCriterionDto("e"), 3, 0, null); Assert.assertEquals(2, ff.size()); // ee ff = queryFeatures(featureSource, new FullTextCriterionDto("ee"), 3, 0, null); Assert.assertEquals(1, ff.size()); } @Test public void AndCriterion() throws Exception { AttributeCriterionDto attr1 = new IntegerAttributeCriterionDto("myInt", "<=", new Integer(2)); AttributeCriterionDto attr2 = new DoubleAttributeCriterionDto("myDouble", ">", new Double(1.5)); LogicalCriterionDto and = new LogicalCriterionDto(LogicalCriterionDto.Operator.AND); and.getChildren().add(attr1); and.getChildren().add(attr2); List<Feature> ff = queryFeatures(featureSource, and, 3, 0, null); Assert.assertEquals(1, ff.size()); assertEquals(f2, ff.get(0)); } @Test public void OrCriterion() throws Exception { AttributeCriterionDto attr1 = new IntegerAttributeCriterionDto("myInt", "<=", new Integer(2)); AttributeCriterionDto attr2 = new DoubleAttributeCriterionDto("myDouble", ">", new Double(1.5)); LogicalCriterionDto or = new LogicalCriterionDto(LogicalCriterionDto.Operator.OR); or.getChildren().add(attr1); or.getChildren().add(attr2); List<Feature> ff = queryFeatures(featureSource, or, 3, 0, null); Assert.assertEquals(3, ff.size()); assertEquals(f1, ff.get(0)); assertEquals(f2, ff.get(1)); assertEquals(f3, ff.get(2)); } @Test public void BboxCriterion() throws Exception { BboxCriterionDto c = new BboxCriterionDto(new Bbox(0, 0, 1.5, 1.5)); List<Feature> ff = queryFeatures(featureSource, c, 3, 0, null); Assert.assertEquals(1, ff.size()); assertEquals(f1, ff.get(0)); } @Test public void DWithinCriterion() throws Exception { Geometry distancePoint = new Geometry(Geometry.POINT, 0, 5); distancePoint.setCoordinates(new Coordinate[] {new Coordinate(1.5, 1.5)}); DWithinCriterionDto c = new DWithinCriterionDto(0.71, "", distancePoint); List<Feature> ff = queryFeatures(featureSource, c, 3, 0, null); Assert.assertEquals(2, ff.size()); assertEquals(f1, ff.get(0)); assertEquals(f2, ff.get(1)); } @Test public void totalBounds() throws Exception { List<Feature> ff = queryFeatures(featureSource, new IntegerAttributeCriterionDto("myInt", "<", new Integer(100)), 3, 0, null); Assert.assertEquals(3, ff.size()); Bbox bounds = command.getTotalBounds(ff); Assert.assertTrue(BboxService.equals(bounds, new Bbox(1, 1, 2, 2), 0.001)); } protected List<Feature> queryFeatures(FeatureSource<SimpleFeatureType, SimpleFeature> source, Criterion criterion, int maxFeatures, int startIndex, List<String> attributeNames) throws IOException, GeomajasException { List<org.geomajas.gwt2.client.map.attribute.AttributeDescriptor> descriptors = new ArrayList<org.geomajas.gwt2.client.map.attribute.AttributeDescriptor>(); for (AttributeDescriptor attributeDescriptor : featureSource.getSchema() .getAttributeDescriptors()) { descriptors.add(createDescriptor(attributeDescriptor)); } Query query = command.createQuery(source.getName().getLocalPart(), descriptors, criterion, maxFeatures, startIndex, attributeNames, "EPSG:4326"); return command.convertFeatures(featureSource.getFeatures(query), 1000, 100); } public void assertEquals(SimpleFeature feature, Feature dto) { for (Property prop : feature.getProperties()) { String name = prop.getName().getLocalPart(); if (name != feature.getDefaultGeometryProperty().getName().getLocalPart()) { Object value = prop.getValue(); Object dtoValue = dto.getAttributes().get(name).getValue(); if (value != null) { if (value instanceof Double) { Assert.assertEquals((Double) value, (Double) dtoValue, 0.0001); } else if (value instanceof BigDecimal) { // big decimal is handled as double (probably because Geomajas does not have primitive type for it ?) Assert.assertEquals(((BigDecimal) value).doubleValue(), (Double) dtoValue, 0.0001); } else { Assert.assertEquals(value, dtoValue); } } else { Assert.assertNull(dtoValue); } } else { Object value = prop.getValue(); Object dtoValue = dto.getGeometry(); if (value != null) { WKTReader reader = new WKTReader(); try { com.vividsolutions.jts.geom.Geometry other = reader.read(WktService.toWkt((Geometry) dtoValue)); Assert.assertTrue("geometries differ", other.equalsExact((com.vividsolutions.jts.geom.Geometry) value, 0.0001)); } catch (Exception e) { Assert.fail(); } } else { Assert.assertNull(dtoValue); } } } } private org.geomajas.gwt2.client.map.attribute.AttributeDescriptor createDescriptor( AttributeDescriptor attributeDescriptor) throws IOException { Class<?> binding = attributeDescriptor.getType().getBinding(); if (binding == null) { throw new IOException("No attribute binding found..."); } String name = attributeDescriptor.getLocalName(); AttributeDescriptorImpl attributeInfo; if (Integer.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.INTEGER), name); } else if (Float.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.FLOAT), name); } else if (Double.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.DOUBLE), name); } else if (BigDecimal.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.DOUBLE), name); } else if (Boolean.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.BOOLEAN), name); } else if (Date.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.DATE), name); } else if (Point.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.POINT), name); } else if (LineString.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.LINESTRING), name); } else if (LinearRing.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.LINEARRING), name); } else if (Polygon.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.POLYGON), name); } else if (MultiPoint.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.MULTIPOINT), name); } else if (MultiLineString.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.MULTILINESTRING), name); } else if (MultiPolygon.class.equals(binding)) { attributeInfo = new AttributeDescriptorImpl( new GeometryAttributeTypeImpl(GeometryType.MULTIPOLYGON), name); } else { attributeInfo = new AttributeDescriptorImpl( new PrimitiveAttributeTypeImpl(PrimitiveType.STRING), name); } return attributeInfo; } @After public void after() throws Exception { server.stop(); } }