/* (c) 2016 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.wms.ncwms; import java.util.Map; import org.geoserver.ows.AbstractDispatcherCallback; import org.geoserver.ows.Request; import org.geoserver.platform.Service; import org.geoserver.platform.ServiceException; import org.geoserver.wms.map.GIFMapResponse; import org.geoserver.wms.style.PaletteParser; import org.geotools.filter.function.EnvFunction; import org.geotools.util.Converters; import org.geotools.util.NumberRange; /** * Integrates the ncWMS extension parameters into the env approach normally chosen by GeoServer to add dynamic parameters (the ones used by the * colormap rendering transformation) */ public class GetMapNcWmsCallback extends AbstractDispatcherCallback { private static String COLORSCALERANGE = "COLORSCALERANGE"; private static String NUMCOLORBANDS = "NUMCOLORBANDS"; private static String ABOVEMAXCOLOR = "ABOVEMAXCOLOR"; private static String BELOWMINCOLOR = "BELOWMINCOLOR"; private static String LOGSCALE = "LOGSCALE"; private static String OPACITY = "OPACITY"; private static String ANIMATION = "ANIMATION"; private GIFMapResponse gifResponse; public GetMapNcWmsCallback(GIFMapResponse gifResponse) { this.gifResponse = gifResponse; } /* * The choice of serviceDispatcher is not random, it allows the EnvironmentInjectionCallback to setup the env vars in the local map (which happens * by calling setLocalValues() and wiping out any previous setting) */ @Override public Service serviceDispatched(Request request, Service service) throws ServiceException { Map kvp = request.getKvp(); Map rawKvp = request.getRawKvp(); if (kvp.containsKey(COLORSCALERANGE)) { String scaleRangeSpec = (String) rawKvp.get(COLORSCALERANGE); NumberRange<Double> range = parseColorScaleRange(scaleRangeSpec); EnvFunction.setLocalValue(PaletteParser.RANGE_MIN, range.getMinimum()); EnvFunction.setLocalValue(PaletteParser.RANGE_MAX, range.getMaximum()); } if (kvp.containsKey(OPACITY)) { String str = (String) rawKvp.get(OPACITY); Integer value = Converters.convert(str, Integer.class); if ((value == null && str != null && !str.trim().isEmpty()) || (value != null && (value < 0 || value > 100))) { throw new ServiceException( "Expected a int value between 0 and 100 for OPACITY but found '" + str + "' instead", ServiceException.INVALID_PARAMETER_VALUE, "OPACITY"); } EnvFunction.setLocalValue(PaletteParser.OPACITY, value / 100f); } if (kvp.containsKey(ANIMATION)) { String str = (String) rawKvp.get(ANIMATION); Boolean animate = Converters.convert(str, Boolean.class); if ((animate == null && str != null && !str.trim().isEmpty())) { throw new ServiceException( "Expected a boolean value for ANIMATION but found '" + str + "' instead", ServiceException.INVALID_PARAMETER_VALUE, "ANIMATION"); } if (animate) { String format = (String) rawKvp.get("format"); if (!gifResponse.getOutputFormats().contains(format)) { throw new ServiceException( "Animation is supported only with image/gif output format", ServiceException.INVALID_PARAMETER_VALUE, "format"); } else if (!GIFMapResponse.IMAGE_GIF_SUBTYPE_ANIMATED.equals(format)) { // switch to animated mode rawKvp.put("format", GIFMapResponse.IMAGE_GIF_SUBTYPE_ANIMATED); kvp.put("format", GIFMapResponse.IMAGE_GIF_SUBTYPE_ANIMATED); } } } mapParameter(kvp, rawKvp, NUMCOLORBANDS, PaletteParser.NUMCOLORS, Integer.class); mapParameter(kvp, rawKvp, BELOWMINCOLOR, PaletteParser.COLOR_BEFORE, String.class); mapParameter(kvp, rawKvp, ABOVEMAXCOLOR, PaletteParser.COLOR_AFTER, String.class); mapParameter(kvp, rawKvp, LOGSCALE, PaletteParser.LOGSCALE, String.class); return service; } /** * Maps a parameter needing at most a simple type conversion from the kvp map to the env function */ private void mapParameter(Map kvp, Map rawKvp, String ncWmsParameter, String paletteParameter, Class targetClass) { if (kvp.containsKey(ncWmsParameter)) { String str = (String) rawKvp.get(ncWmsParameter); Object value = Converters.convert(str, targetClass); if (value == null && str != null && !str.trim().isEmpty()) { throw new ServiceException( "Expected a value of type " + targetClass.getSimpleName() + " for " + ncWmsParameter + " but found '" + str + "' instead", ServiceException.INVALID_PARAMETER_VALUE, ncWmsParameter); } EnvFunction.setLocalValue(paletteParameter, value); } } private NumberRange<Double> parseColorScaleRange(String scaleRangeSpec) { String[] elements = scaleRangeSpec.split("\\s*,\\s*"); if (elements.length != 2) { throw new ServiceException( COLORSCALERANGE + " must be specified as 'min,max' where min and max are numbers", ServiceException.INVALID_PARAMETER_VALUE, COLORSCALERANGE); } double min = parseDouble(elements[0], COLORSCALERANGE); double max = parseDouble(elements[1], COLORSCALERANGE); return NumberRange.create(min, max); } private double parseDouble(String element, String locator) { try { return Double.parseDouble(element); } catch (NumberFormatException e) { throw new ServiceException("Expected a number but got '" + element + "'", ServiceException.INVALID_PARAMETER_VALUE, locator); } } }