terriajs
Version:
Geospatial data visualization platform.
564 lines • 23.2 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import i18next from "i18next";
import flatten from "lodash-es/flatten";
import { action, computed, isObservableArray, runInAction, makeObservable, override } from "mobx";
import URI from "urijs";
import filterOutUndefined from "../../../Core/filterOutUndefined";
import isDefined from "../../../Core/isDefined";
import TerriaError, { networkRequestError } from "../../../Core/TerriaError";
import Reproject from "../../../Map/Vector/Reproject";
import CatalogFunctionMixin from "../../../ModelMixins/CatalogFunctionMixin";
import XmlRequestMixin from "../../../ModelMixins/XmlRequestMixin";
import xml2json from "../../../ThirdParty/xml2json";
import WebProcessingServiceCatalogFunctionTraits from "../../../Traits/TraitsClasses/WebProcessingServiceCatalogFunctionTraits";
import CommonStrata from "../../Definition/CommonStrata";
import CreateModel from "../../Definition/CreateModel";
import LoadableStratum from "../../Definition/LoadableStratum";
import StratumOrder from "../../Definition/StratumOrder";
import updateModelFromJson from "../../Definition/updateModelFromJson";
import BooleanParameter from "../../FunctionParameters/BooleanParameter";
import DateParameter from "../../FunctionParameters/DateParameter";
import DateTimeParameter from "../../FunctionParameters/DateTimeParameter";
import EnumerationParameter from "../../FunctionParameters/EnumerationParameter";
import GeoJsonParameter, { isGeoJsonFunctionParameter } from "../../FunctionParameters/GeoJsonParameter";
import LineParameter from "../../FunctionParameters/LineParameter";
import PointParameter from "../../FunctionParameters/PointParameter";
import PolygonParameter from "../../FunctionParameters/PolygonParameter";
import RectangleParameter from "../../FunctionParameters/RectangleParameter";
import RegionParameter from "../../FunctionParameters/RegionParameter";
import RegionTypeParameter from "../../FunctionParameters/RegionTypeParameter";
import StringParameter from "../../FunctionParameters/StringParameter";
import proxyCatalogItemUrl from "../proxyCatalogItemUrl";
import WebProcessingServiceCatalogFunctionJob from "./WebProcessingServiceCatalogFunctionJob";
import NumberParameter from "../../FunctionParameters/NumberParameter";
class WpsLoadableStratum extends LoadableStratum(WebProcessingServiceCatalogFunctionTraits) {
item;
processDescription;
static stratumName = "wpsLoadable";
constructor(item, processDescription) {
super();
this.item = item;
this.processDescription = processDescription;
makeObservable(this);
}
duplicateLoadableStratum(newModel) {
return new WpsLoadableStratum(newModel, this.processDescription);
}
static async load(item) {
if (!isDefined(item.describeProcessUrl)) {
return;
}
const xml = await item.getXml(item.describeProcessUrl);
if (!isDefined(xml) ||
!isDefined(xml.documentElement) ||
xml.documentElement.localName !== "ProcessDescriptions") {
throwInvalidWpsServerError(item, "DescribeProcess");
}
const json = xml2json(xml);
if (!isDefined(json.ProcessDescription)) {
throw networkRequestError({
sender: this,
title: i18next.t("models.webProcessingService.processDescriptionErrorTitle"),
message: i18next.t("models.webProcessingService.processDescriptionErrorMessage")
});
}
return new WpsLoadableStratum(item, json.ProcessDescription);
}
/**
* Return the inputs in the processDescription
*/
get inputs() {
if (!isDefined(this.processDescription)) {
return [];
}
const dataInputs = this.processDescription.DataInputs;
if (!isDefined(dataInputs) || !isDefined(dataInputs.Input)) {
throw networkRequestError({
sender: this,
title: i18next.t("models.webProcessingService.processInputErrorTitle"),
message: i18next.t("models.webProcessingService.processInputErrorMessage")
});
}
const inputs = Array.isArray(dataInputs.Input) || isObservableArray(dataInputs.Input)
? dataInputs.Input
: [dataInputs.Input];
return inputs;
}
get storeSupported() {
const value = this.processDescription.storeSupported?.toLowerCase();
return value === "true" ? true : value === "false" ? false : undefined;
}
get statusSupported() {
const value = this.processDescription.statusSupported?.toLowerCase();
return value === "true" ? true : value === "false" ? false : undefined;
}
}
__decorate([
computed
], WpsLoadableStratum.prototype, "inputs", null);
__decorate([
action
], WpsLoadableStratum, "load", null);
StratumOrder.addLoadStratum(WpsLoadableStratum.stratumName);
export default class WebProcessingServiceCatalogFunction extends XmlRequestMixin(CatalogFunctionMixin(CreateModel(WebProcessingServiceCatalogFunctionTraits))) {
static type = "wps";
constructor(...args) {
super(...args);
makeObservable(this);
}
get type() {
return WebProcessingServiceCatalogFunction.type;
}
get typeName() {
return "Web Processing Service (WPS)";
}
get cacheDuration() {
if (isDefined(super.cacheDuration)) {
return super.cacheDuration;
}
return "0d";
}
/**
* Returns the proxied URL for the DescribeProcess endpoint.
*/
get describeProcessUrl() {
if (!isDefined(this.url) || !isDefined(this.identifier)) {
return;
}
const uri = new URI(this.url).query({
service: "WPS",
request: "DescribeProcess",
version: "1.0.0",
Identifier: this.identifier
});
return proxyCatalogItemUrl(this, uri.toString());
}
async forceLoadMetadata() {
if (!this.strata.has(WpsLoadableStratum.stratumName)) {
const stratum = await WpsLoadableStratum.load(this);
if (isDefined(stratum)) {
runInAction(() => {
this.strata.set(WpsLoadableStratum.stratumName, stratum);
});
}
}
}
/**
* Must be kept alive due to `subtype` observable property of GeoJsonFunctionParameter
*/
get functionParameters() {
const stratum = this.strata.get(WpsLoadableStratum.stratumName);
if (!isDefined(stratum))
return [];
return stratum.inputs.map((input) => {
const parameter = this.convertInputToParameter(this, input);
if (isDefined(parameter)) {
return parameter;
}
throw new TerriaError({
sender: this,
title: "Unsupported parameter type",
message: `The parameter '${input.Identifier}' is not a supported type of parameter.`
});
});
}
async createJob(id) {
const job = new WebProcessingServiceCatalogFunctionJob(id, this.terria);
const dataInputs = filterOutUndefined(await Promise.all(this.functionParameters
.filter((p) => isDefined(p.value) && p.value !== null)
.map((p) => this.convertParameterToInput(p))));
runInAction(() => updateModelFromJson(job, CommonStrata.user, {
name: `WPS: ${this.name || this.identifier || this.uniqueId} result ${new Date().toISOString()}`,
geojsonFeatures: flatten(this.functionParameters
.map((param) => isGeoJsonFunctionParameter(param)
? param.geoJsonFeature
: undefined)
.filter(isDefined)),
url: this.url,
identifier: this.identifier,
executeWithHttpGet: this.executeWithHttpGet,
statusSupported: this.statusSupported,
storeSupported: this.storeSupported,
wpsParameters: dataInputs,
forceConvertResultsToV8: this.forceConvertResultsToV8
})).raiseError(this.terria, "Error ocurred while updating job model JSON");
return job;
}
convertInputToParameter(catalogFunction, input) {
if (!isDefined(input.Identifier)) {
return;
}
const isRequired = isDefined(input.minOccurs) && input.minOccurs > 0;
for (let i = 0; i < parameterConverters.length; i++) {
const converter = parameterConverters[i];
const parameter = converter.inputToParameter(catalogFunction, input, {
id: input.Identifier,
name: input.Title,
description: input.Abstract,
isRequired
});
if (isDefined(parameter)) {
return parameter;
}
}
}
async convertParameterToInput(parameter) {
const converter = parameterTypeToConverter(parameter);
const result = converter?.parameterToInput(parameter);
if (!isDefined(result)) {
return;
}
const inputValue = await Promise.resolve(result.inputValue);
if (!isDefined(inputValue)) {
return;
}
return {
inputIdentifier: parameter.id,
inputValue: inputValue,
inputType: result.inputType
};
}
}
__decorate([
override
], WebProcessingServiceCatalogFunction.prototype, "cacheDuration", null);
__decorate([
computed
], WebProcessingServiceCatalogFunction.prototype, "describeProcessUrl", null);
__decorate([
computed({
keepAlive: true
})
], WebProcessingServiceCatalogFunction.prototype, "functionParameters", null);
const LiteralDataConverter = {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.LiteralData)) {
return;
}
const allowedValues = input.LiteralData.AllowedValues || input.LiteralData.AllowedValue;
if (isDefined(allowedValues) && isDefined(allowedValues.Value)) {
return new EnumerationParameter(catalogFunction, {
...options,
options: (Array.isArray(allowedValues.Value) ||
isObservableArray(allowedValues.Value)
? allowedValues.Value
: [allowedValues.Value]).map((id) => {
return { id };
})
});
}
else if (isDefined(allowedValues) && isDefined(allowedValues.Range)) {
const np = new NumberParameter(catalogFunction, {
...options
});
np.minimum = isDefined(allowedValues.Range.MinimumValue)
? allowedValues.Range.MinimumValue
: np.minimum;
np.maximum = allowedValues.Range.MaximumValue;
np.defaultValue = isDefined(input.LiteralData.DefaultValue)
? input.LiteralData.DefaultValue
: np.minimum;
return np;
}
else if (isDefined(input.LiteralData.AnyValue)) {
let dtype = null;
if (isDefined(input.LiteralData["dataType"])) {
dtype = input.LiteralData["dataType"];
}
else if (isDefined(input.LiteralData.DataType)) {
if (typeof input.LiteralData.DataType === "string") {
dtype = input.LiteralData.DataType;
}
else if (isDefined(input.LiteralData.DataType["ows:reference"])) {
dtype = input.LiteralData.DataType["ows:reference"];
}
else if (isDefined(input.LiteralData.DataType.text)) {
dtype = input.LiteralData.DataType.text;
}
}
if (dtype !== null) {
if (dtype.indexOf("http://www.w3.org/TR/xmlschema-2/#") === 0) {
dtype = dtype.substring(dtype.lastIndexOf("#") + 1).toLowerCase();
}
}
if (dtype === "string") {
return new StringParameter(catalogFunction, {
...options
});
}
else if (dtype === "boolean") {
return new BooleanParameter(catalogFunction, {
...options
});
}
else if (dtype === "date") {
const dt = new DateParameter(catalogFunction, {
...options,
clock: catalogFunction.terria.timelineClock
});
dt.variant = "literal";
return dt;
}
else if (dtype?.toLowerCase() === "datetime") {
const dt = new DateTimeParameter(catalogFunction, {
...options,
clock: catalogFunction.terria.timelineClock
});
dt.variant = "literal";
return dt;
}
// Assume its a string, if no literal datatype given
return new StringParameter(catalogFunction, {
...options
});
}
},
parameterToInput: function (parameter) {
return {
inputValue: parameter.value,
inputType: "LiteralData"
};
}
};
const ComplexDateConverter = {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.ComplexData) ||
!isDefined(input.ComplexData.Default) ||
!isDefined(input.ComplexData.Default.Format) ||
!isDefined(input.ComplexData.Default.Format.Schema)) {
return undefined;
}
const schema = input.ComplexData.Default.Format.Schema;
if (schema !== "http://www.w3.org/TR/xmlschema-2/#date") {
return undefined;
}
const dparam = new DateParameter(catalogFunction, {
...options,
clock: catalogFunction.terria.timelineClock
});
dparam.variant = "complex";
return dparam;
},
parameterToInput: function (parameter) {
return {
inputType: "ComplexData",
inputValue: DateParameter.formatValueForUrl(parameter?.value?.toString() || "")
};
}
};
const ComplexDateTimeConverter = {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.ComplexData) ||
!isDefined(input.ComplexData.Default) ||
!isDefined(input.ComplexData.Default.Format) ||
!isDefined(input.ComplexData.Default.Format.Schema)) {
return undefined;
}
const schema = input.ComplexData.Default.Format.Schema;
if (schema !== "http://www.w3.org/TR/xmlschema-2/#dateTime") {
return undefined;
}
const dt = new DateTimeParameter(catalogFunction, {
...options,
clock: catalogFunction.terria.timelineClock
});
dt.variant = "complex";
return dt;
},
parameterToInput: function (parameter) {
return {
inputType: "ComplexData",
inputValue: DateTimeParameter.formatValueForUrl(parameter?.value?.toString() || "")
};
}
};
export const PointConverter = simpleGeoJsonDataConverter("point", PointParameter);
const LineConverter = simpleGeoJsonDataConverter("linestring", LineParameter);
const PolygonConverter = simpleGeoJsonDataConverter("polygon", PolygonParameter);
const RectangleConverter = {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.BoundingBoxData) ||
!isDefined(input.BoundingBoxData.Default) ||
!isDefined(input.BoundingBoxData.Default.CRS)) {
return undefined;
}
let code = Reproject.crsStringToCode(input.BoundingBoxData.Default.CRS);
let usedCrs = input.BoundingBoxData.Default.CRS;
// Find out if Terria's CRS is supported.
if (code !== Reproject.TERRIA_CRS &&
isDefined(input.BoundingBoxData.Supported) &&
isDefined(input.BoundingBoxData.Supported.CRS)) {
for (let i = 0; i < input.BoundingBoxData.Supported.CRS.length; i++) {
if (Reproject.crsStringToCode(input.BoundingBoxData.Supported.CRS[i]) ===
Reproject.TERRIA_CRS) {
code = Reproject.TERRIA_CRS;
usedCrs = input.BoundingBoxData.Supported.CRS[i];
break;
}
}
}
// We are currently only supporting Terria's CRS, because if we reproject we don't know the URI or whether
// the bounding box order is lat-long or long-lat.
if (!isDefined(code)) {
return undefined;
}
return new RectangleParameter(catalogFunction, {
...options,
crs: usedCrs
});
},
parameterToInput: function (functionParameter) {
const parameter = functionParameter;
const value = parameter.value;
if (!isDefined(value)) {
return;
}
let bboxMinCoord1, bboxMinCoord2, bboxMaxCoord1, bboxMaxCoord2, urn;
// We only support CRS84 and EPSG:4326
if (parameter.crs.indexOf("crs84") !== -1) {
// CRS84 uses long, lat rather that lat, long order.
bboxMinCoord1 = value.west;
bboxMinCoord2 = value.south;
bboxMaxCoord1 = value.east;
bboxMaxCoord2 = value.north;
// Comfortingly known as WGS 84 longitude-latitude according to Table 3 in OGC 07-092r1.
urn = "urn:ogc:def:crs:OGC:1.3:CRS84";
}
else {
// The URN value urn:ogc:def:crs:EPSG:6.6:4326 shall mean the Coordinate Reference System (CRS) with code
// 4326 specified in version 6.6 of the EPSG database available at http://www.epsg.org/. That CRS specifies
// the axis order as Latitude followed by Longitude.
// We don't know about other URN versions, so are going to return 6.6 regardless of what was requested.
bboxMinCoord1 = value.south;
bboxMinCoord2 = value.west;
bboxMaxCoord1 = value.north;
bboxMaxCoord2 = value.east;
urn = "urn:ogc:def:crs:EPSG:6.6:4326";
}
return {
inputType: "BoundingBoxData",
inputValue: bboxMinCoord1 +
"," +
bboxMinCoord2 +
"," +
bboxMaxCoord1 +
"," +
bboxMaxCoord2 +
"," +
urn
};
}
};
const GeoJsonGeometryConverter = {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.ComplexData) ||
!isDefined(input.ComplexData.Default) ||
!isDefined(input.ComplexData.Default.Format) ||
!isDefined(input.ComplexData.Default.Format.Schema)) {
return;
}
const schema = input.ComplexData.Default.Format.Schema;
if (schema.indexOf("http://geojson.org/geojson-spec.html#") !== 0) {
return undefined;
}
const regionTypeParameter = new RegionTypeParameter(catalogFunction, {
id: "regionType",
name: "Region Type",
description: "The type of region to analyze."
});
const regionParameter = new RegionParameter(catalogFunction, {
id: "regionParameter",
name: "Region Parameter",
regionProvider: regionTypeParameter
});
return new GeoJsonParameter(catalogFunction, {
...options,
regionParameter
});
},
parameterToInput: function (parameter) {
if (!isDefined(parameter.value) || parameter.value === null) {
return;
}
return parameter.getProcessedValue(parameter.value);
}
};
function simpleGeoJsonDataConverter(schemaType, klass) {
return {
inputToParameter: function (catalogFunction, input, options) {
if (!isDefined(input.ComplexData) ||
!isDefined(input.ComplexData.Default) ||
!isDefined(input.ComplexData.Default.Format) ||
!isDefined(input.ComplexData.Default.Format.Schema)) {
return undefined;
}
const schema = input.ComplexData.Default.Format.Schema;
if (schema.indexOf("http://geojson.org/geojson-spec.html#") !== 0) {
return undefined;
}
if (schema.substring(schema.lastIndexOf("#") + 1) !== schemaType) {
return undefined;
}
return new klass(catalogFunction, options);
},
parameterToInput: function (parameter) {
return {
inputType: "ComplexData",
inputValue: klass.formatValueForUrl(parameter.value)
};
}
};
}
function parameterTypeToConverter(parameter) {
switch (parameter.type) {
case BooleanParameter.type:
case StringParameter.type:
case EnumerationParameter.type:
return LiteralDataConverter;
case DateParameter.type:
return parameter.variant === "literal"
? LiteralDataConverter
: ComplexDateConverter;
case DateTimeParameter.type:
return parameter.variant === "literal"
? LiteralDataConverter
: ComplexDateTimeConverter;
case PointParameter.type:
return PointConverter;
case LineParameter.type:
return LineConverter;
case PolygonParameter.type:
return PolygonConverter;
case RectangleParameter.type:
return RectangleConverter;
case GeoJsonParameter.type:
return GeoJsonGeometryConverter;
default:
break;
}
}
const parameterConverters = [
LiteralDataConverter,
ComplexDateConverter,
ComplexDateTimeConverter,
PointConverter,
LineConverter,
PolygonConverter,
RectangleConverter,
GeoJsonGeometryConverter
];
function throwInvalidWpsServerError(wps, endpoint) {
throw networkRequestError({
title: i18next.t("models.webProcessingService.invalidWPSServerTitle"),
message: i18next.t("models.webProcessingService.invalidWPSServerMessage", {
name: wps.name,
endpoint
})
});
}
//# sourceMappingURL=WebProcessingServiceCatalogFunction.js.map