środa, 11 marca 2009

Deklaratywne konfigurowanie handlerów JAX-WS

Pytanie badawcze: Gdzie deklaratywnie konfigurować handlery w JAX-WS tworząc web serwis przy pomocy metodologii top-down? Szperając po dokumentacji JAX-WS i JSRach znalazłem cztery sposoby, które opisuję poniżej.

Wg JSR-109 konfiguracja powinna znajdować się w deskryptorze webservices.xml. Niestety, jak napisałem tutaj, dotychczas nie udało mi się skłonić JAX-WS do korzystania z tego deskryptora (i nie wiem czy jest to możliwe), więc tej metody nie próbowałem.

User Guide dla JAX-WS zawiera trzy propozycje, z czego dwie z nich są zdaje się ze sobą.

W rozdziale 3. Programming Model, w sekcji 3.1.2. Starting from a WSDL File opisany jest proces rozpraszania web serwisu pisanego wg metodologii top-down. Znajduje się tam link do strony zatytułowanej WAR File Packaging, zawierającej przykład konfigurowania handlerów.

Ma to wyglądać następująco:

<?xml version="1.0" encoding="UTF-8"?>
<endpoints ...">
<endpoint ...>
<handler-chain>
<handler-chain-name>somename</handler-chain-name>
<handler>
<handler-name>MyHandler</handler-name>
<handler-class>hello.MyHandler</handler-class>
</handler>
</handler-chain>
</endpoint>
</endpoints>


Niestety, podczas rozpraszania aplikacji otrzymuję następujący błąd:

SEVERE: WSSERVLET11: failed to parse runtime descriptor: unexpected content in runtime descriptor (line 11)
com.sun.xml.ws.server.ServerRtException: unexpected content in runtime descriptor (line 11)
at com.sun.xml.ws.transport.http.DeploymentDescriptorParser.fail(DeploymentDescriptorParser.java:495)
at com.sun.xml.ws.transport.http.DeploymentDescriptorParser.ensureNoContent(DeploymentDescriptorParser.java:489)
...


Ponieważ komunikat błędu jest jasny, wyczerpujący i wyjaśnia wszystko, byłem zmuszony do debuggowania JAX-WS, gdzie natknąłem się na kod, który w deskryptorze zamiast węzła <handler-chain> oczekuje węzła <handler-chains>. Umieściłem <handler-chain> wewnątrz <handler-chains>, jednak błąd nie zniknął.

Zacząłem googlać w poszukiwaniu rozwiązania i natknąłem się na trzeci sposób konfigurowania handlerów, znajdujący się również w User Guide dla JAX-WS, w dziale Handlers. Otóż na końcu sekcji Handler Files znajduje się taki przykład:


<endpoints ....>
<endpoint ....>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
....
</handler-chain>
</handler-chains>
</endpoint>
</endpoints>


Faktycznie <handler-chain> występuje tu wewnątrz <handler-chains>, ale <handler-chains> pochodzi z innego namespace (i dlatego moje próby dodania <handler-chains> na ślepo skończyły się fiaskiem). I ten wariant działa, jakkolwiek walidator XML w Eclipse alarmuje, że węzły <handler-chains> z namespace http://java.sun.com/xml/ns/javaee nie mają prawa znajdować się w tym miejscu (może to kwestia nieprawidłowego XSD, co jest zupełnie inną historią).

Czwarty sposób nie jest związany w żaden sposób z sun-jaxws.xml, lecz wykorzystuje możliwość użycia custom bindings podczas generowania klas Javy na podstawie WSDL przy pomocy narzędzia wsimport. Jest to opisane we wspomnianej już sekcji Handler Files na stronie Handlers.

Plik konfiguracyjny wygląda w ten sposób:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="[lokalizacja naszego WSDL]"
xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="wsdl:definitions" xmlns:jws="http://java.sun.com/xml/ns/javaee">
<jws:handler-chains>
<jws:handler-chain>
<jws:handler>
<jws:handler-class>[full qualified name klasy implementującej handler</jws:handler-class>
</jws:handler>
</jws:handler-chain>
</jws:handler-chains>
</bindings>
</bindings>


Natomiast konfiguracja wsimport w pom.xml wygląda tak:


<plugin>
<groupId>org.codehaus.mojo
<artifactId>jaxws-maven-plugin
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<packageName>[nazwa package]</packageName>
<wsdlDirectory>${basedir}/src/main/webapp/WEB-INF/wsdl</wsdlDirectory>
<wsdlFiles>
<wsdlFile>[nazwa pliku WSDL]</wsdlFile>
</wsdlFiles>
<bindingDirectory>${basedir}/src/main/webapp/WEB-INF/wsdl</bindingDirectory>
<bindingFiles>
<bindingFile>[nazwa pliku z custom binding]</bindingFile>
</bindingFiles>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-tools</artifactId>
<version>2.1.4</version>
</dependency>
</dependencies>
</plugin>


I ten sposób również zadziałał, chociaż musiałem rozwiązać dwa problemy. Pierwszy to gdzie umieścić plik z custom bindings? Domyślna lokalizacja to /src/jaxws i wtedy nie trzeba w pom.xml umieszczać <bindingDirectory> i <bindingFiles>. Niestety, korzystając z tej lokalizacji nie wiem jak wskazać plik WSDL, który jest customizowany. Z tego powodu plik z custom bindings umieściłem w /WEB-INF/wsdl.

Drugi problem związany jest z tym gdzie wsimport wrzuca wygenerowany plik XML dla adnotacji @HandlerChain. Spodziewałem się, że będzie to /target/jaxws/wsimport/java/.., a tymczasem jest to /target/classes, co powoduje pewne perturbacje pod Eclipse, kiedy korzysta się z WTP. Wystarczyło jednak zmienić domyślny output folder z /bin na /target/classes i było ok.

Podsumowując:
1. Istnieją przynajmniej dwa sposoby deklaratywnego konfigurowania handlerów: w pliku sun-jaxws.xml i w konfiguracji wsimport w pom.xml.
2. User Guide dla JAX-WS jest niedopracowany i przeczy sam sobie.
3. Być może sposób z webservices.xml również jest dobry, ale nie wiem jak użyć webservices.xml z JAX-WS.

Brak komentarzy:

Prześlij komentarz