Podpora webových služieb v Java SE 6 a novšej

Ú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:

  1. dodať anotácie, ktorými vyhlásime triedu za vzdialene dostupnú
  2. 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.

Pozor, `wsimport` je len v JDK, nie v JRE!

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

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *