SOAP Stateful Web Service - Java/C#
Vzpomínám si na historku, kterou mi vyprávěl můj bratranec, toho času majitel stavební firmy. Vyhodil z kabiny bagristu, který tvrdil, že to nejde, sedl si tam sám a ukázal, že to jde. Tohle já jsem naposledy neudělal, takže alespoň tímto článkem to chci odčinit.
Webové služby obvykle využívají HTTP protokol, který je bezstavový. Jeho stavovost dokážeme zajistit pomocí session. Když zajistíme stavovost protokolu, dokážeme zajistit i stavovost webové služby. Tak jako vám v USA neprodají střelnou zbraň okamžitě, ale musíte přijít až za několik dní, abyste s ní v afektu nespáchali zločin, i tady je potřeba se důkladně zamyslet, zda jo to dobrý nápad. Řekněme, že my jsme pádný důvod měli.
Java server
Není obtížné najít návod na Java stateful web service server. Nicméně je nešikovný v tom, že si manuálně musíte spravovat svůj objekt v HttpSession, ke které se musíte dostat přes WebServiceContext. Jsem vnitřně přesvědčen, že to jde vždycky udělat lépe a šlo to i tentokrát. Ostatně na co máme SessionScope a dependency injection?
Java klient
Aby klient s takovou službou dokázal fungovat, stačí v Javě podle návodu jednoduše přidat následující.
((BindingProvider)port).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);
C# klient
V C# to bylo složitější z toho důvodu, že jsem jako javista dostal odpověď, že to nejde. Propracoval jsem se ke klíčovému slovu CookieContainer, ale to znamenalo vracet se ke starší verzi jejich frameworku. Alespoň nás to přivedlo na stopu a ke konečnému řešení už byl jen krůček. Programově nastavíte následovně. Zle pochopitelně zapnout i v xml konfiguračním souboru bindingu.
SoapUI klient
K testování webových služeb nejspíš používáte nástroj SoapUI. A ani tam není stavová webová služba problém. Stačí si do hlaviček session přidat. Pro ilustraci přikládám screeshoty.
Contract First
Architektonická odbočka. Stále ještě ne všichni vzali za své, že správný způsob tvoření webových služeb je contract first, tedy sepsat wsdl (kontrakt) a z toho teprve generovat kód. V oblibě je pro programátory pohodlnější varianta: nabušit kód a z toho mi přece něco vyleze.
Spring framework považuji za úžasnou školu softwarového designu. Prohlašují, že jediný správný způsob je contract first, a proto Spring přístup code first vůbec nepodporuje. Vybírám argumenty z jejich dokumentace, konkrétně kapitoly Why Contract First.
Nejdůležitějším úkolem webových služeb je jejich interoperabilita: podpora více platforem jako Java, .NET, Python, PHP atd., které mají různé knihovny, takže je potřeba používat něco, co mají společného, a tím je XML. Třeba TreeMap nemá v XML žádný standard a každý jazyk by si to generoval po svém. Nemluvě o datu. Další třešničkou jsou třeba cyklické grafy, které by v XML vedly k rekurzi.
Pokud generujete wsdl z kódu, jak zaručíte, že se vám kontrakt nezmění? Občas je potřeba rozhraní služby změnit. V Javě pak typicky vytvoříme intefrace MyService2 a k tomu implementaci. Stará služba musí pochopitelně ještě běžet kvůli klientům, kteří doposud nezmigrovali.
V contract first přístupu je slabá vazba (looser coupling) mezi kontraktem a implementací, což nám umožňuje mít obě verze v jedné třídě. Můžeme například použít XSLT transformace staré zprávy do nové.
Stejně jako má ORM problémy s mapováním relačních databází na objekty, tak podobné problémy má i XML. Věci nejsou tak jednoduché, jak se zdají. Je velký rozdíl mezi hierarchickou strukturou XML a grafovým Java modelem. V XSD lze rozšířit data tak, že zavedete nějaké restrikce, třeba regulární výraz ke stringu, něco takového vám Java neumožní.