Source: ogc/wcs/WebCoverageService.js

/*
 * Copyright 2003-2006, 2009, 2017, 2020 United States Government, as represented
 * by the Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASAWorldWind/WebWorldWind platform is 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.
 *
 * NASAWorldWind/WebWorldWind also contains the following 3rd party Open Source
 * software:
 *
 *    ES6-Promise – under MIT License
 *    libtess.js – SGI Free Software License B
 *    Proj4 – under MIT License
 *    JSZip – under MIT License
 *
 * A complete listing of 3rd Party software notices and licenses included in
 * WebWorldWind can be found in the WebWorldWind 3rd-party notices and licenses
 * PDF found in code  directory.
 */
/**
 * @exports WebCoverageService
 */
define([
    '../../error/ArgumentError',
    '../../util/Logger',
    '../../util/Promise',
    '../../ogc/wcs/WcsCapabilities',
    '../../ogc/wcs/WcsCoverage',
    '../../ogc/wcs/WcsCoverageDescriptions'
    ],
    function (ArgumentError,
              Logger,
              Promise,
              WcsCapabilities,
              WcsCoverage,
              WcsCoverageDescriptions) {
        "use strict";

        /**
         * Provides a list of coverages from a Web Coverage Service including the capabilities and coverage description
         * documents. For automated configuration, utilize the create function which provides a Promise with a fully
         * configured WebCoverageService.
         * @constructor
         */
        var WebCoverageService = function () {

            /**
             * The URL for the Web Coverage Service
             */
            this.serviceAddress = null;

            /**
             * A collection of WcsCoverages available from this service. Not populated until service is initialized by
             * the connect method.
             * @type {Array}
             */
            this.coverages = [];

            /**
             * The WCS GetCapabilities document for this service.
             * @type {WcsCapabilities}
             */
            this.capabilities = null;

            /**
             * A map of the coverages to their corresponding DescribeCoverage documents.
             * @type {WcsCoverageDescriptions}
             */
            this.coverageDescriptions = null;
        };

        /**
         * The XML namespace for WCS version 1.0.0.
         * @type {string}
         */
        WebCoverageService.WCS_XLMNS = "http://www.opengis.net/wcs";

        /**
         * The XML namespace for WCS version 2.0.0 and 2.0.1.
         * @type {string}
         */
        WebCoverageService.WCS_2_XLMNS = "http://www.opengis.net/wcs/2.0";

        /**
         * Contacts the Web Coverage Service specified by the service address. This function handles version negotiation
         * and capabilities and describe coverage document retrieval. The return is a Promise to a fully initialized
         * WebCoverageService which includes an array of WcsCoverage objects available from this service.
         * @param serviceAddress the url of the WebCoverageService
         * @returns {PromiseLike<WebCoverageService>}
         */
        WebCoverageService.create = function (serviceAddress) {
            if (!serviceAddress) {
                throw new ArgumentError(
                    Logger.logMessage(Logger.LEVEL_SEVERE, "WebCoverageService", "constructor", "missingUrl"));
            }

            var service = new WebCoverageService();
            service.serviceAddress = serviceAddress;

            return service.retrieveCapabilities()
                .then(function (wcsCapabilities) {
                    service.capabilities = wcsCapabilities;
                    return service.retrieveCoverageDescriptions(wcsCapabilities);
                })
                .then(function (coverages) {
                    service.parseCoverages(coverages);
                    return service;
                });
        };

        /**
         * Returns the coverage associated with the provided id or name
         * @param coverageId the requested coverage id or name
         * @returns {WcsCoverage}
         */
        WebCoverageService.prototype.getCoverage = function (coverageId) {
            // TODO
        };

        // Internal use only
        WebCoverageService.prototype.retrieveCapabilities = function () {
            var self = this, version;

            return self.retrieveXml(self.buildCapabilitiesXmlRequest("2.0.1"))
                .then(function (xmlDom) {
                    // Check if the server supports our preferred version of 2.0.1
                    version = xmlDom.documentElement.getAttribute("version");
                    if (version === "2.0.1" || version === "2.0.0") {
                        return xmlDom;
                    } else {
                        // If needed, try the server again with a 1.0.0 request
                        return self.retrieveXml(self.buildCapabilitiesXmlRequest("1.0.0"));
                    }
                })
                // Parse the result
                .then(function (xmlDom) {
                    return new WcsCapabilities(xmlDom);
                });
        };

        // Internal use only
        WebCoverageService.prototype.retrieveCoverageDescriptions = function () {
            return this.retrieveXml(this.buildDescribeCoverageXmlRequest());
        };

        // Internal use only
        WebCoverageService.prototype.parseCoverages = function (xmlDom) {
            this.coverageDescriptions = new WcsCoverageDescriptions(xmlDom);
            var coverageCount = this.coverageDescriptions.coverages.length;
            var coverageId, coverage;

            for (var i = 0; i < coverageCount; i++) {
                coverageId = this.coverageDescriptions.coverages[i].coverageId
                    || this.coverageDescriptions.coverages[i].name;
                coverage = new WcsCoverage(coverageId, this);
                this.coverages.push(coverage);
            }
        };

        // Internal use only
        WebCoverageService.prototype.retrieveXml = function (request) {
            return new Promise(function (resolve, reject) {
                var xhr = new XMLHttpRequest();
                xhr.open("POST", request.url);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status === 200) {
                            resolve(xhr.responseXML);
                        } else {
                            reject(new Error(
                                Logger.logMessage(Logger.LEVEL_WARNING,
                                    "XML retrieval failed (" + xhr.statusText + "): " + request.url)));
                        }
                    }
                };
                xhr.onerror = function () {
                    reject(new Error(
                        Logger.logMessage(Logger.LEVEL_WARNING, "XML retrieval failed: " + request.url)));
                };
                xhr.ontimeout = function () {
                    reject(new Error(
                        Logger.logMessage(Logger.LEVEL_WARNING, "XML retrieval timed out: " + request.url)));
                };
                xhr.send(request.body);
            });
        };

        // Internal use only
        WebCoverageService.prototype.buildCapabilitiesXmlRequest = function (version) {
            var capabilitiesElement = this.createBaseWcsElement("GetCapabilities", version);

            return {
                url: this.serviceAddress,
                body: new XMLSerializer().serializeToString(capabilitiesElement)
            };
        };

        // Internal use only
        WebCoverageService.prototype.buildDescribeCoverageXmlRequest = function () {
            var version = this.capabilities.version, describeElement, coverageElement, requestUrl,
                coverageCount = this.capabilities.coverages.length;

            describeElement = this.createBaseWcsElement("DescribeCoverage", version);
            if (version === "1.0.0") {
                requestUrl = this.capabilities.capability.request.describeCoverage.get;
            } else if (version === "2.0.1" || version === "2.0.0") {
                requestUrl = this.capabilities.operationsMetadata.getOperationMetadataByName("DescribeCoverage").dcp[0].getMethods[0].url;
            }

            for (var i = 0; i < coverageCount; i++) {
                if (version === "1.0.0") {
                    coverageElement = document.createElementNS(WebCoverageService.WCS_XLMNS, "Coverage");
                    coverageElement.appendChild(document.createTextNode(this.capabilities.coverages[i].name));
                } else if (version === "2.0.1" || version === "2.0.0") {
                    coverageElement = document.createElementNS(WebCoverageService.WCS_2_XLMNS, "CoverageId");
                    coverageElement.appendChild(document.createTextNode(this.capabilities.coverages[i].coverageId));
                }
                describeElement.appendChild(coverageElement);
            }

            return {
                url: requestUrl,
                body: new XMLSerializer().serializeToString(describeElement)
            };
        };

        // Internal use only
        WebCoverageService.prototype.createBaseWcsElement = function (elementName, version) {
            var el;

            if (version === "1.0.0") {
                el = document.createElementNS(WebCoverageService.WCS_XLMNS, elementName);
                el.setAttribute("version", "1.0.0");
            } else if (version === "2.0.1" || version === "2.0.0") {
                el = document.createElementNS(WebCoverageService.WCS_2_XLMNS, elementName);
                el.setAttribute("version", version);
            }

            el.setAttribute("service", "WCS");

            return el;
        };

        return WebCoverageService;
    });