2011-10-17 9 views

risposta

10

riferimento: (Grazie a Doug Hellmann) building soap service

Lo Zolera Sapone Infrastucture (ZSI), è una parte del progetto pywebsvcs. Fornisce librerie complete di server e client per lavorare con SOAP. Per usarlo, uno sviluppatore scrive il file WSDL (a mano o usando un editor WSDL), quindi genera l'origine Python per il client e gli stub per il server. Le strutture dati definite nel file WSDL vengono convertite in classi Python che possono essere utilizzate sia nel codice client sia nel codice server.

abbiamo implementato un semplice servizio di eco che restituisce come output qualunque cosa ottenga come input dal client. Il Listato 1 contiene gli input WSDL fatti a mano per la versione ZSI di questo servizio.

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> 

per generare il codice client e server dal WSDL, alimentano nel programma wsdl2py (incluso con ZSI). Per aggiungere supporto per tipi complessi, aggiungi l'opzione -b, ma non è necessario per questo semplice esempio. wsdl2py sarà, in risposta, producono tre file:

Listing 2

EchoServer_client.py è il codice necessario per creare un client per il servizio 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 

Listing 3

EchoServer_server.py contiene il codice necessario per costruire il server servizio 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' 

Listato 4

EchoServer_types.py è di tipo definizioni utilizzate sia dal client e il codice del server.

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

volta generati, questi file non sono destinate ad essere modificato, perché saranno rigenerate come parte di un processo di generazione ogni volta che cambia ingresso WSDL. Il codice nei file aumenta man mano che vengono aggiunti più tipi e chiamate alla definizione del servizio.

L'implementazione del server viene eseguita in un file separato che importa il codice generato. Nell'esempio, il servizio effettivo si trova sulle righe 18-25 del Listato 5. Il decoratore @soapmethod definisce l'input (un EchoRequest) e l'output (un EchoResponse) per la chiamata. Nell'esempio, l'implementazione di soap_Echo() riempie semplicemente il valore della risposta con il valore della richiesta e restituisce sia la richiesta che la risposta. Da lì, ZSI si occupa della creazione della risposta SOAP e dell'invio al 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 include un esempio di come utilizzare le librerie client ZSI di accedere ai server dal lato client. È sufficiente creare un handle per il servizio Web EchoServer, creare EchoRequest, inviarlo al servizio Web e leggere la risposta.

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