有没有可用的Zolera SOAP基础设施(ZSI)示例?

8 投票
1 回答
8047 浏览
提问于 2025-04-17 04:29

我看了一些例子:

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

但是我在网上搜索了很久,还是找不到一个可以用的例子。

1 个回答

11

参考资料: (感谢 Doug Hellmann) 构建 SOAP 服务

Zolera SOAP 基础设施(ZSI)是 pywebsvcs 项目的一部分。它为使用 SOAP 提供了完整的服务器和客户端库。开发者需要手动编写 WSDL 文件(或者使用 WSDL 编辑器),然后生成客户端的 Python 源代码和服务器的存根代码。WSDL 文件中定义的数据结构会被转换成可以在客户端和服务器代码中使用的 Python 类。

我们实现了一个简单的回声服务,它会把客户端发送的输入原封不动地返回。列表 1 包含了为这个服务手动编写的 WSDL 输入,适用于 ZSI 版本。

列表 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>

要从 WSDL 生成客户端和服务器代码,可以把它输入到 wsdl2py 程序中(这个程序是 ZSI 自带的)。如果需要支持复杂类型,可以加上 -b 选项,但对于这个简单的例子来说并不是必须的。wsdl2py 会生成三个文件:

列表 2

EchoServer_client.py 是构建 SimpleEcho 网络服务客户端所需的代码。

##################################################
# 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

列表 3

EchoServer_server.py 包含构建 SimpleEcho 网络服务服务器所需的代码。

##################################################
# 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'

列表 4

EchoServer_types.py 包含客户端和服务器代码都需要的类型定义。

##################################################
# 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)

一旦生成,这些文件就不应该被编辑,因为每当 WSDL 输入发生变化时,它们会在构建过程中被重新生成。随着服务定义中添加更多类型和调用,文件中的代码也会增加。

服务器的实现放在一个单独的文件中,该文件会导入生成的代码。在这个例子中,实际的服务实现位于列表 5 的第 18 到 25 行。@soapmethod 装饰器定义了调用的输入(一个 EchoRequest)和输出(一个 EchoResponse)。在这个例子中,soap_Echo() 的实现只是把响应值填充为请求值,并返回请求和响应。之后,ZSI 会处理构建 SOAP 响应并将其发送回客户端。

列表 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()

列表 6 展示了如何使用 ZSI 客户端库从客户端访问服务器的示例。只需要创建一个对 EchoServer 网络服务的引用,构建一个 EchoRequest,发送给网络服务,然后读取响应即可。

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

撰写回答