Java na webovém serveru: SOAP webové služby

Dnes navážeme na předchozí díl o RESTful webových službách a budeme se věnovat klasickým webovým službám (web services) využívajícím protokol SOAP. Jedná se svým způsobem o konkurenční technologie, které obě umožňují implementovat API pro naši aplikaci. Na konci tohoto dílu proto naleznete doporučení, kdy kterou z nich zvolit.

Seriál: Java na webovém serveru (16 dílů)

  1. Java na serveru: úvod 8.1.2010
  2. Java na webovém serveru: první web 15.1.2010
  3. Java na webovém serveru: práce s databází 29.1.2010
  4. Java na webovém serveru: práce s databází II 12.2.2010
  5. Java na webovém serveru: lokalizace a formátování 19.2.2010
  6. Java na webovém serveru: autorizace a autentizace 26.2.2010
  7. Java na webovém serveru: autorizace a autentizace II 5.3.2010
  8. Java na webovém serveru: porovnání Javy a PHP 10.3.2010
  9. Java na webovém serveru: Vlastní JSP značky a servlety 17.3.2010
  10. Java na webovém serveru: posílání e-mailů a CAPTCHA 24.3.2010
  11. Java na webovém serveru: píšeme REST API 7.4.2010
  12. Java na webovém serveru: SOAP webové služby 14.4.2010
  13. Java na webovém serveru: hlasování a grafy v SVG 28.4.2010
  14. Java na webovém serveru: Komentáře a integrace s Texy 9.6.2010
  15. Java na webovém serveru: AJAX formuláře 23.6.2010
  16. Java na webovém serveru: implementujeme Jabber 30.6.2010

Původní význam zkratky SOAP je Simple Object Access Protocol, ale dnes se často vykládá spíše jako SOA Protokol – tedy protokol pro architekturu orientovanou na služby. V následujícím textu budu SOAP používat jako zkratku pro webové služby postavené nad tímto protokolem (ne jen pro protokol samotný) a podobně REST pro webové služby nad ním postavené.

Další důležitou zkratkou, kterou je třeba zmínit, je WSDL – Web Services Description Language  – což je XML formát sloužící k popisu služeb. Funguje jako určitá formalizovaná (a strojově čitelná) dokumentace toho, jaké metody (operace) služba nabízí, jaké mají parametry a návratové hodnoty a dalších metadat.

Specifikace a implementace

Podobně jako v případě RESTu i zde u klasických webových služeb máme v Javě specifikaci (JSR 224 – JAX-WS) a několik implementací (referenční Metro nebo např. CXF od Apache).

Jednoduchý příklad

Jako obvykle si nejprve si aktualizujeme zdrojové kódy naší aplikace pomocí Mercurialu:

$ hg pull
$ hg up "12. díl"

Případně je můžete stáhnout jako bzip2 archiv přes web. Pro dnešní příklad jsem vytvořil další webový modul ( nekurak.net-ws), kde naleznete ukázku webové služby.

Opět začneme tím nejjednodušším příkladem. Vytvoříme si službu, která má jeden textový parametr a vrací také textový parametr. Službu implementujeme jako třídu v rámci webového projektu ( nekurak.net-ws), kterou opatříme anotacemi.

@WebService
public class Pokus {
    @WebMethod
    public String pozdrav( String koho) {
    return "Ahoj, " + koho + "!";
    }
}

Jednoduché, že? Ve zdrojových kódech (třída cz.frantovo.nekurak.ws.Pokus) naleznete další anotace, které slouží např. k přejmenování metod nebo jmenných prostorů (ale nejsou nezbytně nutné).

Po přidání anotací se nám v Netbeans automaticky aktivuje druhý zobrazovací režim  – můžeme se na službu dívat jednak jako na zdrojový kód (Source) nebo si přepnout na její vizuální ztvárnění (Design):

Java SOAP

V levém panelu také vidíte nabídku volně dostupných webových služeb – můžete si do tohoto seznamu přidávat další a dívat se na nabízené operace.

Vytvořenou službu si můžeme otestovat pomocí webového rozhraní, které je poskytované frameworkem a nachází se na adrese: /pokusnaSluzba?Tes­ter. WSDL popis služby pak nalezneme na adrese: /pokusnaSluzba?WSDL

Podobně jako v minulém dílu o RESTu, i zde můžeme k otestování použít nástroj cURL. Skript na vyzkoušení služby naleznete ve zdrojových kódech v adresáři /test/ws.

Požadavek na webovou službu vypadá takto (posílá se jako POST na URL služby):

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:pozdravOsobu xmlns:ns2="pokusNS">
            <jmenoOsoby>Franto</jmenoOsoby>
        </ns2:pozdravOsobu>
    </S:Body>
</S:Envelope>

A služba nám vrátí následující odpověď:

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:pozdravOsobuResponse xmlns:ns2="pokusNS">
            <return>Ahoj, Franto!</return>
        </ns2:pozdravOsobuResponse>
    </S:Body>
</S:Envelope>

Klienta k webové službě si můžete napsat v libovolném programovacím jazyce (což je taky jeden z důvodů zavádění webových služeb – nezávislost na platformě a integrace v heterogenních prostředích), ani k tomu nepotřebujete pracovat přímo s XML – existuje řada knihoven, které vám umožní překlad na objekty a metody daného jazyka. Pokud budete chtít psát klienta ve Flashi, jistě se vám bude hodit článek, který zde na Zdrojáku nedávno vyšel: Flex 4: Webové služby.

Praktická ukázka

Google nabízí zajímavou službu zvanou Geocoding, která umožňuje zjištění zeměpisných souřadnic na základě poštovní adresy. To se nám velice hodí – nemůžeme totiž chtít po uživatelích, aby k podniku ručně zadávali GPS souřadnice, ale když zadají adresu, můžeme si tyto souřadnice dopočítat (resp. požádat o to Google).

Vytvoříme si tedy službu, která projde podniky, které dosud nemají nastavené souřadnice, a na základě dat od Googlu je doplní.

Kostra služby vypadá následovně:

package cz.frantovo.nekurak.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
/**
 *
 * @author fiki
 */
@WebService(serviceName = "podnikSluzba", targetNamespace = "podnikNS", portName = "podnikPort")
public class PodnikWS {
    /**
     * Projde podniky, které nemají vyplněné souřadnice,
     * a pokusí se je doplnit na základě poštovní adresy podniku.
     * @return počet podniků, u nichž jsme doplnili souřadnice
     */
    @WebMethod(operationName = "dopocitejSouradnicePodleAdres")
    public int dopocitejSouradnice() {
    …
    }
}

Operace nemá žádné vstupní parametry, jedná se o jednoduchou proceduru. Budeme ji volat v pravidelných intervalech (např. pomocí cronu a nástroje cURL).

Požadavek si připravíme do souboru požadavek.xml:

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header/>
    <S:Body>
        <ns2:dopocitejSouradnicePodleAdres xmlns:ns2="podnikNS"/>
    </S:Body>
</S:Envelope>

A můžeme službu volat pomocí obyčejného cURL z příkazové řádky, aniž bychom potřebovali nějaké složité nástroje nebo cokoli programovat:

curl -s  -H "Content-Type: text/xml"  -d @požadavek.xml http://nekurak.frantovo.cz/nekurak.net-ws/podnikSluzba

Poznámka k architektuře

Naše aplikace (databáze hospod) je příliš jednoduchá na to, aby se v ní našlo smysluplné využití pro technologie, jako jsou REST nebo SOAP služby  – berte je proto prosím jako ukázku technologie – věřím, že ve svých složitějších aplikacích a systémech pro tyto technologie uplatnění najdete

Úlohy, jako doplňování souřadnic k podnikům, by bylo lepší řídit událostmi (PUSH) místo provádění periodických operací (PULL). Po přidání podniku by bylo lepší vytvořit požadavek na dohledání souřadnic a ten vložit do fronty (např. JMS) a zpracovat ho asynchronně (aby uživatel nemusel čekat, než externí služba vrátí výsledek). Rovněž volání pomocí klasického unixového cronu by bylo lepší nahradit technologií, kterou poskytuje samotný aplikační server (např. plánovač Quartz). Ale pro tyto pokročilejší technologie zatím v tomto seriálu nebyl prostor.

Kdy zvolit REST a kdy SOAP

Jak již bylo řečeno v úvodu, webové služby postavené na REST principu a ty využívající SOAP protokol, jsou do jisté míry konkurenční technologie. Při návrhu aplikace tak budete muset volit jednu z nich (případně používat obě). Existují dvě základní kritéria, podle kterých se můžeme rozhodovat:

  • Logický pohled – vycházíme z „obchodní“ podstaty řešené úlohy, rozhodujeme se podle toho, zda pracujeme spíše se zdroji nebo spíše voláme procedury.
  • Pragmatičtější pohled – ohlížíme se více na technologii a řídíme se např. tím, jak snadno se k ní dá napsat klient, nebo jaká metadata lze ke službě přiřadit. A to i za cenu ústupků v logice rozhraní.

V principu lze všechny služby řešit jak SOAPem, tak RESTem. V případě SOAP služeb jednoduše implementujeme služby, které odpovídají CRUD operacím. Jelikož jsou SOAP služby dostatečně obecná technologie, je tento přístup možný a není problém mít procedury pro vytváření, načítání, aktualizování a mazání objektů. Nevýhodou je jistá „nestandardizo­vanost“ takto definovaného API: je jen na nás, zda si jednotlivé akce pojmenujeme jako ulož(), založ(), save(), put() nebo třeba insert(). Programátor volající tyto služby musí použít WSDL, aby věděl jak se která operace jmenuje.

Oproti tomu REST používá HTTP operace, které mají pevně definovaný význam (GET, PUT, POST, DELETE). Ovšem obsah sdělovaných zpráv (např. formát XML nebo JSON dat) často nebývá formálně (strojově čitelně – jako v případě WSDL) specifikován a je třeba použít dokumentaci nebo se jednoduše podívat na data, která služba vrací. Existuje popisný formát WADL, který by měl být tím, čím je WSDL pro SOAP služby, ale jedná se o poměrně mladou záležitost (oproti WSDL) a někteří vývojáři ho odmítají s tím, že není potřeba nebo že jde proti filosofii RESTu.

Pokud chceme implementoval libovolnou (i procedurální – RPC) službu pomocí REST služeb, lze to  – jen jsme trochu omezeni jednoduchostí RESTu a tím, že je určen k provádění CRUD operací a ne libovolných procedur. Tato omezení je možné obejít dvěma způsoby:

  • Vstupní parametry procedury zakódujeme do URL (GET parametry) a REST služba nám vrátí výsledek. Např. si požádáme o „zdroj“ /kalkulacka/secti/?a=123&b=456 a na serveru se provede procedura sčítání a vrátí nám výsledek formou „zdroje“ (ať už XML, prostý text nebo třeba JSON).
  • Pomocí dvou požadavků: jelikož předchozí způsob neumožňuje vkládat jako vstupní parametry složitější struktury (jsme omezeni jen na data typu klíč=hodnota, která se vejdou do URL), vytvoříme si jakýsi pseudozdroj, který službě předáme (POST) a ta nás následně odkáže na jiný pseudozdroj, který si stáhneme druhým HTTP požadavkem (GET) a v něm nalezneme výsledek procedury.

Jak je vidět, technologie je možné si z velké míry „ohnout“ a použít i k úlohám, ke kterým nejsou primárně určené. Co zvolit, vám nebudu obecně radit, záleží na konkrétním zadání. REST oceníte zejména na webu, protože implementovat pro něj klienta např. v Javascriptu je výrazně snadnější. A i u newebových aplikací, kde se pracuje se zdroji (nad kterými provádíme CRUD operace), oceníte elegantnost RESTu. Výhodou SOAPu naopak je přirozenější tvorba procedurálních služeb a možnost propracovanější strojově čitelné specifikace služby (WSDL).

Např. Google od veřejného SOAP API upustil a používá REST – a to i pro typicky procedurální úlohy typu převeďAdresuNaSouřadnice()  – viz jeho Geocoding Service. Zatímco jinde, kde se nepoužívají jen javascriptoví klienti, zase oceníte možnost silného typování SOAPu a možnost využití technologií jako je UDDI pro katalogizaci služeb a zvládání rozsáhlejších systémů.

Závěr

Dnes jsme si ukázali druhý způsob, jak lze vytvořit webové API pro naši aplikaci. V obou případech (REST i SOAP) se jedná o webové technologie, které projdou přes obvyklé firewally a které stojí nad HTTP protokolem. Příště si trochu odpočineme od náročných technologií a budeme se zase trochu věnovat samotné aplikaci a rozvoji jejích funkcí, které jsme teď trochu zanedbávali.

Odkazy

Franta Kučera působí jako Java vývojář na volné noze. Programování je jeho koníčkem už od dětství. Kromě toho má rád Linux, relační SŘBD a XML.

Komentáře: 10

Přehled komentářů

František Kučera Souřadnice
peter zle chapanie RESTu
František Kučera Re: zle chapanie RESTu
peter Re: zle chapanie RESTu
František Kučera slovo bzučák
lzap SOA není SOAP!
František Kučera SOA není SOAP a REST není HTTP-RPC
Jiří Kosek Re: SOA není SOAP a REST není HTTP-RPC
lzap Re: SOA není SOAP a REST není HTTP-RPC
foxo URL obrázku
Zdroj: https://www.zdrojak.cz/?p=3211