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

Reply via email to