Пример #1
0
    def add_to_schema(self, schema_dict, nsmap):
        typ = self.get_datatype()

        self.serializer.add_to_schema(schema_dict, nsmap)

        if not typ in schema_dict:

            complexTypeNode = create_xml_element(
                nsmap.get('xs') + 'complexType', nsmap)
            complexTypeNode.set('name', self.get_datatype())

            sequenceNode = create_xml_subelement(
                complexTypeNode, nsmap.get('xs') + 'sequence')
            elementNode = create_xml_subelement(
                sequenceNode, nsmap.get('xs') + 'element')
            elementNode.set('minOccurs', '0')
            elementNode.set('maxOccurs', 'unbounded')
            elementNode.set('type',
                "%s:%s" % (self.serializer.get_namespace_id(), self.serializer.get_datatype()))
            elementNode.set('name', self.item_name) #changed to item_name

            typeElement = create_xml_element(
                nsmap.get('xs') + 'element', nsmap)
            typeElement.set('name', typ)
            typeElement.set('type',
                "%s:%s" % (self.namespace_id, self.get_datatype()))

            schema_dict['%sElement' % (self.get_datatype(nsmap))] = typeElement
            schema_dict[self.get_datatype(nsmap)] = complexTypeNode
Пример #2
0
    def _add_messages_for_methods(self, root, methods, nsmap):
        '''
        A private method for adding message elements to the wsdl
        @param the the root element of the wsdl
        @param the list of methods.
        '''
        messages = []
        #make messages
        for method in methods:
            methodName = method.name
            # making in part
            inMessage = create_xml_element('message', nsmap)
            inMessage.set('name', method.inMessage.typ)

            inPart = create_xml_subelement(inMessage, 'part')
            inPart.set('name', method.inMessage.name)
            inPart.set('element', 'tns:' + method.inMessage.typ)

            messages.append(inMessage)

            # making out part only if necessary
            if len(method.outMessage.params) > 0:
                outMessage = create_xml_element('message', nsmap)
                outMessage.set('name', method.outMessage.typ)
                outPart = create_xml_subelement(outMessage, 'part')
                outPart.set('name', method.outMessage.name)
                outPart.set('element', 'tns:' + method.outMessage.typ)
                messages.append(outMessage)

        for message in messages:
            root.append(message)
Пример #3
0
    def add_to_schema(cls, schemaDict, nsmap):
        if not cls.get_datatype(nsmap) in schemaDict:
            for k, v in cls.soap_members.items():
                v.add_to_schema(schemaDict, nsmap)

            schema_node = create_xml_element(
                nsmap.get("xs") + "complexType", nsmap)
            schema_node.set('name',cls.get_datatype())

            sequence_node = create_xml_subelement(
                schema_node, nsmap.get('xs') + 'sequence')
            for k, v in cls.soap_members.items():
                member_node = create_xml_subelement(
                    sequence_node, nsmap.get('xs') + 'element')
                member_node.set('name', k)
                member_node.set('minOccurs', '0')
                member_node.set('type',
                    "%s:%s" % (v.get_namespace_id(), v.get_datatype()))

            typeElement = create_xml_element(
                nsmap.get('xs') + 'element', nsmap)
            typeElement.set('name',cls.get_datatype())
            typeElement.set('type',
                "%s:%s" % (cls.get_namespace_id(),cls.get_datatype()))
            schemaDict[cls.get_datatype(nsmap)+'Complex'] = schema_node
            schemaDict[cls.get_datatype(nsmap)] = typeElement
Пример #4
0
def make_soap_envelope(message, tns='', header_elements=None):
    '''
    This method takes the results from a soap method call, and wraps them
    in the appropriate soap envelope with any specified headers

    @param the message of the soap envelope, either an element or
           a list of elements
    @param any header elements to be included in the soap response
    @returns the envelope element
    '''
    nsmap = NamespaceLookup(tns)
    envelope = create_xml_element(nsmap.get('SOAP-ENV') + 'Envelope', nsmap,
        tns)
    if header_elements:
        headerElement = create_xml_subelement(envelope,
            nsmap.get('SOAP-ENV') + 'Header')
        for h in header_elements:
            headerElement.append(h)
    body = create_xml_subelement(envelope, nsmap.get('SOAP-ENV') + 'Body')

    if type(message) == list:
        for m in message:
            body.append(m)
    elif message != None:
        body.append(message)

    return envelope
Пример #5
0
    def _add_schema(self, types, methods, nsmap):
        '''A private method for adding the appropriate entries
        to the schema for the types in the specified methods
        @param the schema node to add the schema elements to
        @param the list of methods.
        '''
        schema_entries = {}
        for method in methods:
            params = method.inMessage.params
            returns = method.outMessage.params

            for name, param in params:
                param.add_to_schema(schema_entries, nsmap)

            if returns:
                returns[0][1].add_to_schema(schema_entries, nsmap)

            method.inMessage.add_to_schema(schema_entries, nsmap)
            method.outMessage.add_to_schema(schema_entries, nsmap)


        schemaNode = create_xml_subelement(types, "schema")
        schemaNode.set("targetNamespace", self.__tns__)
        schemaNode.set("xmlns", "http://www.w3.org/2001/XMLSchema")
        schemaNode.set("elementFormDefault", "qualified")

        for xxx, node in schema_entries.items():
            schemaNode.append(node)

        return schemaNode
Пример #6
0
    def add_to_schema(cls, schema_dict, nsmap):
        complexTypeNode = create_xml_element('complexType', nsmap)
        complexTypeNode.set('name', cls.get_datatype())
        sequenceNode = create_xml_subelement(complexTypeNode, 'sequence')
        faultTypeElem = create_xml_subelement(sequenceNode, 'element')
        faultTypeElem.set('name', 'detail')
        faultTypeElem.set(nsmap.get('xsi') + 'type', 'xs:string')
        faultTypeElem = create_xml_subelement(sequenceNode, 'element')
        faultTypeElem.set('name', 'message')
        faultTypeElem.set(nsmap.get('xsi') + 'type', 'xs:string')

        schema_dict[cls.get_datatype()] = complexTypeNode

        typeElementItem = create_xml_element('element', nsmap)
        typeElementItem.set('name', 'ExceptionFaultType')
        typeElementItem.set(nsmap.get('xsi') + 'type', cls.get_datatype(nsmap))
        schema_dict['%sElement' % (cls.get_datatype(nsmap))] = typeElementItem
Пример #7
0
def make_soap_fault(faultString, faultCode = 'Server', detail = None,
        header_elements = None):
    '''
    This method populates a soap fault message with the provided
    fault string and details.
    @param faultString the short description of the error
    @param detail the details of the exception, such as a stack trace
    @param faultCode defaults to 'Server', but can be overridden
    @param header_elements A list of XML elements to add to the fault header.
    @returns the element corresponding to the fault message
    '''
    nsmap = NamespaceLookup()
    envelope = create_xml_element(nsmap.get('SOAP-ENV') + 'Envelope', nsmap)
    if header_elements:
        header = create_xml_subelement(
            envelope, nsmap.get('SOAP-ENV') + 'Header')
        for element in header_elements:
            header.append(element)
    body = create_xml_subelement(envelope, nsmap.get('SOAP-ENV') + 'Body')
    f = Fault(faultCode, faultString, detail)
    body.append(Fault.to_xml(f, nsmap.get('SOAP-ENV') + "Fault", nsmap))
    return envelope
Пример #8
0
    def add_to_schema(self, schemaDict, nsmap):
        complexType = create_xml_element(nsmap.get('xs') + 'complexType',
            nsmap)
        complexType.set('name', self.typ)

        sequence = create_xml_subelement(complexType,
            nsmap.get('xs') + 'sequence')
        if self.params:
            for name, serializer in self.params:
                e = create_xml_subelement(sequence,
                    nsmap.get('xs') + 'element')
                e.set('name', name)
                e.set('type',
                    "%s:%s" % (serializer.get_namespace_id(),
                        serializer.get_datatype()))

            element = create_xml_element(nsmap.get('xs') + 'element', nsmap)
            element.set('name', self.typ)
            element.set('type', '%s:%s' % ('tns', self.typ))

            schemaDict[self.typ] = complexType
            schemaDict[self.typ + 'Element'] = element
Пример #9
0
    def _add_bindings_for_methods(self, root, serviceName, methods, nsmap):
        '''
        A private method for adding bindings to the wsdld
        @param the root element of the wsdl
        @param the name of this service
        @param the methods to be add to the binding node
        '''
        hasCallbacks = self._hasCallbacks()

        # make binding
        binding = create_xml_subelement(root, 'binding')
        binding.set('name', serviceName)
        binding.set('type', 'tns:%s'%serviceName)

        sbinding = create_xml_subelement(binding,
            nsmap.get('soap') + 'binding')
        sbinding.set('style', 'document')
        sbinding.set('transport', 'http://schemas.xmlsoap.org/soap/http')

        if hasCallbacks:
            callbackBinding = create_xml_subelement(root, 'binding')
            callbackBinding.set('name', '%sCallback' % serviceName)
            callbackBinding.set('type', 'typens:%sCallback' % serviceName)

            sbinding = create_xml_subelement(callbackBinding,
                nsmap.get('soap') + 'binding')
            sbinding.set('transport', 'http://schemas.xmlsoap.org/soap/http')

        for method in methods:
            operation = create_xml_element('operation', nsmap)
            operation.set('name', method.name)

            soapOperation = create_xml_subelement(operation,
                nsmap.get('soap') + 'operation')
            soapOperation.set('soapAction', method.soapAction)

            soapOperation.set('style', 'document')

            input = create_xml_subelement(operation, 'input')
            input.set('name', method.inMessage.typ)
            soapBody = create_xml_subelement(input, nsmap.get('soap') + 'body')
            soapBody.set('use', 'literal')

            if (len(method.outMessage.params) > 0 and
                not method.isAsync and not method.isCallback):
                output = create_xml_subelement(operation, 'output')
                output.set('name', method.outMessage.typ)
                soapBody = create_xml_subelement(output,
                    nsmap.get('soap') + 'body')
                soapBody.set('use', 'literal')

            if method.isCallback:
                relatesTo = create_xml_subelement(input,
                    nsmap.get('soap') + 'header')
                relatesTo.set('message', 'tns:RelatesToHeader')
                relatesTo.set('part', 'RelatesTo')
                relatesTo.set('use', 'literal')
                callbackBinding.append(operation)
            else:
                if method.isAsync:
                    rtHeader = create_xml_subelement(input,
                        nsmap.get('soap') + 'header')
                    rtHeader.set('message', 'tns:ReplyToHeader')
                    rtHeader.set('part', 'ReplyTo')
                    rtHeader.set('use', 'literal')

                    midHeader = create_xml_subelement(input,
                        nsmap.get('soap') + 'header')
                    midHeader.set('message', 'tns:MessageIDHeader')
                    midHeader.set('part', 'MessageID')
                    midHeader.set('use', 'literal')
                binding.append(operation)
Пример #10
0
    def wsdl(self, url):
        '''
        This method generates and caches the wsdl for this object based
        on the soap methods designated by the soapmethod or soapdocument
        descriptors
        @param url the url that this service can be found at.  This must be
        passed in by the caller because this object has no notion of the
        server environment in which it runs.
        @returns the string of the wsdl
        '''
        if not self.__wsdl__ == None:
            # return the cached __wsdl__
            return self.__wsdl__
        url = url.replace('.wsdl', '')
        # otherwise build it
        serviceName = self.__class__.__name__.split('.')[-1]

        tns = self.__tns__
        methods = self.methods()
        hasCallbacks = self._hasCallbacks()

        nsmap = NamespaceLookup(tns, True)
        if hasCallbacks:
            nsmap.set('wsa',
                'http://schemas.xmlsoap.org/ws/2003/03/addressing')

        root = create_xml_element(
            "definitions", nsmap, 'http://schemas.xmlsoap.org/wsdl/')
        root.set('targetNamespace', tns)
        root.set('name', serviceName)

        types = create_xml_subelement(root, "types")

        self._add_schema(types, methods, nsmap)
        self._add_messages_for_methods(root, methods, nsmap)

        # add necessary async headers
        # WS-Addressing -> RelatesTo ReplyTo MessageID
        # callback porttype
        if hasCallbacks:
            wsaSchemaNode = create_xml_subelement(types, "schema")
            wsaSchemaNode.set("targetNamespace", tns+'Callback')
            wsaSchemaNode.set("xmlns", "http://www.w3.org/2001/XMLSchema")
            wsaSchemaNode.set("elementFormDefault", "qualified")

            importNode = create_xml_subelement(wsaSchemaNode, "import")
            importNode.set("namespace",
                "http://schemas.xmlsoap.org/ws/2003/03/addressing")
            importNode.set("schemaLocation",
                "http://schemas.xmlsoap.org/ws/2003/03/addressing/")


            reltMessage = create_xml_subelement(root, 'message')
            reltMessage.set('name', 'RelatesToHeader')
            reltPart = create_xml_subelement(reltMessage, 'part')
            reltPart.set('name', 'RelatesTo')
            reltPart.set('element', 'wsa:RelatesTo')

            replyMessage = create_xml_subelement(root, 'message')
            replyMessage.set('name', 'ReplyToHeader')
            replyPart = create_xml_subelement(replyMessage, 'part')
            replyPart.set('name', 'ReplyTo')
            replyPart.set('element', 'wsa:ReplyTo')

            idHeader = create_xml_subelement(root, 'message')
            idHeader.set('name', 'MessageIDHeader')
            idPart = create_xml_subelement(idHeader, 'part')
            idPart.set('name', 'MessageID')
            idPart.set('element', 'wsa:MessageID')

            # make portTypes
            callbackPortType = create_xml_subelement(root, 'portType')
            callbackPortType.set('name', '%sCallback' % serviceName)

            cbServiceName = '%sCallback' % serviceName
            cbService = create_xml_subelement(root, 'service')
            cbService.set('name', cbServiceName)
            cbWsdlPort = create_xml_subelement(cbService, 'port')
            cbWsdlPort.set('name', cbServiceName)
            cbWsdlPort.set('binding', 'tns:%s' % cbServiceName)
            cbAddr = create_xml_subelement(cbWsdlPort,
                nsmap.get('soap') + 'address')
            cbAddr.set('location', url)


        serviceName = self.__class__.__name__.split('.')[-1]
        portType = create_xml_subelement(root, 'portType')
        portType.set('name', serviceName)
        for method in methods:
            if method.isCallback:
                operation = create_xml_subelement(callbackPortType,
                    'operation')
            else:
                operation = create_xml_subelement(portType, 'operation')

            operation.set('name', method.name)
            params = []
            for name, param in method.inMessage.params:
                params.append(name)

            documentation = create_xml_subelement(operation, 'documentation')
            documentation.text = method.doc
            operation.set('parameterOrder', method.inMessage.typ)
            opInput = create_xml_subelement(operation, 'input')
            opInput.set('name', method.inMessage.typ)
            opInput.set('message', 'tns:%s' % method.inMessage.typ)

            if (len(method.outMessage.params) > 0 and
                not method.isCallback and not method.isAsync):
                opOutput = create_xml_subelement(operation, 'output')
                opOutput.set('name', method.outMessage.typ)
                opOutput.set('message', 'tns:%s' % method.outMessage.typ)

        # make partner link
        plink = create_xml_subelement(root,
            nsmap.get('plnk') + 'partnerLinkType')
        plink.set('name', serviceName)
        role = create_xml_subelement(plink,
            nsmap.get('plnk') + 'role')
        role.set('name', serviceName)
        plinkPortType = create_xml_subelement(role,
            nsmap.get('plnk') + 'portType')
        plinkPortType.set('name', 'tns:%s' % serviceName)

        if hasCallbacks:
            role = create_xml_subelement(plink, nsmap.get('plnk') + 'role')
            role.set('name', '%sCallback' % serviceName)
            plinkPortType = create_xml_subelement(role,
                nsmap.get('plnk') + 'portType')
            plinkPortType.set('name', 'tns:%sCallback' % serviceName)

        self._add_bindings_for_methods(root, serviceName, methods, nsmap)

        service = create_xml_subelement(root, 'service')
        service.set('name', serviceName)
        wsdlPort = create_xml_subelement(service, 'port')
        wsdlPort.set('name', serviceName)
        wsdlPort.set('binding', 'tns:%s' % serviceName)
        addr = create_xml_subelement(wsdlPort, nsmap.get('soap') + 'address')
        addr.set('location', url)

        wsdl = ElementTree.tostring(root)
        wsdl = "<?xml version='1.0' encoding='utf-8' ?>%s" % (wsdl)

        #cache the wsdl for next time
        self.__wsdl__ = wsdl
        return self.__wsdl__
Пример #11
0
 def to_xml(cls, value, name, nsmap=ns):
     fault = create_xml_element(name, nsmap)
     create_xml_subelement(fault, 'faultcode').text = value.faultcode
     create_xml_subelement(fault, 'faultstring').text = value.faultstring
     detail = create_xml_subelement(fault, 'detail').text = value.detail
     return fault
Пример #12
0
def apply_mtom(headers, envelope, params, paramvals):
    '''
    Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    @param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    @param envelope  SOAP envelope string that would have originally been sent.
    @param params    params attribute from the Message object used for the SOAP
    @param paramvals values of the params, passed to Message.to_xml
    @return          tuple of length 2 with dictionary of headers and
                     string of body that can be sent with HTTPConnection
    '''

    # grab the XML element of the message in the SOAP body
    soapmsg = StringIO(envelope)
    soaptree = ElementTree.parse(soapmsg)
    soapns = soaptree.getroot().tag.split('}')[0].strip('{')
    soapbody = soaptree.getroot().find("{%s}Body" % soapns)
    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soapns, ):
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break
    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts
    mtompkg = MIMEMultipart('related',
        boundary='?//<><>soaplib_MIME_boundary<>')
    rootpkg = None
    try:
        rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit)
    except NameError:
        rootpkg = MIMENonMultipart("application", "xop+xml")
        rootpkg.set_payload(envelope)
        encode_7or8bit(rootpkg)

    # Set up multipart headers.
    del(mtompkg['mime-version'])
    mtompkg.set_param('start-info', roottype)
    mtompkg.set_param('start', '<soaplibEnvelope>')
    if 'SOAPAction' in headers:
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))

    # Set up root SOAP part headers.
    del(rootpkg['mime-version'])
    rootpkg.add_header('Content-ID', '<soaplibEnvelope>')
    for n, v in rootparams.items():
        rootpkg.set_param(n, v)
    rootpkg.set_param('type', roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]
        if typ == Attachment:
            id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()), )
            param = message[i]
            param.text = ""
            incl = create_xml_subelement(param,
                "{http://www.w3.org/2004/08/xop/include}Include")
            incl.attrib["href"] = "cid:%s" % id
            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()
            data = paramvals[i].data
            attachment = None
            try:
                attachment = MIMEApplication(data, _encoder=encode_7or8bit)
            except NameError:
                attachment = MIMENonMultipart("application", "octet-stream")
                attachment.set_payload(data)
                encode_7or8bit(attachment)
            del(attachment['mime-version'])
            attachment.add_header('Content-ID', '<%s>' % (id, ))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    soapmsg.close()
    soapmsg = StringIO()
    soaptree.write(soapmsg)
    rootpkg.set_payload(soapmsg.getvalue())
    soapmsg.close()

    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(), )
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)

    return (mtomheaders, mtombody)