def encode_execute_response(self, process, inputs, results, lineage=False): response_elem = WPS("ExecuteResponse", self.encode_process_brief(process), WPS("Status", WPS("ProcessSucceded"), # TODO: other states creationTime=isoformat(now()) ) ) if lineage: response_elem.append( WPS("DataInputs", ) ) response_elem.extend(( WPS("OutputDefinitions", *[ self.encode_parameter(name, parameter, False) for name, parameter in process.outputs.items() ]), WPS("ProcessOutputs", *[ self.encode_output(name, process.outputs[name], data) for name, data in results.items() ]) )) return response_elem
def _encode_process_brief(process, elem): """ Insert a brief process description into an XML element passed as the second argument. The brief process description is shared by both the Capabilities and ProcessDescriptions XML encoders. """ identifier = getattr(process, 'identifier', type(process).__name__) title = getattr(process, 'title', identifier) abstract = getattr(process, 'description', process.__doc__) version = getattr(process, "version", "1.0.0") metadata = getattr(process, "metadata", {}) profiles = getattr(process, "profiles", []) wsdl = getattr(process, "wsdl", None) elem.append(OWS("Identifier", identifier)) elem.append(OWS("Title", title)) elem.attrib[ns_wps("processVersion")] = version if abstract: elem.append(OWS("Abstract", abstract)) elem.extend(_encode_metadata(k, metadata[k]) for k in metadata) elem.extend(WPS("Profile", profile) for profile in profiles) if wsdl: elem.append(WPS("WSDL", **{ns_xlink("href"): wsdl})) return elem
def encode_capabilities(processes): """ Encode Capabilities XML document. """ conf = CapabilitiesConfigReader(get_eoxserver_config()) # Avoid duplicate process offerings ... process_set = set() process_offerings = [] for process in processes: process_identifier = (getattr(process, 'identifier', None) or type(process).__name__) if process_identifier not in process_set: process_offerings.append(encode_process_brief(process)) process_set.add(process_identifier) return WPS( "Capabilities", OWS( "ServiceIdentification", OWS("Title", conf.title), OWS("Abstract", conf.abstract), OWS("Keywords", *(OWS("Keyword", kw) for kw in conf.keywords)), OWS("ServiceType", "WPS"), OWS("ServiceTypeVersion", "1.0.0"), OWS("Fees", conf.fees), OWS("AccessConstraints", conf.access_constraints), ), OWS( "ServiceProvider", OWS("ProviderName", conf.provider_name), OWS("ProviderSite", **{ns_xlink("href"): conf.provider_site}), OWS( "ServiceContact", OWS("IndividualName", conf.individual_name), OWS("PositionName", conf.position_name), OWS( "ContactInfo", OWS("Phone", OWS("Voice", conf.phone_voice), OWS("Facsimile", conf.phone_facsimile)), OWS( "Address", OWS("DeliveryPoint", conf.delivery_point), OWS("City", conf.city), OWS("AdministrativeArea", conf.administrative_area), OWS("PostalCode", conf.postal_code), OWS("Country", conf.country), OWS("ElectronicMailAddress", conf.electronic_mail_address))))), _encode_operations_metadata(conf), WPS("ProcessOfferings", *process_offerings), WPS("Languages", WPS("Default", OWS("Language", "en-US")), WPS("Supported", OWS("Language", "en-US"))), # TODO: WPS("WSDL") **{ "service": "WPS", "version": "1.0.0", ns_xml("lang"): "en-US", "updateSequence": conf.update_sequence, })
def encode_format(self, frmt): elem = WPS("Format", WPS("MimeType", frmt.mime_type) ) if frmt.encoding: elem.append(WPS("Encoding", frmt.encoding)) if frmt.encoding: elem.append(WPS("Schema", frmt.schema))
def encode_response(self, results): """Encode ProcessSucceeded execute response including the output data.""" elem = self._encode_common( WPS("ProcessSucceeded", "The processes execution completed successfully.")) outputs = [] for result, prm, req in itervalues(results): outputs.append(_encode_output(result, prm, req)) elem.append(WPS("ProcessOutputs", *outputs)) return elem
def _encode_complex(data, prm): try: payload = prm.encode_xml(data) except (ValueError, TypeError) as exc: raise InvalidOutputValueError(prm.identifier, exc) elem = WPS("ComplexData", **_encode_format_attr(data, prm)) if isinstance(payload, etree._Element): elem.append(payload) else: elem.text = etree.CDATA(payload) return elem
def _encode_complex(data, prm): """ Encode Data/ComplexData element. """ try: payload = prm.encode_xml(data) except (ValueError, TypeError) as exc: raise InvalidOutputValueError(prm.identifier, exc) elem = WPS("ComplexData", **_encode_format_attr(data, prm)) if isinstance(payload, etree._Element): elem.append(payload) else: elem.text = etree.CDATA(payload) return elem
def _encode_output(data, prm, req): """ Encode one ProcessOutputs sub-element. """ elem = encode_output_exec( Parameter(prm.identifier, req.title or prm.title, req.abstract or prm.abstract)) if isinstance(data, Reference): elem.append(_encode_output_reference(data, prm)) elif isinstance(prm, LiteralData): elem.append(WPS("Data", _encode_literal(data, prm, req))) elif isinstance(prm, BoundingBoxData): elem.append(WPS("Data", _encode_bbox(data, prm))) elif isinstance(prm, ComplexData): elem.append(WPS("Data", _encode_complex(data, prm))) return elem
def encode_paused(self, progress=0): """ Encode ProcessPaused execute response.""" return self._encode_common( WPS("ProcessPaused", "The processes execution is paused.", percentCompleted=("%d" % min(99, max(0, int(float(progress)))))))
def _encode_raw_input_literal(input_raw, prm): """ Encode Data/LiteralData element from a raw (unparsed) input .""" attrib = {'dataType': prm.dtype.name} uom = input_raw.uom or prm.default_uom if prm.uoms: attrib['uom'] = uom return WPS("LiteralData", input_raw.data, **attrib)
def encode_process_descriptions(processes): """ Encode the ProcessDescriptions XML document. """ _proc = [encode_process_full(p) for p in processes] _attr = { "service": "WPS", "version": "1.0.0", ns_xml("lang"): "en-US", } return WPS("ProcessDescriptions", *_proc, **_attr)
def encode_started(self, progress=0, message=None): """ Encode ProcessStarted execute response.""" if not message: message = "The processes execution is in progress." return self._encode_common( WPS("ProcessStarted", message, percentCompleted=("%d" % min(99, max(0, int(float(progress)))))))
def encode_failed(self, exception): """ Encode ProcessFailed execute response.""" # NOTE: Some exceptions such as the urllib2.HTTPError have also # the 'code' attribute and the duck typing does not work very well. # Therefore we need match the exception base type. if isinstance(exception, OWS10Exception): code = exception.code locator = exception.locator else: code = "NoApplicableCode" locator = type(exception).__name__ message = str(exception) exc_attr = {"exceptionCode": str(code)} if locator: exc_attr["locator"] = str(locator) exc_elem = OWS("Exception", OWS("ExceptionText", message), **exc_attr) status = WPS("ProcessFailed", WPS("ExceptionReport", exc_elem)) return self._encode_common(status)
def _encode_input(data, prm, raw): """ Encode one DataInputs sub-element. """ elem = encode_input_exec(raw) if isinstance(raw, InputReference): elem.append(_encode_input_reference(raw)) elif isinstance(prm, LiteralData): elem.append(WPS("Data", _encode_raw_input_literal(raw, prm))) elif isinstance(prm, BoundingBoxData): if data is None: data = prm.parse(raw.data) elem.append(WPS("Data", _encode_bbox(data, prm))) elif isinstance(prm, ComplexData): if data is None: data = prm.parse(data=raw.data, mime_type=raw.mime_type, encoding=raw.encoding, schema=raw.schema) elem.append(WPS("Data", _encode_complex(data, prm))) return elem
def _encode_literal(data, prm, req): """ Encode Data/LiteralData element. """ attrib = {'dataType': prm.dtype.name} uom = req.uom or prm.default_uom if prm.uoms: attrib['uom'] = uom try: encoded_data = prm.encode(data, uom) except (ValueError, TypeError) as exc: raise InvalidOutputValueError(prm.identifier, exc) return WPS("LiteralData", encoded_data, **attrib)
def _encode_common_response(process, status_elem, inputs, raw_inputs, resp_doc): """Encode common execute response part shared by all specific responses.""" inputs = inputs or {} conf = CapabilitiesConfigReader(get_eoxserver_config()) url = conf.http_service_url if url[-1] == "?": url = url[:-1] elem = WPS("ExecuteResponse", encode_process_brief(process), WPS("Status", status_elem, creationTime=isoformat(now())), { "service": "WPS", "version": "1.0.0", ns_xml("lang"): "en-US", "serviceInstance": ( "%s?service=WPS&version=1.0.0&request=GetCapabilities" % url ) }, ) if resp_doc.lineage: inputs_data = [] for id_, prm in process.inputs: if isinstance(prm, RequestParameter): continue prm = fix_parameter(id_, prm) data = inputs.get(id_) rawinp = raw_inputs.get(prm.identifier) if rawinp is not None: inputs_data.append(_encode_input(data, prm, rawinp)) elem.append(WPS("DataInputs", *inputs_data)) outputs_def = [] for id_, prm in process.outputs: prm = fix_parameter(id_, prm) outdef = resp_doc.get(prm.identifier) if outdef is not None: outputs_def.append(encode_output_def(outdef)) elem.append(WPS("OutputDefinitions", *outputs_def)) return elem
def _encode_common_response(process, status_elem, inputs, raw_inputs, resp_doc): """Encode common execute response part shared by all specific responses.""" inputs = inputs or {} conf = CapabilitiesConfigReader(get_eoxserver_config()) url = conf.http_service_url if url[-1] == "?": url = url[:-1] elem = WPS( "ExecuteResponse", encode_process_brief(process), WPS("Status", status_elem, creationTime=isoformat(now())), { "service": "WPS", "version": "1.0.0", ns_xml("lang"): "en-US", "serviceInstance": ("%s?service=WPS&version=1.0.0&request=GetCapabilities" % url) }, ) if resp_doc.lineage: inputs_data = [] for id_, prm in process.inputs: if isinstance(prm, RequestParameter): continue prm = fix_parameter(id_, prm) data = inputs.get(id_) rawinp = raw_inputs.get(prm.identifier) if rawinp is not None: inputs_data.append(_encode_input(data, prm, rawinp)) elem.append(WPS("DataInputs", *inputs_data)) outputs_def = [] for id_, prm in process.outputs: prm = fix_parameter(id_, prm) outdef = resp_doc.get(prm.identifier) if outdef is not None: outputs_def.append(encode_output_def(outdef)) elem.append(WPS("OutputDefinitions", *outputs_def)) return elem
def _encode_bbox(data, prm): """ Encode Data/BoundingBoxData element. """ try: lower, upper, crs = prm.encode_xml(data) except (ValueError, TypeError) as exc: raise InvalidOutputValueError(prm.identifier, exc) return WPS( "BoundingBoxData", OWS("LowerCorner", lower), OWS("UpperCorner", upper), crs=crs, #dimension="%d"%prm.dimension, )
def encode_output_def(outdef): """ Encode execute response Output (definition) element. """ attrib = {} if outdef.uom is not None: attrib['uom'] = outdef.uom if outdef.crs is not None: attrib['crs'] = outdef.crs if outdef.mime_type is not None: attrib['mimeType'] = outdef.mime_type if outdef.encoding is not None: attrib['encoding'] = outdef.encoding if outdef.schema is not None: attrib['schema'] = outdef.schema if outdef.as_reference is not None: attrib['asReference'] = 'true' if outdef.as_reference else 'false' return WPS("Output", *_encode_param_common(outdef, False), **attrib)
def _encode_allowed_value(avobj): """ Encode process description LiteralData allowed values definition. Based on the type of the allowed value definition either AnyValue, ValuesReference, or AllowedValues element is returned. """ enum, ranges, elist = None, [], [] if isinstance(avobj, AllowedAny): return OWS("AnyValue") elif isinstance(avobj, AllowedByReference): return WPS( "ValuesReference", **{ ns_ows("reference"): avobj.url, "valuesForm": avobj.url, }) elif isinstance(avobj, AllowedEnum): enum = avobj elif isinstance(avobj, AllowedRange): ranges = [avobj] elif isinstance(avobj, AllowedRangeCollection): enum, ranges = avobj.enum, avobj.ranges else: raise TypeError("Invalid allowed value object! OBJ=%r" % avobj) dtype = avobj.dtype ddtype = dtype.get_diff_dtype() if enum is not None: elist.extend(OWS("Value", dtype.encode(v)) for v in enum.values) for range_ in ranges: attr, elms = {}, [] if range_.closure != 'closed': attr = {ns_ows("rangeClosure"): range_.closure} if range_.minval is not None: elms.append(OWS("MinimumValue", dtype.encode(range_.minval))) if range_.maxval is not None: elms.append(OWS("MaximumValue", dtype.encode(range_.maxval))) if range_.spacing is not None: elms.append(OWS("Spacing", ddtype.encode(range_.spacing))) elist.append(OWS("Range", *elms, **attr)) return OWS("AllowedValues", *elist)
def _encode_output_reference(ref, prm): """ Encode ProcessOutputs/Reference element. """ #TODO proper output reference encoding mime_type = getattr(ref, 'mime_type', None) encoding = getattr(ref, 'encoding', None) schema = getattr(ref, 'schema', None) if mime_type is None and hasattr(prm, 'default_format'): default_format = prm.default_format mime_type = default_format.mime_type encoding = default_format.encoding schema = default_format.schema attr = { #ns_xlink("href"): ref.href, 'href': ref.href, } if mime_type: attr['mimeType'] = mime_type if encoding is not None: attr['encoding'] = encoding if schema is not None: attr['schema'] = schema return WPS("Reference", **attr)
def encode_process_brief(self, process): elem = WPS("Process", OWS("Identifier", process.identifier), OWS("Title", getattr(process, "title", None) or process.identifier), OWS("Abstract", getattr(process, "description", "")) ) elem.extend([ OWS("Metadata", metadata) for metadata in getattr(process, "metadata", []) ]) elem.extend([ OWS("Profile", profile) for profile in getattr(process, "profiles", []) ]) version = getattr(process, "version", None) if version: elem.attr[ns_wps("processVersion")] = version return elem
def encode_process_brief(process): """ Encode a brief process description (Process element) of the Capabilities XML document. """ return _encode_process_brief(process, WPS("Process"))
def encode_output_exec(prm): """ Encode common part of the execute response Output (data) element. """ return WPS("Output", *_encode_param_common(prm))
def encode_input_exec(prm): """ Encode common part of the execute response Input (data) element. """ return WPS("Input", *_encode_param_common(prm, False))
def encode_accepted(self): """ Encode ProcessAccepted execute response.""" return self._encode_common( WPS("ProcessAccepted", "The processes was accepted for execution."))
def encode_parameter(self, name, parameter, is_input): # support for the shorthand if is_literal_type(parameter): parameter = LiteralData(name, parameter) # TODO: minOccurs/maxOccurs correct elem = WPS("Input" if is_input else "Output", OWS("Identifier", parameter.identifier or name) ) if parameter.title: elem.append(OWS("Title", parameter.title)) if parameter.description: elem.append(OWS("Abstract", parameter.description)) if isinstance(parameter, LiteralData): data_elem = WPS("LiteralData" if is_input else "LiteralOutput") literal_type_name = parameter.type_name if literal_type_name: data_elem.append( OWS("DataType", literal_type_name, **{ ns_ows("reference"): "http://www.w3.org/TR/xmlschema-2/#%s" % literal_type_name }) ) if parameter.uoms: data_elem.append( WPS("UOMs", WPS("Default", OWS("UOM", parameter.uoms[0]) ), WPS("Supported", *[ OWS("UOM", uom) for uom in parameter.uoms ]) ) ) if is_input and parameter.allowed_values: data_elem.append( OWS("AllowedValues", *[ OWS("AllowedValue", str(allowed_value)) for allowed_value in parameter.allowed_values ]) ) elif is_input and parameter.values_reference: data_elem.append( WPS("ValuesReference", **{ ns_ows("reference"): parameter.values_reference, "valuesForm": parameter.values_reference }) ) elif is_input: data_elem.append(OWS("AnyValue")) if is_input and parameter.default is not None: elem.attrib["minOccurs"] = "0" data_elem.append( WPS("Default", str(parameter.default)) ) elif isinstance(parameter, ComplexData): formats = parameter.formats if isinstance(formats, Format): formats = (formats,) data_elem = WPS("ComplexData" if is_input else "ComplexOutput", WPS("Default", self.encode_format(formats[0]) ), WPS("Supported", *[ self.encode_format(frmt) for frmt in formats ]) ) elif isinstance(parameter, BoundingBoxData): # TODO: implement data_elem = WPS("BoundingBoxData" if is_input else "BoundingBoxOutput") elem.append(data_elem) return elem
def _encode_input_reference(ref): """ Encode DataInputs/Reference element. """ #TODO proper input reference encoding return WPS("Reference", **{ns_xlink("href"): ref.href})