(which doesn't), so that SOAPpy can use wstools without needing ZSI
around... which is kinda the point of generic common-code. :)
class SOAPCallInfo:
class ParameterInfo:
class HeaderInfo(ParameterInfo):
def callInfoFromWSDL(port, name):
Next step is to move what's left of wstools/ServiceProxy.py into the ZSI
module (and fix up the imports), so that wstools has *no* soap-stack-specific
code in it.
main
| @@ -7,232 +7,11 @@ | |||
| # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | |||
| # FOR A PARTICULAR PURPOSE. | |||
| from urlparse import urlparse | |||
| from ZSI import * | |||
| from ZSI.client import * | |||
| import weakref | |||
| from Utility import DOM | |||
| import WSDLTools | |||
| class SOAPCallInfo: | |||
| """SOAPCallInfo captures the important binding information about a | |||
| SOAP operation, in a structure that is easier to work with than | |||
| raw WSDL structures.""" | |||
| def __init__(self, methodName): | |||
| self.methodName = methodName | |||
| self.inheaders = [] | |||
| self.outheaders = [] | |||
| self.inparams = [] | |||
| self.outparams = [] | |||
| self.retval = None | |||
| encodingStyle = DOM.NS_SOAP_ENC | |||
| documentation = '' | |||
| soapAction = None | |||
| transport = None | |||
| namespace = None | |||
| location = None | |||
| use = 'encoded' | |||
| style = 'rpc' | |||
| def addInParameter(self, name, type, namespace=None, element_type=0): | |||
| """Add an input parameter description to the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.inparams.append(parameter) | |||
| return parameter | |||
| def addOutParameter(self, name, type, namespace=None, element_type=0): | |||
| """Add an output parameter description to the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.outparams.append(parameter) | |||
| return parameter | |||
| def setReturnParameter(self, name, type, namespace=None, element_type=0): | |||
| """Set the return parameter description for the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.retval = parameter | |||
| return parameter | |||
| def addInHeaderInfo(self, name, type, namespace, element_type=0, | |||
| mustUnderstand=0): | |||
| """Add an input SOAP header description to the call info.""" | |||
| headerinfo = HeaderInfo(name, type, namespace, element_type) | |||
| if mustUnderstand: | |||
| headerinfo.mustUnderstand = 1 | |||
| self.inheaders.append(headerinfo) | |||
| return headerinfo | |||
| def addOutHeaderInfo(self, name, type, namespace, element_type=0, | |||
| mustUnderstand=0): | |||
| """Add an output SOAP header description to the call info.""" | |||
| headerinfo = HeaderInfo(name, type, namespace, element_type) | |||
| if mustUnderstand: | |||
| headerinfo.mustUnderstand = 1 | |||
| self.outheaders.append(headerinfo) | |||
| return headerinfo | |||
| def getInParameters(self): | |||
| """Return a sequence of the in parameters of the method.""" | |||
| return self.inparams | |||
| def getOutParameters(self): | |||
| """Return a sequence of the out parameters of the method.""" | |||
| return self.outparams | |||
| def getReturnParameter(self): | |||
| """Return param info about the return value of the method.""" | |||
| return self.retval | |||
| def getInHeaders(self): | |||
| """Return a sequence of the in headers of the method.""" | |||
| return self.inheaders | |||
| def getOutHeaders(self): | |||
| """Return a sequence of the out headers of the method.""" | |||
| return self.outheaders | |||
| class ParameterInfo: | |||
| """A ParameterInfo object captures parameter binding information.""" | |||
| def __init__(self, name, type, namespace=None, element_type=0): | |||
| if element_type: | |||
| self.element_type = 1 | |||
| if namespace is not None: | |||
| self.namespace = namespace | |||
| self.name = name | |||
| self.type = type | |||
| element_type = 0 | |||
| namespace = None | |||
| default = None | |||
| class HeaderInfo(ParameterInfo): | |||
| """A HeaderInfo object captures SOAP header binding information.""" | |||
| def __init__(self, name, type, namespace, element_type=None): | |||
| ParameterInfo.__init__(self, name, type, namespace, element_type) | |||
| mustUnderstand = 0 | |||
| actor = None | |||
| def callInfoFromWSDL(port, name): | |||
| """Return a SOAPCallInfo given a WSDL port and operation name.""" | |||
| wsdl = port.getService().getWSDL() | |||
| binding = port.getBinding() | |||
| portType = binding.getPortType() | |||
| operation = portType.operations[name] | |||
| opbinding = binding.operations[name] | |||
| messages = wsdl.messages | |||
| callinfo = SOAPCallInfo(name) | |||
| addrbinding = port.getAddressBinding() | |||
| if not isinstance(addrbinding, WSDLTools.SoapAddressBinding): | |||
| raise ValueError, 'Unsupported binding type.' | |||
| callinfo.location = addrbinding.location | |||
| soapbinding = binding.findBinding(WSDLTools.SoapBinding) | |||
| if soapbinding is None: | |||
| raise ValueError, 'Missing soap:binding element.' | |||
| callinfo.transport = soapbinding.transport | |||
| callinfo.style = soapbinding.style or 'document' | |||
| soap_op_binding = opbinding.findBinding(WSDLTools.SoapOperationBinding) | |||
| if soap_op_binding is not None: | |||
| callinfo.soapAction = soap_op_binding.soapAction | |||
| callinfo.style = soap_op_binding.style or callinfo.style | |||
| parameterOrder = operation.parameterOrder | |||
| if operation.input is not None: | |||
| message = messages[operation.input.message] | |||
| msgrole = opbinding.input | |||
| mime = msgrole.findBinding(WSDLTools.MimeMultipartRelatedBinding) | |||
| if mime is not None: | |||
| raise ValueError, 'Mime bindings are not supported.' | |||
| else: | |||
| for item in msgrole.findBindings(WSDLTools.SoapHeaderBinding): | |||
| part = messages[item.message].parts[item.part] | |||
| header = callinfo.addInHeaderInfo( | |||
| part.name, | |||
| part.element or part.type, | |||
| item.namespace, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| header.encodingStyle = item.encodingStyle | |||
| body = msgrole.findBinding(WSDLTools.SoapBodyBinding) | |||
| if body is None: | |||
| raise ValueError, 'Missing soap:body binding.' | |||
| callinfo.encodingStyle = body.encodingStyle | |||
| callinfo.namespace = body.namespace | |||
| callinfo.use = body.use | |||
| if body.parts is not None: | |||
| parts = [] | |||
| for name in body.parts: | |||
| parts.append(message.parts[name]) | |||
| else: | |||
| parts = message.parts.values() | |||
| for part in parts: | |||
| callinfo.addInParameter( | |||
| part.name, | |||
| part.element or part.type, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| if operation.output is not None: | |||
| message = messages[operation.output.message] | |||
| msgrole = opbinding.output | |||
| mime = msgrole.findBinding(WSDLTools.MimeMultipartRelatedBinding) | |||
| if mime is not None: | |||
| raise ValueError, 'Mime bindings are not supported.' | |||
| else: | |||
| for item in msgrole.findBindings(WSDLTools.SoapHeaderBinding): | |||
| part = messages[item.message].parts[item.part] | |||
| header = callinfo.addOutHeaderInfo( | |||
| part.name, | |||
| part.element or part.type, | |||
| item.namespace, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| header.encodingStyle = item.encodingStyle | |||
| body = msgrole.findBinding(WSDLTools.SoapBodyBinding) | |||
| if body is None: | |||
| raise ValueError, 'Missing soap:body binding.' | |||
| callinfo.encodingStyle = body.encodingStyle | |||
| callinfo.namespace = body.namespace | |||
| callinfo.use = body.use | |||
| if body.parts is not None: | |||
| parts = [] | |||
| for name in body.parts: | |||
| parts.append(message.parts[name]) | |||
| else: | |||
| parts = message.parts.values() | |||
| if parts: | |||
| callinfo.setReturnParameter( | |||
| parts[0].name, | |||
| parts[0].element or parts[0].type, | |||
| element_type = parts[0].element and 1 or 0 | |||
| ) | |||
| for part in parts[1:]: | |||
| callinfo.addOutParameter( | |||
| part.name, | |||
| part.element or part.type, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| return callinfo | |||
| from urlparse import urlparse | |||
| import weakref | |||
| class ServiceProxy: | |||
| """A ServiceProxy provides a convenient way to call a remote web | |||
| @@ -949,3 +949,221 @@ def FindExtension(object, kind, t_type=type(())): | |||
| if isinstance(item, kind): | |||
| return item | |||
| return None | |||
| class SOAPCallInfo: | |||
| """SOAPCallInfo captures the important binding information about a | |||
| SOAP operation, in a structure that is easier to work with than | |||
| raw WSDL structures.""" | |||
| def __init__(self, methodName): | |||
| self.methodName = methodName | |||
| self.inheaders = [] | |||
| self.outheaders = [] | |||
| self.inparams = [] | |||
| self.outparams = [] | |||
| self.retval = None | |||
| encodingStyle = DOM.NS_SOAP_ENC | |||
| documentation = '' | |||
| soapAction = None | |||
| transport = None | |||
| namespace = None | |||
| location = None | |||
| use = 'encoded' | |||
| style = 'rpc' | |||
| def addInParameter(self, name, type, namespace=None, element_type=0): | |||
| """Add an input parameter description to the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.inparams.append(parameter) | |||
| return parameter | |||
| def addOutParameter(self, name, type, namespace=None, element_type=0): | |||
| """Add an output parameter description to the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.outparams.append(parameter) | |||
| return parameter | |||
| def setReturnParameter(self, name, type, namespace=None, element_type=0): | |||
| """Set the return parameter description for the call info.""" | |||
| parameter = ParameterInfo(name, type, namespace, element_type) | |||
| self.retval = parameter | |||
| return parameter | |||
| def addInHeaderInfo(self, name, type, namespace, element_type=0, | |||
| mustUnderstand=0): | |||
| """Add an input SOAP header description to the call info.""" | |||
| headerinfo = HeaderInfo(name, type, namespace, element_type) | |||
| if mustUnderstand: | |||
| headerinfo.mustUnderstand = 1 | |||
| self.inheaders.append(headerinfo) | |||
| return headerinfo | |||
| def addOutHeaderInfo(self, name, type, namespace, element_type=0, | |||
| mustUnderstand=0): | |||
| """Add an output SOAP header description to the call info.""" | |||
| headerinfo = HeaderInfo(name, type, namespace, element_type) | |||
| if mustUnderstand: | |||
| headerinfo.mustUnderstand = 1 | |||
| self.outheaders.append(headerinfo) | |||
| return headerinfo | |||
| def getInParameters(self): | |||
| """Return a sequence of the in parameters of the method.""" | |||
| return self.inparams | |||
| def getOutParameters(self): | |||
| """Return a sequence of the out parameters of the method.""" | |||
| return self.outparams | |||
| def getReturnParameter(self): | |||
| """Return param info about the return value of the method.""" | |||
| return self.retval | |||
| def getInHeaders(self): | |||
| """Return a sequence of the in headers of the method.""" | |||
| return self.inheaders | |||
| def getOutHeaders(self): | |||
| """Return a sequence of the out headers of the method.""" | |||
| return self.outheaders | |||
| class ParameterInfo: | |||
| """A ParameterInfo object captures parameter binding information.""" | |||
| def __init__(self, name, type, namespace=None, element_type=0): | |||
| if element_type: | |||
| self.element_type = 1 | |||
| if namespace is not None: | |||
| self.namespace = namespace | |||
| self.name = name | |||
| self.type = type | |||
| element_type = 0 | |||
| namespace = None | |||
| default = None | |||
| class HeaderInfo(ParameterInfo): | |||
| """A HeaderInfo object captures SOAP header binding information.""" | |||
| def __init__(self, name, type, namespace, element_type=None): | |||
| ParameterInfo.__init__(self, name, type, namespace, element_type) | |||
| mustUnderstand = 0 | |||
| actor = None | |||
| def callInfoFromWSDL(port, name): | |||
| """Return a SOAPCallInfo given a WSDL port and operation name.""" | |||
| wsdl = port.getService().getWSDL() | |||
| binding = port.getBinding() | |||
| portType = binding.getPortType() | |||
| operation = portType.operations[name] | |||
| opbinding = binding.operations[name] | |||
| messages = wsdl.messages | |||
| callinfo = SOAPCallInfo(name) | |||
| addrbinding = port.getAddressBinding() | |||
| if not isinstance(addrbinding, WSDLTools.SoapAddressBinding): | |||
| raise ValueError, 'Unsupported binding type.' | |||
| callinfo.location = addrbinding.location | |||
| soapbinding = binding.findBinding(WSDLTools.SoapBinding) | |||
| if soapbinding is None: | |||
| raise ValueError, 'Missing soap:binding element.' | |||
| callinfo.transport = soapbinding.transport | |||
| callinfo.style = soapbinding.style or 'document' | |||
| soap_op_binding = opbinding.findBinding(WSDLTools.SoapOperationBinding) | |||
| if soap_op_binding is not None: | |||
| callinfo.soapAction = soap_op_binding.soapAction | |||
| callinfo.style = soap_op_binding.style or callinfo.style | |||
| parameterOrder = operation.parameterOrder | |||
| if operation.input is not None: | |||
| message = messages[operation.input.message] | |||
| msgrole = opbinding.input | |||
| mime = msgrole.findBinding(WSDLTools.MimeMultipartRelatedBinding) | |||
| if mime is not None: | |||
| raise ValueError, 'Mime bindings are not supported.' | |||
| else: | |||
| for item in msgrole.findBindings(WSDLTools.SoapHeaderBinding): | |||
| part = messages[item.message].parts[item.part] | |||
| header = callinfo.addInHeaderInfo( | |||
| part.name, | |||
| part.element or part.type, | |||
| item.namespace, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| header.encodingStyle = item.encodingStyle | |||
| body = msgrole.findBinding(WSDLTools.SoapBodyBinding) | |||
| if body is None: | |||
| raise ValueError, 'Missing soap:body binding.' | |||
| callinfo.encodingStyle = body.encodingStyle | |||
| callinfo.namespace = body.namespace | |||
| callinfo.use = body.use | |||
| if body.parts is not None: | |||
| parts = [] | |||
| for name in body.parts: | |||
| parts.append(message.parts[name]) | |||
| else: | |||
| parts = message.parts.values() | |||
| for part in parts: | |||
| callinfo.addInParameter( | |||
| part.name, | |||
| part.element or part.type, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| if operation.output is not None: | |||
| message = messages[operation.output.message] | |||
| msgrole = opbinding.output | |||
| mime = msgrole.findBinding(WSDLTools.MimeMultipartRelatedBinding) | |||
| if mime is not None: | |||
| raise ValueError, 'Mime bindings are not supported.' | |||
| else: | |||
| for item in msgrole.findBindings(WSDLTools.SoapHeaderBinding): | |||
| part = messages[item.message].parts[item.part] | |||
| header = callinfo.addOutHeaderInfo( | |||
| part.name, | |||
| part.element or part.type, | |||
| item.namespace, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| header.encodingStyle = item.encodingStyle | |||
| body = msgrole.findBinding(WSDLTools.SoapBodyBinding) | |||
| if body is None: | |||
| raise ValueError, 'Missing soap:body binding.' | |||
| callinfo.encodingStyle = body.encodingStyle | |||
| callinfo.namespace = body.namespace | |||
| callinfo.use = body.use | |||
| if body.parts is not None: | |||
| parts = [] | |||
| for name in body.parts: | |||
| parts.append(message.parts[name]) | |||
| else: | |||
| parts = message.parts.values() | |||
| if parts: | |||
| callinfo.setReturnParameter( | |||
| parts[0].name, | |||
| parts[0].element or parts[0].type, | |||
| element_type = parts[0].element and 1 or 0 | |||
| ) | |||
| for part in parts[1:]: | |||
| callinfo.addOutParameter( | |||
| part.name, | |||
| part.element or part.type, | |||
| element_type = part.element and 1 or 0 | |||
| ) | |||
| return callinfo | |||