00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 ident = "$Id: WSDLTools.py 1122 2006-02-04 01:24:50Z boverhof $"
00011
00012 import weakref
00013 from cStringIO import StringIO
00014 from Namespaces import OASIS, XMLNS, WSA, WSA_LIST, WSRF_V1_2, WSRF
00015 from Utility import Collection, CollectionNS, DOM, ElementProxy, basejoin
00016 from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter
00017
00018
00019 class WSDLReader:
00020 """A WSDLReader creates WSDL instances from urls and xml data."""
00021
00022
00023
00024
00025
00026 def loadFromStream(self, stream, name=None):
00027 """Return a WSDL instance loaded from a stream object."""
00028 document = DOM.loadDocument(stream)
00029 wsdl = WSDL()
00030 if name:
00031 wsdl.location = name
00032 elif hasattr(stream, 'name'):
00033 wsdl.location = stream.name
00034 wsdl.load(document)
00035 return wsdl
00036
00037 def loadFromURL(self, url):
00038 """Return a WSDL instance loaded from the given url."""
00039 document = DOM.loadFromURL(url)
00040 wsdl = WSDL()
00041 wsdl.location = url
00042 wsdl.load(document)
00043 return wsdl
00044
00045 def loadFromString(self, data):
00046 """Return a WSDL instance loaded from an xml string."""
00047 return self.loadFromStream(StringIO(data))
00048
00049 def loadFromFile(self, filename):
00050 """Return a WSDL instance loaded from the given file."""
00051 file = open(filename, 'rb')
00052 try:
00053 wsdl = self.loadFromStream(file)
00054 finally:
00055 file.close()
00056 return wsdl
00057
00058 class WSDL:
00059 """A WSDL object models a WSDL service description. WSDL objects
00060 may be created manually or loaded from an xml representation
00061 using a WSDLReader instance."""
00062
00063 def __init__(self, targetNamespace=None, strict=1):
00064 self.targetNamespace = targetNamespace or 'urn:this-document.wsdl'
00065 self.documentation = ''
00066 self.location = None
00067 self.document = None
00068 self.name = None
00069 self.services = CollectionNS(self)
00070 self.messages = CollectionNS(self)
00071 self.portTypes = CollectionNS(self)
00072 self.bindings = CollectionNS(self)
00073 self.imports = Collection(self)
00074 self.types = Types(self)
00075 self.extensions = []
00076 self.strict = strict
00077
00078 def __del__(self):
00079 if self.document is not None:
00080 self.document.unlink()
00081
00082 version = '1.1'
00083
00084 def addService(self, name, documentation='', targetNamespace=None):
00085 if self.services.has_key(name):
00086 raise WSDLError(
00087 'Duplicate service element: %s' % name
00088 )
00089 item = Service(name, documentation)
00090 if targetNamespace:
00091 item.targetNamespace = targetNamespace
00092 self.services[name] = item
00093 return item
00094
00095 def addMessage(self, name, documentation='', targetNamespace=None):
00096 if self.messages.has_key(name):
00097 raise WSDLError(
00098 'Duplicate message element: %s.' % name
00099 )
00100 item = Message(name, documentation)
00101 if targetNamespace:
00102 item.targetNamespace = targetNamespace
00103 self.messages[name] = item
00104 return item
00105
00106 def addPortType(self, name, documentation='', targetNamespace=None):
00107 if self.portTypes.has_key(name):
00108 raise WSDLError(
00109 'Duplicate portType element: name'
00110 )
00111 item = PortType(name, documentation)
00112 if targetNamespace:
00113 item.targetNamespace = targetNamespace
00114 self.portTypes[name] = item
00115 return item
00116
00117 def addBinding(self, name, type, documentation='', targetNamespace=None):
00118 if self.bindings.has_key(name):
00119 raise WSDLError(
00120 'Duplicate binding element: %s' % name
00121 )
00122 item = Binding(name, type, documentation)
00123 if targetNamespace:
00124 item.targetNamespace = targetNamespace
00125 self.bindings[name] = item
00126 return item
00127
00128 def addImport(self, namespace, location):
00129 item = ImportElement(namespace, location)
00130 self.imports[namespace] = item
00131 return item
00132
00133 def toDom(self):
00134 """ Generate a DOM representation of the WSDL instance.
00135 Not dealing with generating XML Schema, thus the targetNamespace
00136 of all XML Schema elements or types used by WSDL message parts
00137 needs to be specified via import information items.
00138 """
00139 namespaceURI = DOM.GetWSDLUri(self.version)
00140 self.document = DOM.createDocument(namespaceURI ,'wsdl:definitions')
00141
00142
00143 child = DOM.getElement(self.document, None)
00144 child.setAttributeNS(None, 'targetNamespace', self.targetNamespace)
00145 child.setAttributeNS(XMLNS.BASE, 'xmlns:wsdl', namespaceURI)
00146 child.setAttributeNS(XMLNS.BASE, 'xmlns:xsd', 'http://www.w3.org/1999/XMLSchema')
00147 child.setAttributeNS(XMLNS.BASE, 'xmlns:soap', 'http://schemas.xmlsoap.org/wsdl/soap/')
00148 child.setAttributeNS(XMLNS.BASE, 'xmlns:tns', self.targetNamespace)
00149
00150 if self.name:
00151 child.setAttributeNS(None, 'name', self.name)
00152
00153
00154 for item in self.imports:
00155 item.toDom()
00156
00157 for item in self.messages:
00158 item.toDom()
00159
00160 for item in self.portTypes:
00161 item.toDom()
00162
00163 for item in self.bindings:
00164 item.toDom()
00165
00166 for item in self.services:
00167 item.toDom()
00168
00169 def load(self, document):
00170
00171
00172
00173
00174 self.document = document
00175
00176 definitions = DOM.getElement(document, 'definitions', None, None)
00177 if definitions is None:
00178 raise WSDLError(
00179 'Missing <definitions> element.'
00180 )
00181 self.version = DOM.WSDLUriToVersion(definitions.namespaceURI)
00182 NS_WSDL = DOM.GetWSDLUri(self.version)
00183
00184 self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace',
00185 None, None)
00186 self.name = DOM.getAttr(definitions, 'name', None, None)
00187 self.documentation = GetDocumentation(definitions)
00188
00189
00190
00191
00192
00193
00194
00195
00196 imported = []
00197 base_location = self.location
00198 do_it = True
00199 while do_it:
00200 do_it = False
00201 for element in DOM.getElements(definitions, 'import', NS_WSDL):
00202 location = DOM.getAttr(element, 'location')
00203
00204 if base_location is not None:
00205 location = basejoin(base_location, location)
00206
00207 if location not in imported:
00208 do_it = True
00209 self._import(document, element, base_location)
00210 imported.append(location)
00211 else:
00212 definitions.removeChild(element)
00213
00214 base_location = None
00215
00216
00217
00218
00219
00220 for element in DOM.getElements(definitions, None, None):
00221 targetNamespace = DOM.getAttr(element, 'targetNamespace')
00222 localName = element.localName
00223
00224 if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL):
00225 if localName == 'schema':
00226 tns = DOM.getAttr(element, 'targetNamespace')
00227 reader = SchemaReader(base_url=self.imports[tns].location)
00228 schema = reader.loadFromNode(WSDLToolsAdapter(self),
00229 element)
00230
00231 self.types.addSchema(schema)
00232 else:
00233 self.extensions.append(element)
00234 continue
00235
00236 elif localName == 'message':
00237 name = DOM.getAttr(element, 'name')
00238 docs = GetDocumentation(element)
00239 message = self.addMessage(name, docs, targetNamespace)
00240 parts = DOM.getElements(element, 'part', NS_WSDL)
00241 message.load(parts)
00242 continue
00243
00244 elif localName == 'portType':
00245 name = DOM.getAttr(element, 'name')
00246 docs = GetDocumentation(element)
00247 ptype = self.addPortType(name, docs, targetNamespace)
00248
00249
00250 ptype.load(element)
00251 continue
00252
00253 elif localName == 'binding':
00254 name = DOM.getAttr(element, 'name')
00255 type = DOM.getAttr(element, 'type', default=None)
00256 if type is None:
00257 raise WSDLError(
00258 'Missing type attribute for binding %s.' % name
00259 )
00260 type = ParseQName(type, element)
00261 docs = GetDocumentation(element)
00262 binding = self.addBinding(name, type, docs, targetNamespace)
00263 operations = DOM.getElements(element, 'operation', NS_WSDL)
00264 binding.load(operations)
00265 binding.load_ex(GetExtensions(element))
00266 continue
00267
00268 elif localName == 'service':
00269 name = DOM.getAttr(element, 'name')
00270 docs = GetDocumentation(element)
00271 service = self.addService(name, docs, targetNamespace)
00272 ports = DOM.getElements(element, 'port', NS_WSDL)
00273 service.load(ports)
00274 service.load_ex(GetExtensions(element))
00275 continue
00276
00277 elif localName == 'types':
00278 self.types.documentation = GetDocumentation(element)
00279 base_location = DOM.getAttr(element, 'base-location')
00280 if base_location:
00281 element.removeAttribute('base-location')
00282 base_location = base_location or self.location
00283 reader = SchemaReader(base_url=base_location)
00284 for item in DOM.getElements(element, None, None):
00285 if item.localName == 'schema':
00286 schema = reader.loadFromNode(WSDLToolsAdapter(self), item)
00287
00288
00289 schema.setBaseUrl(base_location)
00290 self.types.addSchema(schema)
00291 else:
00292 self.types.addExtension(item)
00293
00294
00295 continue
00296
00297 def _import(self, document, element, base_location=None):
00298 '''Algo take <import> element's children, clone them,
00299 and add them to the main document. Support for relative
00300 locations is a bit complicated. The orig document context
00301 is lost, so we need to store base location in DOM elements
00302 representing <types>, by creating a special temporary
00303 "base-location" attribute, and <import>, by resolving
00304 the relative "location" and storing it as "location".
00305
00306 document -- document we are loading
00307 element -- DOM Element representing <import>
00308 base_location -- location of document from which this
00309 <import> was gleaned.
00310 '''
00311 namespace = DOM.getAttr(element, 'namespace', default=None)
00312 location = DOM.getAttr(element, 'location', default=None)
00313 if namespace is None or location is None:
00314 raise WSDLError(
00315 'Invalid import element (missing namespace or location).'
00316 )
00317 if base_location:
00318 location = basejoin(base_location, location)
00319 element.setAttributeNS(None, 'location', location)
00320
00321 obimport = self.addImport(namespace, location)
00322 obimport._loaded = 1
00323
00324 importdoc = DOM.loadFromURL(location)
00325 try:
00326 if location.find('#') > -1:
00327 idref = location.split('#')[-1]
00328 imported = DOM.getElementById(importdoc, idref)
00329 else:
00330 imported = importdoc.documentElement
00331 if imported is None:
00332 raise WSDLError(
00333 'Import target element not found for: %s' % location
00334 )
00335
00336 imported_tns = DOM.findTargetNS(imported)
00337 if imported_tns != namespace:
00338 return
00339
00340 if imported.localName == 'definitions':
00341 imported_nodes = imported.childNodes
00342 else:
00343 imported_nodes = [imported]
00344 parent = element.parentNode
00345
00346 parent.removeChild(element)
00347
00348 for node in imported_nodes:
00349 if node.nodeType != node.ELEMENT_NODE:
00350 continue
00351 child = DOM.importNode(document, node, 1)
00352 parent.appendChild(child)
00353 child.setAttribute('targetNamespace', namespace)
00354 attrsNS = imported._attrsNS
00355 for attrkey in attrsNS.keys():
00356 if attrkey[0] == DOM.NS_XMLNS:
00357 attr = attrsNS[attrkey].cloneNode(1)
00358 child.setAttributeNode(attr)
00359
00360
00361 if child.localName == 'import':
00362 rlocation = child.getAttributeNS(None, 'location')
00363 alocation = basejoin(location, rlocation)
00364 child.setAttribute('location', alocation)
00365 elif child.localName == 'types':
00366 child.setAttribute('base-location', location)
00367
00368 finally:
00369 importdoc.unlink()
00370 return location
00371
00372 class Element:
00373 """A class that provides common functions for WSDL element classes."""
00374 def __init__(self, name=None, documentation=''):
00375 self.name = name
00376 self.documentation = documentation
00377 self.extensions = []
00378
00379 def addExtension(self, item):
00380 item.parent = weakref.ref(self)
00381 self.extensions.append(item)
00382
00383 def getWSDL(self):
00384 """Return the WSDL object that contains this information item."""
00385 parent = self
00386 while 1:
00387
00388 if isinstance(parent, WSDL):
00389 return parent
00390 try: parent = parent.parent()
00391 except: break
00392
00393 return None
00394
00395
00396 class ImportElement(Element):
00397 def __init__(self, namespace, location):
00398 self.namespace = namespace
00399 self.location = location
00400
00401
00402
00403
00404
00405 def toDom(self):
00406 wsdl = self.getWSDL()
00407 ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
00408 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'import')
00409 epc.setAttributeNS(None, 'namespace', self.namespace)
00410 epc.setAttributeNS(None, 'location', self.location)
00411
00412 _loaded = None
00413
00414
00415 class Types(Collection):
00416 default = lambda self,k: k.targetNamespace
00417 def __init__(self, parent):
00418 Collection.__init__(self, parent)
00419 self.documentation = ''
00420 self.extensions = []
00421
00422 def addSchema(self, schema):
00423 name = schema.targetNamespace
00424 self[name] = schema
00425 return schema
00426
00427 def addExtension(self, item):
00428 self.extensions.append(item)
00429
00430
00431 class Message(Element):
00432 def __init__(self, name, documentation=''):
00433 Element.__init__(self, name, documentation)
00434 self.parts = Collection(self)
00435
00436 def addPart(self, name, type=None, element=None):
00437 if self.parts.has_key(name):
00438 raise WSDLError(
00439 'Duplicate message part element: %s' % name
00440 )
00441 if type is None and element is None:
00442 raise WSDLError(
00443 'Missing type or element attribute for part: %s' % name
00444 )
00445 item = MessagePart(name)
00446 item.element = element
00447 item.type = type
00448 self.parts[name] = item
00449 return item
00450
00451 def load(self, elements):
00452 for element in elements:
00453 name = DOM.getAttr(element, 'name')
00454 part = MessagePart(name)
00455 self.parts[name] = part
00456 elemref = DOM.getAttr(element, 'element', default=None)
00457 typeref = DOM.getAttr(element, 'type', default=None)
00458 if typeref is None and elemref is None:
00459 raise WSDLError(
00460 'No type or element attribute for part: %s' % name
00461 )
00462 if typeref is not None:
00463 part.type = ParseTypeRef(typeref, element)
00464 if elemref is not None:
00465 part.element = ParseTypeRef(elemref, element)
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 def toDom(self):
00492 wsdl = self.getWSDL()
00493 ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
00494 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'message')
00495 epc.setAttributeNS(None, 'name', self.name)
00496
00497 for part in self.parts:
00498 part.toDom(epc._getNode())
00499
00500
00501 class MessagePart(Element):
00502 def __init__(self, name):
00503 Element.__init__(self, name, '')
00504 self.element = None
00505 self.type = None
00506
00507
00508
00509
00510
00511 def getTypeDefinition(self):
00512 wsdl = self.getWSDL()
00513 nsuri,name = self.type
00514 schema = wsdl.types.get(nsuri, {})
00515 return schema.get(name)
00516
00517 def getElementDeclaration(self):
00518 wsdl = self.getWSDL()
00519 nsuri,name = self.element
00520 schema = wsdl.types.get(nsuri, {})
00521 return schema.get(name)
00522
00523 def toDom(self, node):
00524 """node -- node representing message"""
00525 wsdl = self.getWSDL()
00526 ep = ElementProxy(None, node)
00527 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'part')
00528 epc.setAttributeNS(None, 'name', self.name)
00529
00530 if self.element is not None:
00531 ns,name = self.element
00532 prefix = epc.getPrefix(ns)
00533 epc.setAttributeNS(None, 'element', '%s:%s'%(prefix,name))
00534 elif self.type is not None:
00535 ns,name = self.type
00536 prefix = epc.getPrefix(ns)
00537 epc.setAttributeNS(None, 'type', '%s:%s'%(prefix,name))
00538
00539
00540 class PortType(Element):
00541 '''PortType has a anyAttribute, thus must provide for an extensible
00542 mechanism for supporting such attributes. ResourceProperties is
00543 specified in WS-ResourceProperties. wsa:Action is specified in
00544 WS-Address.
00545
00546 Instance Data:
00547 name -- name attribute
00548 resourceProperties -- optional. wsr:ResourceProperties attribute,
00549 value is a QName this is Parsed into a (namespaceURI, name)
00550 that represents a Global Element Declaration.
00551 operations
00552 '''
00553
00554 def __init__(self, name, documentation=''):
00555 Element.__init__(self, name, documentation)
00556 self.operations = Collection(self)
00557 self.resourceProperties = None
00558
00559
00560
00561
00562 def getTargetNamespace(self):
00563 return self.targetNamespace or self.getWSDL().targetNamespace
00564
00565 def getResourceProperties(self):
00566 return self.resourceProperties
00567
00568 def addOperation(self, name, documentation='', parameterOrder=None):
00569 item = Operation(name, documentation, parameterOrder)
00570 self.operations[name] = item
00571 return item
00572
00573 def load(self, element):
00574 self.name = DOM.getAttr(element, 'name')
00575 self.documentation = GetDocumentation(element)
00576 self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
00577
00578 for nsuri in WSRF_V1_2.PROPERTIES.XSD_LIST:
00579 if DOM.hasAttr(element, 'ResourceProperties', nsuri):
00580 rpref = DOM.getAttr(element, 'ResourceProperties', nsuri)
00581 self.resourceProperties = ParseQName(rpref, element)
00582
00583 NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version)
00584 elements = DOM.getElements(element, 'operation', NS_WSDL)
00585 for element in elements:
00586 name = DOM.getAttr(element, 'name')
00587 docs = GetDocumentation(element)
00588 param_order = DOM.getAttr(element, 'parameterOrder', default=None)
00589 if param_order is not None:
00590 param_order = param_order.split(' ')
00591 operation = self.addOperation(name, docs, param_order)
00592
00593 item = DOM.getElement(element, 'input', None, None)
00594 if item is not None:
00595 name = DOM.getAttr(item, 'name')
00596 docs = GetDocumentation(item)
00597 msgref = DOM.getAttr(item, 'message')
00598 message = ParseQName(msgref, item)
00599 for WSA in WSA_LIST:
00600 action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
00601 if action: break
00602 operation.setInput(message, name, docs, action)
00603
00604 item = DOM.getElement(element, 'output', None, None)
00605 if item is not None:
00606 name = DOM.getAttr(item, 'name')
00607 docs = GetDocumentation(item)
00608 msgref = DOM.getAttr(item, 'message')
00609 message = ParseQName(msgref, item)
00610 for WSA in WSA_LIST:
00611 action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
00612 if action: break
00613 operation.setOutput(message, name, docs, action)
00614
00615 for item in DOM.getElements(element, 'fault', None):
00616 name = DOM.getAttr(item, 'name')
00617 docs = GetDocumentation(item)
00618 msgref = DOM.getAttr(item, 'message')
00619 message = ParseQName(msgref, item)
00620 for WSA in WSA_LIST:
00621 action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
00622 if action: break
00623 operation.addFault(message, name, docs, action)
00624
00625 def toDom(self):
00626 wsdl = self.getWSDL()
00627
00628 ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
00629 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'portType')
00630 epc.setAttributeNS(None, 'name', self.name)
00631 if self.resourceProperties:
00632 ns,name = self.resourceProperties
00633 prefix = epc.getPrefix(ns)
00634 epc.setAttributeNS(WSRF.PROPERTIES.LATEST, 'ResourceProperties',
00635 '%s:%s'%(prefix,name))
00636
00637 for op in self.operations:
00638 op.toDom(epc._getNode())
00639
00640
00641
00642 class Operation(Element):
00643 def __init__(self, name, documentation='', parameterOrder=None):
00644 Element.__init__(self, name, documentation)
00645 self.parameterOrder = parameterOrder
00646 self.faults = Collection(self)
00647 self.input = None
00648 self.output = None
00649
00650 def getWSDL(self):
00651 """Return the WSDL object that contains this Operation."""
00652 return self.parent().parent().parent().parent()
00653
00654 def getPortType(self):
00655 return self.parent().parent()
00656
00657 def getInputAction(self):
00658 """wsa:Action attribute"""
00659 return GetWSAActionInput(self)
00660
00661 def getInputMessage(self):
00662 if self.input is None:
00663 return None
00664 wsdl = self.getPortType().getWSDL()
00665 return wsdl.messages[self.input.message]
00666
00667 def getOutputAction(self):
00668 """wsa:Action attribute"""
00669 return GetWSAActionOutput(self)
00670
00671 def getOutputMessage(self):
00672 if self.output is None:
00673 return None
00674 wsdl = self.getPortType().getWSDL()
00675 return wsdl.messages[self.output.message]
00676
00677 def getFaultAction(self, name):
00678 """wsa:Action attribute"""
00679 return GetWSAActionFault(self, name)
00680
00681 def getFaultMessage(self, name):
00682 wsdl = self.getPortType().getWSDL()
00683 return wsdl.messages[self.faults[name].message]
00684
00685 def addFault(self, message, name, documentation='', action=None):
00686 if self.faults.has_key(name):
00687 raise WSDLError(
00688 'Duplicate fault element: %s' % name
00689 )
00690 item = MessageRole('fault', message, name, documentation, action)
00691 self.faults[name] = item
00692 return item
00693
00694 def setInput(self, message, name='', documentation='', action=None):
00695 self.input = MessageRole('input', message, name, documentation, action)
00696 self.input.parent = weakref.ref(self)
00697 return self.input
00698
00699 def setOutput(self, message, name='', documentation='', action=None):
00700 self.output = MessageRole('output', message, name, documentation, action)
00701 self.output.parent = weakref.ref(self)
00702 return self.output
00703
00704 def toDom(self, node):
00705 wsdl = self.getWSDL()
00706
00707 ep = ElementProxy(None, node)
00708 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
00709 epc.setAttributeNS(None, 'name', self.name)
00710 node = epc._getNode()
00711 if self.input:
00712 self.input.toDom(node)
00713 if self.output:
00714 self.output.toDom(node)
00715 for fault in self.faults:
00716 fault.toDom(node)
00717
00718
00719 class MessageRole(Element):
00720 def __init__(self, type, message, name='', documentation='', action=None):
00721 Element.__init__(self, name, documentation)
00722 self.message = message
00723 self.type = type
00724 self.action = action
00725
00726 def getWSDL(self):
00727 """Return the WSDL object that contains this information item."""
00728 parent = self
00729 while 1:
00730
00731 if isinstance(parent, WSDL):
00732 return parent
00733 try: parent = parent.parent()
00734 except: break
00735
00736 return None
00737
00738 def getMessage(self):
00739 """Return the WSDL object that represents the attribute message
00740 (namespaceURI, name) tuple
00741 """
00742 wsdl = self.getWSDL()
00743 return wsdl.messages[self.message]
00744
00745 def toDom(self, node):
00746 wsdl = self.getWSDL()
00747
00748 ep = ElementProxy(None, node)
00749 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
00750 if not isinstance(self.message, basestring) and len(self.message) == 2:
00751 ns,name = self.message
00752 prefix = epc.getPrefix(ns)
00753 epc.setAttributeNS(None, 'message', '%s:%s' %(prefix,name))
00754 else:
00755 epc.setAttributeNS(None, 'message', self.message)
00756
00757 if self.action:
00758 epc.setAttributeNS(WSA.ADDRESS, 'Action', self.action)
00759
00760 if self.name:
00761 epc.setAttributeNS(None, 'name', self.name)
00762
00763
00764 class Binding(Element):
00765 def __init__(self, name, type, documentation=''):
00766 Element.__init__(self, name, documentation)
00767 self.operations = Collection(self)
00768 self.type = type
00769
00770
00771
00772
00773
00774 def getPortType(self):
00775 """Return the PortType object associated with this binding."""
00776 return self.getWSDL().portTypes[self.type]
00777
00778 def findBinding(self, kind):
00779 for item in self.extensions:
00780 if isinstance(item, kind):
00781 return item
00782 return None
00783
00784 def findBindings(self, kind):
00785 return [ item for item in self.extensions if isinstance(item, kind) ]
00786
00787 def addOperationBinding(self, name, documentation=''):
00788 item = OperationBinding(name, documentation)
00789 self.operations[name] = item
00790 return item
00791
00792 def load(self, elements):
00793 for element in elements:
00794 name = DOM.getAttr(element, 'name')
00795 docs = GetDocumentation(element)
00796 opbinding = self.addOperationBinding(name, docs)
00797 opbinding.load_ex(GetExtensions(element))
00798
00799 item = DOM.getElement(element, 'input', None, None)
00800 if item is not None:
00801
00802 mbinding = MessageRoleBinding('input')
00803 mbinding.documentation = GetDocumentation(item)
00804 opbinding.input = mbinding
00805 mbinding.load_ex(GetExtensions(item))
00806 mbinding.parent = weakref.ref(opbinding)
00807
00808 item = DOM.getElement(element, 'output', None, None)
00809 if item is not None:
00810 mbinding = MessageRoleBinding('output')
00811 mbinding.documentation = GetDocumentation(item)
00812 opbinding.output = mbinding
00813 mbinding.load_ex(GetExtensions(item))
00814 mbinding.parent = weakref.ref(opbinding)
00815
00816 for item in DOM.getElements(element, 'fault', None):
00817 name = DOM.getAttr(item, 'name')
00818 mbinding = MessageRoleBinding('fault', name)
00819 mbinding.documentation = GetDocumentation(item)
00820 opbinding.faults[name] = mbinding
00821 mbinding.load_ex(GetExtensions(item))
00822 mbinding.parent = weakref.ref(opbinding)
00823
00824 def load_ex(self, elements):
00825 for e in elements:
00826 ns, name = e.namespaceURI, e.localName
00827 if ns in DOM.NS_SOAP_BINDING_ALL and name == 'binding':
00828 transport = DOM.getAttr(e, 'transport', default=None)
00829 style = DOM.getAttr(e, 'style', default='document')
00830 ob = SoapBinding(transport, style)
00831 self.addExtension(ob)
00832 continue
00833 elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'binding':
00834 verb = DOM.getAttr(e, 'verb')
00835 ob = HttpBinding(verb)
00836 self.addExtension(ob)
00837 continue
00838 else:
00839 self.addExtension(e)
00840
00841 def toDom(self):
00842 wsdl = self.getWSDL()
00843 ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
00844 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'binding')
00845 epc.setAttributeNS(None, 'name', self.name)
00846
00847 ns,name = self.type
00848 prefix = epc.getPrefix(ns)
00849 epc.setAttributeNS(None, 'type', '%s:%s' %(prefix,name))
00850
00851 node = epc._getNode()
00852 for ext in self.extensions:
00853 ext.toDom(node)
00854 for op_binding in self.operations:
00855 op_binding.toDom(node)
00856
00857
00858 class OperationBinding(Element):
00859 def __init__(self, name, documentation=''):
00860 Element.__init__(self, name, documentation)
00861 self.input = None
00862 self.output = None
00863 self.faults = Collection(self)
00864
00865
00866
00867
00868
00869
00870 def getBinding(self):
00871 """Return the parent Binding object of the operation binding."""
00872 return self.parent().parent()
00873
00874 def getOperation(self):
00875 """Return the abstract Operation associated with this binding."""
00876 return self.getBinding().getPortType().operations[self.name]
00877
00878 def findBinding(self, kind):
00879 for item in self.extensions:
00880 if isinstance(item, kind):
00881 return item
00882 return None
00883
00884 def findBindings(self, kind):
00885 return [ item for item in self.extensions if isinstance(item, kind) ]
00886
00887 def addInputBinding(self, binding):
00888 if self.input is None:
00889 self.input = MessageRoleBinding('input')
00890 self.input.parent = weakref.ref(self)
00891 self.input.addExtension(binding)
00892 return binding
00893
00894 def addOutputBinding(self, binding):
00895 if self.output is None:
00896 self.output = MessageRoleBinding('output')
00897 self.output.parent = weakref.ref(self)
00898 self.output.addExtension(binding)
00899 return binding
00900
00901 def addFaultBinding(self, name, binding):
00902 fault = self.get(name, None)
00903 if fault is None:
00904 fault = MessageRoleBinding('fault', name)
00905 fault.addExtension(binding)
00906 return binding
00907
00908 def load_ex(self, elements):
00909 for e in elements:
00910 ns, name = e.namespaceURI, e.localName
00911 if ns in DOM.NS_SOAP_BINDING_ALL and name == 'operation':
00912 soapaction = DOM.getAttr(e, 'soapAction', default=None)
00913 style = DOM.getAttr(e, 'style', default=None)
00914 ob = SoapOperationBinding(soapaction, style)
00915 self.addExtension(ob)
00916 continue
00917 elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'operation':
00918 location = DOM.getAttr(e, 'location')
00919 ob = HttpOperationBinding(location)
00920 self.addExtension(ob)
00921 continue
00922 else:
00923 self.addExtension(e)
00924
00925 def toDom(self, node):
00926 wsdl = self.getWSDL()
00927 ep = ElementProxy(None, node)
00928 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
00929 epc.setAttributeNS(None, 'name', self.name)
00930
00931 node = epc._getNode()
00932 for ext in self.extensions:
00933 ext.toDom(node)
00934 if self.input:
00935 self.input.toDom(node)
00936 if self.output:
00937 self.output.toDom(node)
00938 for fault in self.faults:
00939 fault.toDom(node)
00940
00941
00942 class MessageRoleBinding(Element):
00943 def __init__(self, type, name='', documentation=''):
00944 Element.__init__(self, name, documentation)
00945 self.type = type
00946
00947 def findBinding(self, kind):
00948 for item in self.extensions:
00949 if isinstance(item, kind):
00950 return item
00951 return None
00952
00953 def findBindings(self, kind):
00954 return [ item for item in self.extensions if isinstance(item, kind) ]
00955
00956 def load_ex(self, elements):
00957 for e in elements:
00958 ns, name = e.namespaceURI, e.localName
00959 if ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
00960 encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
00961 namespace = DOM.getAttr(e, 'namespace', default=None)
00962 parts = DOM.getAttr(e, 'parts', default=None)
00963 use = DOM.getAttr(e, 'use', default=None)
00964 if use is None:
00965 raise WSDLError(
00966 'Invalid soap:body binding element.'
00967 )
00968 ob = SoapBodyBinding(use, namespace, encstyle, parts)
00969 self.addExtension(ob)
00970 continue
00971
00972 elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'fault':
00973 encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
00974 namespace = DOM.getAttr(e, 'namespace', default=None)
00975 name = DOM.getAttr(e, 'name', default=None)
00976 use = DOM.getAttr(e, 'use', default=None)
00977 if use is None or name is None:
00978 raise WSDLError(
00979 'Invalid soap:fault binding element.'
00980 )
00981 ob = SoapFaultBinding(name, use, namespace, encstyle)
00982 self.addExtension(ob)
00983 continue
00984
00985 elif ns in DOM.NS_SOAP_BINDING_ALL and name in (
00986 'header', 'headerfault'
00987 ):
00988 encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
00989 namespace = DOM.getAttr(e, 'namespace', default=None)
00990 message = DOM.getAttr(e, 'message')
00991 part = DOM.getAttr(e, 'part')
00992 use = DOM.getAttr(e, 'use')
00993 if name == 'header':
00994 _class = SoapHeaderBinding
00995 else:
00996 _class = SoapHeaderFaultBinding
00997 message = ParseQName(message, e)
00998 ob = _class(message, part, use, namespace, encstyle)
00999 self.addExtension(ob)
01000 continue
01001
01002 elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlReplacement':
01003 ob = HttpUrlReplacementBinding()
01004 self.addExtension(ob)
01005 continue
01006
01007 elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlEncoded':
01008 ob = HttpUrlEncodedBinding()
01009 self.addExtension(ob)
01010 continue
01011
01012 elif ns in DOM.NS_MIME_BINDING_ALL and name == 'multipartRelated':
01013 ob = MimeMultipartRelatedBinding()
01014 self.addExtension(ob)
01015 ob.load_ex(GetExtensions(e))
01016 continue
01017
01018 elif ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
01019 part = DOM.getAttr(e, 'part', default=None)
01020 type = DOM.getAttr(e, 'type', default=None)
01021 ob = MimeContentBinding(part, type)
01022 self.addExtension(ob)
01023 continue
01024
01025 elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
01026 part = DOM.getAttr(e, 'part', default=None)
01027 ob = MimeXmlBinding(part)
01028 self.addExtension(ob)
01029 continue
01030
01031 else:
01032 self.addExtension(e)
01033
01034 def toDom(self, node):
01035 wsdl = self.getWSDL()
01036 ep = ElementProxy(None, node)
01037 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
01038
01039 node = epc._getNode()
01040 for item in self.extensions:
01041 if item: item.toDom(node)
01042
01043
01044 class Service(Element):
01045 def __init__(self, name, documentation=''):
01046 Element.__init__(self, name, documentation)
01047 self.ports = Collection(self)
01048
01049 def getWSDL(self):
01050 return self.parent().parent()
01051
01052 def addPort(self, name, binding, documentation=''):
01053 item = Port(name, binding, documentation)
01054 self.ports[name] = item
01055 return item
01056
01057 def load(self, elements):
01058 for element in elements:
01059 name = DOM.getAttr(element, 'name', default=None)
01060 docs = GetDocumentation(element)
01061 binding = DOM.getAttr(element, 'binding', default=None)
01062 if name is None or binding is None:
01063 raise WSDLError(
01064 'Invalid port element.'
01065 )
01066 binding = ParseQName(binding, element)
01067 port = self.addPort(name, binding, docs)
01068 port.load_ex(GetExtensions(element))
01069
01070 def load_ex(self, elements):
01071 for e in elements:
01072 self.addExtension(e)
01073
01074 def toDom(self):
01075 wsdl = self.getWSDL()
01076 ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
01077 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "service")
01078 epc.setAttributeNS(None, "name", self.name)
01079
01080 node = epc._getNode()
01081 for port in self.ports:
01082 port.toDom(node)
01083
01084
01085 class Port(Element):
01086 def __init__(self, name, binding, documentation=''):
01087 Element.__init__(self, name, documentation)
01088 self.binding = binding
01089
01090
01091
01092
01093 def getService(self):
01094 """Return the Service object associated with this port."""
01095 return self.parent().parent()
01096
01097 def getBinding(self):
01098 """Return the Binding object that is referenced by this port."""
01099 wsdl = self.getService().getWSDL()
01100 return wsdl.bindings[self.binding]
01101
01102 def getPortType(self):
01103 """Return the PortType object that is referenced by this port."""
01104 wsdl = self.getService().getWSDL()
01105 binding = wsdl.bindings[self.binding]
01106 return wsdl.portTypes[binding.type]
01107
01108 def getAddressBinding(self):
01109 """A convenience method to obtain the extension element used
01110 as the address binding for the port."""
01111 for item in self.extensions:
01112 if isinstance(item, SoapAddressBinding) or \
01113 isinstance(item, HttpAddressBinding):
01114 return item
01115 raise WSDLError(
01116 'No address binding found in port.'
01117 )
01118
01119 def load_ex(self, elements):
01120 for e in elements:
01121 ns, name = e.namespaceURI, e.localName
01122 if ns in DOM.NS_SOAP_BINDING_ALL and name == 'address':
01123 location = DOM.getAttr(e, 'location', default=None)
01124 ob = SoapAddressBinding(location)
01125 self.addExtension(ob)
01126 continue
01127 elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'address':
01128 location = DOM.getAttr(e, 'location', default=None)
01129 ob = HttpAddressBinding(location)
01130 self.addExtension(ob)
01131 continue
01132 else:
01133 self.addExtension(e)
01134
01135 def toDom(self, node):
01136 wsdl = self.getWSDL()
01137 ep = ElementProxy(None, node)
01138 epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "port")
01139 epc.setAttributeNS(None, "name", self.name)
01140
01141 ns,name = self.binding
01142 prefix = epc.getPrefix(ns)
01143 epc.setAttributeNS(None, "binding", "%s:%s" %(prefix,name))
01144
01145 node = epc._getNode()
01146 for ext in self.extensions:
01147 ext.toDom(node)
01148
01149
01150 class SoapBinding:
01151 def __init__(self, transport, style='rpc'):
01152 self.transport = transport
01153 self.style = style
01154
01155 def getWSDL(self):
01156 return self.parent().getWSDL()
01157
01158 def toDom(self, node):
01159 wsdl = self.getWSDL()
01160 ep = ElementProxy(None, node)
01161 epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'binding')
01162 if self.transport:
01163 epc.setAttributeNS(None, "transport", self.transport)
01164 if self.style:
01165 epc.setAttributeNS(None, "style", self.style)
01166
01167 class SoapAddressBinding:
01168 def __init__(self, location):
01169 self.location = location
01170
01171 def getWSDL(self):
01172 return self.parent().getWSDL()
01173
01174 def toDom(self, node):
01175 wsdl = self.getWSDL()
01176 ep = ElementProxy(None, node)
01177 epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'address')
01178 epc.setAttributeNS(None, "location", self.location)
01179
01180
01181 class SoapOperationBinding:
01182 def __init__(self, soapAction=None, style=None):
01183 self.soapAction = soapAction
01184 self.style = style
01185
01186 def getWSDL(self):
01187 return self.parent().getWSDL()
01188
01189 def toDom(self, node):
01190 wsdl = self.getWSDL()
01191 ep = ElementProxy(None, node)
01192 epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'operation')
01193 if self.soapAction:
01194 epc.setAttributeNS(None, 'soapAction', self.soapAction)
01195 if self.style:
01196 epc.setAttributeNS(None, 'style', self.style)
01197
01198
01199 class SoapBodyBinding:
01200 def __init__(self, use, namespace=None, encodingStyle=None, parts=None):
01201 if not use in ('literal', 'encoded'):
01202 raise WSDLError(
01203 'Invalid use attribute value: %s' % use
01204 )
01205 self.encodingStyle = encodingStyle
01206 self.namespace = namespace
01207 if type(parts) in (type(''), type(u'')):
01208 parts = parts.split()
01209 self.parts = parts
01210 self.use = use
01211
01212 def getWSDL(self):
01213 return self.parent().getWSDL()
01214
01215 def toDom(self, node):
01216 wsdl = self.getWSDL()
01217 ep = ElementProxy(None, node)
01218 epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body')
01219 epc.setAttributeNS(None, "use", self.use)
01220 epc.setAttributeNS(None, "namespace", self.namespace)
01221
01222
01223 class SoapFaultBinding:
01224 def __init__(self, name, use, namespace=None, encodingStyle=None):
01225 if not use in ('literal', 'encoded'):
01226 raise WSDLError(
01227 'Invalid use attribute value: %s' % use
01228 )
01229 self.encodingStyle = encodingStyle
01230 self.namespace = namespace
01231 self.name = name
01232 self.use = use
01233
01234 def getWSDL(self):
01235 return self.parent().getWSDL()
01236
01237 def toDom(self, node):
01238 wsdl = self.getWSDL()
01239 ep = ElementProxy(None, node)
01240 epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body')
01241 epc.setAttributeNS(None, "use", self.use)
01242 epc.setAttributeNS(None, "name", self.name)
01243 if self.namespace is not None:
01244 epc.setAttributeNS(None, "namespace", self.namespace)
01245 if self.encodingStyle is not None:
01246 epc.setAttributeNS(None, "encodingStyle", self.encodingStyle)
01247
01248
01249 class SoapHeaderBinding:
01250 def __init__(self, message, part, use, namespace=None, encodingStyle=None):
01251 if not use in ('literal', 'encoded'):
01252 raise WSDLError(
01253 'Invalid use attribute value: %s' % use
01254 )
01255 self.encodingStyle = encodingStyle
01256 self.namespace = namespace
01257 self.message = message
01258 self.part = part
01259 self.use = use
01260
01261 tagname = 'header'
01262
01263 class SoapHeaderFaultBinding(SoapHeaderBinding):
01264 tagname = 'headerfault'
01265
01266
01267 class HttpBinding:
01268 def __init__(self, verb):
01269 self.verb = verb
01270
01271 class HttpAddressBinding:
01272 def __init__(self, location):
01273 self.location = location
01274
01275
01276 class HttpOperationBinding:
01277 def __init__(self, location):
01278 self.location = location
01279
01280 class HttpUrlReplacementBinding:
01281 pass
01282
01283
01284 class HttpUrlEncodedBinding:
01285 pass
01286
01287
01288 class MimeContentBinding:
01289 def __init__(self, part=None, type=None):
01290 self.part = part
01291 self.type = type
01292
01293
01294 class MimeXmlBinding:
01295 def __init__(self, part=None):
01296 self.part = part
01297
01298
01299 class MimeMultipartRelatedBinding:
01300 def __init__(self):
01301 self.parts = []
01302
01303 def load_ex(self, elements):
01304 for e in elements:
01305 ns, name = e.namespaceURI, e.localName
01306 if ns in DOM.NS_MIME_BINDING_ALL and name == 'part':
01307 self.parts.append(MimePartBinding())
01308 continue
01309
01310
01311 class MimePartBinding:
01312 def __init__(self):
01313 self.items = []
01314
01315 def load_ex(self, elements):
01316 for e in elements:
01317 ns, name = e.namespaceURI, e.localName
01318 if ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
01319 part = DOM.getAttr(e, 'part', default=None)
01320 type = DOM.getAttr(e, 'type', default=None)
01321 ob = MimeContentBinding(part, type)
01322 self.items.append(ob)
01323 continue
01324
01325 elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
01326 part = DOM.getAttr(e, 'part', default=None)
01327 ob = MimeXmlBinding(part)
01328 self.items.append(ob)
01329 continue
01330
01331 elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
01332 encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
01333 namespace = DOM.getAttr(e, 'namespace', default=None)
01334 parts = DOM.getAttr(e, 'parts', default=None)
01335 use = DOM.getAttr(e, 'use', default=None)
01336 if use is None:
01337 raise WSDLError(
01338 'Invalid soap:body binding element.'
01339 )
01340 ob = SoapBodyBinding(use, namespace, encstyle, parts)
01341 self.items.append(ob)
01342 continue
01343
01344
01345 class WSDLError(Exception):
01346 pass
01347
01348
01349
01350 def DeclareNSPrefix(writer, prefix, nsuri):
01351 if writer.hasNSPrefix(nsuri):
01352 return
01353 writer.declareNSPrefix(prefix, nsuri)
01354
01355 def ParseTypeRef(value, element):
01356 parts = value.split(':', 1)
01357 if len(parts) == 1:
01358 return (DOM.findTargetNS(element), value)
01359 nsuri = DOM.findNamespaceURI(parts[0], element)
01360 return (nsuri, parts[1])
01361
01362 def ParseQName(value, element):
01363 nameref = value.split(':', 1)
01364 if len(nameref) == 2:
01365 nsuri = DOM.findNamespaceURI(nameref[0], element)
01366 name = nameref[-1]
01367 else:
01368 nsuri = DOM.findTargetNS(element)
01369 name = nameref[-1]
01370 return nsuri, name
01371
01372 def GetDocumentation(element):
01373 docnode = DOM.getElement(element, 'documentation', None, None)
01374 if docnode is not None:
01375 return DOM.getElementText(docnode)
01376 return ''
01377
01378 def GetExtensions(element):
01379 return [ item for item in DOM.getElements(element, None, None)
01380 if item.namespaceURI != DOM.NS_WSDL ]
01381
01382 def GetWSAActionFault(operation, name):
01383 """Find wsa:Action attribute, and return value or WSA.FAULT
01384 for the default.
01385 """
01386 attr = operation.faults[name].action
01387 if attr is not None:
01388 return attr
01389 return WSA.FAULT
01390
01391 def GetWSAActionInput(operation):
01392 """Find wsa:Action attribute, and return value or the default."""
01393 attr = operation.input.action
01394 if attr is not None:
01395 return attr
01396 portType = operation.getPortType()
01397 targetNamespace = portType.getTargetNamespace()
01398 ptName = portType.name
01399 msgName = operation.input.name
01400 if not msgName:
01401 msgName = operation.name + 'Request'
01402 if targetNamespace.endswith('/'):
01403 return '%s%s/%s' %(targetNamespace, ptName, msgName)
01404 return '%s/%s/%s' %(targetNamespace, ptName, msgName)
01405
01406 def GetWSAActionOutput(operation):
01407 """Find wsa:Action attribute, and return value or the default."""
01408 attr = operation.output.action
01409 if attr is not None:
01410 return attr
01411 targetNamespace = operation.getPortType().getTargetNamespace()
01412 ptName = operation.getPortType().name
01413 msgName = operation.output.name
01414 if not msgName:
01415 msgName = operation.name + 'Response'
01416 if targetNamespace.endswith('/'):
01417 return '%s%s/%s' %(targetNamespace, ptName, msgName)
01418 return '%s/%s/%s' %(targetNamespace, ptName, msgName)
01419
01420 def FindExtensions(object, kind, t_type=type(())):
01421 if isinstance(kind, t_type):
01422 result = []
01423 namespaceURI, name = kind
01424 return [ item for item in object.extensions
01425 if hasattr(item, 'nodeType') \
01426 and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
01427 and item.name == name ]
01428 return [ item for item in object.extensions if isinstance(item, kind) ]
01429
01430 def FindExtension(object, kind, t_type=type(())):
01431 if isinstance(kind, t_type):
01432 namespaceURI, name = kind
01433 for item in object.extensions:
01434 if hasattr(item, 'nodeType') \
01435 and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
01436 and item.name == name:
01437 return item
01438 else:
01439 for item in object.extensions:
01440 if isinstance(item, kind):
01441 return item
01442 return None
01443
01444
01445 class SOAPCallInfo:
01446 """SOAPCallInfo captures the important binding information about a
01447 SOAP operation, in a structure that is easier to work with than
01448 raw WSDL structures."""
01449
01450 def __init__(self, methodName):
01451 self.methodName = methodName
01452 self.inheaders = []
01453 self.outheaders = []
01454 self.inparams = []
01455 self.outparams = []
01456 self.retval = None
01457
01458 encodingStyle = DOM.NS_SOAP_ENC
01459 documentation = ''
01460 soapAction = None
01461 transport = None
01462 namespace = None
01463 location = None
01464 use = 'encoded'
01465 style = 'rpc'
01466
01467 def addInParameter(self, name, type, namespace=None, element_type=0):
01468 """Add an input parameter description to the call info."""
01469 parameter = ParameterInfo(name, type, namespace, element_type)
01470 self.inparams.append(parameter)
01471 return parameter
01472
01473 def addOutParameter(self, name, type, namespace=None, element_type=0):
01474 """Add an output parameter description to the call info."""
01475 parameter = ParameterInfo(name, type, namespace, element_type)
01476 self.outparams.append(parameter)
01477 return parameter
01478
01479 def setReturnParameter(self, name, type, namespace=None, element_type=0):
01480 """Set the return parameter description for the call info."""
01481 parameter = ParameterInfo(name, type, namespace, element_type)
01482 self.retval = parameter
01483 return parameter
01484
01485 def addInHeaderInfo(self, name, type, namespace, element_type=0,
01486 mustUnderstand=0):
01487 """Add an input SOAP header description to the call info."""
01488 headerinfo = HeaderInfo(name, type, namespace, element_type)
01489 if mustUnderstand:
01490 headerinfo.mustUnderstand = 1
01491 self.inheaders.append(headerinfo)
01492 return headerinfo
01493
01494 def addOutHeaderInfo(self, name, type, namespace, element_type=0,
01495 mustUnderstand=0):
01496 """Add an output SOAP header description to the call info."""
01497 headerinfo = HeaderInfo(name, type, namespace, element_type)
01498 if mustUnderstand:
01499 headerinfo.mustUnderstand = 1
01500 self.outheaders.append(headerinfo)
01501 return headerinfo
01502
01503 def getInParameters(self):
01504 """Return a sequence of the in parameters of the method."""
01505 return self.inparams
01506
01507 def getOutParameters(self):
01508 """Return a sequence of the out parameters of the method."""
01509 return self.outparams
01510
01511 def getReturnParameter(self):
01512 """Return param info about the return value of the method."""
01513 return self.retval
01514
01515 def getInHeaders(self):
01516 """Return a sequence of the in headers of the method."""
01517 return self.inheaders
01518
01519 def getOutHeaders(self):
01520 """Return a sequence of the out headers of the method."""
01521 return self.outheaders
01522
01523
01524 class ParameterInfo:
01525 """A ParameterInfo object captures parameter binding information."""
01526 def __init__(self, name, type, namespace=None, element_type=0):
01527 if element_type:
01528 self.element_type = 1
01529 if namespace is not None:
01530 self.namespace = namespace
01531 self.name = name
01532 self.type = type
01533
01534 element_type = 0
01535 namespace = None
01536 default = None
01537
01538
01539 class HeaderInfo(ParameterInfo):
01540 """A HeaderInfo object captures SOAP header binding information."""
01541 def __init__(self, name, type, namespace, element_type=None):
01542 ParameterInfo.__init__(self, name, type, namespace, element_type)
01543
01544 mustUnderstand = 0
01545 actor = None
01546
01547
01548 def callInfoFromWSDL(port, name):
01549 """Return a SOAPCallInfo given a WSDL port and operation name."""
01550 wsdl = port.getService().getWSDL()
01551 binding = port.getBinding()
01552 portType = binding.getPortType()
01553 operation = portType.operations[name]
01554 opbinding = binding.operations[name]
01555 messages = wsdl.messages
01556 callinfo = SOAPCallInfo(name)
01557
01558 addrbinding = port.getAddressBinding()
01559 if not isinstance(addrbinding, SoapAddressBinding):
01560 raise ValueError, 'Unsupported binding type.'
01561 callinfo.location = addrbinding.location
01562
01563 soapbinding = binding.findBinding(SoapBinding)
01564 if soapbinding is None:
01565 raise ValueError, 'Missing soap:binding element.'
01566 callinfo.transport = soapbinding.transport
01567 callinfo.style = soapbinding.style or 'document'
01568
01569 soap_op_binding = opbinding.findBinding(SoapOperationBinding)
01570 if soap_op_binding is not None:
01571 callinfo.soapAction = soap_op_binding.soapAction
01572 callinfo.style = soap_op_binding.style or callinfo.style
01573
01574 parameterOrder = operation.parameterOrder
01575
01576 if operation.input is not None:
01577 message = messages[operation.input.message]
01578 msgrole = opbinding.input
01579
01580 mime = msgrole.findBinding(MimeMultipartRelatedBinding)
01581 if mime is not None:
01582 raise ValueError, 'Mime bindings are not supported.'
01583 else:
01584 for item in msgrole.findBindings(SoapHeaderBinding):
01585 part = messages[item.message].parts[item.part]
01586 header = callinfo.addInHeaderInfo(
01587 part.name,
01588 part.element or part.type,
01589 item.namespace,
01590 element_type = part.element and 1 or 0
01591 )
01592 header.encodingStyle = item.encodingStyle
01593
01594 body = msgrole.findBinding(SoapBodyBinding)
01595 if body is None:
01596 raise ValueError, 'Missing soap:body binding.'
01597 callinfo.encodingStyle = body.encodingStyle
01598 callinfo.namespace = body.namespace
01599 callinfo.use = body.use
01600
01601 if body.parts is not None:
01602 parts = []
01603 for name in body.parts:
01604 parts.append(message.parts[name])
01605 else:
01606 parts = message.parts.values()
01607
01608 for part in parts:
01609 callinfo.addInParameter(
01610 part.name,
01611 part.element or part.type,
01612 element_type = part.element and 1 or 0
01613 )
01614
01615 if operation.output is not None:
01616 try:
01617 message = messages[operation.output.message]
01618 except KeyError:
01619 if self.strict:
01620 raise RuntimeError(
01621 "Recieved message not defined in the WSDL schema: %s" %
01622 operation.output.message)
01623 else:
01624 message = wsdl.addMessage(operation.output.message)
01625 print "Warning:", \
01626 "Recieved message not defined in the WSDL schema.", \
01627 "Adding it."
01628 print "Message:", operation.output.message
01629
01630 msgrole = opbinding.output
01631
01632 mime = msgrole.findBinding(MimeMultipartRelatedBinding)
01633 if mime is not None:
01634 raise ValueError, 'Mime bindings are not supported.'
01635 else:
01636 for item in msgrole.findBindings(SoapHeaderBinding):
01637 part = messages[item.message].parts[item.part]
01638 header = callinfo.addOutHeaderInfo(
01639 part.name,
01640 part.element or part.type,
01641 item.namespace,
01642 element_type = part.element and 1 or 0
01643 )
01644 header.encodingStyle = item.encodingStyle
01645
01646 body = msgrole.findBinding(SoapBodyBinding)
01647 if body is None:
01648 raise ValueError, 'Missing soap:body binding.'
01649 callinfo.encodingStyle = body.encodingStyle
01650 callinfo.namespace = body.namespace
01651 callinfo.use = body.use
01652
01653 if body.parts is not None:
01654 parts = []
01655 for name in body.parts:
01656 parts.append(message.parts[name])
01657 else:
01658 parts = message.parts.values()
01659
01660 if parts:
01661 for part in parts:
01662 callinfo.addOutParameter(
01663 part.name,
01664 part.element or part.type,
01665 element_type = part.element and 1 or 0
01666 )
01667
01668 return callinfo