[Java SE][JAX-WS] Implementacja web service w Javie SE

Java SE od wersji 6 posiada możliwość utworzenia wbudowanego serwera web methods opartego o protokół SOAP. W odróżnieniu od REST`owego API nie potrzebujemy tutaj żadnego serwera typu tomcat, wildfly co przydaje się w niektórych zastosowaniach.




Poniżej przedstawię przykład udostępnienia takiej web metody:
Pierwszą rzeczą jaką musimy zrobić to utworzyć nowy projekt javy i dodać nowy interfejs, nazwiemy go TestWebMethods:

package pl.test.app;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface TestWebMethods{

@WebMethod String getHelloWorldAsString(String name);
}

Jak widzimy w powyższym interfejsie musimy dodać 3 adnotacje. @WebService oznacza że ten interfejs będzie usługą sieciową, czyli posiadał takie metody które można zdalnie wykonać z poziomu klienta.
@SOAPBinding(style = SOAPBinding.Style.RPC) określa typ formatowania usługi. Wyróżniamy dwa style usługi RPC dla wywołań ścisłych, takich właśnie jak metody, gdzie znamy dokładną strukturę danych. W tym wypadku tak jest ponieważ komunikujemy się pomiędzy dwoma instancjami aplikacji Java, które implementują ten sam standard JAX-WS a także co ważniejsze wywołania metod mają ścisłą konstrukcję. Drugim stylem jest Document, tutaj format zapisu danych jest luźniejszy przez co można zawierać w nim różne dodatkowe dane, ale korzystanie z niego wymaga dodatkowej pracy przy jego wykorzystaniu.
@WebMethod oznaczamy publiczną metodę którą chcemy udostępnić klientowi.

Drugą rzeczą jest utworzenie jego implementacji w postaci klasy TestWebMethodsImpl:

package pl.test.app;

import javax.jws.WebService;

@WebService(endpointInterface="pl.test.app.TestWebMethods")
public class TestWebMethodsImpl implements TestWebMethods{

@Override
public String getHelloWorldAsString(String name) {
return "Hello World JAX-WS " + name;
}

}

@WebService(endpointInterface="pl.test.app.MuzeoWebMethod") jest to trochę zmieniona adnotacja z poprzedniego kroku, dodajemy w niej atrybut endpointInterface a jako wartość pełną nazwę pakietową do interfejsu. Robimy to z tego względu żeby powiązać naszą implementację z interfejsem. Ponieważ możemy posiadać wiele implementacji jednego interfejsu a domyślna nazwa tego parametru pobierana jest z nazwy klasy implementującej to za pomocą takiego zapisu jasno określamy że jest to implementacja interfejsu TestWebMethods.
W ciele metody piszemy już właściwą obsługę web metody która doda prefix do naszego Stringa podanego w argumencie.

Trzecią jest udostępnienie naszej zdalnej końcówki serwera. Możemy tego dokonać standardowo w metodzie main w taki sposób:

package pl.test.app;

import javax.xml.ws.Endpoint;

public class StartWeb {

public static void main(String[] args) {
Endpoint.publish(
"http://localhost:8080/WebServiceExample/test",
new TestWebMethodImpl());

}

}


Warto zauważyć że tworzony tutaj jest osobny wątek końcówki także musimy uważać na kwestie wielowątkowe jeśli będziemy chcieli operować później na wspólnych zasobach co nasze Web methods.

Klient umożliwiającego wykonanie metody na serwerze możemy utworzyć bardzo prosto:

URL wsdlLocation = new URL("http://localhost:8080/WebServiceExample/test?wsdl");
QName serviceName = new QName("http://app.test.pl/", "MuzeoWebMethodImplService");
service = Service.create(wsdlLocation, serviceName);

Tworzymy obiekt URL reprezentujący adres naszego serwera a jako parametr podajemy wsdl który odnosi nad do pliku wsdl.xml opisującego specyfikacje serwisu. Z tego pliku możemy się dowiedzieć jakie metody i pod jakim adresem(QName) są wykonywane.

Następnie tworzymy obiekt QName który jest reprezentacją danej usługi. Domyślnie ta nazwa to http://<odwrócona nazwa pakietu>/, jako drugi argument podajemy nazwę klasy implementującej dany interfejs.
Oczywiście powyższe dwa argumenty możemy zdefiniować sami poprzez odpowiednie atrybuty w adnotacjach na serwerze. Tutaj jednak będę odwoływał się do domyślnych wartości.

Na końcu tworzymy nasz obiekt serwisu, wrzucając do niego dwa poprzednie obiekty.

Teraz wystarczy pobrać z niego interfejs:

TestWebMethod hello = service.getPort(TestWebMethod.class);

I już możemy z niego korzystać jak ze zwykłego obiektu:

System.out.println(hello.getHelloWorldAsString("Ra"));