pythonsoapzsi

Are there any working examples of Zolera SOAP Infrastructure (ZSI)?


i have looked at examples :

  1. http://pywebsvcs.svn.sourceforge.net/viewvc/pywebsvcs/trunk/wstools/
  2. http://pywebsvcs.sourceforge.net/cookbook.pdf

and googled, but could not find a single usable example.


Solution

  • reference: (Thanks to Doug Hellmann ) building soap service

    The Zolera Soap Infrastucture (ZSI), is a part of the pywebsvcs project. It provides complete server and client libraries for working with SOAP. To use it, a developer writes the WSDL file (by hand or using a WSDL editor), and then generates Python source for the client and stubs for the server. The data structures defined in the WSDL file are converted into Python classes that can be used in both client and server code.

    we implemented a simple echo service that returns as output whatever it gets as input from the client. Listing 1 contains the hand-crafted WSDL inputs for the ZSI version of this service.

    Listing 1

    <?xml version="1.0" encoding="UTF-8"?>
    <definitions 
      xmlns="http://schemas.xmlsoap.org/wsdl/"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:tns="urn:ZSI"
      targetNamespace="urn:ZSI" >
    
      <types>
        <xsd:schema elementFormDefault="qualified" 
            targetNamespace="urn:ZSI">
          <xsd:element name="Echo">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:anyType"/>
              </xsd:sequence>
            </xsd:complexType>
          </xsd:element>
        </xsd:schema>
      </types>
    
      <message name="EchoRequest">
        <part name="parameters" element="tns:Echo" />
      </message>
      <message name="EchoResponse">
        <part name="parameters" element="tns:Echo"/>
      </message>
    
      <portType name="EchoServer">
        <operation name="Echo">
          <input message="tns:EchoRequest"/>
          <output message="tns:EchoResponse"/>
        </operation>
      </portType>
    
      <binding name="EchoServer" type="tns:EchoServer">
        <soap:binding style="document" 
                      transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="Echo">
          <soap:operation soapAction="Echo"/>
          <input>
            <soap:body use="literal"/> 
          </input>
          <output>
            <soap:body use="literal"/> 
          </output>
        </operation>
      </binding>
    
      <service name="EchoServer">
        <port name="EchoServer" binding="tns:EchoServer">
          <soap:address location="http://localhost:7000"/>
        </port>
      </service>
    
    </definitions>
    

    To generate the client and server code from the WSDL, feed it into the wsdl2py program (included with ZSI). To add support for complex types, add the -b option, but it isn’t required for this simple example. wsdl2py will, in response, produce three files:

    Listing 2

    EchoServer_client.py is the code needed to build a client for the SimpleEcho web service.

    ##################################################
    # file: EchoServer_client.py
    # 
    # client stubs generated by 
    # "ZSI.generate.wsdl2python.WriteServiceModule"
    # 
    ##################################################
    
    from EchoServer_types import *
    import urlparse, types
    from ZSI.TCcompound import ComplexType, Struct
    from ZSI import client
    from ZSI.schema import GED, GTD
    import ZSI
    from ZSI.generate.pyclass import pyclass_type
    
    # Locator
    class EchoServerLocator:
        EchoServer_address = "http://localhost:7000"
        def getEchoServerAddress(self):
            return EchoServerLocator.EchoServer_address
        def getEchoServer(self, url=None, **kw):
            return EchoServerSOAP(
                url or EchoServerLocator.EchoServer_address, 
                **kw)
    
    # Methods
    class EchoServerSOAP:
        def __init__(self, url, **kw):
            kw.setdefault("readerclass", None)
            kw.setdefault("writerclass", None)
            # no resource properties
            self.binding = client.Binding(url=url, **kw)
            # no ws-addressing
    
        # op: Echo
        def Echo(self, request, **kw):
            if isinstance(request, EchoRequest) is False:
                raise TypeError, "%s incorrect request type" % \
                    (request.__class__)
            # no input wsaction
            self.binding.Send(None, None, request, soapaction="Echo", **kw)
            # no output wsaction
            response = self.binding.Receive(EchoResponse.typecode)
            return response
    
    EchoRequest = GED("urn:ZSI", "Echo").pyclass
    
    EchoResponse = GED("urn:ZSI", "Echo").pyclass
    

    Listing 3

    EchoServer_server.py contains code needed to build the SimpleEcho web service server.

    ##################################################
    # file: EchoServer_server.py
    #
    # skeleton generated by 
    #  "ZSI.generate.wsdl2dispatch.ServiceModuleWriter"
    #
    ##################################################
    
    from ZSI.schema import GED, GTD
    from ZSI.TCcompound import ComplexType, Struct
    from EchoServer_types import *
    from ZSI.ServiceContainer import ServiceSOAPBinding
    
    # Messages  
    EchoRequest = GED("urn:ZSI", "Echo").pyclass
    
    EchoResponse = GED("urn:ZSI", "Echo").pyclass
    
    
    # Service Skeletons
    class EchoServer(ServiceSOAPBinding):
        soapAction = {}
        root = {}
    
        def __init__(self, post='', **kw):
            ServiceSOAPBinding.__init__(self, post)
    
        def soap_Echo(self, ps, **kw):
            request = ps.Parse(EchoRequest.typecode)
            return request,EchoResponse()
    
        soapAction['Echo'] = 'soap_Echo'
        root[(EchoRequest.typecode.nspname,EchoRequest.typecode.pname)] = \
            'soap_Echo'
    

    Listing 4

    EchoServer_types.py has type definitions used by both the client and server code.

    ##################################################
    # file: EchoServer_types.py
    #
    # schema types generated by 
    #  "ZSI.generate.wsdl2python.WriteServiceModule"
    #
    ##################################################
    
    import ZSI
    import ZSI.TCcompound
    from ZSI.schema import (LocalElementDeclaration, ElementDeclaration, 
                            TypeDefinition, GTD, GED)
    from ZSI.generate.pyclass import pyclass_type
    
    ##############################
    # targetNamespace
    # urn:ZSI
    ##############################
    
    class ns0:
        targetNamespace = "urn:ZSI"
    
        class Echo_Dec(ZSI.TCcompound.ComplexType, ElementDeclaration):
            literal = "Echo"
            schema = "urn:ZSI"
            def __init__(self, **kw):
                ns = ns0.Echo_Dec.schema
                TClist = [ZSI.TC.AnyType(pname=(ns,"value"), 
                          aname="_value", minOccurs=1, maxOccurs=1, 
                          nillable=False, typed=False, 
                          encoded=kw.get("encoded"))]
                kw["pname"] = ("urn:ZSI","Echo")
                kw["aname"] = "_Echo"
                self.attribute_typecode_dict = {}
                ZSI.TCcompound.ComplexType.__init__(self,None,TClist,
                                                    inorder=0,**kw)
                class Holder:
                    __metaclass__ = pyclass_type
                    typecode = self
                    def __init__(self):
                        # pyclass
                        self._value = None
                        return
                Holder.__name__ = "Echo_Holder"
                self.pyclass = Holder
    
    # end class ns0 (tns: urn:ZSI)
    

    Once generated, these files are not meant to be edited, because they will be regenerated as part of a build process whenever the WSDL input changes. The code in the files grows as more types and calls are added to the service definition.

    The implementation of the server goes in a separate file that imports the generated code. In the example, the actual service is on lines 18–25 of Listing 5. The @soapmethod decorator defines the input (an EchoRequest) and the output (an EchoResponse) for the call. In the example, the implementation of soap_Echo() just fills in the response value with the request value, and returns both the request and the response. From there, ZSI takes care of building the SOAP response and sending it back to the client.

    Listing 5

    import os
    import sys
    from EchoServer_client import *
    from ZSI.twisted.wsgi import (SOAPApplication,
                                  soapmethod,
                                  SOAPHandlerChainFactory)
    
    class EchoService(SOAPApplication):
        factory = SOAPHandlerChainFactory
        wsdl_content = dict(name='Echo', 
                            targetNamespace='urn:echo', 
                            imports=(), 
                            portType='',
                            )
    
        def __call__(self, env, start_response):
            self.env = env
            return SOAPApplication.__call__(self, env, start_response)
    
        @soapmethod(EchoRequest.typecode, 
                    EchoResponse.typecode, 
                    operation='Echo', 
                    soapaction='Echo')
        def soap_Echo(self, request, response, **kw):
            # Just return what was sent
            response.Value = request.Value
            return request, response
    
    def main():
        from wsgiref.simple_server import make_server
        from ZSI.twisted.wsgi import WSGIApplication
    
        application         = WSGIApplication()
        httpd               = make_server('', 7000, application)
        application['echo'] = EchoService()
        print "listening..."
        httpd.serve_forever()
    
    if __name__ == '__main__':
        main()
    

    Listing 6 includes a sample of how to use the ZSI client libraries to access the servers from the client end. All that needs to be done is to create a handle to the EchoServer web service, build an EchoRequest, send it off to the web service, and read the response.

    from EchoServer_client import *
    import sys, time
    
    loc  = EchoServerLocator()
    port = loc.getEchoServer(url='http://localhost:7000/echo')
    
    print "Echo: ", 
    msg = EchoRequest()
    msg.Value = "Is there an echo in here?"
    rsp = port.Echo(msg)
    print rsp.Value