/* * Copyright (c) 2001 - 2009 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.regex.Pattern; import junit.framework.Test; import org.geotools.data.complex.AppSchemaDataAccess; import org.geotools.wfs.v1_1.WFS; import org.w3c.dom.Document; /** * WFS GetFeature to test integration of {@link AppSchemaDataAccess} with GeoServer. * * @author Ben Caradoc-Davies, CSIRO Exploration and Mining * @author Rini Angreani, Curtin University of Technology */ public class FeatureChainingWfsTest extends AbstractAppSchemaWfsTestSupport { /** * Pattern to match namespace/schemaLocation pair for WFS 1.1 schema. * * <p> * * Use of pattern is to support matching any port number on localhost (can't assume it is alwats * port 80).. */ private static final String DEFAULT_WFS_SCHEMALOCATION = Pattern.quote(WFS.NAMESPACE) + " " + Pattern.quote("http://localhost:") + "\\d+" + Pattern.quote("/geoserver/schemas/wfs/1.1.0/wfs.xsd"); /** * Read-only test so can use one-time setup. * * @return */ public static Test suite() { return new OneTimeTestSetup(new FeatureChainingWfsTest()); } @Override protected NamespaceTestData buildTestData() { return new FeatureChainingMockData(); } /** * Test whether GetCapabilities returns wfs:WFS_Capabilities. */ public void testGetCapabilities() { Document doc = getAsDOM("wfs?request=GetCapabilities"); LOGGER.info("WFS GetCapabilities response:\n" + prettyString(doc)); assertEquals("wfs:WFS_Capabilities", doc.getDocumentElement().getNodeName()); // make sure non-feature types don't appear in FeatureTypeList assertXpathCount(5, "//wfs:FeatureType", doc); ArrayList<String> featureTypeNames = new ArrayList<String>(4); featureTypeNames.add(evaluate("//wfs:FeatureType[1]/wfs:Name", doc)); featureTypeNames.add(evaluate("//wfs:FeatureType[2]/wfs:Name", doc)); featureTypeNames.add(evaluate("//wfs:FeatureType[3]/wfs:Name", doc)); featureTypeNames.add(evaluate("//wfs:FeatureType[4]/wfs:Name", doc)); featureTypeNames.add(evaluate("//wfs:FeatureType[5]/wfs:Name", doc)); // Mapped Feture assertTrue(featureTypeNames.contains("gsml:MappedFeature")); // Geologic Unit assertTrue(featureTypeNames.contains("gsml:GeologicUnit")); // FirstParentFeature assertTrue(featureTypeNames.contains("ex:FirstParentFeature")); // SecondParentFeature assertTrue(featureTypeNames.contains("ex:SecondParentFeature")); // om:Observation assertTrue(featureTypeNames.contains("om:Observation")); } /** * Test whether DescribeFeatureType returns xsd:schema, and if the contents are correct. When no * type name specified, it should return imports for all name spaces involved. If type name is * specified, it should return imports of GML type and the type's top level schema. * * @throws IOException */ public void testDescribeFeatureType() throws IOException { File dataDir = this.getTestData().getDataDirectoryRoot(); /** * gsml:MappedFeature */ Document doc = getAsDOM("wfs?request=DescribeFeatureType&typename=gsml:MappedFeature"); LOGGER.info("WFS DescribeFeatureType, typename=gsml:MappedFeature response:\n" + prettyString(doc)); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); // check target name space is encoded and is correct assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_URI, "//@targetNamespace", doc); // make sure the content is only relevant include assertXpathCount(1, "//xsd:include", doc); // no import to GML since it's already imported inside the included schema // otherwise it's invalid to import twice assertXpathCount(0, "//xsd:import", doc); // GSML schemaLocation assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_SCHEMA_LOCATION_URL, "//xsd:include/@schemaLocation", doc); // nothing else assertXpathCount(0, "//xsd:complexType", doc); assertXpathCount(0, "//xsd:element", doc); /** * gsml:GeologicUnit */ doc = getAsDOM("wfs?request=DescribeFeatureType&typename=gsml:GeologicUnit"); LOGGER.info("WFS DescribeFeatureType, typename=gsml:GeologicUnit response:\n" + prettyString(doc)); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_URI, "//@targetNamespace", doc); assertXpathCount(1, "//xsd:include", doc); assertXpathCount(0, "//xsd:import", doc); // GSML schemaLocation assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_SCHEMA_LOCATION_URL, "//xsd:include/@schemaLocation", doc); // nothing else assertXpathCount(0, "//xsd:complexType", doc); assertXpathCount(0, "//xsd:element", doc); /** * ex:FirstParentFeature and ex:SecondParentFeature */ doc = getAsDOM("wfs?request=DescribeFeatureType&typeName=ex:FirstParentFeature,ex:SecondParentFeature"); LOGGER.info("WFS DescribeFeatureType, typename=ex:FirstParentFeature," + "ex:SecondParentFeature response:\n" + prettyString(doc)); assertXpathEvaluatesTo(FeatureChainingMockData.EX_URI, "//@targetNamespace", doc); assertXpathCount(1, "//xsd:include", doc); assertXpathCount(0, "//xsd:import", doc); // EX include File exSchema = findFile("featureTypes/ex_FirstParentFeature/simpleContent.xsd", dataDir); assertNotNull(exSchema); assertTrue(exSchema.exists()); String exSchemaLocation = exSchema.toURI().toString(); assertXpathEvaluatesTo(exSchemaLocation, "//xsd:include/@schemaLocation", doc); // nothing else assertXpathCount(0, "//xsd:complexType", doc); assertXpathCount(0, "//xsd:element", doc); /** * Mixed name spaces */ doc = getAsDOM("wfs?request=DescribeFeatureType&typeName=gsml:MappedFeature,ex:FirstParentFeature"); LOGGER .info("WFS DescribeFeatureType, typename=gsml:MappedFeature,ex:FirstParentFeature response:\n" + prettyString(doc)); testDescribeFeatureTypeImports(doc, exSchemaLocation); /** * All type names specified, should result the same as above */ doc = getAsDOM("wfs?request=DescribeFeatureType&typeName=gsml:MappedFeature,gsml:GeologicUnit,ex:FirstParentFeature,ex:SecondParentFeature"); LOGGER .info("WFS DescribeFeatureType, typename=gsml:MappedFeature,gsml:GeologicUnit,ex:FirstParentFeature,ex:SecondParentFeature response:\n" + prettyString(doc)); testDescribeFeatureTypeImports(doc, exSchemaLocation); /** * No type name specified, should result the same as all type names */ doc = getAsDOM("wfs?request=DescribeFeatureType"); LOGGER.info("WFS DescribeFeatureType response:\n" + prettyString(doc)); // FIXME: disabled as workaround for GEOS-3722 // testDescribeFeatureTypeImports(doc, exSchemaLocation); } private void testDescribeFeatureTypeImports(Document doc, String exSchemaLocation) { assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); assertXpathCount(0, "//@targetNamespace", doc); assertXpathCount(2, "//xsd:import", doc); assertXpathCount(0, "//xsd:include", doc); // order is unimportant, and could change, so we don't test the order String firstNamespace = evaluate("//xsd:import[1]/@namespace", doc); if (firstNamespace.equals(AbstractAppSchemaMockData.GSML_URI)) { // GSML import assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_SCHEMA_LOCATION_URL, "//xsd:import[1]/@schemaLocation", doc); // EX import assertXpathEvaluatesTo(FeatureChainingMockData.EX_URI, "//xsd:import[2]/@namespace", doc); assertXpathEvaluatesTo(exSchemaLocation, "//xsd:import[2]/@schemaLocation", doc); } else { // EX import assertXpathEvaluatesTo(FeatureChainingMockData.EX_URI, "//xsd:import[1]/@namespace", doc); assertXpathEvaluatesTo(exSchemaLocation, "//xsd:import[1]/@schemaLocation", doc); // GSML import assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_URI, "//xsd:import[2]/@namespace", doc); assertXpathEvaluatesTo(AbstractAppSchemaMockData.GSML_SCHEMA_LOCATION_URL, "//xsd:import[2]/@schemaLocation", doc); } // nothing else assertXpathCount(0, "//xsd:complexType", doc); assertXpathCount(0, "//xsd:element", doc); } /** * Test whether GetFeature returns wfs:FeatureCollection. */ public void testGetFeature() { Document doc = getAsDOM("wfs?request=GetFeature&typename=gsml:MappedFeature"); LOGGER.info("WFS GetFeature&typename=gsml:MappedFeature response:\n" + prettyString(doc)); assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName()); // non-feature type should return nothing/exception doc = getAsDOM("wfs?request=GetFeature&typename=gsml:CompositionPart"); LOGGER.info("WFS GetFeature&typename=gsml:CompositionPart response, exception expected:\n" + prettyString(doc)); assertEquals("ows:ExceptionReport", doc.getDocumentElement().getNodeName()); } /** * Test nesting features of complex types with simple content. Previously the nested features * attributes weren't encoded, so this is to ensure that this works. This also tests that a * feature type can have multiple FEATURE_LINK to be referred by different types. */ public void testComplexTypeWithSimpleContent() { Document doc = getAsDOM("wfs?request=GetFeature&typename=ex:FirstParentFeature"); LOGGER .info("WFS GetFeature&typename=ex:FirstParentFeature response:\n" + prettyString(doc)); assertXpathCount(2, "//ex:FirstParentFeature", doc); // 1 assertXpathCount(2, "//ex:FirstParentFeature[@gml:id='1']/ex:nestedFeature", doc); assertXpathEvaluatesTo( "string_one", "//ex:FirstParentFeature[@gml:id='1']/ex:nestedFeature[1]/ex:SimpleContent/ex:someAttribute", doc); assertXpathEvaluatesTo( "string_two", "//ex:FirstParentFeature[@gml:id='1']/ex:nestedFeature[2]/ex:SimpleContent/ex:someAttribute", doc); assertXpathCount( 0, "//ex:FirstParentFeature[@gml:id='1']/ex:nestedFeature[2]/ex:SimpleContent/FEATURE_LINK", doc); // 2 assertXpathCount(0, "//ex:FirstParentFeature[@gml:id='2']/ex:nestedFeature", doc); doc = getAsDOM("wfs?request=GetFeature&typename=ex:SecondParentFeature"); LOGGER.info("WFS GetFeature&typename=ex:SecondParentFeature response:\n" + prettyString(doc)); assertXpathCount(2, "//ex:SecondParentFeature", doc); // 1 assertXpathCount(0, "//ex:SecondParentFeature[@gml:id='1']/ex:nestedFeature", doc); // 2 assertXpathCount(3, "//ex:SecondParentFeature[@gml:id='2']/ex:nestedFeature", doc); assertXpathEvaluatesTo( "string_one", "//ex:SecondParentFeature[@gml:id='2']/ex:nestedFeature[1]/ex:SimpleContent/ex:someAttribute", doc); assertXpathEvaluatesTo( "string_two", "//ex:SecondParentFeature[@gml:id='2']/ex:nestedFeature[2]/ex:SimpleContent/ex:someAttribute", doc); assertXpathEvaluatesTo( "string_three", "//ex:SecondParentFeature[@gml:id='2']/ex:nestedFeature[3]/ex:SimpleContent/ex:someAttribute", doc); } /** * Test content of GetFeature response. */ public void testGetFeatureContent() throws Exception { Document doc = getAsDOM("wfs?request=GetFeature&typename=gsml:MappedFeature"); LOGGER.info("WFS GetFeature&typename=gsml:MappedFeature response:\n" + prettyString(doc)); assertXpathEvaluatesTo("4", "/wfs:FeatureCollection/@numberOfFeatures", doc); assertXpathCount(4, "//gsml:MappedFeature", doc); String schemaLocation = evaluate("/wfs:FeatureCollection/@xsi:schemaLocation", doc); String gsmlLocation = AbstractAppSchemaMockData.GSML_URI + " " + AbstractAppSchemaMockData.GSML_SCHEMA_LOCATION_URL; if (schemaLocation.startsWith(AbstractAppSchemaMockData.GSML_URI)) { // GSML schema location was encoded first assertTrue(Pattern.matches(Pattern.quote(gsmlLocation) + " " + DEFAULT_WFS_SCHEMALOCATION, schemaLocation)); } else { // WFS schema location was encoded first assertTrue(Pattern.matches(DEFAULT_WFS_SCHEMALOCATION + " " + Pattern.quote(gsmlLocation), schemaLocation)); } // mf1 { String id = "mf1"; assertXpathEvaluatesTo(id, "//gsml:MappedFeature[1]/@gml:id", doc); assertXpathEvaluatesTo("GUNTHORPE FORMATION", "//gsml:MappedFeature[@gml:id='" + id + "']/gml:name", doc); assertXpathEvaluatesTo("-1.2 52.5 -1.2 52.6 -1.1 52.6 -1.1 52.5 -1.2 52.5", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:shape//gml:posList", doc); // specification gu.25699 assertXpathEvaluatesTo("gu.25699", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/@gml:id", doc); // description assertXpathEvaluatesTo("Olivine basalt, tuff, microgabbro, minor sedimentary rocks", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:description", doc); // name assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name", doc); assertXpathEvaluatesTo("Yaugher Volcanic Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name[@codeSpace='urn:ietf:rfc:2141']", doc); assertXpathEvaluatesTo("Yaugher Volcanic Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]", doc); assertXpathEvaluatesTo("urn:ietf:rfc:2141", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]/@codeSpace", doc); assertXpathEvaluatesTo("-Py", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[2]", doc); // feature link shouldn't appear as it's not in the schema assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/FEATURE_LINK", doc); // occurence [sic] assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence", doc); assertXpathEvaluatesTo("", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[1]", doc); assertXpathEvaluatesTo("urn:cgi:feature:MappedFeature:mf1", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence/@xlink:href", doc); // exposureColor assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:exposureColor", doc); assertXpathEvaluatesTo("Blue", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("some:uri", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor/gsml:CGI_TermValue/gsml:value/@codeSpace", doc); // feature link shouldn't appear as it's not in the schema assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // outcropCharacter assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:outcropCharacter", doc); assertXpathEvaluatesTo("x", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter" + "/gsml:CGI_TermValue/gsml:value", doc); // feature link shouldn't appear as it's not in the schema assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // composition assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition", doc); assertXpathEvaluatesTo("significant", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:proportion/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("interbedded component", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:role", doc); // feature link shouldn't appear as it's not in the schema assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:role/FEATURE_LINK", doc); // lithology assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition/gsml:CompositionPart/gsml:lithology", doc); // feature link shouldn't appear as it's not in the schema assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:lithology/FEATURE_LINK", doc); } // mf2 { String id = "mf2"; assertXpathEvaluatesTo(id, "//gsml:MappedFeature[2]/@gml:id", doc); assertXpathEvaluatesTo("MERCIA MUDSTONE GROUP", "//gsml:MappedFeature[@gml:id='" + id + "']/gml:name", doc); assertXpathEvaluatesTo("-1.3 52.5 -1.3 52.6 -1.2 52.6 -1.2 52.5 -1.3 52.5", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:shape//gml:posList", doc); // gu.25678 assertXpathEvaluatesTo("gu.25678", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/@gml:id", doc); // name assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name", doc); assertXpathEvaluatesTo("Yaugher Volcanic Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name[@codeSpace='urn:ietf:rfc:2141']", doc); assertXpathEvaluatesTo("Yaugher Volcanic Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]", doc); assertXpathEvaluatesTo("urn:ietf:rfc:2141", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]/@codeSpace", doc); assertXpathEvaluatesTo("-Py", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[2]", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/FEATURE_LINK", doc); // occurence [sic] assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence", doc); assertXpathEvaluatesTo("", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[1]", doc); assertXpathEvaluatesTo("urn:cgi:feature:MappedFeature:mf2", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[1]/@xlink:href", doc); assertXpathEvaluatesTo("", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[2]", doc); assertXpathEvaluatesTo("urn:cgi:feature:MappedFeature:mf3", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[2]/@xlink:href", doc); // description assertXpathEvaluatesTo("Olivine basalt, tuff, microgabbro, minor sedimentary rocks", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:description", doc); // exposureColor assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:exposureColor", doc); assertXpathEvaluatesTo("Yellow", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor[1]" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("some:uri", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor[1]/gsml:CGI_TermValue/gsml:value/@codeSpace", doc); assertXpathEvaluatesTo("Blue", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor[2]" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("some:uri", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor[2]/gsml:CGI_TermValue/gsml:value/@codeSpace", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // outcropCharacter assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:outcropCharacter", doc); assertXpathEvaluatesTo("y", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter[1]" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("x", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter[2]" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // composition assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition", doc); assertXpathEvaluatesTo("significant", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition[1]" + "/gsml:CompositionPart/gsml:proportion/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("interbedded component", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit[@gml:id='gu.25678']/gsml:composition[1]" + "/gsml:CompositionPart/gsml:role", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition[1]" + "/gsml:CompositionPart/gsml:role/FEATURE_LINK", doc); assertXpathEvaluatesTo("minor", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition[2]" + "/gsml:CompositionPart/gsml:proportion/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("interbedded component", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition[2]" + "/gsml:CompositionPart/gsml:role", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition[2]" + "/gsml:CompositionPart/gsml:role/FEATURE_LINK", doc); // lithology assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition/gsml:CompositionPart/gsml:lithology", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:lithology/FEATURE_LINK", doc); } // mf3 { String id = "mf3"; assertXpathEvaluatesTo(id, "//gsml:MappedFeature[3]/@gml:id", doc); assertXpathEvaluatesTo("CLIFTON FORMATION", "//gsml:MappedFeature[@gml:id='" + id + "']/gml:name", doc); assertXpathEvaluatesTo("-1.2 52.5 -1.2 52.6 -1.1 52.6 -1.1 52.5 -1.2 52.5", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:shape//gml:posList", doc); // gu.25678 assertXpathEvaluatesTo("#gu.25678", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/@xlink:href", doc); // make sure nothing else is encoded assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name", doc); } // mf4 { String id = "mf4"; assertXpathEvaluatesTo(id, "//gsml:MappedFeature[4]/@gml:id", doc); assertXpathEvaluatesTo("MURRADUC BASALT", "//gsml:MappedFeature[@gml:id='" + id + "']/gml:name", doc); assertXpathEvaluatesTo("-1.3 52.5 -1.3 52.6 -1.2 52.6 -1.2 52.5 -1.3 52.5", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:shape//gml:posList", doc); // gu.25682 assertXpathEvaluatesTo("gu.25682", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/@gml:id", doc); // description assertXpathEvaluatesTo("Olivine basalt", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:description", doc); // name assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name", doc); assertXpathEvaluatesTo("New Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gml:name[@codeSpace='urn:ietf:rfc:2141']", doc); assertXpathEvaluatesTo("New Group", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]", doc); assertXpathEvaluatesTo("urn:ietf:rfc:2141", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[1]/@codeSpace", doc); assertXpathEvaluatesTo("-Xy", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gml:name[2]", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/FEATURE_LINK", doc); // occurence [sic] assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence", doc); assertXpathEvaluatesTo("", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence[1]", doc); assertXpathEvaluatesTo("urn:cgi:feature:MappedFeature:mf4", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:occurence/@xlink:href", doc); // exposureColor assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:exposureColor", doc); assertXpathEvaluatesTo("some:uri", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor/gsml:CGI_TermValue/gsml:value/@codeSpace", doc); assertXpathEvaluatesTo("Red", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:exposureColor" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // outcropCharacter assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:outcropCharacter", doc); assertXpathEvaluatesTo("z", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter" + "/gsml:CGI_TermValue/gsml:value", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:outcropCharacter" + "/gsml:CGI_TermValue/FEATURE_LINK", doc); // composition assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition", doc); assertXpathEvaluatesTo("significant", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:proportion/gsml:CGI_TermValue/gsml:value", doc); assertXpathEvaluatesTo("interbedded component", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:role", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:role/FEATURE_LINK", doc); // lithology assertXpathCount(2, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition/gsml:CompositionPart/gsml:lithology", doc); assertXpathCount(3, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition/gsml:CompositionPart/gsml:lithology[1]" + "/gsml:ControlledConcept/gml:name", doc); assertXpathEvaluatesTo("name_a", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit" + "/gsml:composition/gsml:CompositionPart/gsml:lithology[1]" + "/gsml:ControlledConcept/gml:name[1]", doc); assertXpathEvaluatesTo("name_b", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit" + "/gsml:composition/gsml:CompositionPart/gsml:lithology[1]" + "/gsml:ControlledConcept/gml:name[2]", doc); assertXpathEvaluatesTo("name_c", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit" + "/gsml:composition/gsml:CompositionPart/gsml:lithology[1]" + "/gsml:ControlledConcept/gml:name[3]", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:lithology[1]/FEATURE_LINK", doc); assertXpathCount(1, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification" + "/gsml:GeologicUnit/gsml:composition/gsml:CompositionPart/gsml:lithology[2]" + "/gsml:ControlledConcept/gml:name", doc); assertXpathEvaluatesTo("name_2", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit" + "/gsml:composition/gsml:CompositionPart/gsml:lithology[2]" + "/gsml:ControlledConcept/gml:name", doc); assertXpathCount(0, "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/gsml:composition" + "/gsml:CompositionPart/gsml:lithology[2]/FEATURE_LINK", doc); } // check for duplicate gml:id assertXpathCount(1, "//gsml:GeologicUnit[@gml:id='gu.25678']", doc); } /** * Implementation for tests expected to get mf4 only. * * @param xml */ private void checkGetMf4Only(String xml) { Document doc = postAsDOM("wfs", xml); LOGGER.info("WFS filter GetFeature response:\n" + prettyString(doc)); assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName()); assertXpathEvaluatesTo("1", "/wfs:FeatureCollection/@numberOfFeatures", doc); assertXpathCount(1, "//gsml:MappedFeature", doc); // mf4 { String id = "mf4"; assertXpathEvaluatesTo(id, "//gsml:MappedFeature[1]/@gml:id", doc); assertXpathEvaluatesTo("MURRADUC BASALT", "//gsml:MappedFeature[@gml:id='" + id + "']/gml:name", doc); // gu.25682 assertXpathEvaluatesTo("gu.25682", "//gsml:MappedFeature[@gml:id='" + id + "']/gsml:specification/gsml:GeologicUnit/@gml:id", doc); } } /** * Test if we can get mf4 by its name. */ public void testGetFeaturePropertyFilter() { String xml = // "<wfs:GetFeature " // + "service=\"WFS\" " // + "version=\"1.1.0\" " // + "xmlns:cdf=\"http://www.opengis.net/cite/data\" " // + "xmlns:ogc=\"http://www.opengis.net/ogc\" " // + "xmlns:wfs=\"http://www.opengis.net/wfs\" " // + "xmlns:gml=\"http://www.opengis.net/gml\" " // + "xmlns:gsml=\"" + AbstractAppSchemaMockData.GSML_URI + "\" " // + ">" // + " <wfs:Query typeName=\"gsml:MappedFeature\">" // + " <ogc:Filter>" // + " <ogc:PropertyIsEqualTo>" // + " <ogc:PropertyName>gml:name</ogc:PropertyName>" // + " <ogc:Literal>MURRADUC BASALT</ogc:Literal>" // + " </ogc:PropertyIsEqualTo>" // + " </ogc:Filter>" // + " </wfs:Query> " // + "</wfs:GetFeature>"; checkGetMf4Only(xml); } /** * Test if we can get mf4 with a FeatureId fid filter. */ public void testGetFeatureWithFeatureIdFilter() { String xml = // "<wfs:GetFeature " // + "service=\"WFS\" " // + "version=\"1.1.0\" " // + "xmlns:cdf=\"http://www.opengis.net/cite/data\" " // + "xmlns:ogc=\"http://www.opengis.net/ogc\" " // + "xmlns:wfs=\"http://www.opengis.net/wfs\" " // + "xmlns:gml=\"http://www.opengis.net/gml\" " // + "xmlns:gsml=\"" + AbstractAppSchemaMockData.GSML_URI + "\" " // + ">" // + " <wfs:Query typeName=\"gsml:MappedFeature\">" // + " <ogc:Filter>" // + " <ogc:FeatureId fid=\"mf4\"/>" // + " </ogc:Filter>" // + " </wfs:Query> " // + "</wfs:GetFeature>"; checkGetMf4Only(xml); } /** * Test if we can get mf4 with a GmlObjectId gml:id filter. */ public void testGetFeatureWithGmlObjectIdFilter() { String xml = // "<wfs:GetFeature " // + "service=\"WFS\" " // + "version=\"1.1.0\" " // + "xmlns:cdf=\"http://www.opengis.net/cite/data\" " // + "xmlns:ogc=\"http://www.opengis.net/ogc\" " // + "xmlns:wfs=\"http://www.opengis.net/wfs\" " // + "xmlns:gml=\"http://www.opengis.net/gml\" " // + "xmlns:gsml=\"" + AbstractAppSchemaMockData.GSML_URI + "\" " // + ">" // + " <wfs:Query typeName=\"gsml:MappedFeature\">" // + " <ogc:Filter>" // + " <ogc:GmlObjectId gml:id=\"mf4\"/>" // + " </ogc:Filter>" // + " </wfs:Query> " // + "</wfs:GetFeature>"; checkGetMf4Only(xml); } /** * Test anyType as complex attributes. Previously the anyType attribute wouldn't be encoded at * all. */ public void testAnyType() { final String OBSERVATION_ID_PREFIX = "observation:"; Document doc = getAsDOM("wfs?request=GetFeature&typename=om:Observation"); LOGGER.info("WFS GetFeature&typename=om:Observation response:\n" + prettyString(doc)); // om:result in om:Observation is of anyType, and in this case I put in a mapped feature in // it // Because I'm lazy, I used the same properties file for observation where mf1 as observation // contains mf1 as MappedFeature in result attribute assertXpathEvaluatesTo("4", "/wfs:FeatureCollection/@numberOfFeatures", doc); assertXpathCount(4, "//om:Observation", doc); String id = "mf1"; assertXpathEvaluatesTo(OBSERVATION_ID_PREFIX + id, "//om:Observation[1]/@gml:id", doc); assertXpathEvaluatesTo(id, "//om:Observation[1]/om:result/gsml:MappedFeature/@gml:id", doc); id = "mf2"; assertXpathEvaluatesTo(OBSERVATION_ID_PREFIX + id, "//om:Observation[2]/@gml:id", doc); assertXpathEvaluatesTo(id, "//om:Observation[2]/om:result/gsml:MappedFeature/@gml:id", doc); id = "mf3"; assertXpathEvaluatesTo(OBSERVATION_ID_PREFIX + id, "//om:Observation[3]/@gml:id", doc); assertXpathEvaluatesTo(id, "//om:Observation[3]/om:result/gsml:MappedFeature/@gml:id", doc); id = "mf4"; assertXpathEvaluatesTo(OBSERVATION_ID_PREFIX + id, "//om:Observation[4]/@gml:id", doc); assertXpathEvaluatesTo(id, "//om:Observation[4]/om:result/gsml:MappedFeature/@gml:id", doc); } /** * Making sure attributes that are encoded as xlink:href can still be queried in filters. */ public void testFilteringXlinkHref() { String xml = // "<wfs:GetFeature " // + "service=\"WFS\" " // + "version=\"1.1.0\" " // + "xmlns:cdf=\"http://www.opengis.net/cite/data\" " // + "xmlns:ogc=\"http://www.opengis.net/ogc\" " // + "xmlns:wfs=\"http://www.opengis.net/wfs\" " // + "xmlns:gml=\"http://www.opengis.net/gml\" " // + "xmlns:gsml=\"" + AbstractAppSchemaMockData.GSML_URI + "\" " // + ">" // + " <wfs:Query typeName=\"gsml:MappedFeature\">" // + " <ogc:Filter>" // + " <ogc:PropertyIsEqualTo>" // + " <ogc:PropertyName>gsml:specification/gsml:GeologicUnit/gml:name[1]</ogc:PropertyName>" // + " <ogc:Literal>Yaugher Volcanic Group</ogc:Literal>" // + " </ogc:PropertyIsEqualTo>" // + " </ogc:Filter>" // + " </wfs:Query> " // + "</wfs:GetFeature>"; Document doc = postAsDOM("wfs", xml); LOGGER.info("WFS filter GetFeature response:\n" + prettyString(doc)); assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName()); // there should be 3: // - mf1/gu.25699 // - mf2/gu.25678 // - mf3/gu.25678 which is encoded as xlink:href assertXpathEvaluatesTo("3", "/wfs:FeatureCollection/@numberOfFeatures", doc); assertXpathCount(3, "//gsml:MappedFeature", doc); } }