/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.rest.catalog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNull; import static org.custommonkey.xmlunit.XMLAssert.*; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.sf.json.JSON; import net.sf.json.JSONObject; import org.geoserver.catalog.AttributeTypeInfo; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.data.test.SystemTestData; import org.geoserver.rest.RestBaseController; import org.geotools.data.DataAccess; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.junit.Before; import org.junit.Test; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; import org.w3c.dom.Document; import org.springframework.mock.web.MockHttpServletResponse; import com.vividsolutions.jts.geom.MultiPolygon; public class FeatureTypeTest extends CatalogRESTTestSupport { private static String BASEPATH = RestBaseController.ROOT_PATH; @Before public void removePropertyStores() { removeStore("gs", "pds"); removeStore("gs", "ngpds"); } @Before public void addPrimitiveGeoFeature() throws IOException { revertLayer(SystemTestData.PRIMITIVEGEOFEATURE); } @Test public void testGetAllByWorkspace() throws Exception { Document dom = getAsDOM(BASEPATH + "/workspaces/sf/featuretypes.xml"); assertEquals(catalog.getFeatureTypesByNamespace(catalog.getNamespaceByPrefix("sf")).size(), dom.getElementsByTagName("featureType").getLength()); } void addPropertyDataStore(boolean configureFeatureType) throws Exception { ByteArrayOutputStream zbytes = new ByteArrayOutputStream(); ZipOutputStream zout = new ZipOutputStream(zbytes); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bytes)); writer.write("_=name:String,pointProperty:Point\n"); writer.write("pdsa.0='zero'|POINT(0 0)\n"); writer.write("pdsa.1='one'|POINT(1 1)\n"); writer.flush(); zout.putNextEntry(new ZipEntry("pdsa.properties")); zout.write(bytes.toByteArray()); bytes.reset(); writer.write("_=name:String,pointProperty:Point\n"); writer.write("pdsb.0='two'|POINT(2 2)\n"); writer.write("pdsb.1='trhee'|POINT(3 3)\n"); writer.flush(); zout.putNextEntry(new ZipEntry("pdsb.properties")); zout.write(bytes.toByteArray()); zout.flush(); zout.close(); String q = "configure=" + (configureFeatureType ? "all" : "none"); put(BASEPATH + "/workspaces/gs/datastores/pds/file.properties?" + q, zbytes.toByteArray(), "application/zip"); } void addGeomlessPropertyDataStore(boolean configureFeatureType) throws Exception { ByteArrayOutputStream zbytes = new ByteArrayOutputStream(); ZipOutputStream zout = new ZipOutputStream(zbytes); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bytes)); writer.write("_=name:String,intProperty:Integer\n"); writer.write("ngpdsa.0='zero'|0\n"); writer.write("ngpdsa.1='one'|1\n"); writer.flush(); zout.putNextEntry(new ZipEntry("ngpdsa.properties")); zout.write(bytes.toByteArray()); bytes.reset(); writer.write("_=name:String,intProperty:Integer\n"); writer.write("ngpdsb.0='two'|2\n"); writer.write("ngpdsb.1='trhee'|3\n"); writer.flush(); zout.putNextEntry(new ZipEntry("ngpdsb.properties")); zout.write(bytes.toByteArray()); zout.flush(); zout.close(); String q = "configure=" + (configureFeatureType ? "all" : "none"); put(BASEPATH + "/workspaces/gs/datastores/ngpds/file.properties?" + q, zbytes.toByteArray(), "application/zip"); } /** * Add a property data store with multiple feature types, but only configure the first. * @param configureFeatureType * @throws Exception */ void addPropertyDataStoreOnlyConfigureFirst() throws Exception { ByteArrayOutputStream zbytes = new ByteArrayOutputStream(); ZipOutputStream zout = new ZipOutputStream(zbytes); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bytes)); writer.write("_=name:String,pointProperty:Point\n"); writer.write("pdsa.0='zero'|POINT(0 0)\n"); writer.write("pdsa.1='one'|POINT(1 1)\n"); writer.flush(); zout.putNextEntry(new ZipEntry("pdsa.properties")); zout.write(bytes.toByteArray()); bytes.reset(); writer.write("_=name:String,pointProperty:Point\n"); writer.write("pdsb.0='two'|POINT(2 2)\n"); writer.write("pdsb.1='trhee'|POINT(3 3)\n"); writer.flush(); zout.putNextEntry(new ZipEntry("pdsb.properties")); zout.write(bytes.toByteArray()); zout.flush(); zout.close(); String q = "configure=first"; put(BASEPATH + "/workspaces/gs/datastores/pds/file.properties?" + q, zbytes.toByteArray(), "application/zip"); } @Test public void testGetAllByDataStore() throws Exception { // two stores to play with addPropertyDataStore(true); addGeomlessPropertyDataStore(true); Document dom = getAsDOM(BASEPATH + "/workspaces/gs/datastores/pds/featuretypes.xml"); assertEquals(2, dom.getElementsByTagName("featureType").getLength()); assertXpathEvaluatesTo("1", "count(//featureType/name[text()='pdsa'])", dom); assertXpathEvaluatesTo("1", "count(//featureType/name[text()='pdsb'])", dom); } @Test public void testGetAllAvailable() throws Exception { addPropertyDataStore(false); Document dom = getAsDOM( BASEPATH + "/workspaces/gs/datastores/pds/featuretypes.xml?list=available"); assertXpathEvaluatesTo("1", "count(//featureTypeName[text()='pdsa'])", dom); assertXpathEvaluatesTo("1", "count(//featureTypeName[text()='pdsb'])", dom); } @Test public void testGetAllAvailableWithGeometryOnly() throws Exception { addGeomlessPropertyDataStore(false); Document dom = getAsDOM( BASEPATH + "/workspaces/gs/datastores/ngpds/featuretypes.xml?list=available"); assertXpathEvaluatesTo("2", "count(//featureTypeName)", dom); dom = getAsDOM(BASEPATH + "/workspaces/gs/datastores/ngpds/featuretypes.xml?list=available_with_geom"); assertXpathEvaluatesTo("0", "count(//featureTypeName)", dom); } /** * Test that a list of all feature types for a data source are returned when "list=all", including both * configured and unconfigured ones. */ @Test public void testGetAllByDataStoreWithListAll() throws Exception { // Create a data store with only the first feature type configured. addPropertyDataStoreOnlyConfigureFirst(); Document dom = getAsDOM(BASEPATH + "/workspaces/gs/datastores/pds/featuretypes.xml?list=all"); assertEquals(2, dom.getElementsByTagName("featureTypeName").getLength()); assertXpathEvaluatesTo("1", "count(//featureTypeName[text()='pdsa'])", dom); assertXpathEvaluatesTo("1", "count(//featureTypeName[text()='pdsb'])", dom); } @Test public void testPutAllUnauthorized() throws Exception { assertEquals(405, putAsServletResponse(BASEPATH + "/workspaces/sf/datastores/sf/featuretypes") .getStatus()); } @Test public void testDeleteAllUnauthorized() throws Exception { assertEquals(405, deleteAsServletResponse(BASEPATH + "/workspaces/sf/datastores/sf/featuretypes") .getStatus()); } @Test public void testPostAsXML() throws Exception { Document dom = getAsDOM("wfs?request=getfeature&typename=sf:pdsa"); assertEquals("ows:ExceptionReport", dom.getDocumentElement().getNodeName()); addPropertyDataStore(false); String xml = "<featureType>" + "<name>pdsa</name>" + "<nativeName>pdsa</nativeName>" + "<srs>EPSG:4326</srs>" + "<nativeCRS>EPSG:4326</nativeCRS>" + "<nativeBoundingBox>" + "<minx>0.0</minx>" + "<maxx>1.0</maxx>" + "<miny>0.0</miny>" + "<maxy>1.0</maxy>" + "<crs>EPSG:4326</crs>" + "</nativeBoundingBox>" + "<store>pds</store>" + "</featureType>"; MockHttpServletResponse response = postAsServletResponse( BASEPATH + "/workspaces/gs/datastores/pds/featuretypes/", xml, "text/xml"); assertEquals(201, response.getStatus()); assertNotNull(response.getHeader("Location")); assertTrue(response.getHeader("Location") .endsWith("/workspaces/gs/datastores/pds/featuretypes/pdsa")); dom = getAsDOM("wfs?request=getfeature&typename=gs:pdsa"); assertEquals("wfs:FeatureCollection", dom.getDocumentElement().getNodeName()); assertEquals(2, dom.getElementsByTagName("gs:pdsa").getLength()); } @Test public void testPostAsJSON() throws Exception { Document dom = getAsDOM("wfs?request=getfeature&typename=sf:pdsa"); assertEquals("ows:ExceptionReport", dom.getDocumentElement().getNodeName()); addPropertyDataStore(false); String json = "{" + "'featureType':{" + "'name':'pdsa'," + "'nativeName':'pdsa'," + "'srs':'EPSG:4326'," + "'nativeBoundingBox':{" + "'minx':0.0," + "'maxx':1.0," + "'miny':0.0," + "'maxy':1.0," + "'crs':'EPSG:4326'" + "}," + "'nativeCRS':'EPSG:4326'," + "'store':'pds'" + "}" + "}"; MockHttpServletResponse response = postAsServletResponse( BASEPATH + "/workspaces/gs/datastores/pds/featuretypes/", json, "text/json"); assertEquals(201, response.getStatus()); assertNotNull(response.getHeader("Location")); assertTrue(response.getHeader("Location") .endsWith("/workspaces/gs/datastores/pds/featuretypes/pdsa")); dom = getAsDOM("wfs?request=getfeature&typename=gs:pdsa"); assertEquals("wfs:FeatureCollection", dom.getDocumentElement().getNodeName()); assertEquals(2, dom.getElementsByTagName("gs:pdsa").getLength()); } @Test public void testPostToResource() throws Exception { addPropertyDataStore(true); String xml = "<featureType>" + "<name>pdsa</name>" + "</featureType>"; MockHttpServletResponse response = postAsServletResponse( BASEPATH + "/workspaces/gs/datastores/pds/featuretypes/pdsa", xml, "text/xml"); assertEquals(405, response.getStatus()); } @Test public void testGetAsXML() throws Exception { Document dom = getAsDOM(BASEPATH + "/workspaces/sf/featuretypes/PrimitiveGeoFeature.xml"); assertEquals("featureType", dom.getDocumentElement().getNodeName()); assertXpathEvaluatesTo("PrimitiveGeoFeature", "/featureType/name", dom); assertXpathEvaluatesTo("EPSG:4326", "/featureType/srs", dom); assertEquals(CRS.decode("EPSG:4326").toWKT(), xp.evaluate("/featureType/nativeCRS", dom)); FeatureTypeInfo ft = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); /* * ReferencedEnvelope re = ft.getNativeBoundingBox(); assertXpathEvaluatesTo( re.getMinX()+"" , "/featureType/nativeBoundingBox/minx", dom ); * assertXpathEvaluatesTo( re.getMaxX()+"" , "/featureType/nativeBoundingBox/maxx", dom ); assertXpathEvaluatesTo( re.getMinY()+"" , * "/featureType/nativeBoundingBox/miny", dom ); assertXpathEvaluatesTo( re.getMaxY()+"" , "/featureType/nativeBoundingBox/maxy", dom ); */ ReferencedEnvelope re = ft.getLatLonBoundingBox(); assertXpathEvaluatesTo(re.getMinX() + "", "/featureType/latLonBoundingBox/minx", dom); assertXpathEvaluatesTo(re.getMaxX() + "", "/featureType/latLonBoundingBox/maxx", dom); assertXpathEvaluatesTo(re.getMinY() + "", "/featureType/latLonBoundingBox/miny", dom); assertXpathEvaluatesTo(re.getMaxY() + "", "/featureType/latLonBoundingBox/maxy", dom); } @Test public void testGetAsJSON() throws Exception { JSON json = getAsJSON(BASEPATH + "/workspaces/sf/featuretypes/PrimitiveGeoFeature.json"); JSONObject featureType = ((JSONObject) json).getJSONObject("featureType"); assertNotNull(featureType); assertEquals("PrimitiveGeoFeature", featureType.get("name")); assertEquals(CRS.decode("EPSG:4326").toWKT(), featureType.get("nativeCRS")); assertEquals("EPSG:4326", featureType.get("srs")); } @Test public void testGetAsHTML() throws Exception { Document dom = getAsDOM( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature.html"); } @Test public void testGetAllAsHTML() throws Exception { addPropertyDataStore(true); String dom = getAsString(BASEPATH + "/workspaces/gs/datastores/pds/featuretypes.xml"); System.out.println(dom); } @Test public void testGetWrongFeatureType() throws Exception { // Parameters for the request String ws = "sf"; String ds = "sf"; String ft = "PrimitiveGeoFeaturessss"; // Request path String requestPath = BASEPATH + "/workspaces/" + ws + "/featuretypes/" + ft + ".html"; String requestPath2 = BASEPATH + "/workspaces/" + ws + "/datastores/" + ds + "/featuretypes/" + ft + ".html"; // Exception path String exception = "No such feature type: " + ws + "," + ft; String exception2 = "No such feature type: " + ws + "," + ds + "," + ft; // CASE 1: No datastore set // First request should thrown an exception MockHttpServletResponse response = getAsServletResponse(requestPath); assertEquals(404, response.getStatus()); assertContains(response.getContentAsString(), exception); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath + "?quietOnNotFound=true"); assertEquals(404, response.getStatus()); // No exception thrown assertTrue(response.getContentAsString().isEmpty()); // CASE 2: datastore set // First request should thrown an exception response = getAsServletResponse(requestPath2); assertEquals(404, response.getStatus()); assertContains(response.getContentAsString(), exception2); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath2 + "?quietOnNotFound=true"); assertEquals(404, response.getStatus()); // No exception thrown assertTrue(response.getContentAsString().isEmpty()); } @Test public void testPut() throws Exception { String xml = "<featureType>" + "<title>new title</title>" + "</featureType>"; MockHttpServletResponse response = putAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature", xml, "text/xml"); assertEquals(200, response.getStatus()); Document dom = getAsDOM( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature.xml"); assertXpathEvaluatesTo("new title", "/featureType/title", dom); FeatureTypeInfo ft = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); assertEquals("new title", ft.getTitle()); } @Test public void testPutNonDestructive() throws Exception { FeatureTypeInfo ft = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); assertTrue(ft.isEnabled()); boolean isAdvertised = ft.isAdvertised(); int maxFeatures = ft.getMaxFeatures(); int numDecimals = ft.getNumDecimals(); boolean isOverridingServiceSRS = ft.isOverridingServiceSRS(); boolean getSkipNumberMatched = ft.getSkipNumberMatched(); boolean isCircularArcPresent = ft.isCircularArcPresent(); String xml = "<featureType>" + "<title>new title</title>" + "</featureType>"; MockHttpServletResponse response = putAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature", xml, "text/xml"); assertEquals(200, response.getStatus()); ft = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); assertTrue(ft.isEnabled()); assertEquals(isAdvertised, ft.isAdvertised()); assertEquals(maxFeatures, ft.getMaxFeatures()); assertEquals(numDecimals, ft.getNumDecimals()); assertEquals(isOverridingServiceSRS, ft.isOverridingServiceSRS()); assertEquals(getSkipNumberMatched, ft.getSkipNumberMatched()); assertEquals(isCircularArcPresent, ft.isCircularArcPresent()); } /** * Check feature type modification involving calculation of bounds. * * Update: Ensure feature type modification does not reset ResourcePool DataStoreCache */ @SuppressWarnings("rawtypes") @Test public void testPutWithCalculation() throws Exception { DataStoreInfo dataStoreInfo = getCatalog().getDataStoreByName("sf", "sf"); String dataStoreId = dataStoreInfo.getId(); DataAccess dataAccessBefore = dataStoreInfo.getDataStore(null); assertSame("ResourcePool DataStoreCache", dataAccessBefore, getCatalog().getResourcePool().getDataStoreCache().get(dataStoreId)); String clearLatLonBoundingBox = "<featureType>" + "<nativeBoundingBox>" + "<minx>-180.0</minx>" + "<maxx>180.0</maxx>" + "<miny>-90.0</miny>" + "<maxy>90.0</maxy>" + "<crs>EPSG:4326</crs>" + "</nativeBoundingBox>" + "<latLonBoundingBox/>" + "</featureType>"; String path = BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature"; MockHttpServletResponse response = putAsServletResponse(path, clearLatLonBoundingBox, "text/xml"); assertEquals("Couldn't remove lat/lon bounding box:\n" + response.getContentAsString(), 200, response.getStatus()); Document dom = getAsDOM(path + ".xml"); assertXpathEvaluatesTo("0.0", "/featureType/latLonBoundingBox/minx", dom); // confirm ResourcePoool cache of DataStore is unchanged DataAccess dataAccessAfter = getCatalog().getDataStoreByName("sf", "sf").getDataStore(null); assertSame("ResourcePool DataStoreCache check 1", dataAccessBefore, dataAccessAfter); assertSame("ResourcePool DataStoreCache", dataAccessBefore, getCatalog().getResourcePool().getDataStoreCache().get(dataStoreId)); String updateNativeBounds = "<featureType>" + "<srs>EPSG:3785</srs>" + "<nativeBoundingBox>" + "<minx>-20037508.34</minx>" + "<maxx>20037508.34</maxx>" + "<miny>-20037508.34</miny>" + "<maxy>20037508.34</maxy>" + "<crs>EPSG:3785</crs>" + "</nativeBoundingBox>" + "</featureType>"; response = putAsServletResponse(path + ".xml", updateNativeBounds, "text/xml"); assertEquals("Couldn't update native bounding box: \n" + response.getContentAsString(), 200, response.getStatus()); dom = getAsDOM(path + ".xml"); print(dom); assertXpathExists("/featureType/latLonBoundingBox/minx[text()!='0.0']", dom); dataAccessAfter = getCatalog().getDataStoreByName("sf", "sf").getDataStore(null); assertSame("ResourcePool DataStoreCache check 2", dataAccessBefore, dataAccessAfter); assertSame("ResourcePool DataStoreCache", dataAccessBefore, getCatalog().getResourcePool().getDataStoreCache().get(dataStoreId)); } @Test public void testPutNonExistant() throws Exception { String xml = "<featureType>" + "<title>new title</title>" + "</featureType>"; MockHttpServletResponse response = putAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/NonExistant", xml, "text/xml"); assertEquals(404, response.getStatus()); } @Test public void testDelete() throws Exception { FeatureTypeInfo featureType = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); String featureTypeId = featureType.getId(); String dataStoreId = featureType.getStore().getId(); Name name = featureType.getFeatureType().getName(); assertNotNull("PrmitiveGeoFeature available", featureType); for (LayerInfo l : catalog.getLayers(featureType)) { catalog.remove(l); } assertEquals(200, deleteAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature") .getStatus()); assertNull(catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature")); if (catalog.getResourcePool().getFeatureTypeAttributeCache().containsKey(featureTypeId)) { List<AttributeTypeInfo> attributesList = catalog.getResourcePool() .getFeatureTypeAttributeCache().get(featureTypeId); assertNull("attributes cleared", attributesList); } if (catalog.getResourcePool().getDataStoreCache().containsKey(dataStoreId)) { DataAccess dataStore = catalog.getResourcePool().getDataStoreCache().get(dataStoreId); List<Name> names = dataStore.getNames(); assertTrue(names.contains(name)); } } @Test public void testDeleteNonExistant() throws Exception { assertEquals(404, deleteAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/NonExistant") .getStatus()); } @Test public void testDeleteRecursive() throws Exception { assertNotNull(catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature")); assertNotNull(catalog.getLayerByName("sf:PrimitiveGeoFeature")); assertEquals(403, deleteAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature") .getStatus()); assertEquals(200, deleteAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature?recurse=true") .getStatus()); assertNull(catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature")); assertNull(catalog.getLayerByName("sf:PrimitiveGeoFeature")); } @Test public void testPostGeometrylessFeatureType() throws Exception { addGeomlessPropertyDataStore(false); String xml = "<featureType>" + "<name>ngpdsa</name>" + "</featureType>"; MockHttpServletResponse response = postAsServletResponse( BASEPATH + "/workspaces/gs/datastores/ngpds/featuretypes", xml, "text/xml"); assertEquals(201, response.getStatus()); assertNotNull(response.getHeader("Location")); assertTrue(response.getHeader("Location") .endsWith("/workspaces/gs/datastores/ngpds/featuretypes/ngpdsa")); } @Test public void testDeleteWsNotSameAsStoreName() throws Exception { // create a feature type whose store name is not same as workspace name testPostGeometrylessFeatureType(); assertEquals(200, deleteAsServletResponse( BASEPATH + "/workspaces/gs/datastores/ngpds/featuretypes/ngpdsa?recurse=true") .getStatus()); assertNull(catalog.getFeatureTypeByName("gs", "ngpdsa")); } @Test public void testCreateFeatureType() throws Exception { String xml = "<featureType>\n" + " <name>states</name>\n" + " <nativeName>states</nativeName>\n" + " <namespace>\n" + " <name>cite</name>\n" + " </namespace>\n" + " <title>USA Population</title>\n" + " <srs>EPSG:4326</srs>\n" + " <attributes>\n" + " <attribute>\n" + " <name>the_geom</name>\n" + " <binding>com.vividsolutions.jts.geom.MultiPolygon</binding>\n" + " </attribute>\n" + " <attribute>\n" + " <name>STATE_NAME</name>\n" + " <binding>java.lang.String</binding>\n" + " <length>25</length>\n" + " </attribute>\n" + " <attribute>\n" + " <name>LAND_KM</name>\n" + " <binding>java.lang.Double</binding>\n" + " </attribute>\n" + " </attributes>\n" + "</featureType>"; MockHttpServletResponse response = postAsServletResponse( BASEPATH + "/workspaces/cite/datastores/default/featuretypes", xml, "text/xml"); assertEquals(201, response.getStatus()); assertNotNull(response.getHeader("Location")); assertTrue(response.getHeader("Location") .endsWith("/workspaces/cite/datastores/default/featuretypes/states")); FeatureTypeInfo ft = catalog.getFeatureTypeByName("cite", "states"); assertNotNull(ft); FeatureType schema = ft.getFeatureType(); assertEquals("states", schema.getName().getLocalPart()); assertEquals(catalog.getNamespaceByPrefix("cite").getURI(), schema.getName().getNamespaceURI()); assertEquals(3, schema.getDescriptors().size()); assertNotNull(schema.getDescriptor("the_geom")); assertEquals(MultiPolygon.class, schema.getDescriptor("the_geom").getType().getBinding()); assertNotNull(schema.getDescriptor("LAND_KM")); assertEquals(Double.class, schema.getDescriptor("LAND_KM").getType().getBinding()); } @Test public void testRoundTripFeatureTypeXML() throws Exception { // Fetch the feature directly from the catalog FeatureTypeInfo before = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); // Do a round-trip GET and PUT of the resource String xml = getAsString( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature.xml"); MockHttpServletResponse response = putAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature", xml, "text/xml"); assertEquals(200, response.getStatus()); // Fetch the feature from the catalog again, and ensure nothing changed. FeatureTypeInfo after = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); assertEquals(before, after); } @Test public void testRoundTripFeatureTypJSONL() throws Exception { // Fetch the feature directly from the catalog FeatureTypeInfo before = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); // Do a round-trip GET and PUT of the resource String json = getAsString( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature.json"); System.out.println(json); MockHttpServletResponse response = putAsServletResponse( BASEPATH + "/workspaces/sf/datastores/sf/featuretypes/PrimitiveGeoFeature", json, "text/json"); assertEquals(200, response.getStatus()); // Fetch the feature from the catalog again, and ensure nothing changed. FeatureTypeInfo after = catalog.getFeatureTypeByName("sf", "PrimitiveGeoFeature"); assertEquals(before, after); } public static void assertContains(String message, String contains) { assertTrue("Expected \"" + message + "\" to contain \"" + contains + "\"", message.contains(contains)); } }