Úvod
V Jave jestvuje veľké množstvo implementácií odporúčania Web Services a protokolu SOAP. Za všetky spomeňme Apache CXF, Spring Web Services a najmä Glassfish Metro, referenčnú implementáciu špecifikácie JSR 224: JavaTM API for XML-Based Web Services (JAX-WS) 2.0.
Práve Metro slúži ako východisko pre implementáciu, ktoré sú priamou súčasťou Javy 6 a novšej.
Ukážeme si použitie tejto technológie na príklade servera a klienta.
Server
Príprava
Vytvorme si systém na prihlasovanie študentov na skúšky:
public class DefaultTermService {
private List<Term> terms = new ArrayList<Term>();
public DefaultTermService() {
terms.add(new Term(new Date(107, 12, 12), "UINF/PAZ1c", 100));
terms.add(new Term(new Date(107, 12, 15), "UINF/PAZ1c", 75));
terms.add(new Term(new Date(107, 12, 12), "UINF/TVY1a", 50));
}
public List<Term> getTerms(String courseCode) {
List<Term> filteredTerms = new ArrayList<Term>();
for (Term term : terms) {
if(term.getCourseCode().equals(courseCode)) {
filteredTerms.add(term);
}
}
return filteredTerms;
}
public boolean signup(Student student,
String courseCode, Date date) {
List<Term> filteredTerms = new ArrayList<Term>();
for (Term term : terms) {
if(term.getCourseCode().equals(courseCode)
&& term.getDate().equals(date)
&& term.getFreeSlots() > 0)
{
filteredTerms.add(term);
return true;
}
}
return false;
}
Trieda Term
je nudná štruktúra pre dáta skúšky s inštančnými premennými pre jej dátum, názov predmetu a maximálnu kapacitu prihlásených študentov.
Ak chceme publikovať inštanciu triedy ako webovú službu v rámci špecifikácie JAX-WS 2.0 v Jave 6, stačia na to dva kroky:
- dodať anotácie, ktorými vyhlásime triedu za vzdialene dostupnú
- spustiť server a publikovať objekt
Vytvorenie anotácií
Najprv anotujeme interfejs, inak povedané, k triede DefaultTermService
dodáme anotáciu @javax.jws.WebService
:
@WebService
public class DefaultTermService implements TermService {
...
}
Publikovanie služby
V prípade, že máme vygenerované triedy, je publikovanie služby záležitosťou jedného riadka:
public class Server {
public static void main(String[] args) {
Endpoint.publish("http://localhost:8888/terms",
new SimpleTermService());
}
}
Uvedieme URL adresu, na ktorej sa publikuje implementačná trieda DefaultTermService
, a v druhom parametri dodáme inštanciu triedy, ktorá realizuje webovú službu. Po spustení Servera sa naštartuje interný HTTP server, ktorý začne obsluhovať požiadavky.
Ak túto adresu navštívíme z prehliadača, uvidíme testovaciu stránku popisujúcu nasadenú službu, vrátane odkazu na súbor WSDL, ktorý sa štandardne nachádza na http://localhost:8888?wsdl
.
Klient
Na vytvorenie klienta použijeme nástroj wsimport
, ktorý na základe popisu WSDL vygeneruje kompletné zdrojové kódy pre klientskú časť webovej služby, a navyše ich skompiluje.
Nástroj sa nachádza v adresári bin
v inštalačnom adresári JDK. Ak máte javac
v premennej prostredia PATH
, mal by v nej byť aj tento nástroj.
Vytvorte si projektový adresár, ktorý bude obsahovať zdrojové kódy klienta (v IDE typicky nový projekt). Dôležité je negenerovať kódy do projektu so serverom, pretože dôjde k chaosu a zmätku v tom, ktorý kód patrí serveru a ktorý klientovi.
Ak sme napr. v adresári C:\Projects\term-ws-client
, spusťme:
wsimport -d bin -s src http://localhost:8888/terms?wsdl
Do adresára bin
sa skompilujú nasledovné súbory, ktorých zdrojové kódy budú v adresári src
:
sk.novotnyr.GetTerms
sk.novotnyr.GetTermsResponse
sk.novotnyr.ObjectFactory
sk.novotnyr.Signup
sk.novotnyr.SignupResponse
sk.novotnyr.DefaultTermServiceService
sk.novotnyr.Student
sk.novotnyr.Term
sk.novotnyr.DefaultTermService
sk.novotnyr.package-info
Keďže ide o automaticky generované triedy, niektoré názvy môžu byť čudesné (serviceservice). Prispôsobíme ich o chvíľu.
Klienta možno použiť jednoducho:
DefaultTermServiceService service = new DefaultTermServiceService();
DefaultTermService termService = service.getDefaultTermServicePort();
/* alternatívne tiež môžeme:
DefaultTermServiceService termService = service.getPort(DefaultTermServiceService.class);
*/
System.out.println(termService.getTerms("UINF/PAZ1c"));
Inštancia služby sa vytvorí nad pevne daným URI prevzatým z WSDL adresy (teda nad http://localhost:8888/terms) a nad pevne danou službou DefaultTermServiceService. Zmeniť tieto nastavenia môžeme pomocou parametrov v konštruktore DefaultTermService.
Prispôsobenie
Niekedy nám môžu prekážať názvy vygenerovaných tried, prípadne interfejsov. Samozrejme, jestvuje viacero možností, ako si ich prispôsobiť.
Chceme zmeniť názov služby
Môžeme to docieliť parametrom serviceName
v anotácii:
@WebService(serviceName="TermWebService")
V tom prípade sa zmena prejaví i v dynamickom i v statickom klientovi.
V statickom klientovi (ktorého musíme pregenerovať cez wsimport
nanovo!) bude názov triedy:
TermWebService service = new TermWebService();
TermService termService = service.getDefaultTermServicePort();
Chceme zmeniť názov balíčka pre generovaného klienta
Pri wsimport stačí dodať parameter -p
wsimport -d bin -s src -p sk.novotnyr.terms.client http://localhost:8888/terms?wsdl
Podpora pre Maven
V prípade Mavenu môžeme použiť plugin org.jvnet.jax-ws-commons:jaxws-maven-plugin
a jeho cieľ wsimport
.
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
<configuration>
<wsdlUrls>
<wsdlUrl>http://localhost:8888/terms?wsdl</wsdlUrl>
</wsdlUrls>
<packageName>sk.novotnyr.terms.client</packageName>
</configuration>
</plugin>
Záver
Podporu webových služieb v Jave 6 môžeme považovať za vhodnú pre mnoho jednoduchých prípadov (jednoduchá trieda, málo metód, HTTP binding, vyhovujúci HTTP server, žiadne závislosti). Samozrejme, v komplexnejších prípadoch si asi s touto verziou nevystačíme a budeme potrebovať použiť niektorú z ťažkotonážnejších implementácií. Paradoxne, už len samotná referenčná implementácia poskytuje o niečo viac možností – podporu pre prílohy, antovské tasky, možnosť nasadiť službu ako servlet atď.
Napriek tomu je však už i takáto jednoduchá podpora minimálne ekvivalentná s použitím technológie RMI.
Ďalšie odkazy
- SOAPové distribuované systémy, prednáška z predmetu Konkurentné programovanie (UINF/KOPR).