%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% :JAX-WS
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{JAX-WS} \label{JAX-WS}

JAX-WS je oficiální framework od společnosti Sun pro vytváření SOAP webových služeb v~jazyce Java v~souladu se specifikací Java EE. JAX-WS využívá anotací v~jazyce Java, umožnuje tak programovat webovou službu stejným způsobem jako obyčejný kód v~Javě bez nutnosti dědění nebo využívání speciálních knihoven. Dokonce můžete vzít nějakou již naprogramovanou skupinu tříd a~během krátké chvíle z~ní udělat webovou službu pouze dodáním pár řádek anotací, které navíc neohrozí její chod v~desktopovém prostředí. Zároveň je JAX-WS zautomatizovaný, umožní vám tak naprogramovat službu snadno a~rychle.




\subsection{@WebService anotace}

Jedinou věcí, která je potřeba pro nastavení třídy jako webové služby je doplnit takovouto třídu pomocí \texttt{@WebService} anotace z~balíčku \texttt{javax.jws}. To řekne servlet kontejneru, že tuto třídu si přejeme zveřejnit jako webovou službu a~že její (veřejné) metody mohou volat klienti po síti prostřednictvím protokolu SOAP. Jelikož \texttt{@WebService} anotace je 
interpretována až za běhu na serveru, můžeme takto anotovanou třídu testovat pomocí frameworku JUnit tak, jako by šlo o~obyčejnou třídu vytvořenou v~Javě (POJO). Další výhodou je, že na vytvářenou třídu nejsou, až na jednu výjimku, kladeny žádné požadavky co se týče dědičnosti nebo implementace metod z~rozhraní.

\begin{Verbatim}
@WebService
public class Account \{

\}
\end{Verbatim}




\subsection{Jmenný prostor pro webové služby}

Pokud chceme pro svou webovou službu použít jmenný prostor, můžeme tak učinit pomocí nastavení hodnoty parametru \texttt{targetNamespace} anotace \texttt{@WebService}. Implicitně je tento parametr nastavený na prázdný řetezec. Pokud nezadáme svou vlastní hodnotu, framework JAX-WS vygeneruje jmenný prostor podle URI celé webové služby. Je potřeba brát tuto skuečnost na vědomí, jelikož vygenerovaný jmenný prostor nebudeme znát a~budeme se na něj muset podívat do WSDL dokumentu (podrobnosti v~kapitole \ref{WSDL})

\begin{Verbatim}
@WebService\codeHighlight{(targetNamespace="piggybank")}
public class Account \{

\}
\end{Verbatim}

Tímto jsme specifikovali, že naše webová služba bude ležet ve jmenném prostoru \emph{piggybank}. Teď si již nemusíme dělat starosti s~WSDL souborem, jelikož název jmenného prostoru známe (sami jsme si ho vymysleli).




\subsection{Bezparametrický konstruktor}

Jedinou výjimkou z~volnosti navrhování třídy je, že třída musí mít veřejný bezparametrický konstruktor. To je logické, když si zvážíme, že její instance vytváří za běhu aplikace servlet kontejner, který ani nemůže tušit, jaké hodnoty parametrů bychom po něm chtěli. Pokud potřebujete zpracovávat nějaký parametr spojený se všemi, nebo věšinou nabízených metod, není jiná možnost než takovýto parametr předávat v~každé metodě zvlášť jako u~procedurálního programování.





\subsection{Metody webové služby}

V~JAX-WS jsou implicitně všechny veřejné metody nabídnuty pro vzdálený přístup. Pokud potřebujeme, aby některá veřejná metoda nebyla přístupná zvenčí přes protokol SOAP, můžeme použít anotaci \texttt{@WebMethod} z~balíčku \texttt{javax.jws}. Jakmile použijeme, byť jen jedenkrát, tuto anotaci, mění se v~celé třídě této webové služby dříve zmíněné pravidlo na: ``V~JAX-WS jsou pro vzdálený přístup nabízeny takové metody, které jsou veřejné a~navíc anotované pomocí \texttt{@WebMethod}''. Pro větší přehlednost zdrojového kódu je doporučeno anotaci \texttt{@WebMethod} používat vždy a~nespoléhat na to, že si případný čtenář kódu implicitní přístup frameworku pamatuje.

\begin{Verbatim}
@WebService(targetNamespace="piggybank")
public class Account \{

    \codeHighlight{private double balance;}

    \codeHighlight{@WebMethod}
    \codeHighlight{public double getBalance() \{}
    \codeHighlight{    return balance;}
    \codeHighlight{\}}

\}
\end{Verbatim}

Do webové služby \texttt{Account} jsme dodali atribut \texttt{balance} (zbytek na účtu) spolu s~přístupovou metodou \texttt{getBalance}. Ta se bude we webovém rozhraní služby jmenovat stejně, jako ve zdrojovém kódu, tedy \texttt{getBalance}. Pokud se vám takovéto jméno nelíbí (například kvůli použití camelCase), můžete ho změnit pomocí hodnoty parametru \texttt{name} anotace \texttt{@WebMethod}. Takováto změna se uplatní hlavně, pokud jako webovou službu zveřejňujete nějakou starou třídu z~dob, kdy vypovídající názvy metod zdaleka nebyly pravidlem.




\subsection{Návratová hodnota webové metody}

Jak je patrné z~předchozího příkladu, návratová hodnota webové metody se deklaruje velmi jednoduše -- jako u~běžného programování. Takováto hodnota bude v~SOAP odpovědi uložena v~elementu implicitně pojmenovaném \texttt{return}. Pokud chceme toto jméno změnit na něco více vypovídajícího, můžeme to provést pomocí anotace \texttt{@WebResult} z~balíčku \texttt{javax.jws}. U~té je třeba nastavit hodnotu parametru \texttt{name} na požadované jméno.

\begin{Verbatim}
@WebService(targetNamespace="piggybank")
public class Account \{

    private double balance;

    @WebMethod
    \codeHighlight{@WebResult(name="balance")}
    public double getBalance() \{
        return balance;
    \}

\}
\end{Verbatim}

V~příkladu jsme změnili výchozí jméno návratové hodnoty \emph{return} na nové jméno \emph{balance}, které lépe vypovídá o~vráceném výsledku. JAX-WS jakoukoliv návratovou hodnotu zabaluje ještě do elemenu \texttt{MResponse}, kde část jména \texttt{M} se generuje podle názvu webové metody a~navíc leží ve jmenném prostoru webové služby. Toto chování nelze změnit. Vrácená SOAP odpověď na metodu \texttt{getBalance} proto bude vypadat takto:

\begin{Verbatim}
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
    <ns2:getBalanceResponse xmlns:ns2="piggybank">
      <balance>2000.0</balance>
    </ns2:getBalanceResponse>
  </S:Body>
</S:Envelope>
\end{Verbatim}





\subsection{Parametry webové metody} \label{JAX-WS Web Params}

Velmi často budete potřebovat webové metodě dodat parametry. Ty je možné předávat implicitně pouze tak, že je metoda deklaruje (jako u~klasického programování), nebo je ještě doplnit anotací \texttt{@WebParam} z~balíčku \texttt{javax.jws}. Pokud použijeme implicitní přístup, pak JAX-WS bude při nasazení metody na síti a~generaci WSDL souboru ignorovat pravé jména těchto parametrů a~namísto nich bude jména generovat jako \emph{arg0, arg1,...}. Pokud chceme aby měly parametry i~ve webovém rozhraní nějaká intuitivní jména, musíme jim je dodat přes parametr \texttt{name} anotace \texttt{@WebParam}.

\begin{Verbatim}
@WebService(targetNamespace="piggybank")
public class Account \{

    private double balance;

    @WebMethod
    @WebResult(name="balance")
    public double getBalance() \{
        return balance;
    \}

    \codeHighlight{@WebMethod}
    \codeHighlight{@WebResult(name="balance")}
    \codeHighlight{public double deposit(@WebParam(name="amount") double amount) \{}
    \codeHighlight{    balance += amount;}
    \codeHighlight{    return balance;}
    \codeHighlight{\}}

\}
\end{Verbatim}

Tímto jsme přidali metodu \texttt{deposit} pro vkládání penněz na účet. Částku, kterou chceme vložit specifikujeme pomocí hodnoty parametru \texttt{amount}. Jelikož nám jde o~to mít svou webovou službu profesiálně vytvořenou s~dobře čitelným kódem, použili jsme anotaci \texttt{@WebParam}, ve které nastavíme jméno parametru \texttt{amount} na ``amount'' i~pro webové rozhraní celé služby.




\subsection{Jmenný prostor parametrů}

Parametry webových metod neleží implicitně v~žádném jmenném prostoru. Jde o~stejný přístup jako v~jazyce C++, resp. Java. Obecně není dobré používat pro parametry metod jmenné prostory. Pokud byste ale i~přesto chtěli mít parametry začleněné v~nějakém jmenném prostoru, je možné to provést nastavením hodnoty parametry \texttt{targetNamespace} u~anotace \texttt{@WebParam} obdobně, jako jsme to dělali u~celé webové služby.




\subsection{Datové typy pro parametry a~návratové hodnoty}

Jako parametr nebo návratovou hodnotu můžeme použít jakýkoliv primitivní datový typ nebo objekt typu \texttt{String}. Pokud chceme použít nějaký námi navržený objektový datový typ, musí být tento objekt serializovatelný pomocí technologie JAXB. Jeho serializace na XML stejně jako jeho deserializece proběhne automaticky, nemusíme se tedy o~nic dalšího starat.




\subsection{Definování koncových bodů}

Koncové body webové služby jsou v~JAX-WS definovány v~souboru \emph{sun-jaxws.xml} v~adresáři \emph{WEB-INF}. Tento soubor obsahuje jednoduché mapování části URL na třídy webové služby. Následující příklad ukazuje strukturu tohoto souboru.

\begin{Verbatim}
<?xml version="1.0" encoding="UTF-8"?>
<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
  <endpoint implementation="netukar.piggybank.soap.Account" 
            name="Account"
            url-pattern="/account"/>
</endpoints>
\end{Verbatim}

Předpokládejme, že celá aplikace bude nasazena na \emph{www.piggybank.com}. Potom zaslání SOAP požadavku na adresu \emph{www.piggybank.com/account} bude zachyceno zpracovávajícím servletem který tento požadavek analyzuje, vytvoří istanci třídy \texttt{Account} z~balíčku \texttt{netukar.piggybank.soap} a~zavolá příslušnou metodu této instance. Moderní programovací prostředí jako NetBeans vám budou takovéto mapování generovat a~udržovat automaticky.






\subsection{Autorizace v~JAX-WS}

Pro webové služby je celkem běžné, že některé metody požadují autorizaci a~autentikaci. Pokud náš bankovní účet v~aplikaci Piggy Bank má opravdu fungovat, musíme zařídit, že s~ním může manipulovat pouze majitel účtu. Nejdříve potřebujeme mít na serveru vytvořený uživatelský účet s~jménem, heslem a~přidělenou rolí nebo skupinou (záleží na druhu serveru). Pokud používáte některý ze serverů popsaných v~příloze, najdete tam i~postup jak takovýto účet vytvořit. V~opačném případě se budete muset poradit se správcem serveru, na kterém pracujete.

Předpokládejme, že máme na serveru založený účet s~rolí \emph{piggybank\_customer}. Potom omezit přístup webových metod můžeme pomocí anotace \texttt{@RolesAllowed} z~balíčku \texttt{javax.annotation.security}, která bere jako parametr název role. Takovouto anotaci pak přidáme ke každé metodě, u~které budeme žádat autentikaci.

\begin{Verbatim}
@WebService(targetNamespace="piggybank")
public class Account \{

    private double balance;

    @WebMethod
    @WebResult(name="balance")
    \codeHighlight{@RolesAllowed("piggybank_customer")}
    public double getBalance() \{
        return balance;
    \}

    @WebMethod
    @WebResult(name="balance")
    \codeHighlight{@RolesAllowed("piggybank_customer")}
    public double deposit(@WebParam(name="amount") double amount) \{
        balance += amount;
        return balance;
    \}

\}
\end{Verbatim}

Ještě je potřeba předat zprávu o~omezení přístupu serveru. To uděláme v~konfiguračním souboru \emph{web.xml} pomocí XML elementů \texttt{security-constraint} a~\texttt{login-config}. Omezení může vypadat třeba takto:

\begin{Verbatim}
<security-constraint>
  <display-name>SecurityConstraint</display-name>

  <web-resource-collection>
    <web-resource-name>WRCollection</web-resource-name>
    <url-pattern>/account</url-pattern>
  </web-resource-collection>

  <auth-constraint>
    <role-name>piggybank_customer</role-name>
  </auth-constraint>
</security-constraint>

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Piggy Bank Account</realm-name>
</login-config>
\end{Verbatim}
 
Důležité jsou elementy \texttt{url-pattern}, kde je uvedena adresa chráněného zdroje, soubor elementů \texttt{role-name} (může jich být i~více za sebou), kde je uvedeno, které role mají, po příslušné autentikaci, povolený přístup k~takovémuto zdroji, a~element \texttt{auth-method}, který obsahuje autorizační metodu (metody byly popsány v~kapitole \ref{HTTP Authorization}). 

Anonymní uživatel nemá přiřazenu žádnou roli, tedy ani \emph{piggybank\_customer}. Pokud tedy někdo na server pošle přes protokol HTTP SOAP požadavek na vybrání peněz z~účtu (jakéhokoliv), vrátí se mu odpověď \texttt{401 Unauthorized}. Takovýto uživatel pak musí přeposlat svůj požadavek s~udáním svého uživatelského jména a~hesla jak bylo popsáno v~kapitole \ref{HTTP Authorization}




\subsection{Sporné body JAX-WS}

Přestože JAX-WS nabízí velmi pohodlnou možnost pro vytváření SOAP webových služeb, nevyhnul se některým chybám. Nešikovné je generování jmen parametrů zmíněné v~\ref{JAX-WS Web Params} Bohužel Java reflection API nedává možnost získat názvy parametrů. Co je horší, JAX-WS nerespektuje specifikaci HTTP ani specifikaci protokolu SOAP od W3C. Ta říká, že posíláme-li SOAP požadavek přes protokol HTTP, pak jde o~MIME typ \texttt{application/soap+xml}. Servlet \texttt{WSServlet} z~balíčku \texttt{com.sun.xml.ws.transport.http.servlet} dodávaný firmou Sun jako výchozí pro JAX-WS, zahazuje všechny SOAP zprávy, které nemají MIME typ \texttt{text/xml}. Dokonce i~typ \texttt{application/xml}, který se běžně pro strojově zpracovávané XML používá, je zahozen a~servlet vrátí odpověď \texttt{415 Unsupported Media Type}.

Dále pak pokud pošleme na server SOAP požadavek se špatnou syntaxí nebo voláme neexistující metodu, namísto korektní odpovědi \texttt{400 Bad Request} vrátí server \texttt{500 Internal Server Error}. Co je pak podivné, tak pokud v~metodě použijeme neočekávaný parametr, tak dostaname odpověď \texttt{200 OK} a~volání metody se na serveru zpracuje jakoby bylo v~pořádku (takovýto parametr je ignorovám).




\subsection{Závěr}

JAX-WS nabízí rychlou a~komfortní možnost pro psaní webových služeb pro protokol SOAP. Mezi hlavní výhody patří dobře navržené anotace s~intuitivními názvy. Celý framework je funkční a~jednoduchý na používání. Hlavní práce byla přesunuta na zpracovávající servlet. Zmíněné nesrovnalosti se neprojeví, pokud webovou službu používáme správně. Celkově lze JAX-WS pro vyváření webových služeb doporučit. Vytvoření desktopového klienta není bohužel s~JAX-WS možné.


Použitá literatura:\\
\cite{Netbeans JAX-WS Getting Started} \emph{JAX-WS tutoriál na Netbeans.org}\\
\cite{Enterprise JavaBeans 3.0} \emph{Enterprise JavaBeans 3.0 -- Kapitoly 18 a~19}\\
