Až Vám zčerná obrazovka, přejděte na Linux!

Proč používat Linux
Zobrazují se příspěvky se štítkemWebServices. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemWebServices. Zobrazit všechny příspěvky

čtvrtek 26. listopadu 2009

Kdy parametrizovaný GET a kdy dvě operace GET a QUERY?

Na můj předchozí blogpost ze série oRESTování reagoval Petr Ferschmann, člen týmu WinStromu. Kromě poděkování za pochvalu ale také píše:
Osobně považuji za ekvivalentní tyto formy zápisu:
/faktura-vydana/(stavUhrK='uhrazeno%27)
/faktura-vydana/?filter=stavUhrK=%3d%27uhrazeno%27
Jak jistě tušíte, nemohu s tímto souhlasit, a proto vznikl tento článeček.

Věc, která vypadá z pohledu HTTP eqivalentně, z pohledu Java kódu eqivalentně, dokonce i z pohledu uživatele, z pohledu RESTu eqivalentní není. Webovému prohlížeči je jedno, které URL uživatel napíše, je to jenom směs znamének. Jestli je na serveru logika udělaná tak, že v metodě doGet() HttpServletu vezmete z request.getRequestPath() jednu část a prohlásíte ji za vyhledávací řetězec (filtr) nebo tutéž část získáte pomocí request.getParameter("filter"), je také celkem buřt. Pro HTTP protokol je to jedno, protože první řádek bude pokaždé vypadat stejně, tedy buď

GET /faktura-vydana/(stavUhrK='uhrazeno%27) HTTP/1.1

nebo

GET /faktura-vydana/?filter=stavUhrK=%3d%27uhrazeno%27 HTTP/1.1

Jak je to ale z pohledu RESTu? Začněměž tím, že si řekneme kousek základní definice RESTu - je to množina N operací, kde N je dostatečně malé číslo, společným pro všechny objekty systému (kterým říkáme zdroje neboli resources). Každý zdroj je unikátně identifikovatelný pomocí URI, za které se považuje buď URL nebo URN.

Tolik základní definice. Teď něco k operacím. Smysl mít několik málo jednotných operací je fakt, že se klient nemusí příliš zajímat o jaký zdroj se jedná a jaké má rozhraní, prostě s ním provede operaci, kterou požaduje, a ta buď půjde nebo nepůjde nebo udělá něco jiného než na jiném zdroji atd. Vzhledem k tomu, že operace se provádějí na zdrojích, které jsou URIčkované, můžeme prohlásit, že parametrem každé obecné operace je URI zdroje.

Těch parametrů ale může být povícero, a to hned ve dvou směrech. Uvedu dva příklady:

RESTová implementace Facebookového "Sdílet" by měla čtyři parametry: URI mojí zdi (tedy URI kolekce, kde se má zdroj (nový záznam o sdílení) vytvořit), URI toho, co chci sdílet, URI autora (ano, URI, Facebook mne musí UNIKÁTNĚ identifikovat!!!), a komentář.

Druhým příkladem budiž operace GET z WinStromu. GET na URL s jedním záznamem má parametr Accept, který definuje formát záznamu, který klient požaduje (XML,PDF,...).

Když jsme si toto řekli, vraťme se k WinStromu a jeho filtru. Každé URI reprezentuje zdroj. Jiný zdroj! Pakliže budeme chápat operaci GET klasicky, tedy "vrať obsah", tak GET na /faktura-vydana/ vrátí obsah kolekce faktura-vydaná, kdežto GET na /faktura-vydana/(stavUhrK='uhrazeno%27) vrací obsah - ČEHO? Z logiky věci zdroje reprezentujícího všechny zdroje z kolekce "faktura-vydana", které mají stav UhrK "uhrazeno%27". Jenomže - co můžeme říct o tom zdroji? Jedná se o zdroj nezávislý? Můžeme ho čapnout a přenést jinam? Jak se vlastně vytváří? Jaké jsou na něm nadefinovány jiné operace než GET? Není to vlastně jenom takový "virtuální" zdroj?

Musím se přiznat, že při slovním spojení "Virtuální RESTový zdroj" zamrazí v zádech. Zkusme se na to podívat z jiné stránky věci. To, co chceme, není IMHO až tak nový zdroj, jako spíše JINÝ POHLED kolekci "faktura-vydana", tedy na zdroj /faktura-vydana/ . Takový pohled, který bude obsahovat pouze takové zdroje, které odpovídají podmínce 'mají stav UhrK "uhrazeno%27" '. Tento pohled pak z hlediska RESTu můžeme udělat na třech místech: na straně klienta, poskytovatele zdroje či interceptorem. Protože chceme dát klientovi maximální komfort a navíc minimalizovat tok dat, předpokládejme, že tento nový pohled budeme budovat na straně poskytovatele zdroje, tedy na serveru.

Jak toho docílit? Velice jednoduše. Rozšíříme operaci GET o nepovinný parametr Filtr (nebo povinný s existující konstantou reprezentující nefiltrování). Na serveru se pak rozhodneme, zda máme či nemáme filtrovat a jak se k tomu dostaneme. Nemáme tak žádný další, tfuj, "virtuální zdroj", tfuj. A jak to v praxi provedeme? Jak to dělá HTTP - k operaci GET na kolekci přidáme parametr filter.

Pojďme ale ještě dál. Onen pohled reprezentovaný parametrem Filtr mění poměrně významně obsah, který klient dostane. Nejde tedy o čistý "jiný pohled na data". Ihned po interní operaci GET se na výsledek provede operace FILTR (a jestli je to uděláno v Javě, v XSLT/XPath či SQL, je celkem buřt). Můžeme tedy tuto dvojoperaci považovat za jednu - FILTEREDGET. GET pak nemá parametr Filtr, tento parametr je parametrem nové operace.

Zeptáte se - no jo, ale když HTTP operaci FILTEREDGET nemá, tak co s tím? Ale to je přece jednoduché, milý Watsone! Tak jak RESTová operace GET není HTTP GET, pouze se na ni mapuje, pak si řekněmež, že si operaci FILTEREDGET namapujeme tak, že URL HTTP GETové operace na kolekci rozšíříme o parametr filter ... :-D

Že je to stejné jako v případě parametru? Ale jděte. Pouze převod do HTTP je stejný. Na straně serveru vám to napoví, že tuto cestu je dobré řešit jinou interní operací. Při vytvoření RESTové (nebo i SOAPové) WebServisy to budete zveřejňovat jako jinou operaci.

Zkusím to teď ještě zobecnit:

Základní otázka Života, vesmíru a vůbec má jasnou odpověď - 42. Nejasná je právě ona otázka.

Otázka, zda cpát či necpát jazyk do URL má také jasnou odpověď - pro všechnu matku přírodu NEE!!!

Jasná otázka, zda použít princip separátních zdrojů, parametrizovanou operaci GET nebo dvě operace GET a FILTEREDGET/QUERY/COKOLI_PODOBNÉHO, jasnou odpověď nemá. Je třeba k tomu přistupovat s mužskou schopností plnohodnotné syntézy či ženskou intuicí:

Rozdílné zdroje použijte tam, kde se opravdu o dva rozdílné zdroje jedná. GET "Aktuální seznam členů CZLUGu", GET "seznam členů CZLUGu počáteční", GET "seznam členů CZLUGu verze 234".

Parametrizujte tam, kde se jedná o jiné formy reprezentace téhož zdroje. GET "Seznam členů CZLUGu"?platny_ke_dni=[puvodni|fcil|YYYY-MM-DD]. Nebo jiný formát záznamu ala WinStrom.

Jinou operaci, pokud se jedná o stejný zdroj dat, ale s až diametrálně odlišným obsahem - typicky vyhledávání. GET "Seznam členů CZLUGu", QUERY "Seznam členů CZLUGu"?query=ti_co_nezaplatili_a_zacinaji_pismenem_fň "

Ufff. Doufám, že to někomu pomůže při rozhodování či pro lepší pochopení principů RESTu.

pátek 20. listopadu 2009

WinStrom - krásný příklad REST API

Tak jsem se zase rozhodl vrátit se k oRESTování. První příspěvek bude o tom, že i u nás v republice umíme udělat pěkné RESTózní API.
Při shánění materiálů jsem dnes narazil na REST API k účetnímu systému WinStrom. A je opravdu pěkné. Ale má i své mouchy.

Samozřejmě jako transportní protokol použili HTTP. Podporují HTTPS a HttpBasic - což ve spolupráci s přístupovými právy dostatečně zabezpečuje bezpečnost dat. Používají klasické operace GET, POST, PUT a DELETE (PUT a POST zeqivaletnili, což ale samozřejmě není nic proti RESTóznosti API), používají celkem hojně HTTP status.

URL jsou taky HTTP. Celkem logicky nejsou neprůhledná - mají svoji logiku.

Pro práci s kolekcí jedné evidence to jsou:
/ID.firmy/typevidence{/[reports|properties|relations|filtr]}

a pro práci s konkrétní položkou
/ID.firmy/typevidence/ID.záznamu{.formát}{/podevidence} (tady si nejsem jist, jestli ten formát je povinný nebo není, IMHO by být neměl, ale z docky plyne, že je)

Co se týká RESTových operací, tak si vystačí se čtyřmi - klasický CRUD.

CREATE se volá na kolekci. Návratová hodnota je buď neúspěch nebo úspěch. Úspěch v sobě obsahuje identifikátor vytvořeného zdroje.

UPDATE se volá na konkrétní zdroj - tam jdou nová data, zpátky status operace.

DELETE je klasický - jenom jsem nenašel, na co vše se dá volat.

GET je pěkný. Je sice parametrizovaný, ale parametry lze rozdělit do tří kategorií - stránkování a řazení, přidání metadat a (s tím mám kapku problém) XPath na výsledek, jestliže je ve formátu XML (z důvodu omezení přenášených dat)

Až doposud popis a chvála. Teď ale vady na kráse:
  • XPath jsem už zmínil, ale to není zas takový problém
  • Operace CREATE vrátí identifikátor záznamu, nikoli URL, takže URL si uživatel musí sám poskládat, a to je samozřejmě proti RESTu
  • GETové URL obsahuje formát výsledku - zde by bylo na místě použít parametr v QUERY_STRING, ale chápu, že MS Explorer by si s tím nemusel poradit (alespoň v dřevních dobách používal MSIE příponu ke stanovení content-type :-) )
  • A na závěr to nejhorší. PARAMETR filtr pro fitrování dat na kolekci není použit jako parametr, nýbrž jako součást identifikátoru, což je VYSOCE nehezké. Cpát přímo do URL ořezanou obdobu SQL (viz syntaxe Filtrování záznamů) mi přijde více než nechutné.

pátek 1. srpna 2008

WebServisování, díl první - pojem WebServisa ( Web Service )

Dneska jsem Gůglil něco o JBossu a WebServisách a narazil jsem na terminologický problém - pod pojmem Raw Service si různí lidé představují různé věci. A protože jsem si sám nebyl jist, rozhodl jsem si všechno zase oživit, nastudovat a taky o tom něco napsat. Navíc vzhledem k několika diskusím, které jsem tu na téma WebServis rozvířil a v nichž se ukázalo vzájemné nepochopení základního pojmosloví, začnu s tím vším celým tak nějak z gruntu.

Úplně na začátku musím uvést, že ač jsem příznivcem překladů termínů do češtiny, tak anglický termín Web Service překladám jako (TWikiňácky) WebServisa. Vím, že mnozí češtinofilové preferují webová služba, ale mám k tomu překladu hned několik výhrad.

Ponejprv je třeba si říci, že ani samotné slovo Web se nepřekládá, pavučina se zkrátka neujala. Proto u tohoto termínu neexistuje precedent (který se mimochodem také nepřekládá :-) ). Dále pak nepřekládáme pojem Web Server.

Přestože by se dalo říci, že Webová Služba zní pěkně hezky česky a proč to nepoužít, mám jeden velký protipříklad. Mnoho lidí používá termín Webová Služba pro označení portálu nebo funkce portálu. Například https://kontrola.isvav.cvut.cz/ , http://www.zive.cz/default.aspx?server=1&article=141698, http://www.magic-shop.cz/webove-sluzby-atcomputers-s-v-zencart. Takže aby nedošlo ke zmatení nepřítele, budu i nadále používat terminus technicus WebServisa. Může se vám to nelíbit, můžete s tím nesouhlasit... ale to je tak asi všechno, co s tím můžete dělat.

A co to vlastně ta WebServisa je? Už toto je poměrně těžká otázka. Ještě před čtyřmi lety platilo, že v každé firmě, která se nějak podílela na onom WS-H (WebService Hype :-D ), měli svou vlastní definici. Přestože všichni tak nějak intuitivně chápali wocogo, každý si tento termín definoval tak, jak se mu hodilo, a tím se také vymezoval proti ostatním. "Ty že máš WebServisy? Ale kdeže! To MY máme WebServisy..." V roce 2003 (nejsem si rokem přesně jist) vyšel Sun s prohlášením, že ON dělá WebServisy už SEDM let! No nic. Uvedu pár příkladů definice:
* A service is an abstract resource that represents a capability of performing tasks that represents a coherent functionality from the point of view of provider entities and requester entities. To be used, a service must be realized by a concrete provider agent. (W3C ws-arch)
* A service is a mechanism to enable access to one or more capabilities, where the access is provided using a prescribed interface and is exercised consistent with constraints and policies as specified by the service description. (Oasis standard SOA-RM)
* WebService - Loosely coupled software components delivered over Internet standard technologies. (Systinet Server for Java glossary)
* Webová služba je podle definice W3C řešení, jak spolu aplikace mohou komunikovat a vyměňovat si informace přes Internet. (tak hovoří česká Wikipedie)

Néjlepe celou rozepři vystihuje asi Google.

"Kupodivu" ony terminologické pře přestaly přesně v okamžiku, kdy se buzzword WebServisa stal "out" a "in" bylo mluvit jen a jen o SOA.

Já tedy zkusím tak nějak shrnout onu definici ne do věty, ale bodů:
1) WebServisa je kus kódu, který zprostředkovává nějakou funkcionalitu, z pohledu z horního patra sémantiky atomickou.
2) WebServisa má přijímat data v (jednoduše) strojově zpracovatelném stavu a ve stejně jednoduše strojově zpracovatelném stavu produkovat.
3) WebServisa je dostupná svému "zákazníkovi" obdobným způsobem jako webové stránky, může tedy běžet jak na stejném počítači, tak na druhém konci světa.
4) Každá WebServisa má nějaký její jednojednoznačný identifikátor (URI), který je možno použít k jejímu dosažení.
5) Komunikační protokol mezi klientem a WebServisou je otevřený, kýmkoli použitelný, nepodléhá patentům (no, tak tady sice můžeme narazit, ale podle vyjádření IBM a Microsoftu nebudou svá vlastnická práva na SOAP nikdy zpoplatňovat), není závislý na implementaci WebServisy či klienta (je tedy zaručeno, že lze implementovat na všech různých platformách libovolným jazykem). Je tedy možné jednu WebServisu bez obtíží nahradit jinou od jiného dodavatele.
6) Totéž platí pro transportní protokol.

A co se ještě přidává jako "ještě by mělo platit, abychom to jako WebServisu uznali všichni":
1) Data jsou strukturovaná a textová, ideálně XML. Veškerá binární data jsou zakódována do textové podoby (nejčastěji algoritmem Base64).
2) WebServisa má dobře zdokumentované rozhraní.
3) Jako URI se používá URL.

A co je de facto standardem:
1) Transportním protokolem je HTTP a používá se HTTP-SOAP binding, protože na jiný není standard. HTTP je sice aplikační protokol, ale pro potřeby WebServis byl ohnutý tak, aby sloužil jako transportní vrstva.
2) Data jsou zabalena v SOAPové obálce.
3) Klient a WebServisa si spolu povídají jazykem, kterému rozumí Microsoft DotNet framework. Když MS přejde na modré trpaslíky, mýdlo bude zahozeno. Tolik k nezávislosti na jedné firmě.
4) Na popis rozhraní se používá WSDL.
5) Každé volání je synchronní request-response. K WebServisám se tak převážně přistupuje jako ke vzdáleným objektům, tedy takové vylepšené XML-RPC.

Neříkám, že je to přesně ono, ale plus mínus ano.

čtvrtek 31. července 2008

oRESTovaná externalizace dat aneb když to másh nahoře

Další díl z cyklu oRESTování začnu možná trošku zmateně a vyhlásím soutěž o druhou nejlepší RESTovou aplikaci, přičemž je nám všem jasné, že webové prohlížeče (webové stránky jako takové) jsou tou první.

Tak co, už jste na to přišli?

Nechám Vás ještě chvíli se trápit...

Tak dobře. Nebudu Vás dlouho napínat, jsou to Feed Readery.

Mezi námi bloggery není jediný, který by nevěděl, co to je a jen velmi málo, kteří nepoužívají žádný. No ale pro jistotu pro ty, kteří nevědí, o co se jedná, malá naučná vsuvka.

Před dávnými a dávnými lety vznikl ve vývojovém centru firmy Netscape protokol Rich Site Summary (RSS, košatý popis stránky), který umožňoval v kostce popsat obsah stránky. Nejdůležitější částí byl vlastní popis, používaný pro jejich portál (snad vůbec první skutečný portál) my.netscape.com. Jako podružné se tehdy jevily popisy částí stránky.

Postupně se ale se zaváděním publikačních systémů (a hlavně blogů) karta obrátila. Protokol byl přejmenován na Really Simple Syndication (skutečně jednoduchý výcuc, opět RSS, to je ale náhodička, co?) a jeho hlavní náplní se stalo informovat čtenáře stránek o novinkách. Realizace je vskutku jednoduchá - RSS stránky (říká se mu feed) obsahuje ke každému článku jeho identifikátor (typicky část URL článku), odkaz na článek a datum a čas publikace. Potom aplikace, která RSS umí číst (říká se jí čtečka RSS neboli Feed Reader), si poznamená všechny položky seznamu, nabídne jejich seznam uživateli a zvýrazní ty, které nově přibyly a nebo si je ještě nepřečetl. Feed Reader se tedy chová obdobně jako poštovní klient, až na to, že místo do poštovní schránky chodi na URL s RSS Feedem. Po novu se prosazuje ATOM, rozšíření RSS, které kromě vylepšené syntaxe feedů zavádí Atom Publishing Protocol umožňující nejen číst, ale i vytvářet a měnit RSS (Atom) Feedy.

O tom, že systém RSS feedů je RESTová aplikace, snad není pochyb. Distribuce RSS jako u webu (RSS má své URL), přesně definované rozhraní (dokonce i struktura dat), operace jedna jediná - GET, a to buď na RSS feed, stránku nebo její část, bezestavovost komunikace, kešovatelnost, ...

Co má ale společné seznam nových článků na blogu a externalizace (vyvezení ven) dat, Holmesi? To je přeci zřejmé, můj drahý Watsone.

Na blog a jeho články se lze také dívat (a bývá to tak implementováno) jako na relační tabulku, kde jeden řádek databáze odpovídá jednomu článku. Potom vlastně jednotlivé položky RSS feedu nejsou nic jiného než řádky této tabulky nějak převedené na klasické RESTózní zdroje (jeden článek, jedno URL, na němž GET vrací obsah tohoto článku) a ty pak nějak přetransformované do struktury RSS. Odtud je již jen krůček k zobecnění, kdy JAKOUKOLI tabulku, dokonce jakýkoli výsledek SQL dotazu jsme schopni převést do podoby RSS feedu.

A bác ho. Když jsme schopni jakákoli data převést do RSS, můžeme je pak KOMUKOLI na světě v této podobě předat (a navíc mu stačí poslat jenom URLčko a on už vždy bude mít RESTově-aktuální data!) a on si je bude schopen prohlédnou ve svém Feed Readeru.

Navíc můžeme jít ještě dál a říct, že díky pevně dané struktuře RSS lze tato data strojově zpracovat obdobným způsobem, jako by nám je vrátila WebServisa.

Díky transportnímu protokolu HTTP máme ještě k dispozici HTTP-Basic autentizaci a všudypřítomné HTTPS, takže máme bezpečnost dat téměř zadarmo. No není to krása?

Ale svět jde ještě dál. Vznikl nový Buzzword MASHUP. Mashup je stránka či celá webová aplikace vzniknuvší jako syntéza dvou i více webových stránek (aplikací). Typickým příkladem budiž Internetový obchod, který jenom přeprodává zboží jiných Internetových obchodů.

Mashup pak samozřejmě musí nějak získat data od "podřízených" aplikací a rozumět jim. Existují mešupovače (óch, jak je ta na naše řeč bohatá a krásná, že jo, dědo Kovando!), které dokáží vytáhnout data přímo ze stránek, ale nejlépe se pracuje se strojově zpracovatelnými daty, které pro mé potřeby (nebo obecně) někdo zveřejnil, neboli externalizoval. No a nejlépe, pokud tato data mají nějaký rozumný rozšířený formát, kterému rozumí každý. Třeba RSS. A když mashupem je zase RSS, máme tu nádhernou distribuovanou RESTovou aplikaci, ve které máme jediný formát zveřejněných dat - RSS, kde každý si jej může a umí stáhnout, přetransformovat do jiného RSS a to zase zveřejnit...

Na závěr zbývá už jenom jedna otázka. Kolik procent sebere ATOM SOAPu? IMHO není důvod na B2B používat SOAP. Také většina infrastrukturních WebServis jsou stejně jenom donory, dekorátory či akceptory dat, což lze krásně a jednoduše řešit právě ATOMem. A pokud doprostřed celého toho intranetového světa umístíte ATOM repositoř (náhrada za WebDAV), dosáhnete úžasné flexibility.

středa 30. července 2008

Jak oRESTovat Javí aplikaci

Dneska ráno jsem našel naprosto zajímavý článek, první ze série o RESTu, který objasňuje REST na příkladu jeho převedení do světa Javy.

První díl vzali autoři z trošku jiného konce - začali od Bindingu neboli vazby mezi klientem a serverem. Vazbu v RESTu definují jako asociaci logického jména na něco "fyzického", třeba kusu kódu, kus paměti či metodu.

Dávají do kontrastu vazbu mezi jménem třídy v Javě (a klasický ClassLoading) proti volné asociaci mezi URLčkem a "stránkou" Webu. Zasmál jsem se nad přirovnáním, že změna implementace třídy (v jejich příkladě java.util.Date) znamená (bez šíleného overheadu s vlastní implementací ClassLoaderu) restart celého JVM, což v případě Webu je věc naprosto komická. No schválně si představte restart celého Webu. Ten synchronizační komunikační protokol bych chtěl vidět... tedy nechtěl...

Takže si řekli, že:
1. Browser se zeptá Domain Name Service (DNS) na "tapikuv.blogspot.com" (v jejich případě www.theserverside.com, ale co bychom si to neupravili, že :-D) a zpět získá IP adresu.
2. Browser vytvoří TCP/IP spojení na onu IP adresu na portu 80.
3. Spojení použije na odeslání HTTP GET requestu na zdroj "/" na tapikuv.blogspot.com.
4. Server dostane HTTP request, něco s ním udělá a vrátí nějakou reprezentaci zdroje "/".
5. Browser ji dostane, něco s ní provede a zobrazí to uživateli.
6. nakonec browser shodí TCP/IP spsojení a "un-binds" (poměrně hodně podstatné slovo, viz níže) od endpointu.

Takže si kluci zavedli vlastní URI schéma "resource" (např. resource:/customers) a navrhli pár tříd:
1. Context (něco mezi JNDI kontextem a proxy)
2. Request (obdoba HTTP requestu)
3. Representaion (obecná třída, ve své podstatě obdoba java.lang.Object)

Celý proces pak probíhá tak, že na kontextu vytvoří request na konkrétní URI, přidají k němu co potřebují, nechají jej provést a zpět dostanou Representation.

Na první pohled nic nového pod sluncem, máme EJB sdílející s klientem jenom mezixicht (miluji toto slovo, které jsem před víc než 20 lety našel ve VTMku), JNDI Context.lookup(), zavolání metody EJBčka a návrat nějaké hodnoty.

Fígl je v tom, že v tomto systému je jenom jeden mezixicht, sdílí jej tedy VŠECHNA EJBčka. To umožňuje dramaticky omezit různá omezení. Klient se tak de jure nestará o evoluci takovýchto EJBček. Stačí mu jenom znát správné URIčko a umět se vypořádat s instancemi Representation.

Sranda je v tom, že výhody tohoto systému nepochopil téměř žádný diskutující. Odvolávky na zahození typovosti v Javě,když ji přece sami autoři používají, že do Javy to vůbec nepatří, že je to přece k ničemu, když ti server vrátí něco, co ty dopředu nevíš, že vrátí, či na to, že to všechno řeší přece CORBA, DCOM a SOAP, jsou velice srandovní. Šlo přece o vysvětlení na příkladu architektonického stylu. Težko přece budeme dělat RESTovou servisu na operátor ++, že...

Na druhou stranu se autoři zapomněli zmínit o jedné podstatné věci, a tou je právě onen "un-bind". Tato operace totiž není v RESTu definována, kde je nahrazena operací "rebind". Chápu, že ona jemná nuance nemusí být pro mnohé čitelná. Hlavní rozdíl je v tom, že ona vazba mezi logickým jménem a "fyzickou" reprezentací má obvykle trvání přesahující jeden request. Teprve když si klient usmyslí, že je načase aktualizovat odkaz, udělá onen "rebind". Kromě kešování bindingu tu navíc máme ještě kešování reprezentací, kdy zase klient rozhoduje, zda je na čase se podívat po aktuální verzi.

No a samozřejmě mám trochu potíž s onou třídou Context. Podle mne je mnohem lepší ji rozdělit na Registry, Repository a Proxy. Registry mi řekne "fyzičtější" odkaz (zde dělám rebind), Repository mi vrátí Proxy (které si kešuji) a na Proxy pak volám requesty. Přijde mi to logičtější a více RESTózní.

středa 18. června 2008

Metodika návrhu SOA aneb kdy začít s WSDL a kdy s kódem

Přečetl jsem si Vytvářet nejdříve WSDL nebo Java rozhraní od Petra Jůzy a rozhodl jsem se, že také připojím pár svých zkušeností.

Na otázku, zda začít nejdřív s WSDL nebo nejdřív implementovat a potom generovat WSDL neexistuje jednoznačná odpověď. A navíc je třeba podle Cimrmana vzít v potaz i roli kohouta, ale nepředbíhejme :-)

Bavme se tedy v prvé řadě o WebServise, u které tato otázka má smysl, tedy o RPC.

Nedá se říct, že by varianty měly své pro a proti. Prostě jsou každá na něco jiného.

Hodláte-li napsat WebServisu na zelené louce, máte na začátku dva výchozí předpoklady: a)bude to WebServisa někomu zveřejněná a která b)bude něco dělat. Pravděpodobně začnete s nějakou analýzou problému. Z analýzy vypadne struktura dat, která by měla kolovat tam a zase zpátky. Struktura se lépe popíše XML schematem než pomocí tříd. Nad ukázkovým XMLčkem se pak lépe přemýšlí jiným lidem, je to názornější. Proto je tedy v takovém případě nejlepší začít s XML schematem, přidat operace a máte WSDL. Z něj pak generovat kód.

Máte-li už napsaný kus kódu a chcete lokální volání roztrhnout SOAPem, není jednodušší cesty než označit nějakou fasádu jako WebServisu a nechat k ní vygenerovat WSDL. Nejčastější a nejhezčí je ale vypublikovat ji pomocí Endpoint.publish().

Já ale tvrdím, že tato otázka je ve své podstatě nesmyslná. Kde je jádro pudla, nebo lépe řečeno kohouta? V pohledu na věc.

Ať už jde o Integrační, B2B, Intranetový Infrastrukturní či Separační scénář, vždy je na počátku všeho zadání. Jak už nás učili na základní škole, zadání problému se klasicky popisuje trojicí množina vstupních hodnot, množina výstupních hodnot a přechodová funkce, popřípadě jejich množina. A to se dá říct jak o nově vznikající aplikaci či WebServise, také o fasádě nad legacy systémem. Ač se to nezdá, totéž platí i při roztrhávání, protože se může ukázat, že bude daleko čistější vygenerovat novou fasádu. V případě složitějšího problému komunikace mezi více participanty pak také víte (nebo aspoň tušíte), co si ti dva tam budou posílat. Každý z participantů má přece svoji roli a k roli patří zase vstupní i výstupní data a popis, co má dělat.

Proto je nejjednodušším postupem rozdělit si vstupy a výstupy na samostatné celky (= zprávy), ty ozobákovat, pojmenovat si jednotlivé funkce (=operace) a spárovat zprávy k operacím. Výsledkem je pak kostra WSDL. Pro lenochy je pak možné vygenerovat kód z oné kostry, vypublikovat WebServisu čistě jako třídu bez WSDL a do kostry doplnit zbývající části WSDL, které za nás vygeneroval publisher.

Tento přístup má hned několik kladů:
* tvůrce se musí nejdříve zamyslet nad strukturou dat, což nebývá tak úplně zvykem
* to zabrání nutnosti neustále měnit rozhraní (a tím i WSDL) při změně datového modelu
* tvůrce uvažuje v intencích dokumentů a operací nad nimi, což mu umožní přehoupnout se přes onen RPC XORBA zlozvyk
* WSDL je čitelné a "hezké" a interoperabilní (pokud je navrženo jako document-wrapped (.NET nic jiného neumí))
* celý návrh systému je pak mnohem lépe udržovatelný, modularizovatelný, rozšiřitelný, znovupoužitelný, lépe odladitelný

na závěr se s vámi podělím o jednu velice podstatnou metodickou pomůcku. Z jednoho neúspěšného projektu Systinetu jsem si odnesl následující systém návrhu SOA aplikací:
1)Vyjmenuj si všechny role participantů, kteří se na aplikaci (procesu) podílejí.
2)Namaluj si síťový graf procesu podle jednotlivých rolí.
3)Rozděl proces na ucelené podprocesy.
4)Vytvoř XML dle struktury procesů, a to tak, že root elementem bude název procesu a v něm na stejné úrovni jako elementy názvy podprocesů. Při vzájemném zanoření podprocesů zanoř element podřízeného podprocesu do elementu nadřazeného.
5)Ke každému participantovi se pokus navrhnout kostru struktury dat (XML, stačí root element a jednu úroveň elementů v něm), které mohou od nich ostatní požadovat.
6)Tato XMLčka sluč do jednoho dokumentu, a to tak, že je podle pořadí v síťovém grafu poskládáš pod sebe do elementu procesu či podprocesu, ve kterém se role vyskytuje.
7)Ke každé roli označ data, která potřebuje pro svoji práci.
8)Z těchto dat poskládej ke každé roli zprávu, kterou bude participant akceptovat na svém vstupu.
9)Data, která participant produkuje, označ jako odchozí zprávu.
10)Dopodrobna rozpracuj XML schema jednotlivých zpráv

Každá role pak odpovídá jedné operaci WebServisy. Pokud hraje jeden participant více rolí, má jeho WSDL více operací. Každý proces i podproces má ještě dvě fáze, které je také nutno zmínit: iniciační (musí vyletět první zpráva) a ukončovací (poslední zpráva musí někam doputovat).

A co se týká implementace celého systému, máme minimálně principiálně čtyři možnosti.

První a nejlepší možností by bylo použít principy z onoho neúspěšného (když vymyslíte něco, co předběhne dobu o deset let, a stane se to díky tomu nezproduktovatelné, naštve to) produktu. V dubnu 2010 mi vyprší klauzule o mlčenlivosti, tak si počkejte na podrobnosti :-) Nemohu Vás bohužel ani odkázat na nějaký veřejný zdroj, protože bylo všechno staženo včetně blogspotů :-(

Další možností je pouštět data do messagingového systému, kde budou zprávy z jedné instance procesu korelovány. Ale to jsme u TIBCO Randezvous a to Vám fakt nemohu doporučit ;-) .

Třetí možností je dát do každé zprávy tranzitivní obal všech zpráv požadovaných mými následovníky. Tento Message Decorator pattern se používá v ESB, má jak své výhody, tak nevýhody. Některé věci v něm nejde bez Cimrmanova úkroku stranou dělat vůbec.

Čtvrtá možnost je ta nejčastější. Každý proces či subproces je implementován jednou fasádní WebServisou. Pro jednoduché věci je BPEL, složitější logiku je lépe kódovat. Iniciační fázi odpovídá příjem zprávy a finalizační pak odeslání výstupní zprávy. Pro jednoduchost je možno implementovat několik rolí v procesu přímo ve fasádě, ale je dobré si tam minimálně nechat čisté rozhraní pro případné oddělení.

PS: Kdyby to pomohlo alespoň jednomu z vás, nepsal jsem to zbytečně. A vyjmenovat výhody takovéto metodologie návrhu nechám na Vás jako domácí cvičení do komentářů

úterý 17. června 2008

Bude MVC model nahrazen architekturou RIA + SOA?

Uvidíme :-)
Každopádně jsem si dnes přečetl článek od Nolana Wrighta a řekl si - zase další BFW (Buzz Flame War :-) ). Ale přeci jenom mi to nedalo a trošku jsem se nad tím zamyslel. Nemá samozřejmě smysl papouškovat názory od CEO firmy produkující Appcelerate, platformu pro "tvorbu RIA+SOA aplikací" už jenom proto, že s ním nemohu úplně souhlasit.

V čem se vlastně tak liší tyto dvě architektury?
ModelViewController je architektura, která dělí celou aplikaci na tři (ale spíš čtyři) vrstvy:
* View neboli prezentační vrstvu
* Model neboli reprezentaci dat (a tou čtvrtou pod Modelem je pak databáze)
* Controller nebo business logika

Co se týká vývoje Webových Aplikací, o které jde především, se prezentační logika sestává s generování HTML kódu (ve světě Javy JSP) (no dobře, máme ještě nějaké JavaScripty, ale ty slouží čistě jako podpůrný prostředek pro zobrazení, nic víc), Model je Objektová vrstva nad relační databází (ve světě Javy třeba EntityBeans či Hibernate POJOs) a Controller je pak něco mezi (typicky Session Beany + různé controller frameworky, jako třeba Struts, Tapestry či HyperQbs :-) )

Stav je držen primárně na straně Modelu, protože na klientovi toho moc držet nemůžete a Controller by měl být bezestavový.

RIA+SOA je oproti tomu dvouúrovňová architektura. Na straně klienta máme aplikační logiku napsanou v JavaScriptu, na straně serveru pak Webové Služby. Stav se primárně drží na straně klienta a WebServisy slouží pouze primárně jako Donory a Akceptory dat (a tady se s Nolanam vcelku lišíme, protože on přenáší business logiku na stranu WebServis, což potírá samu podstatu RIA - RIA není jenom o pěkném Ajaxovaném xichtu, ale také o tom, že klient obstarává velkou část aplikační logiky).

Stav je tady držen na dvou místech. Primárně je držen na straně klienta a teprve až výsledky aplikace se promítnou na server přes rozhraní Webových služeb, které pak slouží jako poskytovatelé oněch výsledků dalším aplikacím.

Taková RIA+SOA architektura pak přímo vybízí k použití Loosely-Coupled Coarse-Grained WebServis a či dokonce RESTu.

středa 30. dubna 2008

Jak na JBossí WebServisy v IDEA

Po několika dnech Googlování a pokusů a omylů se mi konečně podařilo rozchodit první WebServisí komunikaci klient-servisa na zákeřné kombinaci: Windows XP, Sun J2SE 1.6.0_5, JBoss 4.2.2GA, IntelliJ IDEA 7.0.3

Co je třeba udělat:

  1. nainstalovat ony zmíněné produkty :-)
  2. nepoužívat implicitní JAVA_HOME/jre/lib/endorsed adresář, protože se buď nepodaří zkompilovat vygenerované stuby nebo začne řvát JBoss
  3. stáhnout si a nainstalovat jbossws patch:

    1. rozbalit (ideálně hned vedle jboss-4.2.2GA, ať to máte pohromadě)
    2. přejmenovat JBOSSWS_HOME/ant.properties.template na JBOSSWS_HOME/ant.properties
    3. v JBOSSWS_HOME/ant.properties nastavit propertu jboss422.home na JBOSS_HOME (např ../jboss-4.2.2GA)
    4. v JBOSSWS_HOME/build/build-deploy.xml odstranit závislost targetu deploy-jboss422 na undeploy-jboss422 (jinak na Vás zařve, že nemůže smazat soubory v JBOSS_HOME)
    5. pokud není ant v cestě, tak je třeba nastavit
      set "ANT_HOME=JBOSSWS_HOME\tools\ant"
      set "PATH=%ANT_HOME%\bin;%PATH%"

    6. v JBOSSWS_HOME spustit ant deploy-jboss422 - tím se do JBOSS_HOME/lib/endorsed nahrají patřičné jary JAXBčka


  4. napsat si servisu (Web a WebService (JAXB2.1, nikoli Axis))
  5. nadeployit servisu do JBossu
  6. založit projekt pro klienta (WebService client, JAXB2.1, nikoli Axis)
  7. vygenerovat stuby z WSDLka WebServisy
  8. upravit example.HelloWorldClient tak, aby zavolal onu servisu
  9. vytvořit Run Configuration pro klienta (typ Application)
  10. do VM Parameters dát "-Djava.endorsed.dirs=C:\Documents and Settings\tapik\.IntelliJIdea70 \system\webservices\jaxws-ri-2.1\"
  11. spustit a doufat, že funguje

Pokud funguje, je vymalováno.

středa 23. dubna 2008

Krátké oRESTování

O RESTu se všude vedou dalekosáhlé debaty. Například zde se Vlasta Vávrů snaží přijít oné věci na kloub.
Nejsem sice kdovíjaký REST-guru, ale svoje si k tomu řeknu:
* REST je o zdrojích (resourcech). Každý zdroj má svou jednoznačnou identifikaci - URI. Po dobu jeho životnosti pod tímto URI vždy a za každých okolností najdete tento zdroj (jestli je to URLčko nebo URN do repozitáře je buřt). Každý zdroj JE STAVOVÝ. Minimální sada stavů je jsem - budu - byl jsem. Představíme-li si jako zdroj seznam členů CZLUGu, je jasné, že se bude v čase měnit. Ale pokaždé dostanete logicky totéž, aktuální seznam členů. No, aktuální, RESTózní architektura umožňuje plnohodnotné interceptory, kde například může stát cache, která vrátí seznam klidně včerejší. I o tom REST je. Data nemusí být vždy aktuální.
* důležitou vlastností RESTózních aplikací je omezená množina operací, které lze s daným zdrojem provádět. Proto je HTTP RESTózní, má čtyři hlavní operace GET, POST, PUT a DELETE.
* komunikace MUSÍ BÝT BEZESTAVOVÁ, tedy komunikace nesmí zahrnovat stav klienta. To ale neznamená, že sezení jako takové je v RESTu nesmysl. Pouze jeho řešení pomocí sušenek je nepřípustné. Mám-li sezení zakomponováno do URL, jsme v pohodě. Samo sezení se stává zdrojem. Dostávám se tak do situace, kdy logická operace přidej produkt s URI:XY do košíku patřící sezení s URI:SSS (třeba HTTP POST SSS produkt=XY) bude mít za následek vždy to totéž a o to právě v RESTu jde. Dalším problémem pro bezestavovost komunikace jsou <INPUT TYPE="HIDDEN">. Tyto jsou v HTML zavedeny právě pro udržení stavovosti komunikace, čili typická antiRESTóznost.
Doufám,že si někdy najdu čas a všechno, co o RESTu vím, sem napráskám.