(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 | # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||||
# FOR A PARTICULAR PURPOSE. | # FOR A PARTICULAR PURPOSE. | ||||
from urlparse import urlparse | |||||
from ZSI import * | from ZSI import * | ||||
from ZSI.client import * | from ZSI.client import * | ||||
import weakref | |||||
from Utility import DOM | |||||
import WSDLTools | 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: | class ServiceProxy: | ||||
"""A ServiceProxy provides a convenient way to call a remote web | """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): | if isinstance(item, kind): | ||||
return item | return item | ||||
return None | 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 |