Question #219424 on ladon changed: https://answers.launchpad.net/ladon/+question/219424
GaryS posted a new comment: I have developed a new interface which solves the problem - this seems to work with java-ws clients and .net clients I have tested it with. I called it soapws: # -*- coding: utf-8 -*- from ladon.interfaces.base import BaseInterface,ServiceDescriptor,BaseRequestHandler,BaseResponseHandler,BaseFaultHandler from ladon.interfaces import expose from ladon.compat import PORTABLE_STRING,type_to_xsd,pytype_support,BytesIO from xml.sax.handler import ContentHandler,feature_namespaces from xml.sax import make_parser from xml.sax.xmlreader import InputSource import sys,re,traceback import logging LOG = logging.getLogger(__name__) rx_nil_attr = re.compile(PORTABLE_STRING('^\w*[:]{0,1}nil$'),re.I) class SOAPWSServiceDescriptor(ServiceDescriptor): xsd_type_map = type_to_xsd _content_type = 'text/xml' def generate(self,servicename,servicenumber,typemanager,methodlist,service_url,encoding): """ Generate WSDL file for SOAPWSInterface """ type_dict = typemanager.type_dict type_order = typemanager.type_order def map_type(typ): if typ in SOAPWSServiceDescriptor.xsd_type_map: return SOAPWSServiceDescriptor.xsd_type_map[typ] else: return typ.__name__ def map_type2(typ): if typ in SOAPWSServiceDescriptor.xsd_type_map: tmpval = SOAPWSServiceDescriptor.xsd_type_map[typ] if tmpval == 'decimal': tmpval = 'float' return tmpval else: return typ.__name__ import xml.dom.minidom as md doc = md.Document() # SERVICE DEFINITION # Create the definitions element for the service definitions = doc.createElement('definitions') definitions.setAttribute('xmlns:wsu','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd') definitions.setAttribute('xmlns:wsp','http://www.w3.org/ns/ws-policy') definitions.setAttribute('xmlns:wsp1_2','http://schemas.xmlsoap.org/ws/2004/09/policy') definitions.setAttribute('xmlns:wsam','http://www.w3.org/2007/05/addressing/metadata') definitions.setAttribute('xmlns:soap','http://schemas.xmlsoap.org/wsdl/soap/') definitions.setAttribute('name', servicename) definitions.setAttribute('targetNamespace','urn:%s' % servicename) definitions.setAttribute('xmlns:tns','urn:%s' % servicename) definitions.setAttribute('xmlns','http://schemas.xmlsoap.org/wsdl/') definitions.setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance') definitions.setAttribute('xmlns:xsd','http://www.w3.org/2001/XMLSchema') definitions.setAttribute('xmlns:ns%d' % servicenumber,'urn:%s' % servicename) doc.appendChild(definitions) # TYPES # The types element types = doc.createElement('types') definitions.appendChild(types) # Service schema for types required by the target namespace we defined in the definition element schema = doc.createElement('xsd:schema') schema.setAttribute('targetNamespace','urn:%s' % servicename) schema.setAttribute('xmlns:xs','http://www.w3.org/2001/XMLSchema') schema.setAttribute('xmlns:ns%d' % servicenumber,'urn:%s' % servicename) schema.setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance') schema.setAttribute('xmlns:xsd','http://www.w3.org/2001/XMLSchema') types.appendChild(schema) # Define types, the type_order variable holds all that need to be defined and in the # correct order. for m in methodlist: basictype = doc.createElement('xs:element') basictype.setAttribute('name',m.name()) basictype.setAttribute('type','tns:%s' % m.name()) schema.appendChild(basictype) basictypeR = doc.createElement('xs:element') basictypeR.setAttribute('name',"%sResponse" % m.name()) basictypeR.setAttribute('type','tns:%sResponse' % m.name()) schema.appendChild(basictypeR) for m in methodlist: complextype = doc.createElement('xs:complexType') complextype.setAttribute('name',m.name()) schema.appendChild(complextype) sequence = doc.createElement('xs:sequence') complextype.appendChild(sequence) for arg in m.args(): v = arg['type'] element = doc.createElement('xs:element') element.setAttribute('name',arg['name'].replace('_','-')) element.setAttribute('minOccurs','0') if isinstance(v, list): inner = v[0] if inner in type_dict: element.setAttribute('type','tns:%s' % inner.__name__) else: element.setAttribute('type','xs:%s' % map_type2(inner)) element.setAttribute('maxOccurs','unbounded') if not(isinstance(v, list)): if v in type_dict: element.setAttribute('type','tns:%s' % v.__name__) else: element.setAttribute('type','xs:%s' % map_type2(v)) sequence.appendChild(element) complextype = doc.createElement('xs:complexType') complextype.setAttribute('name',"%sResponse" % m.name()) schema.appendChild(complextype) sequence = doc.createElement('xs:sequence') complextype.appendChild(sequence) v = m._rtype element = doc.createElement('xs:element') element.setAttribute('name','return') element.setAttribute('minOccurs','0') if isinstance(v, list): inner = v[0] if inner in type_dict: element.setAttribute('type','tns:%s' % inner.__name__) element.setAttribute('maxOccurs','unbounded') else: element.setAttribute('type','xs:%s' % map_type2(inner)) element.setAttribute('maxOccurs','unbounded') element.setAttribute('minOccurs','0') if not(isinstance(v, list)): if v in type_dict: element.setAttribute('type','tns:%s' % v.__name__) else: element.setAttribute('type','xs:%s' % map_type2(v)) sequence.appendChild(element) #special types for typ in type_order: if not(isinstance(typ, list)): complextype = doc.createElement('xs:complexType') complextype.setAttribute('name',typ['name']) schema.appendChild(complextype) sequence = doc.createElement('xs:sequence') complextype.appendChild(sequence) for k,v,props in typ['attributes']: element = doc.createElement('xs:element') element.setAttribute('name',k.replace('_','-')) element.setAttribute('maxOccurs','1') element.setAttribute('minOccurs','1') if props.get('nullable')==True: element.setAttribute('minOccurs','0') element.setAttribute('nillable','true') if isinstance(v, list): inner = v[0] #element.setAttribute('type','tns:%s' % map_type2(inner)) if inner in type_dict: element.setAttribute('type','tns:%s' % inner.__name__) else: element.setAttribute('type','xs:%s' % map_type2(inner)) #inner.__name__) element.setAttribute('minOccurs','0') element.setAttribute('maxOccurs','unbounded') element.setAttribute('nillable','true') #element.setAttribute('type','tns:%s' % type(v[0])) if not(isinstance(v, list)): if v in type_dict: element.setAttribute('type','tns:%s' % v.__name__) else: element.setAttribute('type','xs:%s' % map_type2(v)) sequence.appendChild(element) #messages for m in methodlist: message = doc.createElement('message') message.setAttribute('name',m.name()) definitions.appendChild(message) part = doc.createElement('part') part.setAttribute('name','parameters') part.setAttribute('element',"tns:%s" % m.name()) message.appendChild(part) message = doc.createElement('message') message.setAttribute('name',"%sResponse" % m.name()) definitions.appendChild(message) part2 = doc.createElement('part') part2.setAttribute('name','parameters') part2.setAttribute('element',"tns:%sResponse" % m.name()) message.appendChild(part2) porttype = doc.createElement('portType') porttype.setAttribute('name','%sPortType' % servicename) definitions.appendChild(porttype) #operations for m in methodlist: operation = doc.createElement('operation') operation.setAttribute('name',m.name()) porttype.appendChild(operation) if m.__doc__: documentation = doc.createElement('documentation') documentation.appendChild(doc.createTextNode(m.__doc__)) operation.appendChild(documentation) input_tag = doc.createElement('input') input_tag.setAttribute('wsam:Action',"%s/%s" % (service_url,m.name())) input_tag.setAttribute('message','tns:%s' % m.name()) operation.appendChild(input_tag) output_tag = doc.createElement('output') output_tag.setAttribute('wsam:Action',"%s/%sResponse" % (service_url,m.name())) output_tag.setAttribute('message','tns:%sResponse' % m.name()) operation.appendChild(output_tag) #binding binding = doc.createElement('binding') binding.setAttribute('name',servicename) binding.setAttribute('type',"tns:%sPortType" % servicename) transport = doc.createElement('soap:binding') transport.setAttribute('transport','http://schemas.xmlsoap.org/soap/http') transport.setAttribute('style','document') binding.appendChild(transport) definitions.appendChild(binding) for m in methodlist: operation = doc.createElement('operation') operation.setAttribute('name',m.name()) binding.appendChild(operation) soapaction = doc.createElement('soap:operation') soapaction.setAttribute('soapAction','') operation.appendChild(soapaction) m._multipart_response_required input_tag = doc.createElement('input') body_parent = input_tag if m._multipart_request_required: multipart_related = doc.createElement('mime:multipartRelated') mime_body_part = doc.createElement('mime:part') body_parent = mime_body_part mime_content_part = doc.createElement('mime:part') mime_content = doc.createElement('mime:content') mime_content.setAttribute('type','*/*') input_tag.appendChild(multipart_related) multipart_related.appendChild(mime_body_part) multipart_related.appendChild(mime_content_part) mime_content_part.appendChild(mime_content) input_soapbody = doc.createElement('soap:body') input_soapbody.setAttribute('use','literal') body_parent.appendChild(input_soapbody) operation.appendChild(input_tag) output_tag = doc.createElement('output') body_parent = output_tag if m._multipart_request_required: multipart_related = doc.createElement('mime:multipartRelated') mime_body_part = doc.createElement('mime:part') body_parent = mime_body_part mime_content_part = doc.createElement('mime:part') mime_content = doc.createElement('content:part') mime_content.setAttribute('type','*/*') output_tag.appendChild(multipart_related) multipart_related.appendChild(mime_body_part) multipart_related.appendChild(mime_content_part) mime_content_part.appendChild(mime_content) output_soapbody = doc.createElement('soap:body') output_soapbody.setAttribute('use','literal') body_parent.appendChild(output_soapbody) operation.appendChild(output_tag) service = doc.createElement('service') service.setAttribute('name',servicename) documentation = doc.createElement('documentation') documentation.appendChild(doc.createTextNode('Ladon generated service definition')) service.appendChild(documentation) port = doc.createElement('port') port.setAttribute('name',servicename) port.setAttribute('binding','tns:%s' % servicename) service.appendChild(port) address = doc.createElement('soap:address') address.setAttribute('location',service_url) port.appendChild(address) definitions.appendChild(service) if sys.version_info[0]>=3: return doc.toxml() return doc.toxml(encoding) def u(instring): if sys.version_info[0]==2: return PORTABLE_STRING(instring,'utf-8') else: return PORTABLE_STRING(instring) class ContainerSetRef(object): def __init__(self,c,refval): self.c = c self.refval = refval def set(self,val): self.c[self.refval] = val class SOAPWSRequestHandler(BaseRequestHandler): def parse_request(self,soap_body,sinfo,encoding): import xml.dom.minidom as md self.sinfo = sinfo doc = md.parseString(soap_body) soap_envelope = doc.getElementsByTagNameNS('*','Envelope')[0] soap_body = doc.getElementsByTagNameNS('*','Body')[0] EN = soap_body.ELEMENT_NODE soap_method = (node for node in soap_body.childNodes if node.nodeType == EN).next() soap_methodprefix = soap_method.prefix try: m = re.match("^ns(\d+)$",soap_methodprefix) except: m = None servicenumber = None if m: servicenumber = int(m.groups()[0]) self.soap_methodname = soap_method.localName soap_args = {'methodname': self.soap_methodname,'servicenumber':servicenumber} #for typ in self.sinfo.typemanager.type_order: # if not(isinstance(typ, list)): # self.appendToMyLog(typ) TN = soap_method.TEXT_NODE soap_args['args'] = self.getDictForNode(soap_method) #self.appendToMyLog('soap_args is %s' % soap_args) return soap_args def getDictForNode(self, node): localDict={} for n in node.childNodes: if n.nodeType == n.ELEMENT_NODE and not n.hasAttribute('xsi:nil'): if self.isTagList(n.nodeName): lon = self.getListItems(n,node) tList = [] for nn in lon: tList.append(self.getDictForNode(nn)) node.removeChild(nn) localDict[n.nodeName]= tList else: localDict[n.nodeName]=self.getDictForNode(n) elif n.nodeType==n.TEXT_NODE and not n.hasChildNodes() and node.childNodes.length==1: return n.nodeValue elif n.nodeType==n.CDATA_SECTION_NODE: return n.nodeValue return localDict def isTagList(self, tagnm): for typ in self.sinfo.typemanager.type_order: #self.appendToMyLog(typ) a=1 try: a=1 if not isinstance(typ, list): for k,v,props in typ['attributes']: if tagnm == k and isinstance(v,list): return True except: a=2 for m in self.sinfo.method_list(): #self.appendToMyLog(m) #self.appendToMyLog(m.name()) for arg in m.args(): v = arg['type'] if self.soap_methodname == m.name() and arg['name'] == tagnm and isinstance(v,list): #self.appendToMyLog("%s is list!!" % m.name()) return True #if isinstance(m['rtype'], list): # self.appendToMyLog(m['rtype']) # return True return False def getListItems(self, node, parent): tagList=[] for n in parent.childNodes: if n.nodeName==node.nodeName: tagList.append(n) return tagList def appendToMyLog(self, s): f1=open('/home/ye91009/logs/testfile', 'a') print >> f1, s f1.close() class SOAPWSResponseHandler(BaseResponseHandler): _content_type = 'text/xml' _stringify_res_dict = True def dictToList(self,dd): #convert dictionary to list i fpossible, to ensure order in type_order is preserved to giev valid xml export format retList=[] for typ in self.sinfo.typemanager.type_order: if not(isinstance(typ, list)): ld={} for k,v,props in typ['attributes']: ld[k]=None if set(ld)==set(dd): for k,v,props in typ['attributes']: retList.append(k) self.appendToMyLog(retList) return retList for k,v in dd.items(): retList.append(k) return retList def value_to_soapxml(self,value,parent,doc,is_toplevel=False): if isinstance(value, dict): locList = self.dictToList(value) self.appendToMyLog(value) for aname in locList: #for attr_name,attr_val in value.items(): #self.appendToMyLog(aname) attr_name = aname attr_val = value[aname] xml_attr_name = attr_name.replace('_','-') if isinstance(attr_val, (list,tuple)): for item in attr_val: attr_elem = doc.createElement(xml_attr_name) if is_toplevel: attr_elem = doc.createElement('return') parent.appendChild(attr_elem) self.value_to_soapxml(item,attr_elem,doc) else: attr_elem = doc.createElement(xml_attr_name) if is_toplevel: attr_elem = doc.createElement('return') parent.appendChild(attr_elem) self.value_to_soapxml(attr_val,attr_elem,doc) else: if is_toplevel: value_parent = doc.createElement('return') value_parent.setAttribute('dodo','http://schemas.xmlsoap.org/soap/encoding/') parent.appendChild(value_parent) else: value_parent = parent if isinstance(value, (list, tuple)): if not len(value): # Translate empty response arrays to SOAP Null (xsi:nil) value value_parent.setAttribute('xsi:nil','true') else: for item in value: item_element = doc.createElement(value_parent.nodeName) self.value_to_soapxml(item,item_element,doc) value_parent.appendChild(item_element) else: if value==None: # Set xsi:nil to true if value is None value_parent.setAttribute('xsi:nil','true') else: value_parent.appendChild(doc.createTextNode(value)) def build_response(self,res_dict,sinfo,encoding): import xml.dom.minidom as md self.sinfo=sinfo doc = md.Document() envelope = doc.createElement('SOAP-ENV:Envelope') envelope.setAttribute('xmlns:SOAP-ENV','http://schemas.xmlsoap.org/soap/envelope/') envelope.setAttribute('xmlns:SOAP-ENC','http://schemas.xmlsoap.org/soap/encoding/') envelope.setAttribute('xmlns:xsd','http://www.w3.org/2001/XMLSchema') envelope.setAttribute('xmlns:ns','urn:%s' % res_dict['servicename']) envelope.setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance') doc.appendChild(envelope) body_elem = doc.createElement('SOAP-ENV:Body') body_elem.setAttribute('SOAP-ENV:encodingStyle','http://schemas.xmlsoap.org/soap/encoding/') envelope.appendChild(body_elem) method_elem = doc.createElement("tns:%sResponse" % res_dict['method']) method_elem.setAttribute('xmlns:tns','urn:%s' % res_dict['servicename']) #self.appendToMyLog(res_dict) if 'result' in res_dict['result']: self.value_to_soapxml(res_dict['result'],method_elem,doc,is_toplevel=True) else: self.value_to_soapxml({'result':res_dict['result']},method_elem,doc,is_toplevel=True) body_elem.appendChild(method_elem) return doc.toxml(encoding=encoding) def appendToMyLog(self, s): f1=open('/home/ye91009/logs/testfile', 'a') print >> f1, s f1.close() class SOAPWSFaultHandler(BaseFaultHandler): _content_type = 'text/xml' _stringify_res_dict = True soapfault_template = """<?xml version='1.0' encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode xsi:type="xsd:string"></faultcode> <faultstring xsi:type="xsd:string"></faultstring> <detail></detail> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope>""" def build_fault_response(self,service_exc,sinfo,methodname,encoding): import xml.dom.minidom as md if service_exc.detail: detail = service_exc.detail else: detail = traceback.format_exc() d = md.parseString(self.soapfault_template) # Extract fault DOM elements faultcode_elem = d.getElementsByTagName('faultcode')[0] faultstring_elem = d.getElementsByTagName('faultstring')[0] detail_elem = d.getElementsByTagName('detail')[0] # Set the fault values faultcode_elem.appendChild(d.createTextNode(service_exc.faultcode)) faultstring_elem.appendChild(d.createTextNode(service_exc.faultstring)) detail_elem.appendChild(d.createTextNode(detail)) # Return the SoapFault XML object return d.toxml(encoding=encoding) @expose class SOAPWSInterface(BaseInterface): def __init__(self,sinfo,**kw): def_kw = { 'service_descriptor': SOAPWSServiceDescriptor, 'request_handler': SOAPWSRequestHandler, 'response_handler': SOAPWSResponseHandler, 'fault_handler': SOAPWSFaultHandler} def_kw.update(kw) BaseInterface.__init__(self,sinfo,**def_kw) @staticmethod def _interface_name(): return 'soapws' @staticmethod def _accept_basetype(typ): return pytype_support.count(typ)>0 @staticmethod def _accept_list(): return True @staticmethod def _accept_dict(): return False -- You received this question notification because you are a member of Ladon Developer, which is an answer contact for ladon. -- Mailing list: https://launchpad.net/~ladon-dev-team Post to : ladon-dev-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~ladon-dev-team More help : https://help.launchpad.net/ListHelp