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.
 
 
 

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