Package suds :: Module wsdl
[hide private]
[frames] | no frames]

Source Code for Module suds.wsdl

  1  # This program is free software; you can redistribute it and/or modify 
  2  # it under the terms of the (LGPL) GNU Lesser General Public License as 
  3  # published by the Free Software Foundation; either version 3 of the  
  4  # License, or (at your option) any later version. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library Lesser General Public License for more details at 
 10  # ( http://www.gnu.org/licenses/lgpl.html ). 
 11  # 
 12  # You should have received a copy of the GNU Lesser General Public License 
 13  # along with this program; if not, write to the Free Software 
 14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 15  # written by: Jeff Ortel ( jortel@redhat.com ) 
 16   
 17  """ 
 18  The I{wsdl} module provides an objectification of the WSDL. 
 19  The primary class is I{Definitions} as it represends the root element 
 20  found in the document. 
 21  """ 
 22   
 23  from logging import getLogger 
 24  from suds import * 
 25  from suds.sax import splitPrefix 
 26  from suds.sax.element import Element 
 27  from suds.bindings.document import Document 
 28  from suds.bindings.rpc import RPC, Encoded 
 29  from suds.xsd import qualify, Namespace 
 30  from suds.xsd.schema import Schema, SchemaCollection 
 31  from suds.xsd.query import ElementQuery 
 32  from suds.sudsobject import Object, Facade, Metadata 
 33  from suds.reader import DocumentReader, DefinitionsReader 
 34  from urlparse import urljoin 
 35  import re, soaparray 
 36   
 37  log = getLogger(__name__) 
 38   
 39  wsdlns = (None, "http://schemas.xmlsoap.org/wsdl/") 
 40  soapns = (None, 'http://schemas.xmlsoap.org/wsdl/soap/') 
 41  soap12ns = (None, 'http://schemas.xmlsoap.org/wsdl/soap12/') 
42 43 44 -class WObject(Object):
45 """ 46 Base object for wsdl types. 47 @ivar root: The XML I{root} element. 48 @type root: L{Element} 49 """ 50
51 - def __init__(self, root, definitions=None):
52 """ 53 @param root: An XML root element. 54 @type root: L{Element} 55 @param definitions: A definitions object. 56 @type definitions: L{Definitions} 57 """ 58 Object.__init__(self) 59 self.root = root 60 pmd = Metadata() 61 pmd.excludes = ['root'] 62 pmd.wrappers = dict(qname=repr) 63 self.__metadata__.__print__ = pmd
64
65 - def resolve(self, definitions):
66 """ 67 Resolve named references to other WSDL objects. 68 @param definitions: A definitions object. 69 @type definitions: L{Definitions} 70 """ 71 pass
72
73 74 -class NamedObject(WObject):
75 """ 76 A B{named} WSDL object. 77 @ivar name: The name of the object. 78 @type name: str 79 @ivar qname: The I{qualified} name of the object. 80 @type qname: (name, I{namespace-uri}). 81 """ 82
83 - def __init__(self, root, definitions):
84 """ 85 @param root: An XML root element. 86 @type root: L{Element} 87 @param definitions: A definitions object. 88 @type definitions: L{Definitions} 89 """ 90 WObject.__init__(self, root, definitions) 91 self.name = root.get('name') 92 self.qname = (self.name, definitions.tns[1]) 93 pmd = self.__metadata__.__print__ 94 pmd.wrappers['qname'] = repr
95
96 97 -class Definitions(WObject):
98 """ 99 Represents the I{root} container of the WSDL objects as defined 100 by <wsdl:definitions/> 101 @ivar id: The object id. 102 @type id: str 103 @ivar options: An options dictionary. 104 @type options: L{options.Options} 105 @ivar url: The URL used to load the object. 106 @type url: str 107 @ivar tns: The target namespace for the WSDL. 108 @type tns: str 109 @ivar schema: The collective WSDL schema object. 110 @type schema: L{SchemaCollection} 111 @ivar children: The raw list of child objects. 112 @type children: [L{WObject},...] 113 @ivar imports: The list of L{Import} children. 114 @type imports: [L{Import},...] 115 @ivar messages: The dictionary of L{Message} children key'd by I{qname} 116 @type messages: [L{Message},...] 117 @ivar port_types: The dictionary of L{PortType} children key'd by I{qname} 118 @type port_types: [L{PortType},...] 119 @ivar bindings: The dictionary of L{Binding} children key'd by I{qname} 120 @type bindings: [L{Binding},...] 121 @ivar service: The service object. 122 @type service: L{Service} 123 """ 124 125 Tag = 'definitions' 126
127 - def __init__(self, url, options):
128 """ 129 @param url: A URL to the WSDL. 130 @type url: str 131 @param options: An options dictionary. 132 @type options: L{options.Options} 133 """ 134 log.debug('reading wsdl at: %s ...', url) 135 reader = DocumentReader(options) 136 d = reader.open(url) 137 root = d.root() 138 WObject.__init__(self, root) 139 self.id = objid(self) 140 self.options = options 141 self.url = url 142 self.tns = self.mktns(root) 143 self.types = [] 144 self.schema = None 145 self.children = [] 146 self.imports = [] 147 self.messages = {} 148 self.port_types = {} 149 self.bindings = {} 150 self.services = [] 151 self.add_children(self.root) 152 self.children.sort() 153 pmd = self.__metadata__.__print__ 154 pmd.excludes.append('children') 155 pmd.excludes.append('wsdl') 156 pmd.wrappers['schema'] = repr 157 self.open_imports() 158 self.resolve() 159 self.build_schema() 160 self.set_wrapped() 161 for s in self.services: 162 self.add_methods(s) 163 log.debug("wsdl at '%s' loaded:\n%s", url, self)
164
165 - def mktns(self, root):
166 """ Get/create the target namespace """ 167 tns = root.get('targetNamespace') 168 prefix = root.findPrefix(tns) 169 if prefix is None: 170 log.debug('warning: tns (%s), not mapped to prefix', tns) 171 prefix = 'tns' 172 return (prefix, tns)
173
174 - def add_children(self, root):
175 """ Add child objects using the factory """ 176 for c in root.getChildren(ns=wsdlns): 177 child = Factory.create(c, self) 178 if child is None: continue 179 self.children.append(child) 180 if isinstance(child, Import): 181 self.imports.append(child) 182 continue 183 if isinstance(child, Types): 184 self.types.append(child) 185 continue 186 if isinstance(child, Message): 187 self.messages[child.qname] = child 188 continue 189 if isinstance(child, PortType): 190 self.port_types[child.qname] = child 191 continue 192 if isinstance(child, Binding): 193 self.bindings[child.qname] = child 194 continue 195 if isinstance(child, Service): 196 self.services.append(child) 197 continue
198
199 - def open_imports(self):
200 """ Import the I{imported} WSDLs. """ 201 for imp in self.imports: 202 imp.load(self)
203
204 - def resolve(self):
205 """ Tell all children to resolve themselves """ 206 for c in self.children: 207 c.resolve(self)
208
209 - def build_schema(self):
210 """ Process L{Types} objects and create the schema collection """ 211 container = SchemaCollection(self) 212 for t in [t for t in self.types if t.local()]: 213 for root in t.contents(): 214 schema = Schema(root, self.url, self.options, container) 215 container.add(schema) 216 if not len(container): # empty 217 root = Element.buildPath(self.root, 'types/schema') 218 schema = Schema(root, self.url, self.options, container) 219 container.add(schema) 220 self.schema = container.load(self.options) 221 for s in [t.schema() for t in self.types if t.imported()]: 222 self.schema.merge(s) 223 return self.schema
224
225 - def add_methods(self, service):
226 """ Build method view for service """ 227 bindings = { 228 'document/literal' : Document(self), 229 'rpc/literal' : RPC(self), 230 'rpc/encoded' : Encoded(self) 231 } 232 for p in service.ports: 233 binding = p.binding 234 ptype = p.binding.type 235 operations = p.binding.type.operations.values() 236 for name in [op.name for op in operations]: 237 m = Facade('Method') 238 m.name = name 239 m.location = p.location 240 m.binding = Facade('binding') 241 op = binding.operation(name) 242 m.soap = op.soap 243 key = '/'.join((op.soap.style, op.soap.input.body.use)) 244 m.binding.input = bindings.get(key) 245 key = '/'.join((op.soap.style, op.soap.output.body.use)) 246 m.binding.output = bindings.get(key) 247 op = ptype.operation(name) 248 p.methods[name] = m
249
250 - def set_wrapped(self):
251 """ set (wrapped|bare) flag on messages """ 252 for b in self.bindings.values(): 253 for op in b.operations.values(): 254 for body in (op.soap.input.body, op.soap.output.body): 255 body.wrapped = False 256 if len(body.parts) != 1: 257 continue 258 for p in body.parts: 259 if p.element is None: 260 continue 261 query = ElementQuery(p.element) 262 pt = query.execute(self.schema) 263 if pt is None: 264 raise TypeNotFound(query.ref) 265 resolved = pt.resolve() 266 if resolved.builtin(): 267 continue 268 body.wrapped = True
269
270 - def __getstate__(self):
271 nopickle = ('options',) 272 state = self.__dict__.copy() 273 for k in nopickle: 274 if k in state: 275 del state[k] 276 return state
277
278 - def __repr__(self):
279 return 'Definitions (id=%s)' % self.id
280
281 282 -class Import(WObject):
283 """ 284 Represents the <wsdl:import/>. 285 @ivar location: The value of the I{location} attribute. 286 @type location: str 287 @ivar ns: The value of the I{namespace} attribute. 288 @type ns: str 289 @ivar imported: The imported object. 290 @type imported: L{Definitions} 291 """ 292
293 - def __init__(self, root, definitions):
294 """ 295 @param root: An XML root element. 296 @type root: L{Element} 297 @param definitions: A definitions object. 298 @type definitions: L{Definitions} 299 """ 300 WObject.__init__(self, root, definitions) 301 self.location = root.get('location') 302 self.ns = root.get('namespace') 303 self.imported = None 304 pmd = self.__metadata__.__print__ 305 pmd.wrappers['imported'] = repr
306
307 - def load(self, definitions):
308 """ Load the object by opening the URL """ 309 url = self.location 310 log.debug('importing (%s)', url) 311 if '://' not in url: 312 url = urljoin(definitions.url, url) 313 options = definitions.options 314 d = Definitions(url, options) 315 if d.root.match(Definitions.Tag, wsdlns): 316 self.import_definitions(definitions, d) 317 return 318 if d.root.match(Schema.Tag, Namespace.xsdns): 319 self.import_schema(definitions, d) 320 return 321 raise Exception('document at "%s" is unknown' % url)
322
323 - def import_definitions(self, definitions, d):
324 """ import/merge wsdl definitions """ 325 definitions.types += d.types 326 definitions.messages.update(d.messages) 327 definitions.port_types.update(d.port_types) 328 definitions.bindings.update(d.bindings) 329 self.imported = d 330 log.debug('imported (WSDL):\n%s', d)
331
332 - def import_schema(self, definitions, d):
333 """ import schema as <types/> content """ 334 if not len(definitions.types): 335 types = Types.create(definitions) 336 definitions.types.append(types) 337 else: 338 types = definitions.types[-1] 339 types.root.append(d.root) 340 log.debug('imported (XSD):\n%s', d.root)
341
342 - def __gt__(self, other):
343 return False
344
345 346 -class Types(WObject):
347 """ 348 Represents <types><schema/></types>. 349 """ 350 351 @classmethod
352 - def create(cls, definitions):
353 root = Element('types', ns=wsdlns) 354 definitions.root.insert(root) 355 return Types(root, definitions)
356
357 - def __init__(self, root, definitions):
358 """ 359 @param root: An XML root element. 360 @type root: L{Element} 361 @param definitions: A definitions object. 362 @type definitions: L{Definitions} 363 """ 364 WObject.__init__(self, root, definitions) 365 self.definitions = definitions
366
367 - def contents(self):
368 return self.root.getChildren('schema', Namespace.xsdns)
369
370 - def schema(self):
371 return self.definitions.schema
372
373 - def local(self):
374 return ( self.definitions.schema is None )
375
376 - def imported(self):
377 return ( not self.local() )
378
379 - def __gt__(self, other):
380 return isinstance(other, Import)
381
382 383 -class Part(NamedObject):
384 """ 385 Represents <message><part/></message>. 386 @ivar element: The value of the {element} attribute. 387 Stored as a I{qref} as converted by L{suds.xsd.qualify}. 388 @type element: str 389 @ivar type: The value of the {type} attribute. 390 Stored as a I{qref} as converted by L{suds.xsd.qualify}. 391 @type type: str 392 """ 393
394 - def __init__(self, root, definitions):
395 """ 396 @param root: An XML root element. 397 @type root: L{Element} 398 @param definitions: A definitions object. 399 @type definitions: L{Definitions} 400 """ 401 NamedObject.__init__(self, root, definitions) 402 pmd = Metadata() 403 pmd.wrappers = dict(element=repr, type=repr) 404 self.__metadata__.__print__ = pmd 405 tns = definitions.tns 406 self.element = self.__getref('element', tns) 407 self.type = self.__getref('type', tns)
408
409 - def __getref(self, a, tns):
410 """ Get the qualified value of attribute named 'a'.""" 411 s = self.root.get(a) 412 if s is None: 413 return s 414 else: 415 return qualify(s, self.root, tns)
416
417 418 -class Message(NamedObject):
419 """ 420 Represents <message/>. 421 @ivar parts: A list of message parts. 422 @type parts: [I{Part},...] 423 """ 424
425 - def __init__(self, root, definitions):
426 """ 427 @param root: An XML root element. 428 @type root: L{Element} 429 @param definitions: A definitions object. 430 @type definitions: L{Definitions} 431 """ 432 NamedObject.__init__(self, root, definitions) 433 self.parts = [] 434 for p in root.getChildren('part'): 435 part = Part(p, definitions) 436 self.parts.append(part)
437
438 - def __gt__(self, other):
439 return isinstance(other, (Import, Types))
440
441 442 -class PortType(NamedObject):
443 """ 444 Represents <portType/>. 445 @ivar operations: A list of contained operations. 446 @type operations: list 447 """ 448
449 - def __init__(self, root, definitions):
450 """ 451 @param root: An XML root element. 452 @type root: L{Element} 453 @param definitions: A definitions object. 454 @type definitions: L{Definitions} 455 """ 456 NamedObject.__init__(self, root, definitions) 457 self.operations = {} 458 for c in root.getChildren('operation'): 459 op = Facade('Operation') 460 op.name = c.get('name') 461 op.tns = definitions.tns 462 input = c.getChild('input') 463 if input is None: 464 op.input = None 465 else: 466 op.input = input.get('message') 467 output = c.getChild('output') 468 if output is None: 469 op.output = None 470 else: 471 op.output = output.get('message') 472 faults = [] 473 for fault in c.getChildren('fault'): 474 f = Facade('Fault') 475 f.name = fault.get('name') 476 f.message = fault.get('message') 477 faults.append(f) 478 op.faults = faults 479 self.operations[op.name] = op
480
481 - def resolve(self, definitions):
482 """ 483 Resolve named references to other WSDL objects. 484 @param definitions: A definitions object. 485 @type definitions: L{Definitions} 486 """ 487 for op in self.operations.values(): 488 if op.input is None: 489 op.input = Message(Element('no-input'), definitions) 490 else: 491 qref = qualify(op.input, self.root, definitions.tns) 492 msg = definitions.messages.get(qref) 493 if msg is None: 494 raise Exception("msg '%s', not-found" % op.input) 495 else: 496 op.input = msg 497 if op.output is None: 498 op.output = Message(Element('no-output'), definitions) 499 else: 500 qref = qualify(op.output, self.root, definitions.tns) 501 msg = definitions.messages.get(qref) 502 if msg is None: 503 raise Exception("msg '%s', not-found" % op.output) 504 else: 505 op.output = msg 506 for f in op.faults: 507 qref = qualify(f.message, self.root, definitions.tns) 508 msg = definitions.messages.get(qref) 509 if msg is None: 510 raise Exception, "msg '%s', not-found" % f.message 511 f.message = msg
512
513 - def operation(self, name):
514 """ 515 Shortcut used to get a contained operation by name. 516 @param name: An operation name. 517 @type name: str 518 @return: The named operation. 519 @rtype: Operation 520 @raise L{MethodNotFound}: When not found. 521 """ 522 try: 523 return self.operations[name] 524 except Exception, e: 525 raise MethodNotFound(name)
526
527 - def __gt__(self, other):
528 return isinstance(other, (Import, Types, Message))
529
530 531 -class Binding(NamedObject):
532 """ 533 Represents <binding/> 534 @ivar operations: A list of contained operations. 535 @type operations: list 536 """ 537
538 - def __init__(self, root, definitions):
539 """ 540 @param root: An XML root element. 541 @type root: L{Element} 542 @param definitions: A definitions object. 543 @type definitions: L{Definitions} 544 """ 545 NamedObject.__init__(self, root, definitions) 546 self.operations = {} 547 self.type = root.get('type') 548 sr = self.soaproot() 549 if sr is None: 550 self.soap = None 551 log.debug('binding: "%s" not a soap binding', self.name) 552 return 553 soap = Facade('soap') 554 self.soap = soap 555 self.soap.style = sr.get('style', default='document') 556 self.add_operations(self.root, definitions)
557
558 - def soaproot(self):
559 """ get the soap:binding """ 560 for ns in (soapns, soap12ns): 561 sr = self.root.getChild('binding', ns=ns) 562 if sr is not None: 563 return sr 564 return None
565
566 - def add_operations(self, root, definitions):
567 """ Add <operation/> children """ 568 dsop = Element('operation', ns=soapns) 569 for c in root.getChildren('operation'): 570 op = Facade('Operation') 571 op.name = c.get('name') 572 sop = c.getChild('operation', default=dsop) 573 soap = Facade('soap') 574 soap.action = '"%s"' % sop.get('soapAction', default='') 575 soap.style = sop.get('style', default=self.soap.style) 576 soap.input = Facade('Input') 577 soap.input.body = Facade('Body') 578 soap.input.headers = [] 579 soap.output = Facade('Output') 580 soap.output.body = Facade('Body') 581 soap.output.headers = [] 582 op.soap = soap 583 input = c.getChild('input') 584 if input is None: 585 input = Element('input', ns=wsdlns) 586 body = input.getChild('body') 587 self.body(definitions, soap.input.body, body) 588 for header in input.getChildren('header'): 589 self.header(definitions, soap.input, header) 590 output = c.getChild('output') 591 if output is None: 592 output = Element('output', ns=wsdlns) 593 body = output.getChild('body') 594 self.body(definitions, soap.output.body, body) 595 for header in output.getChildren('header'): 596 self.header(definitions, soap.output, header) 597 faults = [] 598 for fault in c.getChildren('fault'): 599 sf = fault.getChild('fault') 600 if sf is None: 601 continue 602 fn = fault.get('name') 603 f = Facade('Fault') 604 f.name = sf.get('name', default=fn) 605 f.use = sf.get('use', default='literal') 606 faults.append(f) 607 soap.faults = faults 608 self.operations[op.name] = op
609
610 - def body(self, definitions, body, root):
611 """ add the input/output body properties """ 612 if root is None: 613 body.use = 'literal' 614 body.namespace = definitions.tns 615 body.parts = () 616 return 617 parts = root.get('parts') 618 if parts is None: 619 body.parts = () 620 else: 621 body.parts = re.split('[\s,]', parts) 622 body.use = root.get('use', default='literal') 623 ns = root.get('namespace') 624 if ns is None: 625 body.namespace = definitions.tns 626 else: 627 prefix = root.findPrefix(ns, 'b0') 628 body.namespace = (prefix, ns)
629
630 - def header(self, definitions, parent, root):
631 """ add the input/output header properties """ 632 if root is None: 633 return 634 header = Facade('Header') 635 parent.headers.append(header) 636 header.use = root.get('use', default='literal') 637 ns = root.get('namespace') 638 if ns is None: 639 header.namespace = definitions.tns 640 else: 641 prefix = root.findPrefix(ns, 'h0') 642 header.namespace = (prefix, ns) 643 msg = root.get('message') 644 if msg is not None: 645 header.message = msg 646 part = root.get('part') 647 if part is not None: 648 header.part = part
649
650 - def resolve(self, definitions):
651 """ 652 Resolve named references to other WSDL objects. This includes 653 cross-linking information (from) the portType (to) the I{soap} 654 protocol information on the binding for each operation. 655 @param definitions: A definitions object. 656 @type definitions: L{Definitions} 657 """ 658 self.resolveport(definitions) 659 for op in self.operations.values(): 660 self.resolvesoapbody(definitions, op) 661 self.resolveheaders(definitions, op) 662 self.resolvefaults(definitions, op)
663
664 - def resolveport(self, definitions):
665 """ 666 Resolve port_type reference. 667 @param definitions: A definitions object. 668 @type definitions: L{Definitions} 669 """ 670 ref = qualify(self.type, self.root, definitions.tns) 671 port_type = definitions.port_types.get(ref) 672 if port_type is None: 673 raise Exception("portType '%s', not-found" % self.type) 674 else: 675 self.type = port_type
676
677 - def resolvesoapbody(self, definitions, op):
678 """ 679 Resolve soap body I{message} parts by 680 cross-referencing with operation defined in port type. 681 @param definitions: A definitions object. 682 @type definitions: L{Definitions} 683 @param op: An I{operation} object. 684 @type op: I{operation} 685 """ 686 ptop = self.type.operation(op.name) 687 if ptop is None: 688 raise Exception, \ 689 "operation '%s' not defined in portType" % op.name 690 soap = op.soap 691 parts = soap.input.body.parts 692 if len(parts): 693 pts = [] 694 for p in ptop.input.parts: 695 if p.name in parts: 696 pts.append(p) 697 soap.input.body.parts = pts 698 else: 699 soap.input.body.parts = ptop.input.parts 700 parts = soap.output.body.parts 701 if len(parts): 702 pts = [] 703 for p in ptop.output.parts: 704 if p.name in parts: 705 pts.append(p) 706 soap.output.body.parts = pts 707 else: 708 soap.output.body.parts = ptop.output.parts
709
710 - def resolveheaders(self, definitions, op):
711 """ 712 Resolve soap header I{message} references. 713 @param definitions: A definitions object. 714 @type definitions: L{Definitions} 715 @param op: An I{operation} object. 716 @type op: I{operation} 717 """ 718 soap = op.soap 719 headers = soap.input.headers + soap.output.headers 720 for header in headers: 721 mn = header.message 722 ref = qualify(mn, self.root, definitions.tns) 723 message = definitions.messages.get(ref) 724 if message is None: 725 raise Exception, "message'%s', not-found" % mn 726 pn = header.part 727 for p in message.parts: 728 if p.name == pn: 729 header.part = p 730 break 731 if pn == header.part: 732 raise Exception, \ 733 "message '%s' has not part named '%s'" % (ref, pn)
734
735 - def resolvefaults(self, definitions, op):
736 """ 737 Resolve soap fault I{message} references by 738 cross-referencing with operation defined in port type. 739 @param definitions: A definitions object. 740 @type definitions: L{Definitions} 741 @param op: An I{operation} object. 742 @type op: I{operation} 743 """ 744 ptop = self.type.operation(op.name) 745 if ptop is None: 746 raise Exception, \ 747 "operation '%s' not defined in portType" % op.name 748 soap = op.soap 749 for fault in soap.faults: 750 for f in ptop.faults: 751 if f.name == fault.name: 752 fault.parts = f.message.parts 753 continue 754 if hasattr(fault, 'parts'): 755 continue 756 raise Exception, \ 757 "fault '%s' not defined in portType '%s'" % (fault.name, self.type.name)
758
759 - def operation(self, name):
760 """ 761 Shortcut used to get a contained operation by name. 762 @param name: An operation name. 763 @type name: str 764 @return: The named operation. 765 @rtype: Operation 766 @raise L{MethodNotFound}: When not found. 767 """ 768 try: 769 return self.operations[name] 770 except: 771 raise MethodNotFound(name)
772
773 - def __gt__(self, other):
774 return ( not isinstance(other, Service) )
775
776 777 -class Port(NamedObject):
778 """ 779 Represents a service port. 780 @ivar service: A service. 781 @type service: L{Service} 782 @ivar binding: A binding name. 783 @type binding: str 784 @ivar location: The service location (url). 785 @type location: str 786 """ 787
788 - def __init__(self, root, definitions, service):
789 """ 790 @param root: An XML root element. 791 @type root: L{Element} 792 @param definitions: A definitions object. 793 @type definitions: L{Definitions} 794 @param service: A service object. 795 @type service: L{Service} 796 """ 797 NamedObject.__init__(self, root, definitions) 798 self.__service = service 799 self.binding = root.get('binding') 800 address = root.getChild('address') 801 if address is None: 802 self.location = None 803 else: 804 self.location = address.get('location').encode('utf-8') 805 self.methods = {}
806
807 - def method(self, name):
808 """ 809 Get a method defined in this portType by name. 810 @param name: A method name. 811 @type name: str 812 @return: The requested method object. 813 @rtype: I{Method} 814 """ 815 return self.methods.get(name)
816
817 818 -class Service(NamedObject):
819 """ 820 Represents <service/>. 821 @ivar port: The contained ports. 822 @type port: [Port,..] 823 @ivar methods: The contained methods for all ports. 824 @type methods: [Method,..] 825 """ 826
827 - def __init__(self, root, definitions):
828 """ 829 @param root: An XML root element. 830 @type root: L{Element} 831 @param definitions: A definitions object. 832 @type definitions: L{Definitions} 833 """ 834 NamedObject.__init__(self, root, definitions) 835 self.ports = [] 836 for p in root.getChildren('port'): 837 port = Port(p, definitions, self) 838 self.ports.append(port)
839
840 - def port(self, name):
841 """ 842 Locate a port by name. 843 @param name: A port name. 844 @type name: str 845 @return: The port object. 846 @rtype: L{Port} 847 """ 848 for p in self.ports: 849 if p.name == name: 850 return p 851 return None
852
853 - def setlocation(self, url, names=None):
854 """ 855 Override the invocation location (url) for service method. 856 @param url: A url location. 857 @type url: A url. 858 @param names: A list of method names. None=ALL 859 @type names: [str,..] 860 """ 861 for p in self.ports: 862 for m in p.methods.values(): 863 if names is None or m.name in names: 864 m.location = url
865
866 - def resolve(self, definitions):
867 """ 868 Resolve named references to other WSDL objects. 869 Ports without soap bindings are discarded. 870 @param definitions: A definitions object. 871 @type definitions: L{Definitions} 872 """ 873 filtered = [] 874 for p in self.ports: 875 ref = qualify(p.binding, self.root, definitions.tns) 876 binding = definitions.bindings.get(ref) 877 if binding is None: 878 raise Exception("binding '%s', not-found" % p.binding) 879 if binding.soap is None: 880 log.debug('binding "%s" - not a soap, discarded', binding.name) 881 continue 882 p.binding = binding 883 filtered.append(p) 884 self.ports = filtered
885
886 - def __gt__(self, other):
887 return True
888
889 890 -class Factory:
891 """ 892 Simple WSDL object factory. 893 @cvar tags: Dictionary of tag->constructor mappings. 894 @type tags: dict 895 """ 896 897 tags =\ 898 { 899 'import' : Import, 900 'types' : Types, 901 'message' : Message, 902 'portType' : PortType, 903 'binding' : Binding, 904 'service' : Service, 905 } 906 907 @classmethod
908 - def create(cls, root, definitions):
909 """ 910 Create an object based on the root tag name. 911 @param root: An XML root element. 912 @type root: L{Element} 913 @param definitions: A definitions object. 914 @type definitions: L{Definitions} 915 @return: The created object. 916 @rtype: L{WObject} 917 """ 918 fn = cls.tags.get(root.name) 919 if fn is not None: 920 return fn(root, definitions) 921 else: 922 return None
923