2011-10-17 9 views

Respuesta

10

referencia: (Gracias a Doug Hellmann) building soap service

El Zolera Jabón infrastucture (ZSI), es una parte del proyecto pywebsvcs. Proporciona bibliotecas completas de servidor y cliente para trabajar con SOAP. Para usarlo, un desarrollador escribe el archivo WSDL (a mano o usando un editor WSDL), y luego genera la fuente de Python para el cliente y los stubs para el servidor. Las estructuras de datos definidas en el archivo WSDL se convierten en clases de Python que se pueden usar tanto en el código del cliente como en el del servidor.

implementamos un servicio echo simple que devuelve como salida lo que sea que obtenga como entrada del cliente. El Listado 1 contiene las entradas WSDL hechas a mano para la versión ZSI de este servicio.

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

para generar el código de cliente y servidor desde el WSDL, se alimentan en el programa de wsdl2py (incluido con ZSI). Para agregar soporte para tipos complejos, agregue la opción -b, pero no es necesario para este ejemplo simple. wsdl2py será, en respuesta, producen tres archivos:

Listado 2

EchoServer_client.py es el código necesario para construir un cliente para el servicio web 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 

Listado 3

EchoServer_server.py contiene el código necesario para construir el servidor de servicios web 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' 

Listado 4

EchoServer_types.py tiene el tipo definiciones utilizadas por el cliente y el código del servidor.

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

Una vez generado, estos archivos no están destinados a ser editado, porque van a ser regenerados como parte de un proceso de construcción cada vez que cambia de entrada WSDL. El código en los archivos crece a medida que se agregan más tipos y llamadas a la definición del servicio.

La implementación del servidor va en un archivo separado que importa el código generado. En el ejemplo, el servicio real está en las líneas 18-25 del Listado 5. El decorador @soapmethod define la entrada (una EchoRequest) y la salida (una EchoResponse) para la llamada. En el ejemplo, la implementación de soap_Echo() simplemente completa el valor de respuesta con el valor de solicitud y devuelve tanto la solicitud como la respuesta. A partir de ahí, ZSI se encarga de construir la respuesta SOAP y enviarla de vuelta al cliente.

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

Listado 6 incluye una muestra de cómo utilizar las bibliotecas de cliente ZSI para acceder a los servidores desde el cliente final. Todo lo que se necesita hacer es crear un identificador para el servicio web EchoServer, crear un EchoRequest, enviarlo al servicio web y leer la respuesta.

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 
Cuestiones relacionadas