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

kamal picture kamal · Oct 17, 2011 · Viewed 7.8k times · Source

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.

Answer

kamal picture kamal · Oct 20, 2011

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