czwartek, 26 lutego 2009

Niejasności dotyczące web serwisowych deskryptorów

Jakie deskryptory należy utworzyć budując web serwis w Javie? Jasne jest, że pewne elementy znajdują się deskryptorze aplikacji webowej, czyli web.xml, zaś podstawowe informacje na temat portu i klasy implementującej web serwis znajdują się w deskryptorze dodatkowym. Ale jakim? Istnieją bowiem dwa deskryptory dodatkowe: webservices.xml i sun-jaxws.xml.

Nie rozumiem dlaczego istnieją dwa deskryptory web serwisów, więc postanowiłem pogrzebać na ten temat w sieci. Pierwszą rzeczą, jaką zauważyłem, jest to, że deskryptory te chyba nigdy nie występują razem w jednym tekście. Albo web.xml i webservices.xml, albo web.xml i sun-jaxws.xml. Ten drugi występuje prawie wyłącznie w kontekście JAX-WS, co jest oczywiste.

Deskryptor webservices.xml opisany jest w JSR-109 zatytułowanym "Web Services for Java EE". Można tam znaleźć następujące informacje:

1. Pełna nazwa deskryptora: Web Services Deployment Descriptor.
2. Nazwa pliku ściśle określona: webservices.xml.
3. Przeznaczenie: definiuje zestaw web serwisów, które mają zostać rozproszone w kontenerze obsługującym web serwisy Java EE.
4. Użycie: opcjonalne, jeśli stosuje się adnotacje.

Deskryptor sun-jaxws.xml z kolei opisany jest w JAX-WS User Guide, w rozdziale 2.9 zatytułowanym "Deploying Metro endpoint". Można się tam dowiedzieć, że:

1. Pełna nazwa deskryptora: JAX-WS Reference Implementation deployment descriptor.
2. Nazwa pliku ściśle określona: sun-jaxws.xml
3. Przeznaczenie: definiuje atrybuty końcówki web serwisu.
4. Użycie, opcjonalne, jeśli stosuje się adnotacje.

Wynika stąd, że oba deskryptory używane są dokładnie do tego samego celu, przy czym sun-jaxws.xml jest specyficzny dla JAX-WS. Ale po co wprowadzać specyficzny deskryptor, skoro webservices.xml zawiera te same informacje?

Pewną wskazówkę znalazłem w JAX-WS User Guide, gdzie znajduje się następujący fragment:


Before you deploy or publish your endpoint, you will need to package
your endpoint application into a WAR file. The requirements when building a WAR:

* All WSDLs, Schema files should be packaged under WEB-INF/wsdl dir.
It is recommended not to package the WSDL if you are doing
Java-first development.

* WebService implementation class should contain @WebService annotation.
Provider based endpoints should have @WebServiceProvider annotation.

* wsdl, service, port attributes are mandatory for Provider based endpoints
and can be specified in @WebServiceProvider annotation
or deployment descriptor (sun-jaxws.xml).

* Deployment descriptors, web.xml, web services deployment descriptor
(sun-jaxws.xml or 109 or spring)


Interesujące są ostatnie dwa stwierdzenia (szczególnie ostatnie), z których wynika, że różne deskryptory można stosować zamiennie. Ale czy na pewno?

Podstanowiłem to sprawdzić eksperymentalnie. W testowym projekcie usunąłem plik sun-jaxws.xml i dodałem plik webservices.xml. Po uruchomieniu serwera otrzymałem następujący komunikat błędu:

SEVERE: WSSERVLET11: failed to parse runtime descriptor:
javax.xml.ws.WebServiceException:
Runtime descriptor "/WEB-INF/sun-jaxws.xml" is mising


Ostatecznie zagadki nie rozwikłałem.

czwartek, 19 lutego 2009

Web serwis top-down, JAX-WS, Eclipse WTP, Maven 2, Apache Tomcat 6.0

Wstęp

Tematem wpisu są problemy i pytania napotykane podczas tworzenia web serwisu metodologią top-down z wykorzystaniem JAX-WS, Eclipse WTP i Maven 2 rozpraszanego na serwerze Apache Tomcat 6.0.

Nie jest to typowy how-to, nie opisuję wszystkiego krok po kroku, ponieważ nie wydaje mi się to konieczne. Koncentruję się natomiast na konkretnych problemach, z jakimi się trzeba zmierzyć.

Założenia
1. Wersja Javy: 1.6
2. IDE: Eclipse 3.3
3. Narzędzie budowania projektu: Maven 2 (plug-in m2eclipse)
4. Metodologia: Top-down
5. Implementacja web serwisu: JAX-WS
6. Serwer: Apache Tomcat 6.0

Kroki do wykonania
1. Utworzenie projektu w Eclipse
2. Skonfigurowanie Mavena
3. Utworzenie definicji web serwisu
4. Wygenerowanie klas na podstawie definicji web serwisu
5. Podłączenie wygenerowanych klas jako źródeł w projekcie Eclipse
6. Zaimplementowanie web serwisu
7. Utworzenie deskryptorów
8. Przetestowanie działania web serwisu

Problemy i kwestie do rozstrzygnięcia
1. Jak pożenić Eclipse WTP z Maven 2?
2. Jak skonfigurować JAX-WS w Maven 2?
- Jaki plugin zastosować?
- Gdzie plugin się znajduje?
- Gdzie umieścić plik WSDL?
3. Jak zidentyfikować błędy wsimport?
4. Jak utworzyć implementację web serwisu?
- Jakich argumentów adnotacji @WebService użyć?
5. Jak utworzyć deskryptory?
- Których deskryptorów trzeba użyć?
- Jaka ma być zawartość deskryptorów?

Eclipse WTP + Maven 2

Maven jest bezdyskusyjnie bardzo dobrym rozwiązaniem podczas automatycznego budowania projektów, w szczególności w przypadku stosowania continuous integration z wykorzystaniem Continuum czy Cruise Control. Jednak dla programisty, oprócz wsparcia jakie daje Maven, bardzo istotne są również narzędzia udostępniane przez środowisko deweloperskie. W przypadku projektów webowych w Javie jest to Eclipse WTP.

Problemem jest jednak skonfigurowanie WTP tak, aby prawidłowo działał w projekcie wykorzystującym Mavena. Nie znam tutaj dobrej, sprawdzającej się we wszystkich przypadkach metody. Stosuję następującą procedurę:

1. Tworzę Dynamic Web Project korzystając z kreatora w Eclipse.
2. Włączam obsługę Mavena.
3. Eksportuję zależności obsługiwane przez Maven jako J2EE Module Dependencies.

Utworzenie projektu

Korzystając z kreatora tworzę tzw. Dynamic Web Project z następującymi ustawieniami:
- Target Runtime: Apache Tomcat v6.0
- Dynamic Web Module: 2.5
- Java: 6.0
- Context Root: [jaki się chce]
- Content Directory: src/main/webapp
- Java Source Directory: src/main/java

Dwa ostatnie parametry wskazują, że będziemy stosować Mavenowy układ katalogów.

Włączenie Mavena

Włączam obsługę zależności przy pomocy Mavena (Enable Dependency Management) podając następujące ustawienia:
- Group Id: [jaki się chce]
- Artifact Id: [jaki się chce]
- Version: [jaką się chce]
- Packaging: war

Eksport zależności Mavena

Włączam eksport zależności obsługiwanych przez Mavena jako J2EE Module Dependencies.

Project Properties -> J2EE Module Dependencies -> zaznaczyć Maven Dependencies w JAR/MODULE

Konfiguracja JAX-WS w Maven 2

Do zrobienia są następujące rzeczy:
1. Konfiguracja kompilatora dla Javy 6.
2. Konfiguracja wsimport do generowania klas ze schemy (ponieważ stosuję metodologię top-down).
3. Konfiguracja zależności projektu.

Konfiguracja kompilatora

Rzecz opisana w wielu miejscach, więc pomijam.

Plug in dla wsimport

Pluginem obsługującym generowanie klas na podstawie WSDL jest jaxws-maven-plugin. Znajduje się w standardowym repozytorium Mavena, groupId=org.codehaus.mojo, artifactId=jaxws-maven-plugin, version=1.10.

Podczas konfigurowania tego plugina istotne jest zdecydowanie gdzie będzie umieszczony plik WSDL. Znalazłem dwa podejścia: katalog /src/wsdl i katalog /src/main/webapp/WEB-INF/wsdl. Pierwsze podejście jest bardziej eleganckie, ale wymaga kopiowania pliku WSDL do miejsca docelowego podczas budowania projektu. Drugie podejście jest prostsze i to zawsze stosuję.

Konfiguracja wsimport


<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<packageName>[nazwa package]</packageName>
<wsdlDirectory>[ścieżka do WSDL]</wsdlDirectory>
<wsdlFiles>
<wsdlFile>[nazwa pliku WSDL]</wsdlFile>
</wsdlFiles>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-tools</artifactId>
<version>2.1.4</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>


Lista zależności

Reference implementation JAX-WS wraz z kodem źródłowym znajduje się w standardowym repozytorium Maven, groupId=com.sun.xml.ws, artifactId=jaxws-rt, version=2.1.4.

Konfiguracja zależności projektu


<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.4</version>
</dependency>
</dependencies>


Uwaga, w dalszej części wpisu lista zależności będzie uzupełniona.

Błędy podczas uruchamiania wsimport

Gdy stosuje się domyślną konfigurację, trudno jest określić rodzaj i przyczynę błędu powstałego podczas uruchamiania wsimport przy pomocy plugina jaxws-maven-plugin. Jeżeli pliku WSDL nie ma, lub nie jest umieszczony w prawidłowym miejscu, komunikat jest jasny, lecz w przypadku błędów w samym pliku WSDL informacje wyświetlane w konsoli są niewystarczające.

Włączając opcję 'debug output' w oknie uruchamiania Mavena w Eclipse, lub stosując parametr -e linii polceceń Mavena można uzyskać więcej informacji, w szczególności stacktrace.

Ja miałem problem z Javą 5, która nie posiadała którejś klasy z pakietu javax.jws, przez co generowanie klas na podstawie WSDL kończyło się błędem. Niestety autorzy plug-ina łapiąc wyjątek ClassDefNotFoundException (w poniższym kodzie jest to zmienna e) nie raczyli wyświetlić pełnego stack trace:


} catch (Exception e) {
throw new MojoExecutionException( "Error executing: wsimport " + args );
}


Notabene po przełączeniu Eclipse na Javę 6 i powrocie do Javy 5 problem zniknął.

Innym razem chodziło o błędne podłączenie JRE zamiast JDK w Eclipse, przez co wsimport nie miał dostępu do tools.jar.

Podłączanie wygenerowanych klas jako źródeł projektu w Eclipse

Wygenerowane klasy standardowo lądują w katalogu /target/jaxws/wsimport/java/, który należy podłączyć jako dodatkowy katalog źródeł projektu w Eclipse.

Po podłączeniu okazuje się, że nie mamy podłączonych klas z pakietu javax.jws, czyli JSR-181. Niestety, w standardowym repozytorium Maven próżno tej biblioteki szukać (a przynajmniej mnie nie udało się znaleźć), więc trzeba do projektu dołączyć repozytorium download.java.net:


<repositories>
<repository>
<id>maven-repository.dev.java.net</id>
<url>http://download.java.net/maven/1/</url>
<layout>legacy</layout>
</repository>
</repositories>


Następnie trzeba dodać do projektu zależność od JSR-181:


<dependencies/>
...
<dependency>
<groupId>javax.jws</groupId>
<artifactId>jsr181-api</artifactId>
<version>1.0-MR1</version>
</dependency>
</dependencies>


Właściwie nie mam pojęcia dlaczego trzeba tę akurat bibliotekę podłączać ręcznie.

Utworzenie deskryptorów

Do uruchomienia web serwisu konieczne jest utworzenie następujących deskryptorów:
1. web.xml
2. sun-jaxws.xml

web.xml

Deployment Descriptor musi zawierać dwa elementy: listener wywoływany podczas rozpraszania aplikacji oraz servlet obsługujący zapytania otrzymywane przez web serwis. Wygląda to następująco:


<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>

<servlet>
<servlet-name>WSServlet</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>WSServlet</servlet-name>
<url-pattern>[względna ścieżka dla JAX-WS zaczynająca się znakiem /]</url-pattern>
</servlet-mapping>


sun-jaxws.xml

Deskryptor JAX-WS zawiera informacje o rozpraszanych web serwisach. Szczerze mówiąc nie mam pojęcia do czego jest w ogóle potrzebny, skoro używane są adnotacje.


<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint
name="[dowolna nazwa]"
implementation="[full-qualified name klasy implementującej web serwis]"
wsdl="[ścieżka do WSDL zaczynająca się od WEB-INF/wsdl/]"
url-pattern="[względna ścieżka dla JAX-WS zaczynająca się znakiem /]"
/>
</endpoints>


Implementacja web serwisu

Podczas implementowania web serwisu istotne jest odpowiednie użycie adnotacji. Wszystko jest dobrze opisane w JSR-181. Ponieważ stosujemy metodykę top-down, konieczne jest zastosowanie adnotacji @WebService z argumentem endpointInterface.

Oprócz argumentu endpointInterface konieczne jest określenie wartości następujących argumentów:
- serviceName (taki jak name w wsdl:service)
- portName (taki jak name w wsdl:port wewnątrz wsdl:service)
- targetNamespace (taki jak targetNamespace w nagłówku WSDL)

Ustawienie tych wartości jest potrzebne aby wygenerowane klasy ściśle odpowiadały definicjom w pliku WSDL. Jeżeli tego nie zrobimy, podczas rozpraszania aplikacji otrzymamy komunikat "Not a primary WSDL" (ze szczegółami, które łatwo pozwalają znaleźć przyczynę ewentualnego problemu).

Możliwe jest również takie skonfigurowanie aplikacji, aby JAX-WS generował własny WSDL na podstawie adnotacji. Wtedy w adnotacji @WebService klasy implementującej web serwis wystarczy tylko argument endpointInterface, a z sun-jaxws.xml należy usunąć parametr wsdl.

Testowanie web serwisu

Rozpraszanie aplikacji

Pierwsza rzecz to prawidłowe rozproszenie aplikacji. W większości przypadków, z którymi miałem do czynienia, komunikaty w logu były sensowne i szybko naprowadzały mnie na przyczynę problemów.

Oprócz komunikatów błędów w logu znaleźć można również ostrzeżenia. Nie wszystkie zdołałem dotąd pojąć. Przykładowo nie wiem dlaczego pojawia się takie ostrzeżenie:


The listener "com.sun.xml.ws.transport.http.servlet.WSServletContextListener" is
already configured for this context. The duplicate definition has been ignored.


Wyświetlanie listy web serwisów

W przypadku rozpraszania na własnej stacji roboczej pod Tomcatem sprawdzamy przy pomocy przeglądarki internetowej rezultat pod adresem http://localhost:8080/[nazwa aplikacji]/[względna ścieżka JAX-WS].

Wysyłanie testowych zapytań

Do wysyłania testowych zapytań można użyć Web Services Explorera dostępnego w Eclipse.

niedziela, 8 lutego 2009

Zalety ręcznej obsługi web serwisów

Czy możliwe jest zaimplementowanie web serwisu bez wykorzystania żadnego frameworku typu Axis, CXF czy JAX-WS? Ba, bez wykorzystania jakiegokolwiek wsparcia dla przetwarzania XML typu JAXP czy JAXB? Choć może się to wydawać pomysłem gorączkującego programisty, coś takiego zostało zrobione w projekcie, w którym obecnie pracuję.

Gdy natknąłem się na fragmenty kodu odpowiedzialne za renderowanie requestów SOAPowych przy pomocy konstrukcji typu

request.append("<?xml version="1.0" encoding=\"UTF\""?>")

i parsowanie odpowiedzi przy pomocy

response.indexOf("<soap:envelope"),

w pierwszej chwili nie mogłem uwierzyć własnym oczom. Składanie i rozkładanie XMLa na części przy pomocy podstawowego API Javy, konwersja znaków specjalnych, przepisywanie danych do klas Javy i na odwrót - żmudna praca, której nigdy nie przyszłoby mi do głowy wykonywać ręcznie.

W czasie, kiedy opracowywałem propozycję ponownej implementacji funkcjonalności, za którą odpowiedzialny jest powyższy kod, wydarzyły się jednak trzy rzeczy, które nieco rozszerzyły mój pogląd na tę sprawę.

Po pierwsze, w web serwisie, z którym komunikuje się wspomniany kod, zmodyfikowano kontrakt poprzez zmianę namespace. Projekty, które wykorzystywały ten web serwis, musiały się do tej zmiany zaadoptować - wygenerować nowe klienty na podstawie kontraktu, a następnie wypuścić nowe wersje aplikacji. Lecz nie wszystkie - w przypadku kodu, o którym wspominam, wystarczyła jedna zmiana w pliku konfiguracyjnym i wszystko działało jak przedtem.

Po drugie, podczas poszukiwania przyczyn pewnego błędu w systemie konieczne było przeanalizowanie żądań wysyłanych przez klienta do web serwisu. Zazwyczaj robię to przechwytując komunikację przy pomocy Wiresharka, co jest dosyć kłopotliwe w przypadku gdy spośród dziesiątek komunikatów trzeba wysupłać ten, o który chodzi. Tymczasem ręczne generowanie XMLa ma tę zaletę, że nie ma żadnego problemu z wpisaniem go do pliku, wyświetleniem podczas debuggowania itp.

Po trzecie, uświadomiłem sobie, że używając jakiegoś frameworku do obsługi web serwisów skazany jestem na używanie takich klas, jakie zostaną wygenerowane na podstawie WSDLa. Istnieje wprawdzie pewna możliwość manewru dzięki konfigurowaniu bindowania XML-Java, ale pewnych rzeczy się nie przeskoczy. Na przykład pomysłu, aby definiować kontrakt pobieżnie, tj. deklarować dla każdej metody web serwisu wartość string na wejściu i wartość string na wyjściu, a do tych stringów wkładać rozbudowane XMLe, których struktura nie jest opisana w WSDLu, tylko... czemu by nie... uzgadniana telefonicznie. Jest to oczywiście przypadek skrajny (z życia wzięty, niestety), ale problem pojawia się nawet wtedy, gdy WSDL zawiera wprawdzie opis struktury żądań i odpowiedzi, lecz struktura ta jest zła, bądź z jakichś powodów nam nie odpowiada. Tymczasem parsując odpowiedzi web serwisu ręcznie można dane przepisać do klas o całkowicie dowolnej strukturze.

Opisane przypadki nie zmieniły moich poglądów na to jak powinno się implementować web serwisy i nadal jestem za wyrzuceniem tego kodu i ponownym zaimplementowaniem funkcjonalności z wykorzystaniem np. JAX-WS. Uświadomiłem sobie jednak, że kod, na którym wieszałem psy, w niektórych sytuacjach wykazał się bardzo istotnymi zaletami.

Koordynaty JAXP, JAXB i JAXR w repozytorium Maven 2

Znalezienie odpowiednich wersji bibliotek związanych z web serwisami w repozytorium Mavena nie jest zadaniem łatwym. Oto co udało mi się niedawno ustalić dla repozytorium repo1.maven.org.

JAXP
API można znaleźć w javax.xml oraz javax.xml.parsers. Implementację można znaleźć w com.sun.cml.parsers.

jaxp-api
  • groupId = javax.xml.parsers, artifactId = jaxp-api, version = 1.4, 1.4.1, 1.4.2
  • groupId = javax.xml, artifactId = jaxp-api, version = 1.4, 1.4.1, 1.4.2
jaxp-ri
  • groupId = com.sun.xml.parsers, artifactId = jaxp-ri, version = 1.4, 1.4.1, 1.4.2
JAXB
API można znaleźć w javax.xml oraz javax.xml.bind. Implementację można znaleźć w javax.xml oraz com.sun.xml.bind.

jaxb-api
  • groupId = javax.xml.bind, artifactId = jaxb-api, version = 1.0, 2.0, 2.1 (wersja 2.1 zawiera także źródła)
  • groupId = javax.xml, artifactId = jaxb-api, version = 1.0.5, 2.0EA3
jaxb-impl
  • groupId = com.sun.xml.bind, artifactId = jaxb-impl, version = 1.0.5, 1.0.6, 2.0, 2.0.1 - 2.0.5, 2.1.1 - 2.1.9 (wersje 2.0 i 2.1.1 - 2.1.9 zawierają także źródła)
  • groupId = javax.xml, artifactId = jaxb-impl, version = 2.0EA3
jaxb-xjc
  • groupId = com.sun.xml, artifactId = jaxb-xjc, version = 2.0EA3
  • groupId = com.sun.xml.bind, artifactId = jaxb-xjc, version = 1.05, 1.0.6, 2.0, 2.0.1 - 2.0.5, 2.1-EA1, 2.1.1 - 2.1.9 (wersje 2.0 oraz 2.1.1 - 2.1.9 zawierają również źródła)
JAXR
Tej biblioteki w ogóle nie udało mi się znaleźć w repozytorium Mavena. Można jednak ściągnąć JWSDP 2.0 ze strony http://java.sun.com/webservices/downloads/previous/webservicespack.jsp i załadować do repozytorium. JWSDP 2.0 zawiera jaxr-api 1.0 i jaxr-impl 1.0.8_01EA.

JAX-WS
API można znaleźć w javax.xml oraz javax.xml.ws

jaxws-api
  • groupId = javax.xml, artifactId = jaxws-api, version = 2.0EA3, 2.0 EA3
  • groupId = javax.xml.ws, artifactId = jaxws-api, version = 2.0, 2.1, 2.1-1 (wersja 2.1-1 zawiera również źródła)
jaxws-rt
  • groupId = javax.xml, artifactId = jaxws-rt, version = 2.0EA3
  • groupId = javax.xml.ws, artifactId = jaxws-rt, version = 2.1EA1, 2.1.3, 2.1.4 (wersje 2.1.3 i 2.1.4 zawierają również źródła)
jaxws-tools
  • groupId = javax.xml, artifactId = jaxws-tools, version = 2.0EA3
  • groupId = javax.xml.ws, artifactId = jaxws-tools, version = 2.1EA1, 2.1.3, 2.1.4 (wersje 2.1.3 i 2.1.4 zawierają również źródła)

Decyzje, jakie należy podjąć przed zaimplementowaniem web serwisu w Javie

Aby zaimplementować web serwis w Javie należy odpowiedzieć na następujące pytania:
  1. Z jakiej wersji Javy zamierzamy korzystać?
  2. Jakiego środowiska developerskiego będziemy używać?
  3. W jaki sposób będziemy budować projekt?
  4. Co będzie punktem wyjścia: kontrakt zapisany w WSDL (top-down) czy kod Javy (bottom-up)?
  5. Jakiej biblioteki użyjemy do zaimplementowania web serwisu?
  6. Na jakim serwerze zamierzamy rozproszyć aplikację?
1. Wersje Javy
Na wybór wersji Javy wpływ mają dwa kryteria: nowoczesne elementy języka (w przypadku web serwisów istotne są adnotacje, których nie ma w Javie 1.4) oraz kompatybilność (z którą są problemy w przypadku Javy 6). Najlepszym wyborem wydaje się Java 5.

2. Środkowisko developerskie
Każde z dostępnych IDE dla Javy posiada własne narzędzia wspierające tworzenie aplikacji webowych i web serwisów: edytory XML, XSD i WSDL, kreatory ułatwiające generowanie kodu na podstawie kontraktu i generowanie kontraktu na podstawie kodu itp. Oczywiście można z tych funkcji nie korzystać i oprzeć się narzędziach budowania projektu, a środowiska developerskiego używać tylko do kompilacji.

3. Narzędzia budowania projektu
Do wyboru: rezygnacja z narzędzi budowania projektu albo skorzystanie z Apache Ant bądź Apache Maven.

Brak narzędzi budowania projektu jest możliwy kiedy korzysta się wyłącznie z możliwości i funkcji środowiska developerskiego. Na dłuższą metę jest to jednak bardzo niewygodne, ponieważ znacznie ogranicza możliwości automatyzacji zadań.

Obecnie Ant jest wypierany przez Mavena, jednak wciąż jest używany w wielu projektach. Maven z kolei wiele rzeczy ułatwia, lecz wprowadza własne problemy.

4. Top-down czy bottom-up
Kod Javy jako punkt wyjścia to rozwiązanie najprostsze. WSDL jako punkt wyjścia to pełna kontrola nad kontraktem web serwisu.

5. Implementacja
Do wyboru całkiem sporo bibliotek: Axis, Axis 2, XFire (CXF), JWSDP i Metro (jax-ws).

Kryteria wyboru: wersja Javy i konieczność komunikowania się z web serwisami, które nie są zgodne z wytycznymi WS-I.

W przypadku Javy 1.4 wybór jest ograniczony do Axis, Axis 2 i JAWSP. Dla Javy 5 i nowszych można skorzystać z najnowszej implementacji, czyli pakietu Metro.

Jeżeli chcemy umożliwić komunikację z web serwisami, które mają interoperability za nic (przykładowo używają rpc/encoded), Axis 2 i Metro odpadają.

6. Wybór serwera
Serwery webowe (np. Tomcat) nie implementują całości specyfikacji JEE (czy też J2EE), więc konieczne jest dodanie do aplikacji bibliotek obsługujących web serwis. W przypadku serwerów aplikacyjnych (np. JBoss, WebLogic) takiej konieczności nie ma.