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.
 
 
 

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