Unverified Commit 240c352f authored by Steve Ikeoka's avatar Steve Ikeoka Committed by GitHub
Browse files

Merge pull request #3418 from sikeoka/GEOS-6977-15

[GEOS-6977][2.15.x] Fixed WCS 1.0.0 GetCoverage KVP ignoring elevation and custom dimension parameters.
parents a6210358 436fde57
......@@ -94,6 +94,11 @@
<constructor-arg ref="geoServer"/>
</bean>
<bean id="wcs100ElevationKvpParser" class="org.geoserver.wcs.kvp.ElevationKvpParser">
<constructor-arg value="ELEVATION"/>
<constructor-arg ref="geoServer"/>
</bean>
<!-- kvp request readers -->
......
......@@ -63,6 +63,7 @@ import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.referencing.util.CRSUtilities;
import org.geotools.util.DateRange;
import org.geotools.util.NumberRange;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.filter.Filter;
......@@ -385,7 +386,7 @@ public class DefaultWebCoverageService100 implements WebCoverageService100 {
if (elevationDimension != null
&& elevationDimension.isEnabled()
&& dimensions.hasElevation()) {
List<Double> elevations = new ArrayList<Double>();
List<Object> elevations = new ArrayList<Object>();
// extract elevation values
List axisSubset = null;
if (request.getRangeSubset() != null) {
......@@ -396,29 +397,17 @@ public class DefaultWebCoverageService100 implements WebCoverageService100 {
String axisName = axis.getName();
if (axisName.equalsIgnoreCase(WCSUtils.ELEVATION)) {
if (axis.getSingleValue().size() > 0) {
for (int s = 0; s < axis.getSingleValue().size(); s++) {
elevations.add(
Double.parseDouble(
((TypedLiteralType)
axis.getSingleValue()
.get(s))
.getValue()));
}
} else if (axis.getInterval().size() > 0) {
IntervalType interval =
(IntervalType) axis.getInterval().get(0);
int min = Integer.parseInt(interval.getMin().getValue());
int max = Integer.parseInt(interval.getMax().getValue());
int res =
(interval.getRes() != null
? Integer.parseInt(interval.getRes().getValue())
: 1);
int count = (int) (Math.floor(max - min) / res + 1);
for (int b = 0; b < count; b++) {
elevations.add(new Double(min + b * res));
}
// grab the elevation values
for (Object object : axis.getSingleValue()) {
TypedLiteralType value = (TypedLiteralType) object;
elevations.add(Double.parseDouble(value.getValue()));
}
// grab the elevation intervals
for (Object object : axis.getInterval()) {
IntervalType interval = (IntervalType) object;
double min = Double.parseDouble(interval.getMin().getValue());
double max = Double.parseDouble(interval.getMax().getValue());
elevations.add(NumberRange.create(min, max));
}
}
}
......@@ -975,28 +964,6 @@ public class DefaultWebCoverageService100 implements WebCoverageService100 {
"Invalid values for axis " + axisSubset.getName(),
InvalidParameterValue,
"AxisSubset");
} else if (axisSubset.getName().equalsIgnoreCase(WCSUtils.ELEVATION)) {
double[] elevations = null;
if (axisSubset.getSingleValue().size() > 0) {
elevations = new double[axisSubset.getSingleValue().size()];
for (int s = 0; s < axisSubset.getSingleValue().size(); s++) {
elevations[s] =
Double.parseDouble(
((TypedLiteralType) axisSubset.getSingleValue().get(s))
.getValue());
}
} else if (axisSubset.getInterval().size() > 0) {
IntervalType interval = (IntervalType) axisSubset.getInterval().get(0);
int min = Integer.parseInt(interval.getMin().getValue());
int max = Integer.parseInt(interval.getMax().getValue());
int res =
(interval.getRes() != null
? Integer.parseInt(interval.getRes().getValue())
: 1);
elevations = new double[(int) (Math.floor(max - min) / res + 1)];
for (int b = 0; b < elevations.length; b++) elevations[b] = (min + b * res);
}
}
}
}
......
/* (c) 2019 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wcs.kvp;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.kvp.ElevationParser;
import org.geoserver.wcs.WCSInfo;
import org.geotools.util.Version;
/**
* A {@link ElevationKvpParser} picking the max number of values to be parsed from the WCS
* configuration
*/
public class ElevationKvpParser extends org.geoserver.ows.kvp.ElevationKvpParser {
private final GeoServer geoServer;
/**
* Creates the parser specifying the name of the key to latch to.
*
* @param key The key whose associated value to parse.
*/
public ElevationKvpParser(String key, GeoServer geoServer) {
super(key);
setService("WCS");
setVersion(new Version("1.0.0"));
this.geoServer = geoServer;
}
protected ElevationParser getElevationParser() {
WCSInfo info = geoServer.getService(WCSInfo.class);
int maxRequestedDimensionValues = info.getMaxRequestedDimensionValues();
return new ElevationParser(maxRequestedDimensionValues);
}
}
......@@ -14,6 +14,7 @@ import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.opengis.gml.CodeType;
import net.opengis.gml.DirectPositionType;
import net.opengis.gml.Gml4wcsFactory;
......@@ -34,6 +35,9 @@ import net.opengis.wcs10.TimeSequenceType;
import net.opengis.wcs10.TypedLiteralType;
import net.opengis.wcs10.Wcs10Factory;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.DimensionInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.ows.kvp.EMFKvpRequestReader;
import org.geoserver.ows.util.KvpUtils;
import org.geoserver.ows.util.KvpUtils.Tokenizer;
......@@ -45,6 +49,7 @@ import org.geotools.metadata.i18n.Errors;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.util.DateRange;
import org.geotools.util.NumberRange;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
......@@ -389,6 +394,27 @@ public class Wcs10GetCoverageRequestReader extends EMFKvpRequestReader {
} else checkTypeAxisRange(rangeSubset, axis, "ELEVATION");
}
// check for custom dimensions
CoverageInfo coverage = this.catalog.getCoverageByName(coverageName);
if (coverage != null) {
for (Entry<String, ?> entry : coverage.getMetadata().entrySet()) {
String name = entry.getKey();
if (name.startsWith(ResourceInfo.CUSTOM_DIMENSION_PREFIX)
&& entry.getValue() instanceof DimensionInfo
&& ((DimensionInfo) entry.getValue()).isEnabled()) {
name = name.substring(ResourceInfo.CUSTOM_DIMENSION_PREFIX.length());
Object value = kvp.get(name);
// ignore anything that got converted by a KVP parser so that they
// are only handled as keywords and not as a custom dimension since
// WCS 1.0.0 does not define away to avoid these name clashes.
if (value instanceof String) {
name = name.toUpperCase();
checkTypeAxisRange(rangeSubset, Arrays.asList(value), name);
}
}
}
}
return rangeSubset;
}
......@@ -396,6 +422,7 @@ public class Wcs10GetCoverageRequestReader extends EMFKvpRequestReader {
* @param rangeSubset
* @param axis
*/
@SuppressWarnings("unchecked")
private void checkTypeAxisRange(
final RangeSubsetType rangeSubset, Object axis, String axisName) {
if (axis instanceof String) {
......@@ -467,6 +494,27 @@ public class Wcs10GetCoverageRequestReader extends EMFKvpRequestReader {
axisSubset.getSingleValue().add(singleValue);
rangeSubset.getAxisSubset().add(axisSubset);
} else if (axis instanceof Collection) {
AxisSubsetType axisSubset = Wcs10Factory.eINSTANCE.createAxisSubsetType();
axisSubset.setName(axisName);
for (Object value : (Collection<?>) axis) {
if (value instanceof NumberRange) {
NumberRange<?> range = (NumberRange<?>) value;
IntervalType interval = Wcs10Factory.eINSTANCE.createIntervalType();
TypedLiteralType min = Wcs10Factory.eINSTANCE.createTypedLiteralType();
TypedLiteralType max = Wcs10Factory.eINSTANCE.createTypedLiteralType();
min.setValue(Double.toString(range.getMinimum()));
max.setValue(Double.toString(range.getMaximum()));
interval.setMin(min);
interval.setMax(max);
axisSubset.getInterval().add(interval);
} else {
TypedLiteralType singleValue = Wcs10Factory.eINSTANCE.createTypedLiteralType();
singleValue.setValue(String.valueOf(value));
axisSubset.getSingleValue().add(singleValue);
}
}
rangeSubset.getAxisSubset().add(axisSubset);
}
}
......
......@@ -56,6 +56,20 @@ public class CustomDimensionsTest extends CoverageTestSupport {
assertNull(image);
}
@Test
public void testGetCoverageKVPBadValue() throws Exception {
// check that we get no data when requesting an incorrect value for custom dimension
String request = getWaterTempRequestKVP("bad_dimension_value");
MockHttpServletResponse response = getAsServletResponse(request);
BufferedImage image = ImageIO.read(getBinaryInputStream(response));
assertNull(image);
request = request.replace(DIMENSION_NAME, DIMENSION_NAME.toLowerCase());
response = getAsServletResponse(request);
image = ImageIO.read(getBinaryInputStream(response));
assertNull(image);
}
@Test
public void testGetCoverageGoodValue() throws Exception {
// check that we get data when requesting a correct value for custom dimension
......@@ -72,6 +86,30 @@ public class CustomDimensionsTest extends CoverageTestSupport {
assertEquals("image/tiff", response.getContentType());
}
@Test
public void testGetCoverageKVPGoodValue() throws Exception {
// check that we get data when requesting a correct value for custom dimension
String request = getWaterTempRequestKVP("CustomDimValueA");
MockHttpServletResponse response = getAsServletResponse(request);
BufferedImage image = ImageIO.read(getBinaryInputStream(response));
assertNotNull(image);
assertEquals("image/tiff", response.getContentType());
request = request.replace(DIMENSION_NAME, DIMENSION_NAME.toLowerCase());
response = getAsServletResponse(request);
image = ImageIO.read(getBinaryInputStream(response));
assertNotNull(image);
assertEquals("image/tiff", response.getContentType());
}
private String getWaterTempRequestKVP(String dimensionValue) {
String url =
"wcs?service=WCS&version=1.0.0&request=GetCoverage"
+ "&sourceCoverage=%s&format=GEOTIFF&width=25&height=24"
+ "&crs=EPSG:4326&bbox=0.237,40.562,14.593,44.558&%s=%s";
return String.format(url, getLayerId(CUST_WATTEMP), DIMENSION_NAME, dimensionValue);
}
private String getWaterTempRequest(String dimensionValue) {
String request =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
......
......@@ -60,6 +60,20 @@ public class DynamicDimensionsTest extends CoverageTestSupport {
assertNull(image);
}
@Test
public void testGetCoverageKVPBadValue() throws Exception {
// check that we get no data when requesting an incorrect value for custom dimension
String request = getWaterTempRequestKVP("bad_dimension_value");
MockHttpServletResponse response = getAsServletResponse(request);
BufferedImage image = ImageIO.read(getBinaryInputStream(response));
assertNull(image);
request = request.replace(DIMENSION_NAME, DIMENSION_NAME.toUpperCase());
response = getAsServletResponse(request);
image = ImageIO.read(getBinaryInputStream(response));
assertNull(image);
}
@Test
public void testGetCoverageGoodValue() throws Exception {
// check that we get data when requesting a correct value for custom dimension
......@@ -76,6 +90,30 @@ public class DynamicDimensionsTest extends CoverageTestSupport {
assertEquals("image/tiff", response.getContentType());
}
@Test
public void testGetCoverageKVPGoodValue() throws Exception {
// check that we get data when requesting a correct value for custom dimension
String request = getWaterTempRequestKVP("100");
MockHttpServletResponse response = getAsServletResponse(request);
BufferedImage image = ImageIO.read(getBinaryInputStream(response));
assertNotNull(image);
assertEquals("image/tiff", response.getContentType());
request = request.replace(DIMENSION_NAME, DIMENSION_NAME.toUpperCase());
response = getAsServletResponse(request);
image = ImageIO.read(getBinaryInputStream(response));
assertNotNull(image);
assertEquals("image/tiff", response.getContentType());
}
private String getWaterTempRequestKVP(String dimensionValue) {
String url =
"wcs?service=WCS&version=1.0.0&request=GetCoverage"
+ "&sourceCoverage=%s&format=GEOTIFF&width=25&height=24"
+ "&crs=EPSG:4326&bbox=0.237,40.562,14.593,44.558&%s=%s";
return String.format(url, getLayerId(WATTEMP), DIMENSION_NAME, dimensionValue);
}
private String getWaterTempRequest(String dimensionValue) {
String request =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
......
......@@ -696,6 +696,18 @@ public class GetCoverageTest extends WCSTestSupport {
checkPixelValue(response, 10, 10, 18.2849999185419);
}
@Test
public void testElevationFirstKVP() throws Exception {
String queryString =
"request=getcoverage&service=wcs&version=1.0.0&format=image/geotiff"
+ "&bbox=0.237,40.562,14.593,44.558&crs=EPSG:4326&width=25&height=25"
+ "&elevation=0.0&coverage="
+ getLayerId(WATTEMP);
MockHttpServletResponse response = getAsServletResponse("wcs?" + queryString);
assertEquals("image/tiff", response.getContentType());
checkPixelValue(response, 10, 10, 18.2849999185419);
}
@Test
public void testElevationSecond() throws Exception {
String request = getWaterTempElevationRequest("100.0");
......@@ -719,6 +731,69 @@ public class GetCoverageTest extends WCSTestSupport {
checkPixelValue(response, 10, 10, 13.337999683572);
}
@Test
public void testElevationSecondKVP() throws Exception {
String queryString =
"request=getcoverage&service=wcs&version=1.0.0&format=image/geotiff"
+ "&bbox=0.237,40.562,14.593,44.558&crs=EPSG:4326&width=25&height=25"
+ "&elevation=100.0&coverage="
+ getLayerId(WATTEMP);
MockHttpServletResponse response = getAsServletResponse("wcs?" + queryString);
assertEquals("image/tiff", response.getContentType());
checkPixelValue(response, 10, 10, 13.337999683572);
}
@Test
public void testElevationTooMany() throws Exception {
GeoServer gs = getGeoServer();
WCSInfo wcs = gs.getService(WCSInfo.class);
wcs.setMaxRequestedDimensionValues(2);
gs.save(wcs);
try {
String queryString =
"request=getcoverage&service=wcs&version=1.0.0&format=image/geotiff"
+ "&bbox=0.237,40.562,14.593,44.558&crs=EPSG:4326&width=25&height=25"
+ "&elevation=0.0/1000.0/1.0&coverage="
+ getLayerId(WATTEMP);
MockHttpServletResponse response = getAsServletResponse("wcs?" + queryString);
assertEquals("application/vnd.ogc.se_xml", response.getContentType());
Document dom = dom(response, true);
print(dom);
String text =
checkLegacyException(
dom, ServiceException.INVALID_PARAMETER_VALUE, "elevation");
assertThat(text, containsString("More than 2 elevations"));
} finally {
wcs.setMaxRequestedDimensionValues(
DimensionInfo.DEFAULT_MAX_REQUESTED_DIMENSION_VALUES);
gs.save(wcs);
}
}
@Test
public void testElevationRangeKVP() throws Exception {
String baseUrl =
"wcs?request=getcoverage&service=wcs&version=1.0.0&format=image/geotiff"
+ "&bbox=0.237,40.562,14.593,44.558&crs=EPSG:4326&width=25&height=25"
+ "&coverage="
+ getLayerId(WATTEMP);
// last range
MockHttpServletResponse response = getAsServletResponse(baseUrl + "&ELEVATION=75.0/100.0");
assertEquals("image/tiff", response.getContentType());
checkPixelValue(response, 10, 10, 13.337999683572);
// middle hole, no data --> we should get back an exception
Document dom = getAsDOM(baseUrl + "&ELEVATION=25.0/75.0");
// print(dom);
XMLAssert.assertXpathEvaluatesTo("1", "count(//ServiceExceptionReport)", dom);
// first range
response = getAsServletResponse(baseUrl + "&ELEVATION=0.0/25.0");
assertEquals("image/tiff", response.getContentType());
checkPixelValue(response, 10, 10, 18.2849999185419);
}
private String getWaterTempElevationRequest(String elevation) {
String request =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment