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.
 
 
 

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