/* * 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.coverage.ws.rs; // Jersey dependencies import org.constellation.ServiceDef; import org.constellation.ServiceDef.Specification; import org.constellation.api.QueryConstants; import org.constellation.coverage.ws.DefaultWCSWorker; import org.constellation.coverage.ws.WCSWorker; import org.constellation.ws.CstlServiceException; import org.constellation.ws.ExceptionCode; import org.constellation.ws.MimeType; import org.constellation.ws.Worker; import org.constellation.ws.rs.GridWebService; import org.constellation.ws.rs.provider.SchemaLocatedExceptionResponse; import org.geotoolkit.client.RequestsUtilities; import org.geotoolkit.gml.xml.v311.CodeType; import org.geotoolkit.gml.xml.v311.DirectPositionType; import org.geotoolkit.gml.xml.v311.EnvelopeType; import org.geotoolkit.gml.xml.v311.GridLimitsType; import org.geotoolkit.gml.xml.v311.GridType; import org.geotoolkit.ogc.xml.exception.ServiceExceptionReport; import org.geotoolkit.ogc.xml.exception.ServiceExceptionType; import org.geotoolkit.ows.xml.AcceptFormats; import org.geotoolkit.ows.xml.AcceptVersions; import org.geotoolkit.ows.xml.ExceptionResponse; import org.geotoolkit.ows.xml.RequestBase; import org.geotoolkit.ows.xml.Sections; import org.geotoolkit.ows.xml.v110.BoundingBoxType; import org.geotoolkit.ows.xml.v110.ExceptionReport; import org.geotoolkit.ows.xml.v110.SectionsType; import org.geotoolkit.resources.Errors; import org.geotoolkit.util.StringUtilities; import org.geotoolkit.wcs.xml.DescribeCoverage; import org.geotoolkit.wcs.xml.DescribeCoverageResponse; import org.geotoolkit.wcs.xml.DomainSubset; import org.geotoolkit.wcs.xml.GetCapabilities; import org.geotoolkit.wcs.xml.GetCapabilitiesResponse; import org.geotoolkit.wcs.xml.GetCoverage; import org.geotoolkit.wcs.xml.TimeSequence; import org.geotoolkit.wcs.xml.WCSMarshallerPool; import org.geotoolkit.wcs.xml.WCSXmlFactory; import org.geotoolkit.wcs.xml.v111.GridCrsType; import org.geotoolkit.wcs.xml.v111.RangeSubsetType.FieldSubset; import javax.inject.Singleton; import javax.ws.rs.Path; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.StringTokenizer; import java.util.logging.Level; import static org.constellation.api.QueryConstants.ACCEPT_FORMATS_PARAMETER; import static org.constellation.api.QueryConstants.REQUEST_PARAMETER; import static org.constellation.api.QueryConstants.SECTIONS_PARAMETER; import static org.constellation.api.QueryConstants.UPDATESEQUENCE_PARAMETER; import static org.constellation.api.QueryConstants.VERSION_PARAMETER; import static org.constellation.coverage.ws.WCSConstant.ASCII_GRID; import static org.constellation.coverage.ws.WCSConstant.BMP; import static org.constellation.coverage.ws.WCSConstant.DESCRIBECOVERAGE; import static org.constellation.coverage.ws.WCSConstant.GEOTIFF; import static org.constellation.coverage.ws.WCSConstant.GETCAPABILITIES; import static org.constellation.coverage.ws.WCSConstant.GETCOVERAGE; import static org.constellation.coverage.ws.WCSConstant.GIF; import static org.constellation.coverage.ws.WCSConstant.JPEG; import static org.constellation.coverage.ws.WCSConstant.JPG; import static org.constellation.coverage.ws.WCSConstant.KEY_BBOX; import static org.constellation.coverage.ws.WCSConstant.KEY_BOUNDINGBOX; import static org.constellation.coverage.ws.WCSConstant.KEY_CATEGORIES; import static org.constellation.coverage.ws.WCSConstant.KEY_COVERAGE; import static org.constellation.coverage.ws.WCSConstant.KEY_CRS; import static org.constellation.coverage.ws.WCSConstant.KEY_DEPTH; import static org.constellation.coverage.ws.WCSConstant.KEY_FORMAT; import static org.constellation.coverage.ws.WCSConstant.KEY_GRIDBASECRS; import static org.constellation.coverage.ws.WCSConstant.KEY_GRIDCS; import static org.constellation.coverage.ws.WCSConstant.KEY_GRIDOFFSETS; import static org.constellation.coverage.ws.WCSConstant.KEY_GRIDORIGIN; import static org.constellation.coverage.ws.WCSConstant.KEY_GRIDTYPE; import static org.constellation.coverage.ws.WCSConstant.KEY_HEIGHT; import static org.constellation.coverage.ws.WCSConstant.KEY_IDENTIFIER; import static org.constellation.coverage.ws.WCSConstant.KEY_COVERAGE_ID; import static org.constellation.coverage.ws.WCSConstant.KEY_INTERPOLATION; import static org.constellation.coverage.ws.WCSConstant.KEY_MEDIA_TYPE; import static org.constellation.coverage.ws.WCSConstant.KEY_RANGESUBSET; import static org.constellation.coverage.ws.WCSConstant.KEY_RESPONSE_CRS; import static org.constellation.coverage.ws.WCSConstant.KEY_RESX; import static org.constellation.coverage.ws.WCSConstant.KEY_RESY; import static org.constellation.coverage.ws.WCSConstant.KEY_RESZ; import static org.constellation.coverage.ws.WCSConstant.KEY_SECTION; import static org.constellation.coverage.ws.WCSConstant.KEY_TIME; import static org.constellation.coverage.ws.WCSConstant.KEY_TIMESEQUENCE; import static org.constellation.coverage.ws.WCSConstant.KEY_WIDTH; import static org.constellation.coverage.ws.WCSConstant.MATRIX; import static org.constellation.coverage.ws.WCSConstant.NETCDF; import static org.constellation.coverage.ws.WCSConstant.PNG; import static org.constellation.coverage.ws.WCSConstant.TIF; import static org.constellation.coverage.ws.WCSConstant.TIFF; 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.MISSING_PARAMETER_VALUE; import static org.geotoolkit.ows.xml.OWSExceptionCode.OPERATION_NOT_SUPPORTED; import static org.geotoolkit.ows.xml.OWSExceptionCode.VERSION_NEGOTIATION_FAILED; import org.geotoolkit.wcs.xml.v200.GetCoverageType; // J2SE dependencies // Constellation dependencies // Geotoolkit dependencies /** * The Web Coverage Service (WCS) REST facade for Constellation. * <p> * This service implements the following methods: * <ul> * <li>{@code GetCoverage(.)}</li> * <li>{@code DescribeCoverage(.)}</li> * <li>{@code GetCapabilities(.)}</li> * </ul> * of the Open Geospatial Consortium (OGC) WCS specifications. As of * Constellation version 0.3, this Web Coverage Service complies with the * specification version 1.0.0 (OGC document 03-065r6) and mostly complies with * specification version 1.1.1 (OGC document 06-083r8). * </p> * * @version $Id$ * @author Guilhem Legal * @author Cédric Briançon * @since 0.3 */ @Path("wcs/{serviceId}") @Singleton public class WCSService extends GridWebService<WCSWorker> { /** * Build a new instance of the webService and initialize the JAXB context. */ public WCSService() { super(Specification.WCS); setFullRequestLog(true); //we build the JAXB marshaller and unmarshaller to bind java/xml setXMLContext(WCSMarshallerPool.getInstance()); LOGGER.log(Level.INFO, "WCS REST service running ({0} instances)", getWorkerMapSize()); } /** * {@inheritDoc} */ @Override protected Class getWorkerClass() { return DefaultWCSWorker.class; } /** * {@inheritDoc} */ @Override public Response treatIncomingRequest(Object objectRequest, final WCSWorker worker) { ServiceDef serviceDef = null; try { String request = ""; // if the request is not an xml request we fill the request parameter. if (objectRequest == null) { request = getParameter(REQUEST_PARAMETER, true); objectRequest = adaptQuery(request, worker); } if (objectRequest instanceof GetCapabilities){ final GetCapabilities getcaps = (GetCapabilities)objectRequest; serviceDef = worker.getVersionFromNumber(getcaps.getVersion()); final GetCapabilitiesResponse capsResponse = worker.getCapabilities(getcaps); return Response.ok(capsResponse, MimeType.TEXT_XML).build(); } if (objectRequest instanceof DescribeCoverage) { final DescribeCoverage desccov = (DescribeCoverage)objectRequest; if (desccov.getVersion() == null) { throw new CstlServiceException("The parameter version must be specified", MISSING_PARAMETER_VALUE, "version"); } serviceDef = worker.getVersionFromNumber(desccov.getVersion()); final DescribeCoverageResponse describeResponse = worker.describeCoverage(desccov); return Response.ok(describeResponse, MimeType.TEXT_XML).build(); } if (objectRequest instanceof GetCoverage) { final GetCoverage getcov = (GetCoverage)objectRequest; if (getcov.getVersion() == null) { throw new CstlServiceException("The parameter version must be specified", MISSING_PARAMETER_VALUE, "version"); } else if (getcov.getFormat() == null) { throw new CstlServiceException("The parameter format must be specified", MISSING_PARAMETER_VALUE, "format"); } serviceDef = worker.getVersionFromNumber(getcov.getVersion()); String format = getcov.getFormat(); if (!isSupportedFormat(getcov.getVersion().toString(), format)){ throw new CstlServiceException("The format specified is not recognized. Please choose a known format " + "for your coverage, defined in a DescribeCoverage response on the coverage.", INVALID_FORMAT, KEY_FORMAT.toLowerCase()); } format = getOutputFormat(format, getcov.getMediaType()); return Response.ok(worker.getCoverage(getcov), format).build(); } throw new CstlServiceException("This service can not handle the requested operation: " + request + ".", OPERATION_NOT_SUPPORTED, QueryConstants.REQUEST_PARAMETER.toLowerCase()); } catch (CstlServiceException ex) { /* * This block handles all the exceptions which have been generated * anywhere in the service and transforms them to a response message * for the protocol stream which JAXB, in this case, will then * marshall and serialize into an XML message HTTP response. */ return processExceptionResponse(ex, serviceDef, worker); } } private String getOutputFormat(String format, String mediaType) { if (mediaType != null) { return mediaType; } if (format.equalsIgnoreCase(MATRIX)) { format = MimeType.MATRIX; } else if (format.equalsIgnoreCase(ASCII_GRID)) { format = MimeType.ASCII_GRID; } else if (format.equalsIgnoreCase(NETCDF)) { format = MimeType.NETCDF; } else if (format.equalsIgnoreCase(PNG)) { format = MimeType.IMAGE_PNG; } else if (format.equalsIgnoreCase(GIF)) { format = MimeType.IMAGE_GIF; } else if (format.equalsIgnoreCase(BMP)) { format = MimeType.IMAGE_BMP; } else if (format.equalsIgnoreCase(JPEG) || format.equalsIgnoreCase(JPG)) { format = MimeType.IMAGE_JPEG; } else if (format.equalsIgnoreCase(TIF) || format.equalsIgnoreCase(TIFF)) { format = MimeType.IMAGE_TIFF; } else if (format.equalsIgnoreCase(GEOTIFF)) { format = "image/geotiff"; } return format; } private boolean isSupportedFormat(final String version, final String format) { if (version.equals("2.0.1")) { return format.equalsIgnoreCase(MimeType.IMAGE_TIFF) || format.equalsIgnoreCase(MimeType.NETCDF); } else { return format.equalsIgnoreCase(MimeType.IMAGE_BMP) ||format.equalsIgnoreCase(BMP) || format.equalsIgnoreCase(MimeType.IMAGE_GIF) ||format.equalsIgnoreCase(GIF) || format.equalsIgnoreCase(MimeType.IMAGE_JPEG) ||format.equalsIgnoreCase(JPEG) || format.equalsIgnoreCase(JPG) ||format.equalsIgnoreCase(TIF) || format.equalsIgnoreCase(MimeType.IMAGE_TIFF) ||format.equalsIgnoreCase(TIFF) || format.equalsIgnoreCase(MimeType.IMAGE_PNG) ||format.equalsIgnoreCase(PNG) || format.equalsIgnoreCase(GEOTIFF) ||format.equalsIgnoreCase(NETCDF) || format.equalsIgnoreCase(MATRIX) ||format.equalsIgnoreCase(ASCII_GRID); } } /** * {@inheritDoc} */ @Override protected Response processExceptionResponse(final CstlServiceException ex, ServiceDef serviceDef, final Worker w) { logException(ex); // SEND THE HTTP RESPONSE final ExceptionResponse report; if (serviceDef == null) { // TODO: Get the best version for WCS. For the moment, just 1.0.0. serviceDef = ServiceDef.WCS_1_0_0; //serviceDef = getBestVersion(null); } final String locator = ex.getLocator(); final String code; if (ex.getExceptionCode() instanceof ExceptionCode) { code = StringUtilities.transformCodeName(ex.getExceptionCode().name()); } else { code = ex.getExceptionCode().name(); } if (serviceDef.owsCompliant) { report = new ExceptionReport(ex.getMessage(), code, locator, serviceDef.exceptionVersion.toString()); } else { final ServiceExceptionReport exReport = new ServiceExceptionReport(serviceDef.exceptionVersion, (locator == null) ? new ServiceExceptionType(ex.getMessage(), code) : new ServiceExceptionType(ex.getMessage(), code, locator)); report = new SchemaLocatedExceptionResponse(exReport, "http://www.opengis.net/ogc http://schemas.opengis.net/wcs/1.0.0/OGC-exception.xsd"); } return Response.ok(report, MimeType.APP_SE_XML).build(); } public RequestBase adaptQuery(final String request, final Worker w) throws CstlServiceException { if (GETCAPABILITIES.equalsIgnoreCase(request)) { return adaptKvpGetCapabilitiesRequest(w); } else if (GETCOVERAGE.equalsIgnoreCase(request)) { return adaptKvpGetCoverageRequest(w); } else if (DESCRIBECOVERAGE.equalsIgnoreCase(request)) { return adaptKvpDescribeCoverageRequest(w); } throw new CstlServiceException("The operation " + request + " is not supported by the service", INVALID_PARAMETER_VALUE, "request"); } /** * Build a new {@linkplain AbstractGetCapabilities GetCapabilities} request from * from a request formulated as a Key-Value Pair either in the URL or as a * plain text message body. * * @return a marshallable GetCapabilities request. * @throws CstlServiceException */ private GetCapabilities adaptKvpGetCapabilitiesRequest(final Worker w) throws CstlServiceException { final String service = getParameter(QueryConstants.SERVICE_PARAMETER, true); if (!service.equalsIgnoreCase("WCS")) { throw new CstlServiceException("The parameter SERVICE must be specified as WCS", MISSING_PARAMETER_VALUE, QueryConstants.SERVICE_PARAMETER.toLowerCase()); } // TODO: find the best version when the WCS 1.1.1 will be fully implemented. // For the moment, the version chosen is always the 1.0.0. String inputVersion = getParameter(QueryConstants.VERSION_PARAMETER, false); if (inputVersion == null) { inputVersion = getParameter("acceptversions", false); if (inputVersion == null) { inputVersion = w.getBestVersion(null).version.toString(); } else { //we verify that the version is supported w.checkVersionSupported(inputVersion, true); } } final String finalVersion = w.getBestVersion(inputVersion).version.toString(); final String updateSequence = getParameter(UPDATESEQUENCE_PARAMETER, false); if (finalVersion.equals("1.0.0")) { final String section = getParameter(KEY_SECTION, false); final Sections sections = WCSXmlFactory.buildSections(finalVersion, Arrays.asList(section)); return WCSXmlFactory.createGetCapabilities(finalVersion, null, sections, null, updateSequence, service); } else if (finalVersion.equals("1.1.1") || finalVersion.equals("2.0.1")) { final String acceptformat = getParameter(ACCEPT_FORMATS_PARAMETER, false); final AcceptFormats formats = WCSXmlFactory.buildAcceptFormat(finalVersion, Arrays.asList(acceptformat)); //We transform the String of sections in a list. //In the same time we verify that the requested sections are valid. final String section = getParameter(SECTIONS_PARAMETER, false); final List<String> requestedSections; if (section != null) { requestedSections = new ArrayList<>(); final StringTokenizer tokens = new StringTokenizer(section, ",;"); while (tokens.hasMoreTokens()) { final String token = tokens.nextToken().trim(); if (SectionsType.getExistingSections(ServiceDef.WCS_1_1_1.version.toString()).contains(token)) { requestedSections.add(token); } else { throw new CstlServiceException("The section " + token + " does not exist", INVALID_PARAMETER_VALUE, KEY_SECTION.toLowerCase()); } } } else { //if there is no requested Sections we add all the sections requestedSections = SectionsType.getExistingSections(ServiceDef.WCS_1_1_1.version.toString()); } final Sections sections = WCSXmlFactory.buildSections(finalVersion, requestedSections); final AcceptVersions versions = WCSXmlFactory.buildAcceptVersion(finalVersion, Arrays.asList(finalVersion)); return WCSXmlFactory.createGetCapabilities(finalVersion, versions, sections, formats, updateSequence, service); } else { throw new CstlServiceException("The version number specified for this request " + "is not handled.", VERSION_NEGOTIATION_FAILED, QueryConstants.VERSION_PARAMETER.toLowerCase()); } } /** * Build a new {@linkplain AbstractDescribeCoverage DescribeCoverage} * request from a Key-Value Pair request. * * @return a marshallable DescribeCoverage request. * @throws CstlServiceException */ private DescribeCoverage adaptKvpDescribeCoverageRequest(final Worker w) throws CstlServiceException { final String strVersion = getParameter(QueryConstants.VERSION_PARAMETER, true); w.checkVersionSupported(strVersion, false); final String coverage; if ("1.0.0".equals(strVersion)) { coverage = getParameter(KEY_COVERAGE, true); } else if ("1.1.1".equals(strVersion)) { coverage = getParameter(KEY_IDENTIFIER, true); } else if ("2.0.1".equals(strVersion)) { coverage = getParameter(KEY_COVERAGE_ID, true); } else { throw new CstlServiceException("The version number specified for this request " + "is not handled.", VERSION_NEGOTIATION_FAILED, QueryConstants.VERSION_PARAMETER.toLowerCase()); } return WCSXmlFactory.createDescribeCoverage(strVersion, Arrays.asList(coverage)); } /** * Build a new {@linkplain AbstractGetCoverage GetCoverage} request from a * Key-Value Pair request. * * @return a marshallable GetCoverage request. * @throws CstlServiceException */ private GetCoverage adaptKvpGetCoverageRequest(final Worker w) throws CstlServiceException { final String strVersion = getParameter(VERSION_PARAMETER, true); w.checkVersionSupported(strVersion, false); if (strVersion.equals("1.0.0")) { return adaptKvpGetCoverageRequest100(); } else if (strVersion.equals("1.1.1")) { return adaptKvpGetCoverageRequest111(); } else if (strVersion.equals("2.0.1")) { return adaptKvpGetCoverageRequest200(); } else { throw new CstlServiceException("The version number specified for this request " + "is not handled.", VERSION_NEGOTIATION_FAILED, QueryConstants.VERSION_PARAMETER.toLowerCase()); } } /** * Generate a marshallable {@linkplain org.geotoolkit.wcs.xml.v200.GetCoverage GetCoverage} * request in version 1.0.0, from what the user specified. * * @return The GetCoverage request in version 2.0.1 * @throws CstlServiceException */ private GetCoverage adaptKvpGetCoverageRequest200() throws CstlServiceException { final String coverageID = getParameter(KEY_COVERAGE_ID, true); final String format = getParameter(KEY_FORMAT, false); final String mediaType = getParameter(KEY_MEDIA_TYPE, false); return new GetCoverageType(coverageID, format, mediaType); } /** * Generate a marshallable {@linkplain org.geotoolkit.wcs.xml.v100.GetCoverage GetCoverage} * request in version 1.0.0, from what the user specified. * * @return The GetCoverage request in version 1.0.0 * @throws CstlServiceException */ private GetCoverage adaptKvpGetCoverageRequest100() throws CstlServiceException { final String width = getParameter(KEY_WIDTH, false); final String height = getParameter(KEY_HEIGHT, false); final String depth = getParameter(KEY_DEPTH, false); final String resx = getParameter(KEY_RESX, false); final String resy = getParameter(KEY_RESY, false); final String resz = getParameter(KEY_RESZ, false); // temporal subset TimeSequence temporal = null; final String time = getParameter(KEY_TIME, false); if (time != null) { temporal = WCSXmlFactory.createTimeSequence("1.0.0", time); } /* * spatial subset */ // the boundingBox/envelope final String bbox = getParameter(KEY_BBOX, false); if (bbox == null && time == null) { throw new CstlServiceException("Either BBOX or TIME parameter must be specified", MISSING_PARAMETER_VALUE); } List<DirectPositionType> pos = null; if (bbox != null) { pos = new ArrayList<>(); final List<String> bboxValues = StringUtilities.toStringList(bbox); final double minimumLon = RequestsUtilities.toDouble(bboxValues.get(0)); final double maximumLon = RequestsUtilities.toDouble(bboxValues.get(2)); try { if (minimumLon > maximumLon) { throw new IllegalArgumentException( Errors.format(Errors.Keys.IllegalRange_2, minimumLon, maximumLon)); } final double minimumLat = RequestsUtilities.toDouble(bboxValues.get(1)); final double maximumLat = RequestsUtilities.toDouble(bboxValues.get(3)); if (minimumLat > maximumLat) { throw new IllegalArgumentException( Errors.format(Errors.Keys.IllegalRange_2, minimumLat, maximumLat)); } if (bboxValues.size() > 4) { final double minimumDepth = RequestsUtilities.toDouble(bboxValues.get(4)); final double maximumDepth = RequestsUtilities.toDouble(bboxValues.get(5)); if (minimumLat > maximumLat) { throw new IllegalArgumentException( Errors.format(Errors.Keys.IllegalRange_2, minimumDepth, maximumDepth)); } pos.add(new DirectPositionType(minimumLon, minimumLat, minimumDepth)); pos.add(new DirectPositionType(maximumLon, maximumLat, maximumDepth)); } else { pos.add(new DirectPositionType(minimumLon, minimumLat)); pos.add(new DirectPositionType(maximumLon, maximumLat)); } } catch (IllegalArgumentException ex) { throw new CstlServiceException(ex, INVALID_PARAMETER_VALUE); } } final EnvelopeType envelope = new EnvelopeType(pos, getParameter(KEY_CRS, true)); if ((width == null || height == null) && (resx == null || resy == null)) { throw new CstlServiceException("You should specify either width/height or resx/resy.", INVALID_DIMENSION_VALUE); } final List<String> axis = new ArrayList<>(); axis.add("width"); axis.add("height"); int[] low = null; int[] high = null; if (width != null && height != null) { if (depth != null) { low = new int[3]; high = new int[3]; axis.add("depth"); low[2] = 0; high[2] = Integer.valueOf(depth); } else { low = new int[2]; high = new int[2]; } low[0] = 0; low[1] = 0; high[0] = Integer.valueOf(width); high[1] = Integer.valueOf(height); } final GridLimitsType limits = new GridLimitsType(low, high); final GridType grid = new GridType(limits, axis); //spatial subset final org.geotoolkit.wcs.xml.v100.SpatialSubsetType spatial = new org.geotoolkit.wcs.xml.v100.SpatialSubsetType(envelope, grid); //domain subset final DomainSubset domain = WCSXmlFactory.createDomainSubset("1.0.0", temporal, spatial); //range subset final org.geotoolkit.wcs.xml.v100.RangeSubsetType rangeSubset; final String categories = getParameter(KEY_CATEGORIES, false); if (categories != null) { final List<Double[]> ranges = RequestsUtilities.toCategoriesRange(categories); final List<Object> objects = new ArrayList<>(); for (Double[] range : ranges) { if (Objects.equals(range[0], range[1])) { objects.add(new org.geotoolkit.wcs.xml.v100.TypedLiteralType(String.valueOf(range[0]), "xs:double")); } else { objects.add(new org.geotoolkit.wcs.xml.v100.IntervalType( new org.geotoolkit.wcs.xml.v100.TypedLiteralType(String.valueOf(range[0]), "xs:double"), new org.geotoolkit.wcs.xml.v100.TypedLiteralType(String.valueOf(range[1]), "xs:double"))); } } final org.geotoolkit.wcs.xml.v100.RangeSubsetType.AxisSubset axisSubset = new org.geotoolkit.wcs.xml.v100.RangeSubsetType.AxisSubset(KEY_CATEGORIES, objects); final List<org.geotoolkit.wcs.xml.v100.RangeSubsetType.AxisSubset> axisSubsets = Collections.singletonList(axisSubset); rangeSubset = new org.geotoolkit.wcs.xml.v100.RangeSubsetType(axisSubsets); } else { rangeSubset = null; } //interpolation method final String interpolation = getParameter(KEY_INTERPOLATION, false); //output final List<Double> resolutions; if (resx != null && resy != null) { resolutions = new ArrayList<>(); resolutions.add(Double.valueOf(resx)); resolutions.add(Double.valueOf(resy)); if (resz != null) { resolutions.add(Double.valueOf(resz)); } } else { resolutions = null; } final org.geotoolkit.wcs.xml.v100.OutputType output = new org.geotoolkit.wcs.xml.v100.OutputType(getParameter(KEY_FORMAT, true), getParameter(KEY_RESPONSE_CRS, false), resolutions); return WCSXmlFactory.createGetCoverage("1.0.0", getParameter(KEY_COVERAGE, true), domain, rangeSubset, interpolation, output); } /** * Generate a marshallable {@linkplain org.geotoolkit.wcs.xml.v111.GetCoverage GetCoverage} * request in version 1.1.1, from what the user specified. * * @return The GetCoverage request in version 1.1.1 * @throws CstlServiceException */ private GetCoverage adaptKvpGetCoverageRequest111() throws CstlServiceException { // temporal subset TimeSequence temporal = null; final String timeParameter = getParameter(KEY_TIMESEQUENCE, false); if (timeParameter != null) { if (timeParameter.indexOf('/') == -1) { temporal = WCSXmlFactory.createTimeSequence("1.1.1", timeParameter); } else { throw new CstlServiceException("The service does not handle TimePeriod", INVALID_PARAMETER_VALUE); } } /* * spatial subset */ // the boundingBox/envelope String bbox = getParameter(KEY_BOUNDINGBOX, true); final String crs; if (bbox.indexOf(',') != -1) { crs = bbox.substring(bbox.lastIndexOf(',') + 1, bbox.length()); bbox = bbox.substring(0, bbox.lastIndexOf(',')); } else { throw new CstlServiceException("The correct pattern for BoundingBox parameter are" + " crs,minX,minY,maxX,maxY,CRS", INVALID_PARAMETER_VALUE, KEY_BOUNDINGBOX.toLowerCase()); } BoundingBoxType envelope = null; if (bbox != null) { final StringTokenizer tokens = new StringTokenizer(bbox, ",;"); final Double[] coordinates = new Double[tokens.countTokens()]; int i = 0; while (tokens.hasMoreTokens()) { coordinates[i] = RequestsUtilities.toDouble(tokens.nextToken()); i++; } if (i < 4) { throw new CstlServiceException("The correct pattern for BoundingBox parameter are" + " crs,minX,minY,maxX,maxY,CRS", INVALID_PARAMETER_VALUE, KEY_BOUNDINGBOX.toLowerCase()); } envelope = new BoundingBoxType(crs, coordinates[0], coordinates[1], coordinates[2], coordinates[3]); } //domain subset final DomainSubset domain = WCSXmlFactory.createDomainSubset("1.1.1", temporal, envelope); //range subset. org.geotoolkit.wcs.xml.v111.RangeSubsetType range = null; final String rangeSubset = getParameter(KEY_RANGESUBSET, false); if (rangeSubset != null) { //for now we don't handle Axis Identifiers if (rangeSubset.indexOf('[') != -1 || rangeSubset.indexOf(']') != -1) { throw new CstlServiceException("The service does not handle axis identifiers", INVALID_PARAMETER_VALUE, "axis"); } final StringTokenizer tokens = new StringTokenizer(rangeSubset, ";"); final List<FieldSubset> fields = new ArrayList<>(tokens.countTokens()); while (tokens.hasMoreTokens()) { final String value = tokens.nextToken(); String interpolation = null; String rangeIdentifier; if (value.indexOf(':') != -1) { rangeIdentifier = value.substring(0, rangeSubset.indexOf(':')); interpolation = value.substring(rangeSubset.indexOf(':') + 1); } else { rangeIdentifier = value; } fields.add(new FieldSubset(rangeIdentifier, interpolation)); } range = new org.geotoolkit.wcs.xml.v111.RangeSubsetType(fields); } String gridType = getParameter(KEY_GRIDTYPE, false); if (gridType == null) { gridType = "urn:ogc:def:method:WCS:1.1:2dSimpleGrid"; } String gridOrigin = getParameter(KEY_GRIDORIGIN, false); if (gridOrigin == null) { gridOrigin = "0.0,0.0"; } StringTokenizer tokens = new StringTokenizer(gridOrigin, ",;"); final List<Double> origin = new ArrayList<>(tokens.countTokens()); while (tokens.hasMoreTokens()) { origin.add(RequestsUtilities.toDouble(tokens.nextToken())); } final String gridOffsets = getParameter(KEY_GRIDOFFSETS, false); final List<Double> offset = new ArrayList<>(); if (gridOffsets != null) { tokens = new StringTokenizer(gridOffsets, ",;"); while (tokens.hasMoreTokens()) { offset.add(RequestsUtilities.toDouble(tokens.nextToken())); } } String gridCS = getParameter(KEY_GRIDCS, false); if (gridCS == null) { gridCS = "urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS"; } //output final CodeType codeCRS = new CodeType(crs); final GridCrsType grid = new GridCrsType(codeCRS, getParameter(KEY_GRIDBASECRS, false), gridType, origin, offset, gridCS, ""); final org.geotoolkit.wcs.xml.v111.OutputType output = new org.geotoolkit.wcs.xml.v111.OutputType(grid, getParameter(KEY_FORMAT, true)); return WCSXmlFactory.createGetCoverage("1.1.1", getParameter(KEY_IDENTIFIER, true), domain, range, null, output); } }