Update of /cvsroot/pywebsvcs/zsi/ZSI/wsdl In directory sc8-pr-cvs1:/tmp/cvs-serv7890 Modified Files: ServiceProxy.py Utility.py WSDLTools.py XMLSchema.py Removed Files: SOAPCallInfo.py Transports.py XMLWriter.py Log Message: Simplify code: -Remove toXML methods, and WSDLWriter class. -Remove SMTP transport, since only use of Transports is for WSDL reading. Should remove timeout stuff altogether and use Python's current URL library. -Merge some smaller files into the only place they're used. Index: ServiceProxy.py =================================================================== RCS file: /cvsroot/pywebsvcs/zsi/ZSI/wsdl/ServiceProxy.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ServiceProxy.py 18 Mar 2003 05:04:08 -0000 1.1 +++ ServiceProxy.py 21 Mar 2003 16:31:25 -0000 1.2 @@ -7,13 +7,232 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -from SOAPCallInfo import callInfoFromWSDL -from WSDLTools import WSDLReader 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 + class ServiceProxy: """A ServiceProxy provides a convenient way to call a remote web @@ -22,7 +241,7 @@ def __init__(self, wsdl, service=None, port=None): if not hasattr(wsdl, 'targetNamespace'): - wsdl = WSDLReader().loadFromURL(wsdl) + wsdl = WSDLTools.WSDLReader().loadFromURL(wsdl) # for item in wsdl.types.items(): # self._serializer.loadSchema(item) self._service = wsdl.services[service or 0] Index: Utility.py =================================================================== RCS file: /cvsroot/pywebsvcs/zsi/ZSI/wsdl/Utility.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- Utility.py 18 Mar 2003 05:04:08 -0000 1.1 +++ Utility.py 21 Mar 2003 16:31:25 -0000 1.2 @@ -10,9 +10,110 @@ from string import join, strip, split from UserDict import UserDict from StringIO import StringIO -from Transports import urlopen import xml.dom.minidom, weakref +import string, httplib, smtplib, urllib, socket +from TimeoutSocket import TimeoutSocket, TimeoutError +from StringIO import StringIO +from urlparse import urlparse +from httplib import HTTPConnection, HTTPSConnection + +class HTTPResponse: + """Captures the information in an HTTP response message.""" + + def __init__(self, response): + self.status = response.status + self.reason = response.reason + self.headers = response.msg + self.body = response.read() or None + response.close() + +class TimeoutHTTP(HTTPConnection): + """A custom http connection object that supports socket timeout.""" + def __init__(self, host, port=None, timeout=20): + HTTPConnection.__init__(self, host, port) + self.timeout = timeout + + def connect(self): + self.sock = TimeoutSocket(self.timeout) + self.sock.connect((self.host, self.port)) + + +class TimeoutHTTPS(HTTPSConnection): + """A custom https object that supports socket timeout. Note that this + is not really complete. The builtin SSL support in the Python socket + module requires a real socket (type) to be passed in to be hooked to + SSL. That means our fake socket won't work and our timeout hacks are + bypassed for send and recv calls. Since our hack _is_ in place at + connect() time, it should at least provide some timeout protection.""" + def __init__(self, host, port=None, timeout=20, **kwargs): + if not hasattr(socket, 'ssl'): + raise ValueError( + 'This Python installation does not have SSL support.' + ) + HTTPSConnection.__init__(self, str(host), port, **kwargs) + self.timeout = timeout + + def connect(self): + sock = TimeoutSocket(self.timeout) + sock.connect((self.host, self.port)) + realsock = getattr(sock.sock, '_sock', sock.sock) + ssl = socket.ssl(realsock, self.key_file, self.cert_file) + self.sock = httplib.FakeSocket(sock, ssl) + +def urlopen(url, timeout=20, redirects=None): + """A minimal urlopen replacement hack that supports timeouts for http. + Note that this supports GET only.""" + scheme, host, path, params, query, frag = urlparse(url) + if not scheme in ('http', 'https'): + return urllib.urlopen(url) + if params: path = '%s;%s' % (path, params) + if query: path = '%s?%s' % (path, query) + if frag: path = '%s#%s' % (path, frag) + + if scheme == 'https': + if not hasattr(socket, 'ssl'): + raise ValueError( + 'This Python installation does not have SSL support.' + ) + conn = TimeoutHTTPS(host, None, timeout) + else: + conn = TimeoutHTTP(host, None, timeout) + + conn.putrequest('GET', path) + conn.putheader('Connection', 'close') + conn.endheaders() + response = None + while 1: + response = conn.getresponse() + if response.status != 100: + break + conn._HTTPConnection__state = httplib._CS_REQ_SENT + conn._HTTPConnection__response = None + + status = response.status + + # If we get an HTTP redirect, we will follow it automatically. + if status >= 300 and status < 400: + location = response.msg.getheader('location') + if location is not None: + response.close() + if redirects is not None and redirects.has_key(location): + raise RecursionError( + 'Circular HTTP redirection detected.' + ) + if redirects is None: + redirects = {} + redirects[location] = 1 + return urlopen(location, timeout, redirects) + raise HTTPResponse(response) + + if not (status >= 200 and status < 300): + raise HTTPResponse(response) + + body = StringIO(response.read()) + response.close() + return body class DOM: """The DOM singleton defines a number of XML related constants and @@ -325,17 +426,6 @@ if preserve_ws is None: value = strip(value) return value - - def elementToStream(self, element, stream, format=0): - """Write the xml representation of an element to a stream.""" - if format: element.writexml(stream, '', ' ', '\n') - else: element.writexml(stream) - return stream - - def elementToString(self, element, format=0): - """Return an xml string representation of an element.""" - method = format and element.toprettyxml or element.toxml - return method() def findNamespaceURI(self, prefix, node): """Find a namespace uri given a prefix and a context node.""" Index: WSDLTools.py =================================================================== RCS file: /cvsroot/pywebsvcs/zsi/ZSI/wsdl/WSDLTools.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- WSDLTools.py 18 Mar 2003 05:04:08 -0000 1.1 +++ WSDLTools.py 21 Mar 2003 16:31:25 -0000 1.2 @@ -1,1376 +1,971 @@ -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. - -from Utility import DOM, Collection -from XMLSchema import XMLSchema [...2316 lines suppressed...] + for item in object.extensions: + if isinstance(item, kind): + result.append(item) + return result + +def FindExtension(object, kind, t_type=type(())): + if isinstance(kind, t_type): + namespaceURI, name = kind + for item in object.extensions: + if not hasattr(item, 'nodeType'): + continue + if DOM.nsUriMatch(namespaceURI, item.namespaceURI) and \ + item.name == name: + return item + else: + for item in object.extensions: + if isinstance(item, kind): + return item + return None + Index: XMLSchema.py =================================================================== RCS file: /cvsroot/pywebsvcs/zsi/ZSI/wsdl/XMLSchema.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- XMLSchema.py 18 Mar 2003 05:04:08 -0000 1.1 +++ XMLSchema.py 21 Mar 2003 16:31:25 -0000 1.2 @@ -48,11 +48,6 @@ self.targetNamespace = DOM.getAttr(element, 'targetNamespace') self.element = element - def toXML(self, writer): - strval = DOM.elementToString(self.element) - writer.writeXML(strval) - - class realXMLSchema: """A schema is a collection of schema components derived from one or more schema documents, that is, one or more <schema> element --- SOAPCallInfo.py DELETED --- --- Transports.py DELETED --- --- XMLWriter.py DELETED --- |