/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.constellation.map.ws.rs;
import org.apache.sis.util.Version;
import org.constellation.ServiceDef;
import org.constellation.ServiceDef.Specification;
import org.constellation.api.QueryConstants;
import org.constellation.map.ws.DefaultWMSWorker;
import org.constellation.map.ws.QueryContext;
import org.constellation.map.ws.WMSConstant;
import org.constellation.map.ws.WMSWorker;
import org.constellation.portrayal.internal.PortrayalResponse;
import org.constellation.util.Util;
import org.constellation.ws.CstlServiceException;
import org.constellation.ws.MimeType;
import org.constellation.ws.Worker;
import org.constellation.ws.rs.GridWebService;
import org.constellation.ws.rs.MapUtilities;
import org.constellation.ws.rs.provider.SchemaLocatedExceptionResponse;
import org.geotoolkit.client.RequestsUtilities;
import org.geotoolkit.display2d.service.DefaultPortrayalService;
import org.geotoolkit.ogc.xml.exception.ServiceExceptionReport;
import org.geotoolkit.ogc.xml.exception.ServiceExceptionType;
import org.geotoolkit.ows.xml.RequestBase;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.sld.MutableStyledLayerDescriptor;
import org.geotoolkit.sld.xml.GetLegendGraphic;
import org.geotoolkit.sld.xml.Specification.StyledLayerDescriptor;
import org.geotoolkit.sld.xml.StyleXmlIO;
import org.geotoolkit.sld.xml.v110.DescribeLayerResponseType;
import org.geotoolkit.util.StringUtilities;
import org.geotoolkit.temporal.util.TimeParser;
import org.geotoolkit.wms.xml.AbstractWMSCapabilities;
import org.geotoolkit.wms.xml.DescribeLayer;
import org.geotoolkit.wms.xml.GetCapabilities;
import org.geotoolkit.wms.xml.GetFeatureInfo;
import org.geotoolkit.wms.xml.GetMap;
import org.geotoolkit.wms.xml.WMSMarshallerPool;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.FactoryException;
import javax.inject.Singleton;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBException;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import static org.constellation.api.QueryConstants.REQUEST_PARAMETER;
import static org.constellation.api.QueryConstants.SERVICE_PARAMETER;
import static org.constellation.api.QueryConstants.UPDATESEQUENCE_PARAMETER;
import static org.constellation.api.QueryConstants.VERSION_PARAMETER;
import static org.constellation.map.ws.WMSConstant.CAPABILITIES;
import static org.constellation.map.ws.WMSConstant.DESCRIBELAYER;
import static org.constellation.map.ws.WMSConstant.GETCAPABILITIES;
import static org.constellation.map.ws.WMSConstant.GETFEATUREINFO;
import static org.constellation.map.ws.WMSConstant.GETLEGENDGRAPHIC;
import static org.constellation.map.ws.WMSConstant.GETMAP;
import static org.constellation.map.ws.WMSConstant.KEY_AZIMUTH;
import static org.constellation.map.ws.WMSConstant.KEY_BBOX;
import static org.constellation.map.ws.WMSConstant.KEY_BGCOLOR;
import static org.constellation.map.ws.WMSConstant.KEY_CRS_V111;
import static org.constellation.map.ws.WMSConstant.KEY_CRS_V130;
import static org.constellation.map.ws.WMSConstant.KEY_ELEVATION;
import static org.constellation.map.ws.WMSConstant.KEY_FEATURE_COUNT;
import static org.constellation.map.ws.WMSConstant.KEY_FORMAT;
import static org.constellation.map.ws.WMSConstant.KEY_HEIGHT;
import static org.constellation.map.ws.WMSConstant.KEY_INFO_FORMAT;
import static org.constellation.map.ws.WMSConstant.KEY_I_V111;
import static org.constellation.map.ws.WMSConstant.KEY_I_V130;
import static org.constellation.map.ws.WMSConstant.KEY_J_V111;
import static org.constellation.map.ws.WMSConstant.KEY_J_V130;
import static org.constellation.map.ws.WMSConstant.KEY_LANGUAGE;
import static org.constellation.map.ws.WMSConstant.KEY_LAYER;
import static org.constellation.map.ws.WMSConstant.KEY_LAYERS;
import static org.constellation.map.ws.WMSConstant.KEY_QUERY_LAYERS;
import static org.constellation.map.ws.WMSConstant.KEY_REMOTE_OWS_URL;
import static org.constellation.map.ws.WMSConstant.KEY_RULE;
import static org.constellation.map.ws.WMSConstant.KEY_SCALE;
import static org.constellation.map.ws.WMSConstant.KEY_SLD;
import static org.constellation.map.ws.WMSConstant.KEY_SLD_BODY;
import static org.constellation.map.ws.WMSConstant.KEY_SLD_VERSION;
import static org.constellation.map.ws.WMSConstant.KEY_STYLE;
import static org.constellation.map.ws.WMSConstant.KEY_STYLES;
import static org.constellation.map.ws.WMSConstant.KEY_TIME;
import static org.constellation.map.ws.WMSConstant.KEY_TRANSPARENT;
import static org.constellation.map.ws.WMSConstant.KEY_WIDTH;
import static org.constellation.map.ws.WMSConstant.KEY_WMTVER;
import static org.constellation.map.ws.WMSConstant.MAP;
import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_CRS;
import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_DIMENSION_VALUE;
import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_FORMAT;
import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_PARAMETER_VALUE;
import static org.geotoolkit.ows.xml.OWSExceptionCode.INVALID_POINT;
import static org.geotoolkit.ows.xml.OWSExceptionCode.MISSING_PARAMETER_VALUE;
import static org.geotoolkit.ows.xml.OWSExceptionCode.OPERATION_NOT_SUPPORTED;
import static org.geotoolkit.ows.xml.OWSExceptionCode.STYLE_NOT_DEFINED;
import org.opengis.util.GenericName;
//J2SE dependencies
/**
* The REST facade to an OGC Web Map Service, implementing versions 1.1.1 and
* 1.3.0.
*
* @version 0.9
*
* @author Guilhem Legal (Geomatys)
* @author Cédric Briançon (Geomatys)
* @author Benjain Garcia (Geomatys)
* @since 0.1
*/
//@Named
@Path("wms/{serviceId}")
@Singleton
public class WMSService extends GridWebService<WMSWorker> {
public static boolean writeDTD = true;
/**
* Build a new instance of the webService and initialize the JAXB context.
*/
public WMSService() {
super(Specification.WMS);
//we build the JAXB marshaller and unmarshaller to bind java/xml
setXMLContext(WMSMarshallerPool.getInstance());
setFullRequestLog(true);
LOGGER.log(Level.INFO, "WMS REST service running ({0} instances)", getWorkerMapSize());
}
@Override
protected Class getWorkerClass() {
return DefaultWMSWorker.class;
}
/**
* {@inheritDoc}
*/
@Override
public Response treatIncomingRequest(final Object objectRequest, final WMSWorker worker) {
final QueryContext queryContext = new QueryContext();
ServiceDef version = null;
try {
final RequestBase request;
if (objectRequest == null) {
version = worker.getVersionFromNumber(getParameter(VERSION_PARAMETER, false)); // needed if exception is launch before request build
request = adaptQuery(getParameter(REQUEST_PARAMETER, true), worker, queryContext);
} else if (objectRequest instanceof RequestBase) {
request = (RequestBase) objectRequest;
} else {
throw new CstlServiceException("The operation " + objectRequest.getClass().getName() + " is not supported by the service",
INVALID_PARAMETER_VALUE, "request");
}
version = worker.getVersionFromNumber(request.getVersion());
//Handle user's requests.
if (request instanceof GetFeatureInfo) {
final GetFeatureInfo requestFeatureInfo = (GetFeatureInfo) request;
final Map.Entry<String, Object> result = worker.getFeatureInfo(requestFeatureInfo);
if (result != null) {
final String infoFormat = result.getKey();
return Response.ok(result.getValue(), infoFormat).build();
}
//throw an exception if result of GetFeatureInfo visitor is null
throw new CstlServiceException("An error occurred during GetFeatureInfo response building.");
}
if (request instanceof GetMap) {
final GetMap requestMap = (GetMap)request;
final PortrayalResponse map = worker.getMap(requestMap);
return Response.ok(map, requestMap.getFormat()).build();
}
if (request instanceof GetCapabilities) {
final GetCapabilities requestCapab = (GetCapabilities) request;
final AbstractWMSCapabilities capabilities = worker.getCapabilities(requestCapab);
return Response.ok(capabilities, requestCapab.getFormat()).build();
}
if (request instanceof GetLegendGraphic) {
final GetLegendGraphic requestLegend = (GetLegendGraphic)request;
final PortrayalResponse legend = worker.getLegendGraphic(requestLegend);
return Response.ok(legend, requestLegend.getFormat()).build();
}
if (request instanceof DescribeLayer) {
final DescribeLayer describeLayer = (DescribeLayer)request;
final DescribeLayerResponseType response = worker.describeLayer(describeLayer);
return Response.ok(response, MimeType.TEXT_XML).build();
}
throw new CstlServiceException("The operation " + request + " is not supported by the service",
OPERATION_NOT_SUPPORTED, QueryConstants.REQUEST_PARAMETER.toLowerCase());
} catch (CstlServiceException ex) {
return processExceptionResponse(queryContext, ex, version, worker);
}
}
/**
* Build request object from KVP parameters.
*
* @param request
* @return
* @throws CstlServiceException
*/
private RequestBase adaptQuery(final String request, final Worker worker, final QueryContext queryContext) throws CstlServiceException {
if (GETMAP.equalsIgnoreCase(request) || MAP.equalsIgnoreCase(request)) {
return adaptGetMap(true, queryContext, worker);
} else if (GETFEATUREINFO.equalsIgnoreCase(request)) {
return adaptGetFeatureInfo(queryContext, worker);
// For backward compatibility between WMS 1.1.1 and WMS 1.0.0, we handle the "Capabilities" request
// as "GetCapabilities" request in version 1.1.1.
} else if (GETCAPABILITIES.equalsIgnoreCase(request) || CAPABILITIES.equalsIgnoreCase(request)) {
return adaptGetCapabilities(request, worker);
} else if (GETLEGENDGRAPHIC.equalsIgnoreCase(request)) {
return adaptGetLegendGraphic();
} else if (DESCRIBELAYER.equalsIgnoreCase(request)) {
return adaptDescribeLayer(worker);
}
throw new CstlServiceException("The operation " + request + " is not supported by the service", INVALID_PARAMETER_VALUE, "request");
}
/**
* Generate an error response in image if query asks it.
* Otherwise this call will fallback on normal xml error.
*/
private Response processExceptionResponse(final QueryContext queryContext, final CstlServiceException ex, ServiceDef serviceDef, final Worker w) {
logException(ex);
// Now handle in image response or exception report.
if (queryContext.isErrorInimage()) {
final BufferedImage image = DefaultPortrayalService.writeException(ex, new Dimension(600, 400), queryContext.isOpaque());
return Response.ok(image, queryContext.getExceptionImageFormat()).build();
} else {
return processExceptionResponse(ex, serviceDef, w);
}
}
/**
* {@inheritDoc}
*/
@Override
protected Response processExceptionResponse(final CstlServiceException ex, ServiceDef serviceDef, final Worker w) {
if (serviceDef == null) {
serviceDef = w.getBestVersion(null);
}
final Version version = serviceDef.exceptionVersion;
final String locator = ex.getLocator();
final ServiceExceptionReport report = new ServiceExceptionReport(version,
(locator == null) ? new ServiceExceptionType(ex.getMessage(), ex.getExceptionCode()) :
new ServiceExceptionType(ex.getMessage(), ex.getExceptionCode(), locator));
final String schemaLocation;
if (serviceDef.equals(ServiceDef.WMS_1_1_1_SLD) || serviceDef.equals(ServiceDef.WMS_1_1_1)) {
schemaLocation = "http://schemas.opengis.net/wms/1.1.1/exception_1_1_1.dtd";
} else {
schemaLocation = "http://www.opengis.net/ogc http://schemas.opengis.net/wms/1.3.0/exceptions_1_3_0.xsd";
}
final SchemaLocatedExceptionResponse response = new SchemaLocatedExceptionResponse(report, schemaLocation);
final String mimeException = (serviceDef.version.equals(ServiceDef.WMS_1_1_1_SLD.version)) ? MimeType.APP_SE_XML : MimeType.TEXT_XML;
return Response.ok(response, mimeException).build();
}
/**
* Converts a DescribeLayer request composed of string values, to a container
* of real java objects.
*
* @return The DescribeLayer request.
* @throws CstlServiceException
*/
private DescribeLayer adaptDescribeLayer(final Worker worker) throws CstlServiceException {
String version = getParameter(VERSION_PARAMETER, false);
if (version == null) {
version = getParameter(KEY_WMTVER, false);
}
if (version == null) {
throw new CstlServiceException("The parameter version must be specified",
MISSING_PARAMETER_VALUE, "version");
}
ServiceDef serviceDef = worker.getVersionFromNumber(version);
if (serviceDef == null) {
serviceDef = worker.getBestVersion(null);
}
worker.checkVersionSupported(version, false);
final String strLayer = getParameter(KEY_LAYERS, true);
final List<String> layers = StringUtilities.toStringList(strLayer);
return new DescribeLayer(layers, serviceDef.version);
}
/**
* Converts a GetCapabilities request composed of string values, to a container
* of real java objects.
*
* @return A GetCapabilities request.
* @throws CstlServiceException
*/
private GetCapabilities adaptGetCapabilities(final String request, final Worker worker) throws CstlServiceException {
String version;
if (CAPABILITIES.equalsIgnoreCase(request)) {
version = ServiceDef.WMS_1_1_1_SLD.version.toString();
} else {
version = getParameter(VERSION_PARAMETER, false);
if (version == null) {
// For backward compatibility with WMS 1.0.0, we try to find the version number
// from the WMTVER parameter too.
version = getParameter(KEY_WMTVER, false);
}
}
final String service = getParameter(SERVICE_PARAMETER, true);
if (!ServiceDef.Specification.WMS.toString().equalsIgnoreCase(service)) {
throw new CstlServiceException("Invalid service specified. Should be WMS.",
INVALID_PARAMETER_VALUE, SERVICE_PARAMETER.toLowerCase());
}
final String language = getParameter(KEY_LANGUAGE, false);
if (version == null) {
final ServiceDef capsService = worker.getBestVersion(null);
String format = getParameter(KEY_FORMAT, false);
// Verify that the format is not null, and is not something totally different from the known
// output formats. If it is the case, choose the default output format according to the version.
if (format == null || format.isEmpty() ||
(!format.equalsIgnoreCase(MimeType.APP_XML) && !format.equalsIgnoreCase(MimeType.APPLICATION_XML)
&& !format.equalsIgnoreCase(MimeType.TEXT_XML) && !format.equalsIgnoreCase(MimeType.APP_WMS_XML)))
{
format = (ServiceDef.WMS_1_1_1_SLD.version.equals(capsService.version)) ?
MimeType.APP_WMS_XML : MimeType.TEXT_XML;
}
return new GetCapabilities(capsService.version, format, language);
}
final ServiceDef bestVersion = worker.getBestVersion(version);
String format = getParameter(KEY_FORMAT, false);
// Verify that the format is not null, and is not something totally different from the known
// output formats. If it is the case, choose the default output format according to the version.
if (format == null || format.isEmpty() ||
(!format.equalsIgnoreCase(MimeType.APP_XML) && !format.equalsIgnoreCase(MimeType.APPLICATION_XML)
&& !format.equalsIgnoreCase(MimeType.TEXT_XML) && !format.equalsIgnoreCase(MimeType.APP_WMS_XML)))
{
format = (ServiceDef.WMS_1_1_1_SLD.version.equals(bestVersion.version)) ?
MimeType.APP_WMS_XML : MimeType.TEXT_XML;
}
final String updateSequence = getParameter(UPDATESEQUENCE_PARAMETER, false);
return new GetCapabilities(bestVersion.version, format, language, updateSequence);
}
/**
* Converts a GetFeatureInfo request composed of string values, to a container
* of real java objects.
*
* @return A GetFeatureInfo request.
* @throws CstlServiceException
*/
private GetFeatureInfo adaptGetFeatureInfo(final QueryContext queryContext, final Worker worker) throws CstlServiceException, NumberFormatException {
final GetMap getMap = adaptGetMap(false, queryContext, worker);
String version = getParameter(VERSION_PARAMETER, false);
if (version == null) {
version = getParameter(KEY_WMTVER, false);
}
if (version == null) {
throw new CstlServiceException("The parameter version must be specified",
MISSING_PARAMETER_VALUE, "version");
}
final String strX = getParameter(version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString()) ? KEY_I_V111 : KEY_I_V130, true);
final String strY = getParameter(version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString()) ? KEY_J_V111 : KEY_J_V130, true);
final String strQueryLayers = getParameter(KEY_QUERY_LAYERS, true);
String infoFormat = getParameter(KEY_INFO_FORMAT, false);
final String strFeatureCount = getParameter(KEY_FEATURE_COUNT, false);
final List<String> queryLayers = StringUtilities.toStringList(strQueryLayers);
final List<String> queryableLayers = MapUtilities.areQueryableLayers(queryLayers, null);
final List<GenericName> namedQueryableLayers = parseNamespaceLayerList(queryableLayers);
if (infoFormat == null) {
infoFormat = MimeType.TEXT_XML;
}
final int x, y;
try {
x = RequestsUtilities.toInt(strX);
} catch (NumberFormatException ex) {
throw new CstlServiceException("Integer value waited. " + ex.getMessage(), ex, INVALID_POINT,
version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString()) ? KEY_I_V111 : KEY_I_V130);
}
try {
y = RequestsUtilities.toInt(strY);
} catch (NumberFormatException ex) {
throw new CstlServiceException("Integer value waited. " + ex.getMessage(), ex, INVALID_POINT,
version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString()) ? KEY_J_V111 : KEY_J_V130);
}
final Integer featureCount;
if (strFeatureCount == null || strFeatureCount.isEmpty()) {
featureCount = 1;
} else {
featureCount = RequestsUtilities.toInt(strFeatureCount);
}
return new GetFeatureInfo(getMap, x, y, namedQueryableLayers, infoFormat, featureCount);
}
/**
* Return a List of named Layer (namespace : name) from a string list.
*
* @param layerNames
* @return
*/
private List<GenericName> parseNamespaceLayerList(List<String> layerNames) {
final List<GenericName> result = new ArrayList<>();
for (String layerName : layerNames) {
result.add(Util.parseLayerName(layerName));
}
return result;
}
/**
* Converts a GetLegendGraphic request composed of string values, to a container
* of real java objects.
*
* @return The GetLegendGraphic request.
* @throws CstlServiceException
*/
private GetLegendGraphic adaptGetLegendGraphic() throws CstlServiceException {
final GenericName strLayer = Util.parseLayerName(getParameter(KEY_LAYER, true));
final String strFormat = getParameter(KEY_FORMAT, true );
// Verify that the format is known, otherwise returns an exception.
final String format;
try {
format = RequestsUtilities.toFormat(strFormat);
} catch (IllegalArgumentException i) {
throw new CstlServiceException(i, INVALID_FORMAT);
}
final String strWidth = getParameter(KEY_WIDTH, false);
final String strHeight = getParameter(KEY_HEIGHT, false);
final Integer width;
final Integer height;
if (strWidth == null || strHeight == null) {
width = null;
height = null;
} else {
try {
width = RequestsUtilities.toInt(strWidth);
} catch (NumberFormatException n) {
throw new CstlServiceException(n, INVALID_PARAMETER_VALUE, KEY_WIDTH.toLowerCase());
}
try {
height = RequestsUtilities.toInt(strHeight);
} catch (NumberFormatException n) {
throw new CstlServiceException(n, INVALID_PARAMETER_VALUE, KEY_HEIGHT.toLowerCase());
}
}
final String strStyle = getParameter(KEY_STYLE, false);
final String strSld = getParameter(KEY_SLD, false);
final String strSldVers = getParameter(KEY_SLD_VERSION, (strSld != null) ? true : false);
final String strRule = getParameter(KEY_RULE, false);
final StyledLayerDescriptor sldVersion;
if (strSldVers == null) {
sldVersion = null;
} else if (strSldVers.equalsIgnoreCase("1.0.0")) {
sldVersion = StyledLayerDescriptor.V_1_0_0;
} else if (strSldVers.equalsIgnoreCase("1.1.0")) {
sldVersion = StyledLayerDescriptor.V_1_1_0;
} else {
throw new CstlServiceException("The given sld version number "+ strSldVers +" is not known.",
INVALID_PARAMETER_VALUE, KEY_SLD_VERSION.toLowerCase());
}
final String strScale = getParameter(KEY_SCALE, false);
final Double scale = RequestsUtilities.toDouble(strScale);
return new GetLegendGraphic(strLayer, format, width, height, strStyle, strSld, sldVersion, strRule, scale, ServiceDef.WMS_1_1_1_SLD.version);
}
private boolean isV111orUnder(String version) {
return version.equals(ServiceDef.WMS_1_0_0.version.toString()) ||
version.equals(ServiceDef.WMS_1_0_0_SLD.version.toString()) ||
version.equals(ServiceDef.WMS_1_1_1.version.toString()) ||
version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString());
}
/**
* Converts a GetMap request composed of string values, to a container of real
* java objects.
*
* @param fromGetMap {@code true} if the request is done for a GetMap, {@code false}
* otherwise (in the case of a GetFeatureInfo for example).
* @return The GetMap request.
* @throws CstlServiceException
*/
private GetMap adaptGetMap(final boolean fromGetMap, final QueryContext queryContext, final Worker w) throws CstlServiceException {
String version = getParameter(VERSION_PARAMETER, false);
if (version == null) {
version = getParameter(KEY_WMTVER, false);
}
if (version == null) {
throw new CstlServiceException("The parameter version must be specified", MISSING_PARAMETER_VALUE, "version");
}
w.checkVersionSupported(version, false);
final String strExceptions = getParameter(WMSConstant.KEY_EXCEPTIONS, false);
/*
* we verify that the exception format is an allowed value
*/
if (ServiceDef.WMS_1_3_0_SLD.version.toString().equals(version)) {
if (strExceptions != null && !WMSConstant.EXCEPTION_130.contains(strExceptions)) {
throw new CstlServiceException("exception format:" + strExceptions + " is not allowed. Use XML, INIMAGE or BLANK", INVALID_PARAMETER_VALUE);
}
} else {
if (strExceptions != null && !WMSConstant.EXCEPTION_111.contains(strExceptions)) {
throw new CstlServiceException("exception format:" + strExceptions + " is not allowed. Use application/vnd.ogc.se_xml, application/vnd.ogc.se_inimage or application/vnd.ogc.se_blank", INVALID_PARAMETER_VALUE);
}
}
if (strExceptions != null && (strExceptions.equalsIgnoreCase(MimeType.APP_INIMAGE) || strExceptions.equalsIgnoreCase("INIMAGE"))) {
queryContext.setErrorInimage(true);
}
final String strFormat = getParameter(KEY_FORMAT, fromGetMap);
if (strFormat != null && !strFormat.isEmpty()) {
// Ensures that the format specified is known, to use it as the format of the
// image which will contain the exception.
if (strFormat.equalsIgnoreCase(MimeType.IMAGE_BMP) ||
strFormat.equalsIgnoreCase(MimeType.IMAGE_GIF) ||
strFormat.equalsIgnoreCase(MimeType.IMAGE_JPEG)||
strFormat.equalsIgnoreCase(MimeType.IMAGE_PNG) ||
strFormat.equalsIgnoreCase(MimeType.IMAGE_TIFF))
{
queryContext.setExceptionImageFormat(strFormat);
}
}
final String strCRS = getParameter((version.equals(ServiceDef.WMS_1_1_1_SLD.version.toString())) ?
KEY_CRS_V111 : KEY_CRS_V130, true);
final String strBBox = getParameter(KEY_BBOX, true);
final String strLayers = getParameter(KEY_LAYERS, true);
final String strWidth = getParameter(KEY_WIDTH, true);
final String strHeight = getParameter(KEY_HEIGHT, true);
final String strElevation = getParameter(KEY_ELEVATION, false);
final String strTime = getParameter(KEY_TIME, false);
final String strBGColor = getParameter(KEY_BGCOLOR, false);
final String strTransparent = getParameter(KEY_TRANSPARENT, false);
//final String strRemoteOwsType = getParameter(KEY_REMOTE_OWS_TYPE, false);
final String strRemoteOwsUrl = getParameter(KEY_REMOTE_OWS_URL, false);
final String urlSLD = getParameter(KEY_SLD, false);
final String bodySLD = getParameter(KEY_SLD_BODY, false);
final String strSldVersion = getParameter(KEY_SLD_VERSION, (urlSLD != null) ? true : false);
final String strAzimuth = getParameter(KEY_AZIMUTH, false);
final String strStyles = getParameter(KEY_STYLES, ((urlSLD != null)) ? false : fromGetMap);
final CoordinateReferenceSystem crs;
boolean forceLongitudeFirst = false;
try {
if (isV111orUnder(version)) {
/*
* If we are in version older than WMS 1.3.0, then the bounding box is
* expressed with the longitude in first, even if the CRS has the latitude as
* first axis. Consequently we have to force the longitude in first for the
* CRS decoding.
*/
forceLongitudeFirst = true;
}
crs = CRS.decode(strCRS, forceLongitudeFirst);
} catch (FactoryException ex) {
if (isV111orUnder(version)) {
throw new CstlServiceException(ex, org.constellation.ws.ExceptionCode.INVALID_SRS);
} else {
throw new CstlServiceException(ex, INVALID_CRS);
}
}
final Envelope env;
try {
env = RequestsUtilities.toEnvelope(strBBox, crs);
} catch (IllegalArgumentException i) {
throw new CstlServiceException(i, INVALID_PARAMETER_VALUE);
}
final String format;
try {
format = RequestsUtilities.toFormat(strFormat);
} catch (IllegalArgumentException i) {
throw new CstlServiceException(i, INVALID_FORMAT, KEY_FORMAT.toLowerCase());
}
final List<String> layers = StringUtilities.toStringList(strLayers);
final List<GenericName> namedLayers = parseNamespaceLayerList(layers);
final List<String> styles = StringUtilities.toStringList(strStyles);
MutableStyledLayerDescriptor sld = null;
final Double elevation;
try {
elevation = (strElevation != null) ? RequestsUtilities.toDouble(strElevation) : null;
} catch (NumberFormatException n) {
throw new CstlServiceException(n, INVALID_PARAMETER_VALUE, KEY_ELEVATION.toLowerCase());
}
final ArrayList<Date> dates = new ArrayList<>();
try {
TimeParser.parse(strTime, 0l, dates);
} catch (ParseException ex) {
throw new CstlServiceException(ex, INVALID_PARAMETER_VALUE, KEY_TIME.toLowerCase());
}
final int width;
final int height;
try {
width = RequestsUtilities.toInt(strWidth);
height = RequestsUtilities.toInt(strHeight);
} catch (NumberFormatException n) {
throw new CstlServiceException(n, INVALID_DIMENSION_VALUE);
}
final Dimension size = new Dimension(width, height);
final Color background = RequestsUtilities.toColor(strBGColor);
final boolean transparent = RequestsUtilities.toBoolean(strTransparent);
queryContext.setOpaque(!transparent);
if (strRemoteOwsUrl != null) {
InputStream in = null;
try {
in = new FileInputStream(new File(strRemoteOwsUrl));
} catch (FileNotFoundException ex) {
throw new CstlServiceException(ex, STYLE_NOT_DEFINED);
}
final StyleXmlIO sldparser = new StyleXmlIO();
try {
sld = sldparser.readSLD(in,
StyledLayerDescriptor.V_1_0_0);
} catch (JAXBException ex) {
// If a JAXBException occurs it can be because it is not parsed in the
// good version. Let's just continue with the other version.
LOGGER.finest(ex.getLocalizedMessage());
} catch (FactoryException ex) {
throw new CstlServiceException(ex, STYLE_NOT_DEFINED);
}
if (sld == null) {
try {
sld = sldparser.readSLD(in,
StyledLayerDescriptor.V_1_1_0);
} catch (JAXBException ex) {
throw new CstlServiceException(ex, STYLE_NOT_DEFINED);
} catch (FactoryException ex) {
throw new CstlServiceException(ex, STYLE_NOT_DEFINED);
}
}
} else {
try {
final StyledLayerDescriptor sldVersion;
if (strSldVersion == null) {
sldVersion = null;
} else if (strSldVersion.equalsIgnoreCase("1.1.0")) {
sldVersion = StyledLayerDescriptor.V_1_1_0;
} else if (strSldVersion.equalsIgnoreCase("1.0.0")) {
sldVersion = StyledLayerDescriptor.V_1_0_0;
} else {
throw new CstlServiceException("The given sld version "+ strSldVersion +" is not known.",
INVALID_PARAMETER_VALUE, KEY_SLD_VERSION.toLowerCase());
}
sld = MapUtilities.toSLD(bodySLD, urlSLD, sldVersion);
} catch (MalformedURLException ex) {
throw new CstlServiceException(ex, STYLE_NOT_DEFINED);
}
}
final double azimuth;
try {
azimuth = (strAzimuth == null) ? 0.0 : RequestsUtilities.toDouble(strAzimuth);
} catch(NumberFormatException ex) {
throw new CstlServiceException(ex, INVALID_PARAMETER_VALUE, KEY_AZIMUTH.toLowerCase());
}
// Builds the request.
return new GetMap(env, new Version(version), format, namedLayers, styles, sld, elevation,
dates, size, background, transparent, azimuth, strExceptions, getParameters());
}
}