You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1595 lines
57 KiB

  1. # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
  2. #
  3. # This software is subject to the provisions of the Zope Public License,
  4. # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
  5. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  6. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  7. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  8. # FOR A PARTICULAR PURPOSE.
  9. ident = "$Id$"
  10. import urllib, weakref
  11. from cStringIO import StringIO
  12. from Namespaces import OASIS, WSA, XMLNS
  13. from Utility import Collection, CollectionNS, DOM, ElementProxy
  14. from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter
  15. class WSDLReader:
  16. """A WSDLReader creates WSDL instances from urls and xml data."""
  17. # Custom subclasses of WSDLReader may wish to implement a caching
  18. # strategy or other optimizations. Because application needs vary
  19. # so widely, we don't try to provide any caching by default.
  20. def loadFromStream(self, stream, name=None):
  21. """Return a WSDL instance loaded from a stream object."""
  22. document = DOM.loadDocument(stream)
  23. wsdl = WSDL()
  24. if name:
  25. wsdl.location = name
  26. elif hasattr(stream, 'name'):
  27. wsdl.location = stream.name
  28. wsdl.load(document)
  29. return wsdl
  30. def loadFromURL(self, url):
  31. """Return a WSDL instance loaded from the given url."""
  32. document = DOM.loadFromURL(url)
  33. wsdl = WSDL()
  34. wsdl.location = url
  35. wsdl.load(document)
  36. return wsdl
  37. def loadFromString(self, data):
  38. """Return a WSDL instance loaded from an xml string."""
  39. return self.loadFromStream(StringIO(data))
  40. def loadFromFile(self, filename):
  41. """Return a WSDL instance loaded from the given file."""
  42. file = open(filename, 'rb')
  43. try:
  44. wsdl = self.loadFromStream(file)
  45. finally:
  46. file.close()
  47. return wsdl
  48. class WSDL:
  49. """A WSDL object models a WSDL service description. WSDL objects
  50. may be created manually or loaded from an xml representation
  51. using a WSDLReader instance."""
  52. def __init__(self, targetNamespace=None, strict=1):
  53. self.targetNamespace = targetNamespace or 'urn:this-document.wsdl'
  54. self.documentation = ''
  55. self.location = None
  56. self.document = None
  57. self.name = None
  58. self.services = CollectionNS(self)
  59. self.messages = CollectionNS(self)
  60. self.portTypes = CollectionNS(self)
  61. self.bindings = CollectionNS(self)
  62. self.imports = Collection(self)
  63. self.types = Types(self)
  64. self.extensions = []
  65. self.strict = strict
  66. def __del__(self):
  67. if self.document is not None:
  68. self.document.unlink()
  69. version = '1.1'
  70. def addService(self, name, documentation='', targetNamespace=None):
  71. if self.services.has_key(name):
  72. raise WSDLError(
  73. 'Duplicate service element: %s' % name
  74. )
  75. item = Service(name, documentation)
  76. if targetNamespace:
  77. item.targetNamespace = targetNamespace
  78. self.services[name] = item
  79. return item
  80. def addMessage(self, name, documentation='', targetNamespace=None):
  81. if self.messages.has_key(name):
  82. raise WSDLError(
  83. 'Duplicate message element: %s.' % name
  84. )
  85. item = Message(name, documentation)
  86. if targetNamespace:
  87. item.targetNamespace = targetNamespace
  88. self.messages[name] = item
  89. return item
  90. def addPortType(self, name, documentation='', targetNamespace=None):
  91. if self.portTypes.has_key(name):
  92. raise WSDLError(
  93. 'Duplicate portType element: name'
  94. )
  95. item = PortType(name, documentation)
  96. if targetNamespace:
  97. item.targetNamespace = targetNamespace
  98. self.portTypes[name] = item
  99. return item
  100. def addBinding(self, name, type, documentation='', targetNamespace=None):
  101. if self.bindings.has_key(name):
  102. raise WSDLError(
  103. 'Duplicate binding element: %s' % name
  104. )
  105. item = Binding(name, type, documentation)
  106. if targetNamespace:
  107. item.targetNamespace = targetNamespace
  108. self.bindings[name] = item
  109. return item
  110. def addImport(self, namespace, location):
  111. item = ImportElement(namespace, location)
  112. self.imports[namespace] = item
  113. return item
  114. def toDom(self):
  115. """ Generate a DOM representation of the WSDL instance.
  116. Not dealing with generating XML Schema, thus the targetNamespace
  117. of all XML Schema elements or types used by WSDL message parts
  118. needs to be specified via import information items.
  119. """
  120. namespaceURI = DOM.GetWSDLUri(self.version)
  121. self.document = DOM.createDocument(namespaceURI ,'wsdl:definitions')
  122. # Set up a couple prefixes for easy reading.
  123. child = DOM.getElement(self.document, None)
  124. child.setAttributeNS(None, 'targetNamespace', self.targetNamespace)
  125. child.setAttributeNS(XMLNS.BASE, 'xmlns:wsdl', namespaceURI)
  126. child.setAttributeNS(XMLNS.BASE, 'xmlns:xsd', 'http://www.w3.org/1999/XMLSchema')
  127. child.setAttributeNS(XMLNS.BASE, 'xmlns:soap', 'http://schemas.xmlsoap.org/wsdl/soap/')
  128. child.setAttributeNS(XMLNS.BASE, 'xmlns:tns', self.targetNamespace)
  129. # wsdl:import
  130. for item in self.imports:
  131. item.toDom()
  132. # wsdl:message
  133. for item in self.messages:
  134. item.toDom()
  135. # wsdl:portType
  136. for item in self.portTypes:
  137. item.toDom()
  138. # wsdl:binding
  139. for item in self.bindings:
  140. item.toDom()
  141. # wsdl:service
  142. for item in self.services:
  143. item.toDom()
  144. def load(self, document):
  145. # We save a reference to the DOM document to ensure that elements
  146. # saved as "extensions" will continue to have a meaningful context
  147. # for things like namespace references. The lifetime of the DOM
  148. # document is bound to the lifetime of the WSDL instance.
  149. self.document = document
  150. definitions = DOM.getElement(document, 'definitions', None, None)
  151. if definitions is None:
  152. raise WSDLError(
  153. 'Missing <definitions> element.'
  154. )
  155. self.version = DOM.WSDLUriToVersion(definitions.namespaceURI)
  156. NS_WSDL = DOM.GetWSDLUri(self.version)
  157. self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace',
  158. None, None)
  159. self.name = DOM.getAttr(definitions, 'name', None, None)
  160. self.documentation = GetDocumentation(definitions)
  161. # Resolve (recursively) any import elements in the document.
  162. imported = {}
  163. base_location = self.location
  164. while 1:
  165. #XXX
  166. imports = []
  167. for element in DOM.getElements(definitions, 'import', NS_WSDL):
  168. location = DOM.getAttr(element, 'location')
  169. # Resolve relative location, and save
  170. location = urllib.basejoin(base_location, location)
  171. if not imported.has_key(location):
  172. imports.append(element)
  173. if not imports:
  174. break
  175. for element in imports:
  176. location = DOM.getAttr(element, 'location')
  177. self._import(document, element, base_location)
  178. location = urllib.basejoin(base_location, location)
  179. imported[location] = 1
  180. base_location = ''
  181. #reader = SchemaReader(base_url=self.location)
  182. for element in DOM.getElements(definitions, None, None):
  183. targetNamespace = DOM.getAttr(element, 'targetNamespace')
  184. localName = element.localName
  185. if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL):
  186. if localName == 'schema':
  187. reader = SchemaReader(base_url=self.location)
  188. schema = reader.loadFromNode(WSDLToolsAdapter(self), element)
  189. schema.setBaseUrl(self.location)
  190. self.types.addSchema(schema)
  191. else:
  192. self.extensions.append(element)
  193. continue
  194. elif localName == 'message':
  195. name = DOM.getAttr(element, 'name')
  196. docs = GetDocumentation(element)
  197. message = self.addMessage(name, docs, targetNamespace)
  198. parts = DOM.getElements(element, 'part', NS_WSDL)
  199. message.load(parts)
  200. continue
  201. elif localName == 'portType':
  202. name = DOM.getAttr(element, 'name')
  203. docs = GetDocumentation(element)
  204. ptype = self.addPortType(name, docs, targetNamespace)
  205. #operations = DOM.getElements(element, 'operation', NS_WSDL)
  206. #ptype.load(operations)
  207. ptype.load(element)
  208. continue
  209. elif localName == 'binding':
  210. name = DOM.getAttr(element, 'name')
  211. type = DOM.getAttr(element, 'type', default=None)
  212. if type is None:
  213. raise WSDLError(
  214. 'Missing type attribute for binding %s.' % name
  215. )
  216. type = ParseQName(type, element)
  217. docs = GetDocumentation(element)
  218. binding = self.addBinding(name, type, docs, targetNamespace)
  219. operations = DOM.getElements(element, 'operation', NS_WSDL)
  220. binding.load(operations)
  221. binding.load_ex(GetExtensions(element))
  222. continue
  223. elif localName == 'service':
  224. name = DOM.getAttr(element, 'name')
  225. docs = GetDocumentation(element)
  226. service = self.addService(name, docs, targetNamespace)
  227. ports = DOM.getElements(element, 'port', NS_WSDL)
  228. service.load(ports)
  229. service.load_ex(GetExtensions(element))
  230. continue
  231. elif localName == 'types':
  232. self.types.documentation = GetDocumentation(element)
  233. base_location = DOM.getAttr(element, 'base-location')
  234. if base_location:
  235. element.removeAttribute('base-location')
  236. base_location = base_location or self.location
  237. reader = SchemaReader(base_url=base_location)
  238. for item in DOM.getElements(element, None, None):
  239. if item.localName == 'schema':
  240. schema = reader.loadFromNode(WSDLToolsAdapter(self), item)
  241. # XXX <types> could have been imported
  242. #schema.setBaseUrl(self.location)
  243. schema.setBaseUrl(base_location)
  244. self.types.addSchema(schema)
  245. else:
  246. self.types.addExtension(item)
  247. # XXX remove the attribute
  248. # element.removeAttribute('base-location')
  249. continue
  250. def _import(self, document, element, base_location=None):
  251. '''Algo take <import> element's children, clone them,
  252. and add them to the main document. Support for relative
  253. locations is a bit complicated. The orig document context
  254. is lost, so we need to store base location in DOM elements
  255. representing <types>, by creating a special temporary
  256. "base-location" attribute, and <import>, by resolving
  257. the relative "location" and storing it as "location".
  258. document -- document we are loading
  259. element -- DOM Element representing <import>
  260. base_location -- location of document from which this
  261. <import> was gleaned.
  262. '''
  263. namespace = DOM.getAttr(element, 'namespace', default=None)
  264. location = DOM.getAttr(element, 'location', default=None)
  265. if namespace is None or location is None:
  266. raise WSDLError(
  267. 'Invalid import element (missing namespace or location).'
  268. )
  269. if base_location:
  270. location = urllib.basejoin(base_location, location)
  271. element.setAttributeNS(None, 'location', location)
  272. location = urllib.basejoin(self.location, location)
  273. obimport = self.addImport(namespace, location)
  274. obimport._loaded = 1
  275. importdoc = DOM.loadFromURL(location)
  276. try:
  277. if location.find('#') > -1:
  278. idref = location.split('#')[-1]
  279. imported = DOM.getElementById(importdoc, idref)
  280. else:
  281. imported = importdoc.documentElement
  282. if imported is None:
  283. raise WSDLError(
  284. 'Import target element not found for: %s' % location
  285. )
  286. imported_tns = DOM.findTargetNS(imported)
  287. if imported_tns != namespace:
  288. return
  289. if imported.localName == 'definitions':
  290. imported_nodes = imported.childNodes
  291. else:
  292. imported_nodes = [imported]
  293. parent = element.parentNode
  294. for node in imported_nodes:
  295. if node.nodeType != node.ELEMENT_NODE:
  296. continue
  297. child = DOM.importNode(document, node, 1)
  298. parent.appendChild(child)
  299. child.setAttribute('targetNamespace', namespace)
  300. attrsNS = imported._attrsNS
  301. for attrkey in attrsNS.keys():
  302. if attrkey[0] == DOM.NS_XMLNS:
  303. attr = attrsNS[attrkey].cloneNode(1)
  304. child.setAttributeNode(attr)
  305. #XXX Quick Hack, should be in WSDL Namespace.
  306. if child.localName == 'import':
  307. rlocation = child.getAttributeNS(None, 'location')
  308. alocation = urllib.basejoin(location, rlocation)
  309. child.setAttribute('location', alocation)
  310. elif child.localName == 'types':
  311. child.setAttribute('base-location', location)
  312. finally:
  313. importdoc.unlink()
  314. return location
  315. class Element:
  316. """A class that provides common functions for WSDL element classes."""
  317. def __init__(self, name=None, documentation=''):
  318. self.name = name
  319. self.documentation = documentation
  320. self.extensions = []
  321. def addExtension(self, item):
  322. item.parent = weakref.ref(self)
  323. self.extensions.append(item)
  324. class ImportElement(Element):
  325. def __init__(self, namespace, location):
  326. self.namespace = namespace
  327. self.location = location
  328. def getWSDL(self):
  329. """Return the WSDL object that contains this Message Part."""
  330. return self.parent().parent()
  331. def toDom(self):
  332. wsdl = self.getWSDL()
  333. ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
  334. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'import')
  335. epc.setAttributeNS(None, 'namespace', self.namespace)
  336. epc.setAttributeNS(None, 'location', self.location)
  337. _loaded = None
  338. class Types(Collection):
  339. default = lambda self,k: k.targetNamespace
  340. def __init__(self, parent):
  341. Collection.__init__(self, parent)
  342. self.documentation = ''
  343. self.extensions = []
  344. def addSchema(self, schema):
  345. name = schema.targetNamespace
  346. self[name] = schema
  347. return schema
  348. def addExtension(self, item):
  349. self.extensions.append(item)
  350. class Message(Element):
  351. def __init__(self, name, documentation=''):
  352. Element.__init__(self, name, documentation)
  353. self.parts = Collection(self)
  354. def addPart(self, name, type=None, element=None):
  355. if self.parts.has_key(name):
  356. raise WSDLError(
  357. 'Duplicate message part element: %s' % name
  358. )
  359. if type is None and element is None:
  360. raise WSDLError(
  361. 'Missing type or element attribute for part: %s' % name
  362. )
  363. item = MessagePart(name)
  364. item.element = element
  365. item.type = type
  366. self.parts[name] = item
  367. return item
  368. def load(self, elements):
  369. for element in elements:
  370. name = DOM.getAttr(element, 'name')
  371. part = MessagePart(name)
  372. self.parts[name] = part
  373. elemref = DOM.getAttr(element, 'element', default=None)
  374. typeref = DOM.getAttr(element, 'type', default=None)
  375. if typeref is None and elemref is None:
  376. raise WSDLError(
  377. 'No type or element attribute for part: %s' % name
  378. )
  379. if typeref is not None:
  380. part.type = ParseTypeRef(typeref, element)
  381. if elemref is not None:
  382. part.element = ParseTypeRef(elemref, element)
  383. def getWSDL(self):
  384. """Return the WSDL object that contains this Message Part."""
  385. return self.parent().parent()
  386. def toDom(self):
  387. wsdl = self.getWSDL()
  388. ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
  389. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'message')
  390. epc.setAttributeNS(None, 'name', self.name)
  391. for part in self.parts:
  392. part.toDom(epc._getNode())
  393. class MessagePart(Element):
  394. def __init__(self, name):
  395. Element.__init__(self, name, '')
  396. self.element = None
  397. self.type = None
  398. def getWSDL(self):
  399. """Return the WSDL object that contains this Message Part."""
  400. return self.parent().parent().parent().parent()
  401. def getTypeDefinition(self):
  402. wsdl = self.getWSDL()
  403. nsuri,name = self.type
  404. schema = wsdl.types.get(nsuri, {})
  405. return schema.get(name)
  406. def getElementDeclaration(self):
  407. wsdl = self.getWSDL()
  408. nsuri,name = self.element
  409. schema = wsdl.types.get(nsuri, {})
  410. return schema.get(name)
  411. def toDom(self, node):
  412. """node -- node representing message"""
  413. wsdl = self.getWSDL()
  414. ep = ElementProxy(None, node)
  415. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'part')
  416. epc.setAttributeNS(None, 'name', self.name)
  417. if self.element is not None:
  418. ns,name = self.element
  419. prefix = epc.getPrefix(ns)
  420. epc.setAttributeNS(None, 'element', '%s:%s'%(prefix,name))
  421. elif self.type is not None:
  422. ns,name = self.type
  423. prefix = epc.getPrefix(ns)
  424. epc.setAttributeNS(None, 'type', '%s:%s'%(prefix,name))
  425. class PortType(Element):
  426. '''PortType has a anyAttribute, thus must provide for an extensible
  427. mechanism for supporting such attributes. ResourceProperties is
  428. specified in WS-ResourceProperties. wsa:Action is specified in
  429. WS-Address.
  430. Instance Data:
  431. name -- name attribute
  432. resourceProperties -- optional. wsr:ResourceProperties attribute,
  433. value is a QName this is Parsed into a (namespaceURI, name)
  434. that represents a Global Element Declaration.
  435. operations
  436. '''
  437. def __init__(self, name, documentation=''):
  438. Element.__init__(self, name, documentation)
  439. self.operations = Collection(self)
  440. self.resourceProperties = None
  441. def getWSDL(self):
  442. return self.parent().parent()
  443. def getTargetNamespace(self):
  444. return self.targetNamespace or self.getWSDL().targetNamespace
  445. def getResourceProperties(self):
  446. return self.resourceProperties
  447. def addOperation(self, name, documentation='', parameterOrder=None):
  448. item = Operation(name, documentation, parameterOrder)
  449. self.operations[name] = item
  450. return item
  451. def load(self, element):
  452. self.name = DOM.getAttr(element, 'name')
  453. self.documentation = GetDocumentation(element)
  454. self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
  455. if DOM.hasAttr(element, 'ResourceProperties', OASIS.PROPERTIES):
  456. rpref = DOM.getAttr(element, 'ResourceProperties', OASIS.PROPERTIES)
  457. self.resourceProperties = ParseQName(rpref, element)
  458. NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version)
  459. elements = DOM.getElements(element, 'operation', NS_WSDL)
  460. for element in elements:
  461. name = DOM.getAttr(element, 'name')
  462. docs = GetDocumentation(element)
  463. param_order = DOM.getAttr(element, 'parameterOrder', default=None)
  464. if param_order is not None:
  465. param_order = param_order.split(' ')
  466. operation = self.addOperation(name, docs, param_order)
  467. item = DOM.getElement(element, 'input', None, None)
  468. if item is not None:
  469. name = DOM.getAttr(item, 'name')
  470. docs = GetDocumentation(item)
  471. msgref = DOM.getAttr(item, 'message')
  472. message = ParseQName(msgref, item)
  473. action = DOM.getAttr(item, 'Action', WSA.ADDRESS2004, None)
  474. if not action:
  475. action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
  476. operation.setInput(message, name, docs, action)
  477. item = DOM.getElement(element, 'output', None, None)
  478. if item is not None:
  479. name = DOM.getAttr(item, 'name')
  480. docs = GetDocumentation(item)
  481. msgref = DOM.getAttr(item, 'message')
  482. message = ParseQName(msgref, item)
  483. action = DOM.getAttr(item, 'Action', WSA.ADDRESS2004, None)
  484. if not action:
  485. action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
  486. operation.setOutput(message, name, docs, action)
  487. for item in DOM.getElements(element, 'fault', None):
  488. name = DOM.getAttr(item, 'name')
  489. docs = GetDocumentation(item)
  490. msgref = DOM.getAttr(item, 'message')
  491. message = ParseQName(msgref, item)
  492. action = DOM.getAttr(item, 'Action', WSA.ADDRESS2004, None)
  493. if not action:
  494. action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
  495. operation.addFault(message, name, docs, action)
  496. def toDom(self):
  497. wsdl = self.getWSDL()
  498. ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
  499. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'portType')
  500. epc.setAttributeNS(None, 'name', self.name)
  501. if self.resourceProperties:
  502. ns,name = self.resourceProperties
  503. prefix = epc.getPrefix(ns)
  504. epc.setAttributeNS(OASIS.PROPERTIES, 'ResourceProperties', '%s:%s'%(prefix,name))
  505. for op in self.operations:
  506. op.toDom(epc._getNode())
  507. class Operation(Element):
  508. def __init__(self, name, documentation='', parameterOrder=None):
  509. Element.__init__(self, name, documentation)
  510. self.parameterOrder = parameterOrder
  511. self.faults = Collection(self)
  512. self.input = None
  513. self.output = None
  514. def getWSDL(self):
  515. """Return the WSDL object that contains this Operation."""
  516. return self.parent().parent().parent().parent()
  517. def getPortType(self):
  518. return self.parent().parent()
  519. def getInputAction(self):
  520. """wsa:Action attribute"""
  521. return GetWSAActionInput(self)
  522. def getInputMessage(self):
  523. if self.input is None:
  524. return None
  525. wsdl = self.getPortType().getWSDL()
  526. return wsdl.messages[self.input.message]
  527. def getOutputAction(self):
  528. """wsa:Action attribute"""
  529. return GetWSAActionOutput(self)
  530. def getOutputMessage(self):
  531. if self.output is None:
  532. return None
  533. wsdl = self.getPortType().getWSDL()
  534. return wsdl.messages[self.output.message]
  535. def getFaultAction(self, name):
  536. """wsa:Action attribute"""
  537. return GetWSAActionFault(self, name)
  538. def getFaultMessage(self, name):
  539. wsdl = self.getPortType().getWSDL()
  540. return wsdl.messages[self.faults[name].message]
  541. def addFault(self, message, name, documentation='', action=None):
  542. if self.faults.has_key(name):
  543. raise WSDLError(
  544. 'Duplicate fault element: %s' % name
  545. )
  546. item = MessageRole('fault', message, name, documentation, action)
  547. self.faults[name] = item
  548. return item
  549. def setInput(self, message, name='', documentation='', action=None):
  550. self.input = MessageRole('input', message, name, documentation, action)
  551. self.input.parent = weakref.ref(self)
  552. return self.input
  553. def setOutput(self, message, name='', documentation='', action=None):
  554. self.output = MessageRole('output', message, name, documentation, action)
  555. self.output.parent = weakref.ref(self)
  556. return self.output
  557. def toDom(self, node):
  558. wsdl = self.getWSDL()
  559. ep = ElementProxy(None, node)
  560. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
  561. epc.setAttributeNS(None, 'name', self.name)
  562. node = epc._getNode()
  563. if self.input:
  564. self.input.toDom(node)
  565. if self.output:
  566. self.output.toDom(node)
  567. for fault in self.faults:
  568. fault.toDom(node)
  569. class MessageRole(Element):
  570. def __init__(self, type, message, name='', documentation='', action=None):
  571. Element.__init__(self, name, documentation)
  572. self.message = message
  573. self.type = type
  574. self.action = action
  575. def getWSDL(self):
  576. """Return the WSDL object that contains this MessageRole."""
  577. if self.parent().getWSDL() == 'fault':
  578. return self.parent().parent().getWSDL()
  579. return self.parent().getWSDL()
  580. def toDom(self, node):
  581. wsdl = self.getWSDL()
  582. ep = ElementProxy(None, node)
  583. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
  584. epc.setAttributeNS(None, 'message', self.message)
  585. if self.action:
  586. epc.setAttributeNS(WSA.ADDRESS2004, 'Action', self.action)
  587. class Binding(Element):
  588. def __init__(self, name, type, documentation=''):
  589. Element.__init__(self, name, documentation)
  590. self.operations = Collection(self)
  591. self.type = type
  592. def getWSDL(self):
  593. """Return the WSDL object that contains this binding."""
  594. return self.parent().parent()
  595. def getPortType(self):
  596. """Return the PortType object associated with this binding."""
  597. return self.getWSDL().portTypes[self.type]
  598. def findBinding(self, kind):
  599. for item in self.extensions:
  600. if isinstance(item, kind):
  601. return item
  602. return None
  603. def findBindings(self, kind):
  604. return [ item for item in self.extensions if isinstance(item, kind) ]
  605. def addOperationBinding(self, name, documentation=''):
  606. item = OperationBinding(name, documentation)
  607. self.operations[name] = item
  608. return item
  609. def load(self, elements):
  610. for element in elements:
  611. name = DOM.getAttr(element, 'name')
  612. docs = GetDocumentation(element)
  613. opbinding = self.addOperationBinding(name, docs)
  614. opbinding.load_ex(GetExtensions(element))
  615. item = DOM.getElement(element, 'input', None, None)
  616. if item is not None:
  617. mbinding = MessageRoleBinding('input')
  618. mbinding.documentation = GetDocumentation(item)
  619. opbinding.input = mbinding
  620. mbinding.load_ex(GetExtensions(item))
  621. item = DOM.getElement(element, 'output', None, None)
  622. if item is not None:
  623. mbinding = MessageRoleBinding('output')
  624. mbinding.documentation = GetDocumentation(item)
  625. opbinding.output = mbinding
  626. mbinding.load_ex(GetExtensions(item))
  627. for item in DOM.getElements(element, 'fault', None):
  628. name = DOM.getAttr(item, 'name')
  629. mbinding = MessageRoleBinding('fault', name)
  630. mbinding.documentation = GetDocumentation(item)
  631. opbinding.faults[name] = mbinding
  632. mbinding.load_ex(GetExtensions(item))
  633. def load_ex(self, elements):
  634. for e in elements:
  635. ns, name = e.namespaceURI, e.localName
  636. if ns in DOM.NS_SOAP_BINDING_ALL and name == 'binding':
  637. transport = DOM.getAttr(e, 'transport', default=None)
  638. style = DOM.getAttr(e, 'style', default='document')
  639. ob = SoapBinding(transport, style)
  640. self.addExtension(ob)
  641. continue
  642. elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'binding':
  643. verb = DOM.getAttr(e, 'verb')
  644. ob = HttpBinding(verb)
  645. self.addExtension(ob)
  646. continue
  647. else:
  648. self.addExtension(e)
  649. def toDom(self):
  650. wsdl = self.getWSDL()
  651. ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
  652. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'binding')
  653. epc.setAttributeNS(None, 'name', self.name)
  654. ns,name = self.type
  655. prefix = epc.getPrefix(ns)
  656. epc.setAttributeNS(None, 'type', '%s:%s' %(prefix,name))
  657. node = epc._getNode()
  658. for ext in self.extensions:
  659. ext.toDom(node)
  660. for op_binding in self.operations:
  661. op_binding.toDom(node)
  662. class OperationBinding(Element):
  663. def __init__(self, name, documentation=''):
  664. Element.__init__(self, name, documentation)
  665. self.input = None
  666. self.output = None
  667. self.faults = Collection(self)
  668. def getWSDL(self):
  669. """Return the WSDL object that contains this binding."""
  670. return self.parent().parent().parent().parent()
  671. def getBinding(self):
  672. """Return the parent Binding object of the operation binding."""
  673. return self.parent().parent()
  674. def getOperation(self):
  675. """Return the abstract Operation associated with this binding."""
  676. return self.getBinding().getPortType().operations[self.name]
  677. def findBinding(self, kind):
  678. for item in self.extensions:
  679. if isinstance(item, kind):
  680. return item
  681. return None
  682. def findBindings(self, kind):
  683. return [ item for item in self.extensions if isinstance(item, kind) ]
  684. def addInputBinding(self, binding):
  685. if self.input is None:
  686. self.input = MessageRoleBinding('input')
  687. self.input.parent = weakref.ref(self)
  688. self.input.addExtension(binding)
  689. return binding
  690. def addOutputBinding(self, binding):
  691. if self.output is None:
  692. self.output = MessageRoleBinding('output')
  693. self.output.parent = weakref.ref(self)
  694. self.output.addExtension(binding)
  695. return binding
  696. def addFaultBinding(self, name, binding):
  697. fault = self.get(name, None)
  698. if fault is None:
  699. fault = MessageRoleBinding('fault', name)
  700. fault.addExtension(binding)
  701. return binding
  702. def load_ex(self, elements):
  703. for e in elements:
  704. ns, name = e.namespaceURI, e.localName
  705. if ns in DOM.NS_SOAP_BINDING_ALL and name == 'operation':
  706. soapaction = DOM.getAttr(e, 'soapAction', default=None)
  707. style = DOM.getAttr(e, 'style', default=None)
  708. ob = SoapOperationBinding(soapaction, style)
  709. self.addExtension(ob)
  710. continue
  711. elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'operation':
  712. location = DOM.getAttr(e, 'location')
  713. ob = HttpOperationBinding(location)
  714. self.addExtension(ob)
  715. continue
  716. else:
  717. self.addExtension(e)
  718. def toDom(self, node):
  719. wsdl = self.getWSDL()
  720. ep = ElementProxy(None, node)
  721. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
  722. epc.setAttributeNS(None, 'name', self.name)
  723. node = epc._getNode()
  724. for ext in self.extensions:
  725. ext.toDom(node)
  726. if self.input:
  727. self.input.toDom(node)
  728. if self.output:
  729. self.output.toDom(node)
  730. for fault in self.faults:
  731. fault.toDom(node)
  732. class MessageRoleBinding(Element):
  733. def __init__(self, type, name='', documentation=''):
  734. Element.__init__(self, name, documentation)
  735. self.type = type
  736. def getWSDL(self):
  737. """Return the WSDL object that contains this MessageRole."""
  738. if self.type == 'fault':
  739. return self.parent().parent().getWSDL()
  740. return self.parent().getWSDL()
  741. def findBinding(self, kind):
  742. for item in self.extensions:
  743. if isinstance(item, kind):
  744. return item
  745. return None
  746. def findBindings(self, kind):
  747. return [ item for item in self.extensions if isinstance(item, kind) ]
  748. def load_ex(self, elements):
  749. for e in elements:
  750. ns, name = e.namespaceURI, e.localName
  751. if ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
  752. encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
  753. namespace = DOM.getAttr(e, 'namespace', default=None)
  754. parts = DOM.getAttr(e, 'parts', default=None)
  755. use = DOM.getAttr(e, 'use', default=None)
  756. if use is None:
  757. raise WSDLError(
  758. 'Invalid soap:body binding element.'
  759. )
  760. ob = SoapBodyBinding(use, namespace, encstyle, parts)
  761. self.addExtension(ob)
  762. continue
  763. elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'fault':
  764. encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
  765. namespace = DOM.getAttr(e, 'namespace', default=None)
  766. name = DOM.getAttr(e, 'name', default=None)
  767. use = DOM.getAttr(e, 'use', default=None)
  768. if use is None or name is None:
  769. raise WSDLError(
  770. 'Invalid soap:fault binding element.'
  771. )
  772. ob = SoapFaultBinding(name, use, namespace, encstyle)
  773. self.addExtension(ob)
  774. continue
  775. elif ns in DOM.NS_SOAP_BINDING_ALL and name in (
  776. 'header', 'headerfault'
  777. ):
  778. encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
  779. namespace = DOM.getAttr(e, 'namespace', default=None)
  780. message = DOM.getAttr(e, 'message')
  781. part = DOM.getAttr(e, 'part')
  782. use = DOM.getAttr(e, 'use')
  783. if name == 'header':
  784. _class = SoapHeaderBinding
  785. else:
  786. _class = SoapHeaderFaultBinding
  787. message = ParseQName(message, e)
  788. ob = _class(message, part, use, namespace, encstyle)
  789. self.addExtension(ob)
  790. continue
  791. elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlReplacement':
  792. ob = HttpUrlReplacementBinding()
  793. self.addExtension(ob)
  794. continue
  795. elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlEncoded':
  796. ob = HttpUrlEncodedBinding()
  797. self.addExtension(ob)
  798. continue
  799. elif ns in DOM.NS_MIME_BINDING_ALL and name == 'multipartRelated':
  800. ob = MimeMultipartRelatedBinding()
  801. self.addExtension(ob)
  802. ob.load_ex(GetExtensions(e))
  803. continue
  804. elif ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
  805. part = DOM.getAttr(e, 'part', default=None)
  806. type = DOM.getAttr(e, 'type', default=None)
  807. ob = MimeContentBinding(part, type)
  808. self.addExtension(ob)
  809. continue
  810. elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
  811. part = DOM.getAttr(e, 'part', default=None)
  812. ob = MimeXmlBinding(part)
  813. self.addExtension(ob)
  814. continue
  815. else:
  816. self.addExtension(e)
  817. def toDom(self, node):
  818. wsdl = self.getWSDL()
  819. ep = ElementProxy(None, node)
  820. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
  821. node = epc._getNode()
  822. for item in self.extensions:
  823. if item: item.toDom(node)
  824. class Service(Element):
  825. def __init__(self, name, documentation=''):
  826. Element.__init__(self, name, documentation)
  827. self.ports = Collection(self)
  828. def getWSDL(self):
  829. return self.parent().parent()
  830. def addPort(self, name, binding, documentation=''):
  831. item = Port(name, binding, documentation)
  832. self.ports[name] = item
  833. return item
  834. def load(self, elements):
  835. for element in elements:
  836. name = DOM.getAttr(element, 'name', default=None)
  837. docs = GetDocumentation(element)
  838. binding = DOM.getAttr(element, 'binding', default=None)
  839. if name is None or binding is None:
  840. raise WSDLError(
  841. 'Invalid port element.'
  842. )
  843. binding = ParseQName(binding, element)
  844. port = self.addPort(name, binding, docs)
  845. port.load_ex(GetExtensions(element))
  846. def load_ex(self, elements):
  847. for e in elements:
  848. self.addExtension(e)
  849. def toDom(self):
  850. wsdl = self.getWSDL()
  851. ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
  852. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "service")
  853. epc.setAttributeNS(None, "name", self.name)
  854. node = epc._getNode()
  855. for port in self.ports:
  856. port.toDom(node)
  857. class Port(Element):
  858. def __init__(self, name, binding, documentation=''):
  859. Element.__init__(self, name, documentation)
  860. self.binding = binding
  861. def getWSDL(self):
  862. return self.parent().parent().getWSDL()
  863. def getService(self):
  864. """Return the Service object associated with this port."""
  865. return self.parent().parent()
  866. def getBinding(self):
  867. """Return the Binding object that is referenced by this port."""
  868. wsdl = self.getService().getWSDL()
  869. return wsdl.bindings[self.binding]
  870. def getPortType(self):
  871. """Return the PortType object that is referenced by this port."""
  872. wsdl = self.getService().getWSDL()
  873. binding = wsdl.bindings[self.binding]
  874. return wsdl.portTypes[binding.type]
  875. def getAddressBinding(self):
  876. """A convenience method to obtain the extension element used
  877. as the address binding for the port, or None if undefined."""
  878. for item in self.extensions:
  879. if isinstance(item, SoapAddressBinding) or \
  880. isinstance(item, HttpAddressBinding):
  881. return item
  882. raise WSDLError(
  883. 'No address binding found in port.'
  884. )
  885. def load_ex(self, elements):
  886. for e in elements:
  887. ns, name = e.namespaceURI, e.localName
  888. if ns in DOM.NS_SOAP_BINDING_ALL and name == 'address':
  889. location = DOM.getAttr(e, 'location', default=None)
  890. ob = SoapAddressBinding(location)
  891. self.addExtension(ob)
  892. continue
  893. elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'address':
  894. location = DOM.getAttr(e, 'location', default=None)
  895. ob = HttpAddressBinding(location)
  896. self.addExtension(ob)
  897. continue
  898. else:
  899. self.addExtension(e)
  900. def toDom(self, node):
  901. wsdl = self.getWSDL()
  902. ep = ElementProxy(None, node)
  903. epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "port")
  904. epc.setAttributeNS(None, "name", self.name)
  905. ns,name = self.binding
  906. prefix = epc.getPrefix(ns)
  907. epc.setAttributeNS(None, "binding", "%s:%s" %(prefix,name))
  908. node = epc._getNode()
  909. for ext in self.extensions:
  910. ext.toDom(node)
  911. class SoapBinding:
  912. def __init__(self, transport, style='rpc'):
  913. self.transport = transport
  914. self.style = style
  915. def getWSDL(self):
  916. return self.parent().getWSDL()
  917. def toDom(self, node):
  918. wsdl = self.getWSDL()
  919. ep = ElementProxy(None, node)
  920. epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'binding')
  921. if self.transport:
  922. epc.setAttributeNS(None, "transport", self.transport)
  923. if self.style:
  924. epc.setAttributeNS(None, "style", self.style)
  925. class SoapAddressBinding:
  926. def __init__(self, location):
  927. self.location = location
  928. def getWSDL(self):
  929. return self.parent().getWSDL()
  930. def toDom(self, node):
  931. wsdl = self.getWSDL()
  932. ep = ElementProxy(None, node)
  933. epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'address')
  934. epc.setAttributeNS(None, "location", self.location)
  935. class SoapOperationBinding:
  936. def __init__(self, soapAction=None, style=None):
  937. self.soapAction = soapAction
  938. self.style = style
  939. def getWSDL(self):
  940. return self.parent().getWSDL()
  941. def toDom(self, node):
  942. wsdl = self.getWSDL()
  943. ep = ElementProxy(None, node)
  944. epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'operation')
  945. if self.soapAction:
  946. epc.setAttributeNS(None, 'soapAction', self.soapAction)
  947. if self.style:
  948. epc.setAttributeNS(None, 'style', self.style)
  949. class SoapBodyBinding:
  950. def __init__(self, use, namespace=None, encodingStyle=None, parts=None):
  951. if not use in ('literal', 'encoded'):
  952. raise WSDLError(
  953. 'Invalid use attribute value: %s' % use
  954. )
  955. self.encodingStyle = encodingStyle
  956. self.namespace = namespace
  957. if type(parts) in (type(''), type(u'')):
  958. parts = parts.split()
  959. self.parts = parts
  960. self.use = use
  961. def getWSDL(self):
  962. return self.parent().getWSDL()
  963. def toDom(self, node):
  964. wsdl = self.getWSDL()
  965. ep = ElementProxy(None, node)
  966. epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body')
  967. epc.setAttributeNS(None, "use", self.use)
  968. epc.setAttributeNS(None, "namespace", self.namespace)
  969. class SoapFaultBinding:
  970. def __init__(self, name, use, namespace=None, encodingStyle=None):
  971. if not use in ('literal', 'encoded'):
  972. raise WSDLError(
  973. 'Invalid use attribute value: %s' % use
  974. )
  975. self.encodingStyle = encodingStyle
  976. self.namespace = namespace
  977. self.name = name
  978. self.use = use
  979. class SoapHeaderBinding:
  980. def __init__(self, message, part, use, namespace=None, encodingStyle=None):
  981. if not use in ('literal', 'encoded'):
  982. raise WSDLError(
  983. 'Invalid use attribute value: %s' % use
  984. )
  985. self.encodingStyle = encodingStyle
  986. self.namespace = namespace
  987. self.message = message
  988. self.part = part
  989. self.use = use
  990. tagname = 'header'
  991. class SoapHeaderFaultBinding(SoapHeaderBinding):
  992. tagname = 'headerfault'
  993. class HttpBinding:
  994. def __init__(self, verb):
  995. self.verb = verb
  996. class HttpAddressBinding:
  997. def __init__(self, location):
  998. self.location = location
  999. class HttpOperationBinding:
  1000. def __init__(self, location):
  1001. self.location = location
  1002. class HttpUrlReplacementBinding:
  1003. pass
  1004. class HttpUrlEncodedBinding:
  1005. pass
  1006. class MimeContentBinding:
  1007. def __init__(self, part=None, type=None):
  1008. self.part = part
  1009. self.type = type
  1010. class MimeXmlBinding:
  1011. def __init__(self, part=None):
  1012. self.part = part
  1013. class MimeMultipartRelatedBinding:
  1014. def __init__(self):
  1015. self.parts = []
  1016. def load_ex(self, elements):
  1017. for e in elements:
  1018. ns, name = e.namespaceURI, e.localName
  1019. if ns in DOM.NS_MIME_BINDING_ALL and name == 'part':
  1020. self.parts.append(MimePartBinding())
  1021. continue
  1022. class MimePartBinding:
  1023. def __init__(self):
  1024. self.items = []
  1025. def load_ex(self, elements):
  1026. for e in elements:
  1027. ns, name = e.namespaceURI, e.localName
  1028. if ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
  1029. part = DOM.getAttr(e, 'part', default=None)
  1030. type = DOM.getAttr(e, 'type', default=None)
  1031. ob = MimeContentBinding(part, type)
  1032. self.items.append(ob)
  1033. continue
  1034. elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
  1035. part = DOM.getAttr(e, 'part', default=None)
  1036. ob = MimeXmlBinding(part)
  1037. self.items.append(ob)
  1038. continue
  1039. elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
  1040. encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
  1041. namespace = DOM.getAttr(e, 'namespace', default=None)
  1042. parts = DOM.getAttr(e, 'parts', default=None)
  1043. use = DOM.getAttr(e, 'use', default=None)
  1044. if use is None:
  1045. raise WSDLError(
  1046. 'Invalid soap:body binding element.'
  1047. )
  1048. ob = SoapBodyBinding(use, namespace, encstyle, parts)
  1049. self.items.append(ob)
  1050. continue
  1051. class WSDLError(Exception):
  1052. pass
  1053. def DeclareNSPrefix(writer, prefix, nsuri):
  1054. if writer.hasNSPrefix(nsuri):
  1055. return
  1056. writer.declareNSPrefix(prefix, nsuri)
  1057. def ParseTypeRef(value, element):
  1058. parts = value.split(':', 1)
  1059. if len(parts) == 1:
  1060. return (DOM.findTargetNS(element), value)
  1061. nsuri = DOM.findNamespaceURI(parts[0], element)
  1062. return (nsuri, parts[1])
  1063. def ParseQName(value, element):
  1064. nameref = value.split(':', 1)
  1065. if len(nameref) == 2:
  1066. nsuri = DOM.findNamespaceURI(nameref[0], element)
  1067. name = nameref[-1]
  1068. else:
  1069. nsuri = DOM.findTargetNS(element)
  1070. name = nameref[-1]
  1071. return nsuri, name
  1072. def GetDocumentation(element):
  1073. docnode = DOM.getElement(element, 'documentation', None, None)
  1074. if docnode is not None:
  1075. return DOM.getElementText(docnode)
  1076. return ''
  1077. def GetExtensions(element):
  1078. return [ item for item in DOM.getElements(element, None, None)
  1079. if item.namespaceURI != DOM.NS_WSDL ]
  1080. def GetWSAActionFault(operation, name):
  1081. """Find wsa:Action attribute, and return value or WSA.FAULT
  1082. for the default.
  1083. """
  1084. attr = operation.faults[name].action
  1085. if attr is not None:
  1086. return attr
  1087. return WSA.FAULT
  1088. def GetWSAActionInput(operation):
  1089. """Find wsa:Action attribute, and return value or the default."""
  1090. attr = operation.input.action
  1091. if attr is not None:
  1092. return attr
  1093. portType = operation.getPortType()
  1094. targetNamespace = portType.getTargetNamespace()
  1095. ptName = portType.name
  1096. msgName = operation.input.name
  1097. if not msgName:
  1098. msgName = operation.name + 'Request'
  1099. if targetNamespace.endswith('/'):
  1100. return '%s%s/%s' %(targetNamespace, ptName, msgName)
  1101. return '%s/%s/%s' %(targetNamespace, ptName, msgName)
  1102. def GetWSAActionOutput(operation):
  1103. """Find wsa:Action attribute, and return value or the default."""
  1104. attr = operation.output.action
  1105. if attr is not None:
  1106. return attr
  1107. targetNamespace = operation.getPortType().getTargetNamespace()
  1108. ptName = operation.getPortType().name
  1109. msgName = operation.output.name
  1110. if not msgName:
  1111. msgName = operation.name + 'Response'
  1112. if targetNamespace.endswith('/'):
  1113. return '%s%s/%s' %(targetNamespace, ptName, msgName)
  1114. return '%s/%s/%s' %(targetNamespace, ptName, msgName)
  1115. def FindExtensions(object, kind, t_type=type(())):
  1116. if isinstance(kind, t_type):
  1117. result = []
  1118. namespaceURI, name = kind
  1119. return [ item for item in object.extensions
  1120. if hasattr(item, 'nodeType') \
  1121. and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
  1122. and item.name == name ]
  1123. return [ item for item in object.extensions if isinstance(item, kind) ]
  1124. def FindExtension(object, kind, t_type=type(())):
  1125. if isinstance(kind, t_type):
  1126. namespaceURI, name = kind
  1127. for item in object.extensions:
  1128. if hasattr(item, 'nodeType') \
  1129. and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
  1130. and item.name == name:
  1131. return item
  1132. else:
  1133. for item in object.extensions:
  1134. if isinstance(item, kind):
  1135. return item
  1136. return None
  1137. class SOAPCallInfo:
  1138. """SOAPCallInfo captures the important binding information about a
  1139. SOAP operation, in a structure that is easier to work with than
  1140. raw WSDL structures."""
  1141. def __init__(self, methodName):
  1142. self.methodName = methodName
  1143. self.inheaders = []
  1144. self.outheaders = []
  1145. self.inparams = []
  1146. self.outparams = []
  1147. self.retval = None
  1148. encodingStyle = DOM.NS_SOAP_ENC
  1149. documentation = ''
  1150. soapAction = None
  1151. transport = None
  1152. namespace = None
  1153. location = None
  1154. use = 'encoded'
  1155. style = 'rpc'
  1156. def addInParameter(self, name, type, namespace=None, element_type=0):
  1157. """Add an input parameter description to the call info."""
  1158. parameter = ParameterInfo(name, type, namespace, element_type)
  1159. self.inparams.append(parameter)
  1160. return parameter
  1161. def addOutParameter(self, name, type, namespace=None, element_type=0):
  1162. """Add an output parameter description to the call info."""
  1163. parameter = ParameterInfo(name, type, namespace, element_type)
  1164. self.outparams.append(parameter)
  1165. return parameter
  1166. def setReturnParameter(self, name, type, namespace=None, element_type=0):
  1167. """Set the return parameter description for the call info."""
  1168. parameter = ParameterInfo(name, type, namespace, element_type)
  1169. self.retval = parameter
  1170. return parameter
  1171. def addInHeaderInfo(self, name, type, namespace, element_type=0,
  1172. mustUnderstand=0):
  1173. """Add an input SOAP header description to the call info."""
  1174. headerinfo = HeaderInfo(name, type, namespace, element_type)
  1175. if mustUnderstand:
  1176. headerinfo.mustUnderstand = 1
  1177. self.inheaders.append(headerinfo)
  1178. return headerinfo
  1179. def addOutHeaderInfo(self, name, type, namespace, element_type=0,
  1180. mustUnderstand=0):
  1181. """Add an output SOAP header description to the call info."""
  1182. headerinfo = HeaderInfo(name, type, namespace, element_type)
  1183. if mustUnderstand:
  1184. headerinfo.mustUnderstand = 1
  1185. self.outheaders.append(headerinfo)
  1186. return headerinfo
  1187. def getInParameters(self):
  1188. """Return a sequence of the in parameters of the method."""
  1189. return self.inparams
  1190. def getOutParameters(self):
  1191. """Return a sequence of the out parameters of the method."""
  1192. return self.outparams
  1193. def getReturnParameter(self):
  1194. """Return param info about the return value of the method."""
  1195. return self.retval
  1196. def getInHeaders(self):
  1197. """Return a sequence of the in headers of the method."""
  1198. return self.inheaders
  1199. def getOutHeaders(self):
  1200. """Return a sequence of the out headers of the method."""
  1201. return self.outheaders
  1202. class ParameterInfo:
  1203. """A ParameterInfo object captures parameter binding information."""
  1204. def __init__(self, name, type, namespace=None, element_type=0):
  1205. if element_type:
  1206. self.element_type = 1
  1207. if namespace is not None:
  1208. self.namespace = namespace
  1209. self.name = name
  1210. self.type = type
  1211. element_type = 0
  1212. namespace = None
  1213. default = None
  1214. class HeaderInfo(ParameterInfo):
  1215. """A HeaderInfo object captures SOAP header binding information."""
  1216. def __init__(self, name, type, namespace, element_type=None):
  1217. ParameterInfo.__init__(self, name, type, namespace, element_type)
  1218. mustUnderstand = 0
  1219. actor = None
  1220. def callInfoFromWSDL(port, name):
  1221. """Return a SOAPCallInfo given a WSDL port and operation name."""
  1222. wsdl = port.getService().getWSDL()
  1223. binding = port.getBinding()
  1224. portType = binding.getPortType()
  1225. operation = portType.operations[name]
  1226. opbinding = binding.operations[name]
  1227. messages = wsdl.messages
  1228. callinfo = SOAPCallInfo(name)
  1229. addrbinding = port.getAddressBinding()
  1230. if not isinstance(addrbinding, SoapAddressBinding):
  1231. raise ValueError, 'Unsupported binding type.'
  1232. callinfo.location = addrbinding.location
  1233. soapbinding = binding.findBinding(SoapBinding)
  1234. if soapbinding is None:
  1235. raise ValueError, 'Missing soap:binding element.'
  1236. callinfo.transport = soapbinding.transport
  1237. callinfo.style = soapbinding.style or 'document'
  1238. soap_op_binding = opbinding.findBinding(SoapOperationBinding)
  1239. if soap_op_binding is not None:
  1240. callinfo.soapAction = soap_op_binding.soapAction
  1241. callinfo.style = soap_op_binding.style or callinfo.style
  1242. parameterOrder = operation.parameterOrder
  1243. if operation.input is not None:
  1244. message = messages[operation.input.message]
  1245. msgrole = opbinding.input
  1246. mime = msgrole.findBinding(MimeMultipartRelatedBinding)
  1247. if mime is not None:
  1248. raise ValueError, 'Mime bindings are not supported.'
  1249. else:
  1250. for item in msgrole.findBindings(SoapHeaderBinding):
  1251. part = messages[item.message].parts[item.part]
  1252. header = callinfo.addInHeaderInfo(
  1253. part.name,
  1254. part.element or part.type,
  1255. item.namespace,
  1256. element_type = part.element and 1 or 0
  1257. )
  1258. header.encodingStyle = item.encodingStyle
  1259. body = msgrole.findBinding(SoapBodyBinding)
  1260. if body is None:
  1261. raise ValueError, 'Missing soap:body binding.'
  1262. callinfo.encodingStyle = body.encodingStyle
  1263. callinfo.namespace = body.namespace
  1264. callinfo.use = body.use
  1265. if body.parts is not None:
  1266. parts = []
  1267. for name in body.parts:
  1268. parts.append(message.parts[name])
  1269. else:
  1270. parts = message.parts.values()
  1271. for part in parts:
  1272. callinfo.addInParameter(
  1273. part.name,
  1274. part.element or part.type,
  1275. element_type = part.element and 1 or 0
  1276. )
  1277. if operation.output is not None:
  1278. try:
  1279. message = messages[operation.output.message]
  1280. except KeyError:
  1281. if self.strict:
  1282. raise RuntimeError(
  1283. "Recieved message not defined in the WSDL schema: %s" %
  1284. operation.output.message)
  1285. else:
  1286. message = wsdl.addMessage(operation.output.message)
  1287. print "Warning:", \
  1288. "Recieved message not defined in the WSDL schema.", \
  1289. "Adding it."
  1290. print "Message:", operation.output.message
  1291. msgrole = opbinding.output
  1292. mime = msgrole.findBinding(MimeMultipartRelatedBinding)
  1293. if mime is not None:
  1294. raise ValueError, 'Mime bindings are not supported.'
  1295. else:
  1296. for item in msgrole.findBindings(SoapHeaderBinding):
  1297. part = messages[item.message].parts[item.part]
  1298. header = callinfo.addOutHeaderInfo(
  1299. part.name,
  1300. part.element or part.type,
  1301. item.namespace,
  1302. element_type = part.element and 1 or 0
  1303. )
  1304. header.encodingStyle = item.encodingStyle
  1305. body = msgrole.findBinding(SoapBodyBinding)
  1306. if body is None:
  1307. raise ValueError, 'Missing soap:body binding.'
  1308. callinfo.encodingStyle = body.encodingStyle
  1309. callinfo.namespace = body.namespace
  1310. callinfo.use = body.use
  1311. if body.parts is not None:
  1312. parts = []
  1313. for name in body.parts:
  1314. parts.append(message.parts[name])
  1315. else:
  1316. parts = message.parts.values()
  1317. if parts:
  1318. # XXX no idea what this is for, but it breaks everything. jrb
  1319. #callinfo.setReturnParameter(
  1320. # parts[0].name,
  1321. # parts[0].element or parts[0].type,
  1322. # element_type = parts[0].element and 1 or 0
  1323. # )
  1324. #for part in parts[1:]:
  1325. for part in parts:
  1326. callinfo.addOutParameter(
  1327. part.name,
  1328. part.element or part.type,
  1329. element_type = part.element and 1 or 0
  1330. )
  1331. return callinfo