pysimplesoap: pythonovský klient k webovej službe JAX-WS 2.0

@Deprecated článok

K tomuto článku už existuje novšia verzia.

Inštalácia pysimplesoap

  1. Predpokladám, že máte nainštalovaný Python.
  2. Predpokladám, že máte nainštalované setuptools. Ak nie, urobte tak pomocou manuálu na stránke nástroja
  3. V inštalačnom adresári Pythonu, v podadresári Scripts sa ocitol easy_install.exe
  4. Nainštalujte pip, obal nad setuptools, ktorý vylepšuje zopár vecí:

    c:\Programs\Python>easy_install pip
    
  5. Nainštalujte pysimplesoap, SOAPový klient.

    pip install pysimplesoap
    
  6. Nainštalujte httplib2, vylepšený HTTP klient pre Python. pysimplesoap na Windowse je totiž bez neho nervózny.

Ukážkový server [JAX-WS 2.0]

Ukážkový server v Jave:

@WebService
public class ChocolateService  {
    private List<Chocolate> chocolates = new CopyOnWriteArrayList<Chocolate>();

    public ChocolateService() {
        chocolates.add(new Chocolate(1L, "Lindt Excellence 70%", 70));
        chocolates.add(new Chocolate(2L, "Milka Alpenmilch", 40));
        chocolates.add(new Chocolate(3L, "Christmas Angel Figure", 15));
    }

    @WebMethod
    public List<Chocolate> list() {
        return chocolates;
    }

    @WebMethod
    public void add(Chocolate chocolate) {
        System.out.println(chocolate);
        this.chocolates.add(chocolate);
    }
}

Vypublikujeme ho cez:

Endpoint endpoint = Endpoint.publish("http://localhost:10000/ws/chocolate", new ChocolateService());

Ukážkový klient [Python]

Jednoduchý klient môže vyzerať nasledovne:

from pysimplesoap.client import SoapClient
client = SoapClient(wsdl="http://localhost:10000/ws/chocolate?wsdl", trace=True, ns="x")
vysledok = client.list("");
print vysledok[0]

Výsledkom je dict dictov:

[
    {'return': {'percentage': 70, 'id': 1L, 'title': u'Lindt Excellence 70%'}}, 
    {'return': {'percentage': 40, 'id': 2L, 'title': u'Milka Alpenmilch'}}, 
    {'return': {'percentage': 15, 'id': 3L, 'title': u'Christmas Angel Figure'}}
]   

K prvému prvku sa vieme teda dostať cez

vysledok[0]["return"]

Dôležité sú tri zádrhele:

Zapnite traceovanie

Je viac než vhodné si zapnúť _trace_ovanie, teda výpis odchádzajúcich a prichádzajúcich správ; aspoň bude vidieť, čo sa deje na drôte.

Metódy bez parametrov

Metóda list() nemá na strane servera žiadne parametre. Ak zavoláte z klienta len…

vysledok = client.list();

… JAX-WS server odpovie faultom:

Cannot find dispatch method for {}

Príčinou je telo odchádzajúcej správy

<soap:Body>

</soap:Body>

Áno, naozaj vo vnútri nič nie je a preto úbohý JAX-WS netuší, ktorú metódu spustiť.

Zrejme je to bug vo vnútri pythonovského klienta. „Hackom“ je poslať napr. prázdny reťazec, čo sa namapuje na:

<x:list>
        <None/>
</x:list>

To síce vygeneruje nevalidný dokument, ale aspoň povedie ku korektnému zavolaniu služby. Nevalidnosť spočíva v narušení XML schémy vo WSDL, ktorá hovorí, že element nesmie obsahovať podelementy:

<xs:complexType name="list">
    <xs:sequence/>
</xs:complexType>

Zapnite explicitné menné priestory

Zapnite si podporu explicitného menného priestoru pre telá správ. JAX-WS z neznámeho dôvodu ignoruje správy s implicitnými mennými priestormi. Bez neho to bude vyzerať:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:x="http://jaxws.novotnyr.ics.upjs.sk/">
    <soapenv:Header/>
    <soapenv:Body>
        <list xmlns="http://jaxws.novotnyr.ics.upjs.sk/">
            <None></None>
        </list>
    </soapenv:Body>
</soapenv:Envelope>

S explicitným menným priestorom (ns = "x") bude odchádzajúca správa takáto:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:x="http://jaxws.novotnyr.ics.upjs.sk/">
    <soapenv:Header/>
    <soapenv:Body>
        <x:list>
            <None/>
        </x:list>
    </soapenv:Body>
</soapenv:Envelope>

Skúsenosti ukazujú, že JAX-WS 2.0 si poradí len s druhým spôsobom.

Ukážkový klient 2

Pythonovský klient podporuje aj komplexné typy, a to cez slovníky dict:

chocolate = dict(id=1, title="Lindt", percentage=0.7)
client.add(chocolate)

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *