@dlr-eoc/utils-ogc
Version:
This library bundles our clients for OGC standards. The long-term-strategy is to make all services in `@dlr-eoc/services-ogc` independent of angular and move them here.
1 lines • 84.3 kB
Source Map (JSON)
{"version":3,"file":"dlr-eoc-utils-ogc.mjs","sources":["../../../projects/utils-ogc/src/lib/wps/wps100/wps_marshaller_1.0.0.ts","../../../projects/utils-ogc/src/lib/wps/wps200/helpers.ts","../../../projects/utils-ogc/src/lib/wps/wps200/wps_marshaller_2.0.0.ts","../../../projects/utils-ogc/src/lib/wps/utils/polling.ts","../../../projects/utils-ogc/src/lib/wps/cache.ts","../../../projects/utils-ogc/src/lib/wps/wpsclient.ts","../../../projects/utils-ogc/src/lib/wps/wps_datatypes.ts","../../../projects/utils-ogc/src/lib/wms/wms.service.ts","../../../projects/utils-ogc/src/public-api.ts","../../../projects/utils-ogc/src/dlr-eoc-utils-ogc.ts"],"sourcesContent":["import { WpsMarshaller, WpsInput, WpsOutputDescription, WpsResult, WpsCapability, WpsBboxValue, WpsData,\n WpsDataDescription, WpsState, WpsDataFormat, WpsProcessDescription } from '../wps_datatypes';\nimport {\n WPSCapabilitiesType, IWpsExecuteProcessBody, Execute, DataInputsType,\n InputType, ResponseFormType, DataType, IWpsExecuteResponse, DocumentOutputDefinitionType,\n ResponseDocumentType, InputReferenceType, ExecuteResponse, IWpsDescribeProcessResponse,\n InputDescriptionType, OutputDescriptionType } from './wps_1.0.0';\nimport * as xmlserializer from 'xmlserializer';\n\n\n\nexport class WpsMarshaller100 implements WpsMarshaller {\n\n constructor() { }\n\n getCapabilitiesUrl(baseurl: string): string {\n return `${baseurl}?service=WPS&request=GetCapabilities&version=1.0.0`;\n }\n\n getDescribeProcessUrl(baseurl: string, processId: string): string {\n return `${baseurl}?service=WPS&request=DescribeProcess&version=1.0.0&Identifier=${processId}`;\n }\n\n executeUrl(baseurl: string, processId: string): string {\n return `${baseurl}?service=WPS&request=Execute&version=1.0.0&identifier=${processId}`;\n }\n\n unmarshalCapabilities(capabilities: WPSCapabilitiesType): WpsCapability[] {\n const out: WpsCapability[] = [];\n capabilities.processOfferings.process.forEach(process => {\n out.push({\n id: process.identifier.value\n });\n });\n return out;\n }\n\n unmarshalProcessDescription(processDescriptionJson: IWpsDescribeProcessResponse): WpsProcessDescription {\n const description = processDescriptionJson.processDescription[0];\n\n const inputs: WpsInput[] = [];\n for (const dataInput of description.dataInputs.input) {\n inputs.push({\n description: this.unmarshalInputDescription(dataInput),\n value: null\n });\n }\n\n const outputs: WpsResult[] = [];\n for (const processOutput of description.processOutputs.output) {\n outputs.push({\n description: this.unmarshalOutputDescription(processOutput),\n value: null\n });\n }\n\n return {\n id: description.identifier.value,\n processVersion: description.processVersion,\n description: description._abstract?.value,\n title: description.title.value,\n inputs: inputs,\n outputs: outputs,\n };\n }\n\n unmarshalSyncExecuteResponse(responseJson: IWpsExecuteResponse, url: string, processId: string,\n inputs: WpsInput[], outputDescriptions: WpsOutputDescription[]): WpsResult[] {\n\n const out: WpsResult[] = [];\n\n if (responseJson.value.status.processFailed) { // Failure?\n out.push({\n description: {\n id: responseJson.value.process.identifier.value,\n title: responseJson.value.process.title.value,\n reference: true,\n type: 'error'\n },\n value: responseJson.value.statusLocation\n });\n } else if (responseJson.value.processOutputs) { // synchronous request?\n for (const output of responseJson.value.processOutputs.output) {\n const isReference = output.reference ? true : false;\n\n let datatype: 'literal' | 'complex' | 'bbox' | 'status' | 'error';\n let data;\n let format: WpsDataFormat | undefined;\n if (output.reference) {\n datatype = 'complex';\n data = output.reference.href || null;\n format = output.reference.mimeType as WpsDataFormat;\n } else {\n if (output.data && output.data.literalData) {\n datatype = 'literal';\n format = output.data.literalData.dataType as WpsDataFormat;\n } else if (output.data && output.data.complexData) {\n datatype = 'complex';\n format = output.data.complexData.mimeType as WpsDataFormat;\n } else {\n datatype = 'bbox';\n format = undefined;\n }\n // @ts-ignore\n data = this.unmarshalOutputData(output.data);\n }\n\n out.push({\n description: {\n id: output.identifier.value,\n title: output.title.value,\n format,\n reference: isReference,\n type: datatype\n },\n value: data,\n });\n }\n } else if (responseJson.value.statusLocation) { // asynchronous request?\n out.push({\n description: {\n id: responseJson.value.process.identifier.value,\n title: responseJson.value.process.title.value,\n reference: true,\n type: 'status'\n },\n value: this.unmarshalGetStateResponse(responseJson, url, processId, inputs, outputDescriptions)\n });\n }\n\n return out;\n }\n\n protected unmarshalOutputData(data: DataType): any {\n if (data.complexData) {\n\n if (data.complexData.encoding === 'base64') {\n if (typeof module !== 'undefined' && module.exports) { // node\n data.complexData.content.map(c => Buffer.from(c, 'base64').toString('ascii'));\n } else { // browser\n data.complexData.content.map(c => atob(c));\n }\n }\n\n switch (data.complexData.mimeType) {\n case 'application/vnd.geo+json':\n case 'application/json':\n return data.complexData.content.map(cont => JSON.parse(cont));\n case 'application/WMS':\n return data.complexData.content;\n case 'text/xml':\n case 'application/xml':\n return xmlserializer.serializeToString(data.complexData.content[0]); // @TODO: better: handle actual xml-data\n default:\n throw new Error(`Cannot unmarshal data of format ${data.complexData.mimeType}`);\n }\n } else if (data.literalData) {\n switch (data.literalData.dataType) {\n case 'string':\n default:\n return data.literalData.value;\n }\n }\n\n throw new Error(`Not yet implemented: ${data}`);\n }\n\n protected unmarshalInputDescription(data: InputDescriptionType): WpsDataDescription {\n if (data.boundingBoxData) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: false,\n type: 'bbox',\n description: data._abstract?.value,\n format: 'text/plain',\n };\n }\n else if (data.complexData) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: data.storeSupported,\n type: 'complex',\n description: data._abstract?.value,\n format: data.complexData._default.format.mimeType as WpsDataFormat\n };\n }\n else if (data.literalData) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: false,\n type: 'literal',\n description: data._abstract?.value,\n defaultValue: data.literalData.defaultValue,\n options: data.literalData.allowedValues?.valueOrRange.map(v => v.value),\n format: 'text/plain'\n };\n } else {\n throw new Error(`Cannot unmarshal the input-description for ${data.identifier.value}`);\n }\n }\n\n protected unmarshalOutputDescription(data: OutputDescriptionType): WpsDataDescription {\n if (data.complexOutput) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: true,\n type: 'complex',\n format: data.complexOutput._default.format.mimeType as WpsDataFormat\n };\n } else if (data.boundingBoxOutput) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: false,\n type: 'bbox',\n };\n } else if (data.literalOutput) {\n return {\n id: data.identifier.value,\n title: data.title.value,\n reference: false,\n type: 'literal',\n };\n } else {\n throw new Error(`Cannot unmarshal the input-description for ${data.identifier.value}`);\n }\n }\n\n unmarshalAsyncExecuteResponse(responseJson: any, url: string, processId: string, inputs: WpsInput[], outputDescriptions: WpsDataDescription[]): WpsState {\n return this.unmarshalGetStateResponse(responseJson, url, processId, inputs, outputDescriptions);\n }\n\n unmarshalGetStateResponse(responseJson: any, serverUrl: string, processId: string,\n inputs: WpsData[], outputDescriptions: WpsDataDescription[]): WpsState {\n\n const response: ExecuteResponse = responseJson.value;\n\n const status = response.status.processSucceeded ? 'Succeeded' :\n response.status.processAccepted ? 'Accepted' :\n response.status.processStarted ? 'Running' :\n response.status.processFailed ? 'Failed' :\n 'Failed';\n\n const state: WpsState = {\n status,\n statusLocation: response.statusLocation,\n };\n\n if (response.processOutputs && response.processOutputs.output) {\n state.results = responseJson; // this.unmarshalSyncExecuteResponse(responseJson, serverUrl, processId, inputs, outputDescriptions);\n }\n\n return state;\n }\n\n marshalExecBody(processId: string, inputs: WpsInput[], outputs: WpsOutputDescription[], async: boolean): IWpsExecuteProcessBody {\n\n const wps1Inputs = this.marshalInputs(inputs);\n const wps1ResponseForm = this.marshalResponseForm(outputs, async);\n\n const bodyValue: Execute = {\n dataInputs: wps1Inputs,\n identifier: processId,\n responseForm: wps1ResponseForm,\n service: 'WPS',\n version: '1.0.0'\n };\n\n const body: IWpsExecuteProcessBody = {\n name: {\n key: '{http://www.opengis.net/wps/1.0.0}Execute',\n localPart: 'Execute',\n namespaceURI: 'http://www.opengis.net/wps/1.0.0',\n prefix: 'wps',\n string: '{http://www.opengis.net/wps/1.0.0}wps:Execute'\n },\n value: bodyValue\n };\n\n return body;\n\n }\n\n\n protected marshalResponseForm(outputs: WpsOutputDescription[], async = false): ResponseFormType {\n\n const outputDefinitions: DocumentOutputDefinitionType[] = [];\n for (const output of outputs) {\n let defType: DocumentOutputDefinitionType;\n switch (output.type) {\n case 'literal':\n defType = {\n identifier: { value: output.id },\n asReference: output.reference,\n mimeType: output.format\n };\n break;\n case 'complex':\n defType = {\n identifier: { value: output.id },\n asReference: output.reference,\n mimeType: output.format\n };\n break;\n default:\n throw new Error(`This Wps-outputtype has not been implemented yet! ${output} `);\n }\n outputDefinitions.push(defType);\n }\n\n const responseDocument: ResponseDocumentType = {\n output: outputDefinitions,\n status: async ? true : false,\n storeExecuteResponse: async ? true : false\n };\n\n const form: ResponseFormType = {\n responseDocument\n };\n return form;\n }\n\n\n protected marshalInputs(inputArr: WpsInput[]): DataInputsType {\n const theInputs: InputType[] = [];\n for (const inp of inputArr) {\n if (inp.value === null || inp.value === undefined) {\n throw new Error(`Value for input ${inp.description.id} is not set`);\n }\n const marshalledInput = this.marshalInput(inp);\n theInputs.push(marshalledInput);\n }\n const inputs: DataInputsType = {\n input: theInputs\n };\n return inputs;\n }\n\n protected marshalInput(input: WpsInput): InputType {\n const id = input.description.id;\n const title = input.description.id;\n const abstract = '';\n\n const inputType: InputType = {\n identifier: { value: id },\n title: { value: title },\n _abstract: { value: abstract }\n };\n\n if (input.description.reference) {\n inputType.reference = this.marshalReferenceInput(input);\n } else {\n inputType.data = this.marshalDataInput(input);\n }\n\n return inputType;\n }\n\n protected marshalDataInput(input: WpsInput): DataType {\n let data: DataType;\n switch (input.description.type) {\n case 'literal':\n data = {\n literalData: { value: String(input.value) }\n };\n break;\n case 'bbox':\n const values: WpsBboxValue = input.value;\n data = {\n boundingBoxData: {\n lowerCorner: [values.lllat, values.lllon],\n upperCorner: [values.urlat, values.urlon]\n }\n };\n break;\n case 'complex':\n switch (input.description.format) {\n case 'text/xml':\n data = {\n complexData: {\n content: [input.value], // @TODO: we assume here that text/xml-data is already stringified\n mimeType: input.description.format\n }\n };\n break;\n default:\n data = {\n complexData: {\n content: [JSON.stringify(input.value)],\n mimeType: input.description.format\n }\n };\n }\n break;\n default:\n throw Error(`This input is of type ${input.description.type}. We can only marshal input of type literal, bbox or complex.`);\n }\n return data;\n }\n\n protected marshalReferenceInput(input: WpsInput): InputReferenceType {\n const ref: InputReferenceType = {\n href: input.value,\n method: 'GET',\n mimeType: input.description.format\n };\n return ref;\n }\n\n marshallGetStatusBody(serverUrl: string, processId: string, statusId: string) {\n // WPS-1.0 does not send a body with a GetStatus request.\n return {};\n }\n\n marshallGetResultBody(serverUrl: string, processId: string, jobID: string) {\n // WPS-1.0 does not send a body with a GetStatus request.\n return {};\n }\n\n dismissUrl(serverUrl: string, processId: string, jobId: string): string {\n /** this does only work in geoserver:\n * return `${serverUrl}?service=WPS&version=1.0.0&request=Dismiss&executionId=${jobId}`;\n */\n throw new Error('Wps 1.0 does not support Dismiss-operations.');\n }\n\n marshalDismissBody(processId: string) {\n throw new Error('Wps 1.0 does not support Dismiss-operations.');\n }\n\n unmarshalDismissResponse(jsonResponse: any, serverUrl: string, processId: string): WpsState {\n throw new Error('Wps 1.0 does not support Dismiss-operations.');\n }\n}\n","import { StatusInfo, DataOutputType, Result } from './wps_2.0';\n\n\nexport const isStatusInfo = (obj: object): obj is StatusInfo => {\n return obj.hasOwnProperty('jobID')\n && obj.hasOwnProperty('status');\n};\n\nexport const isDataOutputType = (obj: object): obj is DataOutputType => {\n return obj.hasOwnProperty('id') &&\n (obj.hasOwnProperty('data') || obj.hasOwnProperty('reference') || obj.hasOwnProperty('output'));\n};\n\nexport const isResult = (obj: object): obj is Result => {\n return (obj.hasOwnProperty('output'));\n};\n","import { WpsMarshaller, WpsInput, WpsOutputDescription, WpsResult, WpsCapability, WpsDataDescription,\n WpsData, WpsState, WpsProcessDescription, WpsDataFormat } from '../wps_datatypes';\nimport { WPSCapabilitiesType, ExecuteRequestType, DataInputType, OutputDefinitionType, IWpsExecuteProcessBody,\n IWpsExecuteResponse, IGetStatusRequest, Data, IGetResultRequest, IDismissRequest, IDismissResponse, ProcessOfferings,\n InputDescriptionType, OutputDescriptionType, LiteralDataType } from './wps_2.0';\nimport { isStatusInfo, isResult } from './helpers';\nimport * as xmlserializer from 'xmlserializer';\n\n\nexport class WpsMarshaller200 implements WpsMarshaller {\n\n constructor() { }\n\n getCapabilitiesUrl(baseurl: string): string {\n return `${baseurl}?service=WPS&request=GetCapabilities&version=2.0.0`;\n }\n\n getDescribeProcessUrl(baseurl: string, processId: string): string {\n return `${baseurl}?service=WPS&request=DescribeProcess&version=2.0.0&Identifier=${processId}`;\n }\n\n unmarshalProcessDescription(processDescriptionJson: ProcessOfferings): WpsProcessDescription {\n const description = processDescriptionJson.processOffering[0];\n\n const inputs: WpsInput[] = [];\n for (const dataInput of description.process.input) {\n inputs.push({\n description: this.unmarshalInputDescription(dataInput),\n value: null\n });\n }\n\n const outputs: WpsResult[] = [];\n for (const processOutput of description.process.output) {\n outputs.push({\n description: this.unmarshalOutputDescription(processOutput),\n value: null\n });\n }\n\n return {\n id: description.process.identifier.value,\n processVersion: description.processVersion || '',\n description: description.process._abstract?.value,\n title: description.process.title?.value || '',\n inputs: inputs,\n outputs: outputs,\n };\n }\n\n protected unmarshalInputDescription(dataInput: InputDescriptionType): WpsDataDescription {\n if (dataInput.dataDescription.name.localPart === 'BoundingBoxData') {\n return {\n id: dataInput.identifier.value,\n title: dataInput.title.value,\n reference: false,\n type: 'bbox',\n description: dataInput.abstract?.value\n };\n } else if (dataInput.dataDescription.name.localPart === 'LiteralData') {\n return {\n id: dataInput.identifier.value,\n title: dataInput.title.value,\n reference: false,\n type: 'literal',\n defaultValue: (dataInput.dataDescription.value as LiteralDataType).literalDataDomain?.defaultValue?.value,\n options: (dataInput.dataDescription.value as LiteralDataType).literalDataDomain?.allowedValues.valueOrRange.map(v => v.value),\n description: dataInput.abstract?.value\n };\n } else if (dataInput.dataDescription.name.localPart === 'ComplexData') {\n return {\n id: dataInput.identifier.value,\n title: dataInput.title.value,\n reference: true,\n type: 'complex',\n format: dataInput.dataDescription.value.format[0].mimeType as WpsDataFormat,\n description: dataInput.abstract?.value\n };\n } else {\n throw new Error(`Cannot unmarshal input-description ${dataInput.identifier.value}`);\n }\n }\n\n protected unmarshalOutputDescription(processOutput: OutputDescriptionType): WpsDataDescription {\n if (processOutput.dataDescription.name.localPart === 'BoundingBoxData') {\n return {\n id: processOutput.identifier.value,\n title: processOutput.title.value,\n reference: false,\n type: 'bbox',\n description: processOutput.abstract?.value\n };\n } else if (processOutput.dataDescription.name.localPart === 'LiteralData') {\n return {\n id: processOutput.identifier.value,\n title: processOutput.title.value,\n reference: false,\n type: 'literal',\n description: processOutput.abstract?.value\n };\n } else if (processOutput.dataDescription.name.localPart === 'ComplexData') {\n return {\n id: processOutput.identifier.value,\n title: processOutput.title.value,\n reference: true,\n type: 'complex',\n format: processOutput.dataDescription.value.format[0].mimeType as WpsDataFormat,\n description: processOutput.abstract?.value\n };\n } else {\n throw new Error(`Cannot unmarshal input-description ${processOutput.identifier.value}`);\n }\n }\n\n executeUrl(baseurl: string, processId: string): string {\n // return `${baseurl}?service=WPS&request=Execute&version=2.0.0&identifier=${processId}`;\n return baseurl;\n }\n\n unmarshalCapabilities(capabilities: WPSCapabilitiesType): WpsCapability[] {\n const out: WpsCapability[] = [];\n capabilities.contents.processSummary.forEach(summary => {\n out.push({\n id: summary.identifier.value\n });\n });\n return out;\n }\n\n unmarshalSyncExecuteResponse(responseJson: IWpsExecuteResponse, url: string, processId: string,\n inputs: WpsInput[], outputDescriptions: WpsOutputDescription[]): WpsResult[] {\n const out: WpsResult[] = [];\n\n if (isResult(responseJson.value)) {\n for (const output of responseJson.value.output) {\n const outputDescription = outputDescriptions.find(od => od.id === output.id);\n if (!outputDescription) {\n throw new Error(`Could not find an output-description for the parameter ${output.id}.`);\n }\n\n const isReference = outputDescription.reference;\n const datatype = outputDescription.type;\n const format = outputDescription.format;\n let data;\n if (output.reference) {\n data = output.reference.href || null;\n } else if (output.data) {\n data = this.unmarshalOutputData(output.data, outputDescription);\n } else {\n throw new Error(`Output has neither reference nor data field.`);\n }\n\n out.push({\n description: {\n id: output.id,\n title: outputDescription.title,\n format,\n reference: isReference,\n type: datatype\n },\n value: data,\n });\n }\n } else if (isStatusInfo(responseJson.value)) {\n const state: WpsState = {\n status: responseJson.value.status,\n jobID: responseJson.value.jobID,\n percentCompleted: responseJson.value.percentCompleted\n };\n\n out.push({\n description: {\n id: processId,\n title: '',\n reference: true,\n type: 'status'\n },\n value: state\n });\n }\n\n return out;\n }\n\n protected unmarshalOutputData(data: Data, description: WpsOutputDescription): any {\n if (description.type === 'complex') {\n\n if (data.encoding === 'base64') {\n if (typeof module !== 'undefined' && module.exports) { // node\n data.content.map(c => Buffer.from(c, 'base64').toString('ascii'));\n } else { // browser\n data.content.map((c: any) => atob(c));\n }\n }\n\n switch (data.mimeType) {\n case 'application/vnd.geo+json':\n case 'application/json':\n return data.content.map((cont: any) => JSON.parse(cont));\n case 'application/WMS':\n return data.content;\n case 'text/xml':\n case 'application/xml':\n return xmlserializer.serializeToString(data.content[0]); // @TODO: better: handle actual xml-data\n default:\n throw new Error(`Cannot unmarshal complex data of format ${data.mimeType}`);\n }\n } else if (description.type === 'literal') {\n return data.content;\n }\n\n throw new Error(`Not yet implemented: ${data}`);\n }\n\n unmarshalAsyncExecuteResponse(responseJson: any, url: string, processId: string, inputs: WpsData[], outputDescriptions: WpsDataDescription[]): WpsState {\n return this.unmarshalGetStateResponse(responseJson, url, processId, inputs, outputDescriptions);\n }\n\n unmarshalGetStateResponse(responseJson: any, serverUrl: string, processId: string,\n inputs: WpsData[], outputDescriptions: WpsDataDescription[]): WpsState {\n if (isStatusInfo(responseJson.value)) {\n const state: WpsState = {\n status: responseJson.value.status,\n jobID: responseJson.value.jobID,\n percentCompleted: responseJson.value.percentCompleted\n };\n return state;\n } else {\n throw new Error(`Not a status-info: ${responseJson}`);\n }\n }\n\n marshalExecBody(processId: string, inputs: WpsInput[], outputs: WpsOutputDescription[], async: boolean) {\n const inputsMarshalled = this.marshalInputs(inputs);\n const outputsMarshalled = this.marshalOutputs(outputs);\n\n const bodyValue: ExecuteRequestType = {\n TYPE_NAME: 'WPS_2_0.ExecuteRequestType',\n service: 'WPS',\n version: '2.0.0',\n identifier: { value: processId },\n input: inputsMarshalled,\n output: outputsMarshalled,\n mode: async ? 'async' : 'sync',\n response: 'document'\n };\n\n const body: IWpsExecuteProcessBody = {\n name: {\n key: '{http://www.opengis.net/wps/2.0}Execute',\n localPart: 'Execute',\n namespaceURI: 'http://www.opengis.net/wps/2.0',\n prefix: 'wps',\n string: '{http://www.opengis.net/wps/2.0}wps:Execute'\n },\n value: bodyValue\n };\n\n return body;\n }\n\n private marshalInputs(inputs: WpsData[]): DataInputType[] {\n\n return inputs.map(i => {\n if (i.description.reference) {\n return {\n id: i.description.id,\n reference: {\n href: i.value,\n mimeType: i.description.format,\n schema: i.description.schema,\n encoding: i.description.encoding || \"UTF-8\"\n }\n };\n } else {\n return {\n id: i.description.id,\n data: {\n content: this.marshalInput(i),\n mimeType: i.description.format,\n // schema: i.description.schema,\n // encoding: i.description.encoding || \"UTF-8\"\n }\n };\n }\n });\n }\n\n private marshalInput(i: WpsData): any {\n if (i.description.type === 'literal') {\n return [i.value];\n } else {\n return [JSON.stringify(i.value)];\n }\n }\n\n private marshalOutputs(outputs: WpsDataDescription[]): OutputDefinitionType[] {\n return outputs.map(o => {\n return {\n id: o.id,\n mimeType: o.format,\n transmission: o.reference ? 'reference' : 'value' // @TODO: maybe just comment out this line?\n };\n });\n }\n\n marshallGetStatusBody(serverUrl: string, processId: string, statusId: string) {\n const request: IGetStatusRequest = {\n name: {\n key: '{http://www.opengis.net/wps/2.0}GetStatus',\n localPart: 'GetStatus',\n namespaceURI: 'http://www.opengis.net/wps/2.0',\n prefix: 'wps',\n string: '{http://www.opengis.net/wps/2.0}wps:GetStatus'\n },\n value: {\n jobID: statusId,\n service: 'WPS',\n version: '2.0.0'\n }\n };\n return request;\n }\n\n marshallGetResultBody(serverUrl: string, processId: string, jobID: string) {\n const request: IGetResultRequest = {\n name: {\n key: '{http://www.opengis.net/wps/2.0}GetResult',\n localPart: 'GetResult',\n namespaceURI: 'http://www.opengis.net/wps/2.0',\n prefix: 'wps',\n string: '{http://www.opengis.net/wps/2.0}wps:GetResult'\n },\n value: {\n service: 'WPS',\n version: '2.0.0',\n jobID\n }\n };\n return request;\n }\n\n dismissUrl(serverUrl: string, processId: string, jobId: string): string {\n return serverUrl;\n }\n\n marshalDismissBody(jobId: string) {\n const body: IDismissRequest = {\n name: {\n key: '{http://www.opengis.net/wps/2.0}Dismiss',\n localPart: 'Dismiss',\n namespaceURI: 'http://www.opengis.net/wps/2.0',\n prefix: 'wps',\n string: '{http://www.opengis.net/wps/2.0}wps:Dismiss'\n },\n value: {\n jobID: jobId,\n service: 'WPS',\n version: '2.0.0'\n }\n };\n return body;\n }\n\n unmarshalDismissResponse(jsonResponse: IDismissResponse, serverUrl: string, processId: string): WpsState {\n const state: WpsState = {\n status: jsonResponse.value.status,\n jobID: jsonResponse.value.jobID\n };\n return state;\n }\n}\n","import { Observable, timer, of, forkJoin } from 'rxjs';\nimport { tap, map, mergeMap, retry } from 'rxjs/operators';\n\n\n\n\nexport function pollUntil<T>(\n task$: Observable<T>, predicate: (results: any) => boolean, doWhile?: (t: T | null) => any, minWaitTime: number = 1000): Observable<T> {\n\n if (doWhile) {\n doWhile(null);\n }\n\n const tappedTask$: Observable<T> = task$.pipe(\n tap((r: any) => {\n if (doWhile) {\n doWhile(r);\n }\n })\n );\n\n const requestTakesAtLeast$: Observable<T> = forkJoin([tappedTask$, timer(minWaitTime)]).pipe(\n map(r => r[0])\n );\n\n const polledRequest$: Observable<T> = requestTakesAtLeast$.pipe(\n mergeMap((response: any) => {\n if (predicate(response)) {\n // console.log(`obtained correct answer ${response}`);\n return of(response);\n } else {\n // console.log(`obtained false answer ${response}. trying again...`);\n return polledRequest$;\n }\n })\n );\n\n return polledRequest$;\n}\n\n\nexport function delayedRetry(delayMs: number, maxRetries = 3) {\n return (src$: Observable<any>) => {\n return src$.pipe(\n // If an error occurs ...\n retry({\n count: maxRetries, delay: (error: any, retryCount: number) => {\n if (error.status && error.status === 400) {\n // In case of a server error, repeating won't help.\n throw error;\n } else if (retryCount <= maxRetries) {\n console.log('http-error. Retrying ...');\n return timer(delayMs); // Adding a timer from RxJS to return observable to delay param.\n } else {\n console.log(`Persistent http-errors after ${retryCount} attempts. Giving up.`);\n throw error; // an error causes request to be given up on.\n }\n }\n })\n );\n };\n}","import { WpsData } from './wps_datatypes';\nimport { Observable, of } from 'rxjs';\n\n\nexport interface Cache {\n set(input: any, output: any): Observable<any>;\n get(input: any): Observable<any>;\n}\n\nexport class FakeCache implements Cache {\n set(input: object, output: WpsData[]): Observable<boolean> {\n return of(true);\n }\n\n get(input: object): Observable<WpsData[] | null> {\n return of(null);\n }\n}\n","import { WpsMarshaller, WpsInput, WpsVersion, WpsResult, WpsOutputDescription, WpsData, WpsState,\n WpsCapability, WpsProcessDescription } from './wps_datatypes';\nimport { WpsMarshaller100 } from './wps100/wps_marshaller_1.0.0';\nimport { WpsMarshaller200 } from './wps200/wps_marshaller_2.0.0';\nimport { Observable, of } from 'rxjs';\nimport { map, switchMap, tap, share, mergeMap } from 'rxjs/operators';\nimport * as XLink_1_0_Factory from 'w3c-schemas/lib/XLink_1_0'; const XLink_1_0 = XLink_1_0_Factory.XLink_1_0;\nimport * as OWS_1_1_0_Factory from 'ogc-schemas/lib/OWS_1_1_0'; const OWS_1_1_0 = OWS_1_1_0_Factory.OWS_1_1_0;\nimport * as OWS_2_0_Factory from 'ogc-schemas/lib/OWS_2_0'; const OWS_2_0 = OWS_2_0_Factory.OWS_2_0;\nimport * as WPS_1_0_0_Factory from 'ogc-schemas/lib/WPS_1_0_0'; const WPS_1_0_0 = WPS_1_0_0_Factory.WPS_1_0_0;\nimport * as WPS_2_0_Factory from 'ogc-schemas/lib/WPS_2_0'; const WPS_2_0 = WPS_2_0_Factory.WPS_2_0;\nimport * as JsonixFactory from 'jsonix'; const Jsonix = JsonixFactory.Jsonix;\nimport { pollUntil, delayedRetry } from './utils/polling';\nimport { Cache, FakeCache } from './cache';\nimport { HttpClient } from '../httpClient/httpclient';\n\n\n\n/**\n * The Wps-client abstracts away the differences between Wps1.0.0 and Wps2.0.0\n * There are two layers of marshalling:\n * - the Wps-marshaller marshals user-facing data to wps-specific types\n * - Jsonix marshals wps-specific data to xml.\n * user-facing data -> wpsmarshaller -> Wps-type-specific data -> Jsonix-marhsaller -> XML ->\n * -> webclient -> WPS -> XML -> Jsonix-unmarshaller -> Wps-type-specific data -> wpsmarshaller -> user-facing data\n */\nexport class WpsClient {\n\n private version: WpsVersion;\n private xmlmarshaller: any;\n private xmlunmarshaller: any;\n private wpsmarshaller: WpsMarshaller;\n private cache: Cache = new FakeCache();\n\n constructor(\n version: WpsVersion = '1.0.0',\n private webclient: HttpClient,\n cache?: Cache\n ) {\n this.version = version;\n if (cache) this.cache = cache;\n let context;\n if (this.version === '1.0.0') {\n this.wpsmarshaller = new WpsMarshaller100();\n context = new Jsonix.Context([XLink_1_0, OWS_1_1_0, WPS_1_0_0]);\n } else if (this.version === '2.0.0') {\n this.wpsmarshaller = new WpsMarshaller200();\n context = new Jsonix.Context([XLink_1_0, OWS_2_0, WPS_2_0]);\n } else {\n throw new Error('You entered a WPS version other than 1.0.0 or 2.0.0.');\n }\n this.xmlunmarshaller = context.createUnmarshaller();\n this.xmlmarshaller = context.createMarshaller();\n }\n\n\n getCapabilities(url: string): Observable<WpsCapability[]> {\n const getCapabilitiesUrl = this.wpsmarshaller.getCapabilitiesUrl(url);\n return this.getRaw(getCapabilitiesUrl).pipe(\n map((response: any) => {\n const responseJson = this.xmlunmarshaller.unmarshalString(response);\n return this.wpsmarshaller.unmarshalCapabilities(responseJson.value);\n }) // @TODO: handle case when instead of WpsCapabilites an ExceptionReport is returned\n );\n }\n\n\n describeProcess(url: string, processId: string): Observable<WpsProcessDescription> {\n const describeProcessUrl = this.wpsmarshaller.getDescribeProcessUrl(url, processId);\n return this.getRaw(describeProcessUrl).pipe(\n map((response: string) => {\n const responseJson = this.xmlunmarshaller.unmarshalString(response);\n return this.wpsmarshaller.unmarshalProcessDescription(responseJson.value);\n })\n );\n }\n\n\n executeAsync(url: string, processId: string, inputs: WpsInput[], outputs: WpsOutputDescription[],\n pollingRate: number = 1000,\n tapFunction?: (response: WpsState | null) => any, unmarshalFunction?: (jsonResponse: any) => WpsData[]): Observable<WpsResult[]> {\n\n const executeRequest$: Observable<WpsState> = this.executeAsyncBasic(url, processId, inputs, outputs);\n\n const query$ = executeRequest$.pipe(\n\n // poll until succeeded\n mergeMap((currentState: WpsState) => {\n const nextState$: Observable<WpsState> = this.getNextState(currentState, url, processId, inputs, outputs);\n\n const poll$: Observable<WpsState> = pollUntil<WpsState>(\n nextState$,\n (response: WpsState) => {\n if (response.status === 'Failed') {\n throw new Error(`Error during execution of process ${processId}: ` + response.statusLocation);\n }\n return response.status === 'Succeeded';\n },\n tapFunction,\n pollingRate\n );\n\n return poll$;\n }),\n\n // fetch results\n mergeMap((lastState: WpsState) => {\n return this.fetchResults(lastState, url, processId, inputs, outputs, unmarshalFunction);\n }),\n\n // In case of errors:\n tap((response: WpsData[]) => {\n for (const result of response) {\n if (result.description.type === 'error') {\n console.log('server responded with 200, but body contained an error-result: ', result);\n throw new Error(result.value);\n }\n }\n })\n );\n\n return this.cachedQuery(url, processId, inputs, outputs, query$);\n }\n\n private cachedQuery(url: string, processId: string, inputs: WpsInput[],\n outputs: WpsOutputDescription[], query$: Observable<WpsData[]>): Observable<WpsData[]> {\n\n const cachedResponse$: Observable<WpsResult[] | null> = this.cache.get({url, processId, inputs, outputs});\n return cachedResponse$.pipe(\n switchMap((results) => {\n if (results) {\n return of(results);\n } else {\n return query$.pipe(\n tap((response: WpsData[]) => {\n this.cache.set({url, processId, inputs, outputs}, response).subscribe(success => {\n console.log('set data in cache', success);\n });\n })\n );\n }\n })\n );\n }\n\n private getNextState(currentState: WpsState, serverUrl: string, processId: string, inputs: WpsInput[],\n outputDescriptions: WpsOutputDescription[]): Observable<WpsState> {\n\n let request$: Observable<string>;\n if (this.version === '1.0.0') {\n\n if (!currentState.statusLocation) {\n throw Error('No status location');\n }\n request$ = this.getRaw(currentState.statusLocation);\n\n } else if (this.version === '2.0.0') {\n\n if (!currentState.jobID) {\n throw Error('No job-Id');\n }\n const execbody = this.wpsmarshaller.marshallGetStatusBody(serverUrl, processId, currentState.jobID);\n const xmlExecbody = this.xmlmarshaller.marshalString(execbody);\n\n request$ = this.postRaw(serverUrl, xmlExecbody);\n\n } else {\n throw new Error(`'GetStatus' has not yet been implemented for this WPS-Version (${this.version}).`);\n }\n\n const request1$: Observable<WpsState> = request$.pipe(\n delayedRetry(2000, 2),\n map((xmlResponse: string) => {\n const jsonResponse = this.xmlunmarshaller.unmarshalString(xmlResponse);\n const output: WpsState =\n this.wpsmarshaller.unmarshalGetStateResponse(jsonResponse, serverUrl, processId, inputs, outputDescriptions);\n return output;\n })\n );\n\n return request1$;\n }\n\n private fetchResults(lastState: WpsState, serverUrl: string, processId: string, inputs: WpsInput[],\n outputDescriptions: WpsOutputDescription[], unmarshalFunction?: (jsonResponse: any) => WpsData[]): Observable<WpsData[]> {\n\n if (lastState.results) { // WPS 1.0: results should already be in last state\n let output: WpsData[];\n if (unmarshalFunction) {\n output = unmarshalFunction(lastState.results);\n } else {\n output = this.wpsmarshaller.unmarshalSyncExecuteResponse(lastState.results, serverUrl, processId, inputs, outputDescriptions);\n }\n return of(output);\n\n\n } else { // WPS 2.0: get results with post request\n if (!lastState.jobID) {\n throw new Error(`You want me to get a result, but I can't find a jobId. I don't know what to do now!`);\n }\n\n const execBody = this.wpsmarshaller.marshallGetResultBody(serverUrl, processId, lastState.jobID);\n const xmlExecBody = this.xmlmarshaller.marshalString(execBody);\n\n return this.postRaw(serverUrl, xmlExecBody).pipe(\n map((xmlResponse: string) => {\n const jsonResponse = this.xmlunmarshaller.unmarshalString(xmlResponse);\n let output: WpsData[];\n if (unmarshalFunction) {\n output = unmarshalFunction(jsonResponse);\n } else {\n output = this.wpsmarshaller.unmarshalSyncExecuteResponse(jsonResponse, serverUrl, processId, inputs, outputDescriptions);\n }\n return output;\n }),\n );\n }\n }\n\n\n private executeAsyncBasic(url: string, processId: string, inputs: WpsInput[],\n outputDescriptions: WpsOutputDescription[]): Observable<WpsState> {\n\n const executeUrl = this.wpsmarshaller.executeUrl(url, processId);\n const execbody = this.wpsmarshaller.marshalExecBody(processId, inputs, outputDescriptions, true);\n const xmlExecbody = this.xmlmarshaller.marshalString(execbody);\n\n return this.postRaw(executeUrl, xmlExecbody).pipe(\n map((xmlResponse: string) => {\n const jsonResponse = this.xmlunmarshaller.unmarshalString(xmlResponse);\n const output: WpsState =\n this.wpsmarshaller.unmarshalAsyncExecuteResponse(jsonResponse, url, processId, inputs, outputDescriptions);\n return output;\n })\n );\n }\n\n execute(url: string, processId: string, inputs: WpsInput[],\n outputDescriptions: WpsOutputDescription[], unmarshalFunction?: (jsonResponse: any) => WpsData[]): Observable<WpsResult[]> {\n\n const executeUrl = this.wpsmarshaller.executeUrl(url, processId);\n const execbody = this.wpsmarshaller.marshalExecBody(processId, inputs, outputDescriptions, false);\n const xmlExecbody = this.xmlmarshaller.marshalString(execbody);\n\n return this.postRaw(executeUrl, xmlExecbody).pipe(\n map((xmlResponse: string) => {\n const jsonResponse = this.xmlunmarshaller.unmarshalString(xmlResponse);\n if (unmarshalFunction) {\n return unmarshalFunction(jsonResponse);\n }\n const output: WpsData[] =\n this.wpsmarshaller.unmarshalSyncExecuteResponse(jsonResponse, url, processId, inputs, outputDescriptions);\n return output;\n })\n );\n }\n\n dismiss(serverUrl: string, processId: string, jobId: string): Observable<any> {\n\n const dismissUrl = this.wpsmarshaller.dismissUrl(serverUrl, processId, jobId);\n const dismissBody = this.wpsmarshaller.marshalDismissBody(jobId);\n const xmlDismissBody = this.xmlmarshaller.marshalString(dismissBody);\n\n return this.postRaw(dismissUrl, xmlDismissBody).pipe(\n map((xmlResponse: string) => {\n const jsonResponse = this.xmlunmarshaller.unmarshalString(xmlResponse);\n const output = this.wpsmarshaller.unmarshalDismissResponse(jsonResponse, serverUrl, processId);\n return output;\n })\n );\n }\n\n postRaw(url: string, xmlBody: string): Observable<string> {\n const paras = {\n headers: {\n 'Content-Type': 'text/xml',\n 'Accept': 'text/xml, application/xml'\n },\n responseType: 'text'\n };\n return this.webclient.post(url, xmlBody, paras).pipe(\n delayedRetry(2000, 2),\n tap(r => {this.parseResponseForErrors(url, r)}),\n share() // turning hot: to make sure that multiple subscribers dont cause multiple requests\n );\n }\n\n getRaw(url: string): Observable<string> {\n const paras = {\n headers: {\n 'Accept': 'text/xml, application/xml'\n },\n responseType: 'text'\n };\n return this.webclient.get(url, paras).pipe(\n delayedRetry(2000, 2),\n tap(r => {this.parseResponseForErrors(url, r)}),\n );\n }\n\n private parseResponseForErrors(url: string, response: string): void {\n if (response.match('<title>404 Not Found</title>') || response.match('ows:ExceptionReport')) {\n throw new Error(`From ${url}: ` + response);\n }\n }\n\n /**\n * Use this method if you want to set the caching mechanism on a client-level\n * (as opposed to on a app-wide level)\n * @param cache : Cache (@dlr-eoc/services-ogc)\n */\n setCache(cache: Cache): void {\n this.cache = cache;\n }\n}\n","export type WpsVersion = '1.0.0' | '2.0.0';\nexport type WpsDataFormat = 'application/vnd.geo+json' | 'application/json' | 'application/WMS' |\n 'application/xml' | 'text/xml' | 'application/text' | 'image/geotiff' |\n 'text/plain';\n\n\nexport type ProcessId = string;\nexport type ProductId = string;\n\nexport interface WpsDataDescription {\n id: ProductId;\n title: string;\n type: 'literal' | 'complex' | 'bbox' | 'status' | 'error';\n reference: boolean;\n /** http://earthquake.usgs.gov/eqcenter/shakemap , ... */\n schema?: string;\n /** UTF-8, ... */\n encoding?: string;\n format?: WpsDataFormat;\n description?: string;\n defaultValue?: any;\n options?: any[];\n}\nexport type WpsInputDescription = WpsDataDescription;\nexport type WpsOutputDescription = WpsDataDescription;\n\n\nexport interface WpsData {\n description: WpsDataDescription;\n value: any;\n}\nexport type WpsInput = WpsData;\nexport type WpsResult = WpsData;\n\nexport interface WpsBboxDescription {\n id: ProductId;\n type: 'bbox';\n reference: boolean;\n format?: WpsDataFormat;\n description?: string;\n defaultValue?: any;\n}\n\nexport interface WpsBboxValue {\n crs: string;\n lllon: number;\n lllat: number;\n urlon: number;\n urlat: number;\n}\n\nexport const isBbox = (obj: object): obj is WpsBboxValue => {\n return (\n obj.hasOwnProperty('crs') &&\n obj.hasOwnProperty('lllon') &&\n obj.hasOwnProperty('lllat') &&\n obj.hasOwnProperty('urlon') &&\n obj.hasOwnProperty('urlat')\n );\n};\n\n\nexport interface WpsState {\n status: 'Succeeded' | 'Failed' | 'Accepted' | 'Running' | 'Dismissed';\n percentCompleted?: number;\n /** WPS 2.0 only */\n jobID?: string;\n /** WPS 1.0 only */\n statusLocation?: string;\n /** WPS 1.0 only: a success-state already contains the results */\n results?: any;\n}\n\nexport function isWpsState(obj: object): obj is WpsState {\n return obj && obj.hasOwnProperty('status') && (obj.hasOwnProperty('jobID') || obj.hasOwnProperty('statusLocation'));\n}\n\n\nexport interface WpsBboxData {\n description: WpsBboxDescription;\n value: WpsBboxValue;\n}\n\nexport interface WpsCapability {\n id: string;\n}\n\n\nexport interface WpsProcessDescription {\n id: string;\n processVersion: string;\n title?: string;\n description?: string;\n inputs: WpsInput[];\n outputs: WpsResult[];\n}\n\nexport interface WpsServerDescription {\n serverUrl: string;\n serverVersion: WpsVersion;\n}\n\n\nexport interface WpsMarshaller {\n\n executeUrl(url: string, processId: string): string;\n dismissUrl(serverUrl: string, processId: string, jobId: string): string;\n getCapabilitiesUrl(baseurl: string): string;\n getDescribeProcessUrl(baseurl: string, processId: string): string;\n\n marshalExecBody(processId: string, inputs: WpsInput[], outputs: WpsOutputDescription[], async: boolean): any;\n marshallGetStatusBody(serverUrl: string, processId: string, statusId: string): any;\n marshallGetResultBody(serverUrl: string, processId: string, jobID: string): any;\n marshalDismissBody(jobId: string): any;\n\n unmarshalCapabilities(capabilitiesJson: any): WpsCapability[];\n unmarshalProcessDescription(processDescriptionJson: any): WpsProcessDescription;\n unmarshalSyncExecuteResponse(responseJson: any, url: string, processId: string, inputs: WpsInput[], outputDescriptions: WpsOutputDescription[]): WpsResult[];\n unmarshalAsyncExecuteResponse(responseJson: any, url: string, processId: string, inputs: WpsInput[], outputDescriptions: WpsOutputDescription[]): WpsState;\n unmarshalGetStateResponse(jsonResponse: any, serverUrl: string, processId: string, inputs: WpsInput[], outputDescriptions: WpsOutputDescription[]): WpsState;\n unmarshalDismissResponse(jsonResponse: any, serverUrl: string, processId: string): WpsState;\n}\n","import { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { WMSCapabilities } from 'ol/format';\nimport { HttpClient } from '../httpClient/httpclient';\n\n\n\n\n\n\nexport type WmsVersion = '1.1.0' | '1.1.1' | '1.3.0';\n\nexport class WmsClient {\n private parser: WMSCapabilities;\n\n constructor(private http: HttpClient) {\n this.parser = new WMSCapabilities();\n }\n\n public getCapabilities(url: string, version: WmsVersion = '1.1.0'): Observable<any> {\n const getCapabilitiesUrl = `${url}?SERVICE=WMS&REQUEST=GetCapabilities&VERSION=${version}`;\n return this.http.get(getCapabilitiesUrl, { headers: {\n 'Content-Type': 'text/xml',\n 'Accept': 'text/xml, application/xml'\n }, responseType: 'text' }).pipe(\n map(response => {\n return this.parser.read(response);\n })\n );\n }\n\n /**\n * Searches capabilities-document for a layer with given name\n * @param name\n * @param capabilities\n */\n public getLayerFromCapabilities(name: string, capabilities: any): any {\n /** http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd - The Layer Element */\n const rootLayer: null | any = capabilities.Capability.Layer;\n return this.getLayerFromCapabilitiesLayer(name, rootLayer);\n }\n \n /**\n * @param name\n * @param layer http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd - The Layer Element\n * @returns any\n */\n priv