Architektury Usług Internetowych Laboratorium 2. Usługi sieciowe Wstęp Celem laboratorium jest zapoznanie się z modelem usług sieciowych na przykładzie prostego serwera Apache Axis2. Apache Axis2 Apache Axis2 jest silnikiem usług sieciowych opartym na technologiach Web Services / SOAP / WSDL. Silnik dostępny jest w dwóch wersjach: jako samodzielny serwer oraz jako aplikacja webowa która może być uruchomiona w kontenerze servletów. Instalacja i uruchomienie Axis2 Aby zainstalować samodzielny serwer należy ściągnąć odpowiednią paczkę ze strony http://axis.apache.org/axis2/java/core/, a następnie rozpakować ją w dowolnym katalogu. Uruchomienie serwera może wymagać ustawieniach poniższych zmiennych środowiskowych: JAVA_HOME wskazuje na katalog instalacyjny JDK w systemie, AXIS2_HOME wskazuje na katalog domowy serwera. W celu uruchomienia serwera należy wykonać jedno z poniższych poleceń: %AXIS2_HOME%\bin\axis2server.bat (Windows), $AXIS2_HOME/bin/axis2server.sh (Unix). Domyślnie wszystkie uruchomione usługi będą dostępne pod adresem http://localhost:8080/axis2/services/. Należy zwrócić uwagę aby w czasie uruchamiania serwera, żadne inne serwery aplikacji nie były uruchomione (GlassFish, Apache Tomcat). Budowanie i uruchamianie usługi Apache Ant jest narzędziem pozwalającym na zautomatyzowanie procesu budowania projektu. Pozwala na definiowanie celów związanych m.in. z kompilacją kodów źródłowych, generowaniem dokumentacji, wdrażaniem aplikacji, itd. Konfiguracja procesu budowania projektu odbywa się poprzez definiowanie celów w pliku build.xml. Dokładniejsze informacje można znaleźć na stronie http://ant.apache.org/. 2010-2012 Michał Wójcik 1
Standardowo każdy projekt stworzony w środowisku NetBeans IDE jest budowany przez Apache Ant i zawiera wygenerowany plik build.xml, który początkowemu użytkownikowi może wydać się zbyt skomplikowany. Przykład załączony do tej instrukcji opiera się o prostym pliku build.xml o następującej strukturze: <?xml version="1.0" encoding="utf-8"?> <project name="services" basedir="." default="generate.service"> <property environment="env"/> <property name="axis2_home" value="/home/psysiu/apps/axis2-1.6.2"/> <property name="build.dir" value="${basedir}/build"/> <property name="serviceclass" value="pl.gda.pg.eti.kask.aui.services.helloservice"/> <property name="aarname" value="helloservice"/> <property name="wsdlname" value="helloservice"/> <property name="targetnamespace" value="http://services.aui.kask.eti.pg.gda.pl/"/> <property name="schematargetnamespace" value="http://services.aui.kask.eti.pg.gda.pl/xsd"/> <path id="axis2.classpath"> <fileset dir="${axis2_home}/lib"> <include name="*.jar"/> </fileset> </path> <target name="compile.service"> <target name="generate.wsdl" depends="compile.service"> <target name="generate.service" depends="compile.service"> <target name="generate.client" depends="generate.wsdl"> <target name="clean"> <target name="run" depends="compile.service"> </project> Głównym elementem pliku konfiguracyjnego jest <project> zawierający nazwę projektu, katalog bazowy oraz domyślny cel. Dalej zostały zdefiniowane zmienne wykorzystywane w poszczególnych celach projektu: AXIS2_HOME katalog domowy serwera, build.dir katalog do którego zostaną wgrane skompilowane klasy, serviceclass klasa usługi sieciowej, 2010-2012 Michał Wójcik 2
aarname nazwa archiwum zawierającego usługę sieciową, wsdlname nazwa pliku wsdl opisującego usługę, targetnamespace przestrzeń nazw w postaci adres, schematargetnamespace lokalizacja schemy dla przestrzeni nazw. Następnymi elementami są definicje poszczególnych celów. W przypadku celów od siebie zależnych wykorzystywany jest argument depends powodujący łąńcuchowe wywoływanie celów. Przygotowane cele to: compile.serivce kompiluje wszystkie kody źródłowe, generate.wsdl na podstawie klasy usługi generuje jej opis w postaci pliku wsdl, generate.service na podstawie skompilowanych klas generuje archiwum usługi i wgrywa je do serwera (aktualizacja usługi na serwerze może wymagać jego restartu), generate.client na podstawie pliku wsdl generuje stuby pozwalające na interakcję z usługą wdrożoną na serwerze, clean usuwa katalog z skompilowanymi klasami, run uruchamia przygotowanego klienta usługi. Cele generate.wsdl i generate.client opierają się na wywołaniu odpowiednich metod z klas dostarczonych z Axis2. Cele compile.serivice, generate.service, clean i run korzystają ze sandardowych narzędzi platformy Java (javac, java i jar) oraz operacji na plikach (mkdir, copy, delete). Wywołanie poszczególnych celów w środowisku NetBeans IDE może być wykonane z zakładki files poprzez kliknięcie prawym przyciskiem myszy na plik build.xml i wybranie odpowiedniego celu do wykonania. Wszystkie cele ant mogą również być wołane z konsoli (o ile w systemie jest zainstalowana aplikacja Apache Ant) poprzez polecenie ant nazwa_celu. Przykładowy projekt Przykładowy projekt składa się z następujących plików: resources/meta-inf services.xml deskryptor usługi pozwalający na jej wdrożenie na serwerze, definiuje nazwę usługi, jej zasięg, schemę oraz klasę ją implementującą; src/pl/gda/pg/eti/kask/aui/services: HelloService.java implementacja usługi, HelloServiceCallbackHandler.java abstrakcyjna klasa wygenerowana przez cel generate.client pozwalająca na zdefiniowanie obsługi wyników zwracanych przez usługę, 2010-2012 Michał Wójcik 3
HelloServiceCallbackHandlerImpl.java przykładowa implementacja obsługi wyników, HelloServiceStub.java klasa wygenerowana przez cel generate.client pozwalająca na interakcję z usługą, ServiceCaller główna klasa klienta z przykładowymi wywołaniami usługi. Aby edytor w NetBeans IDE poprawnie podpowiadał składnię i nie zgłaszał błędów podczas edycji należy do projektu dodać następujące biblioteki: activation-1.1.jar, axiom-api-1.2.8.jar, axiom-impl-1.2.8.jar, axis2-adb-1.5.1.jar, axis2-kernel-1.5.1.jar, axis2-transport-http-1.5.1.jar, axis2-transport-local-1.5.1.jar, commons-codec-1.3.jar, commons-httpclient-3.1.jar, commons-logging-1.1.1.jar, httpcore-4.0.jar, mail-1.4.jar, neethi-2.0.4.jar, wsdl4j-1.6.2.jar, XmlSchema-1.4.3.jar. Wszystkie biblioteki można znaleźć w katalogu domowym serwera w katalogu lib. Domyślnie Axis2 opakowuje parametry i wyniki usług w wygenerowane obiekty. Przykładowo aby wywołać usługę String sayhello() należy: String ret = stub.sayhello(sayhello).get_return(); Analogicznie wywołanie usługi String sayhelloto(string name) wymaga: SayHelloTo sayhelloto = new HelloServiceStub.SayHelloTo(); sayhelloto.setname("psysiu"); String ret = stub.sayhelloto(sayhelloto).get_return(); Wygenerowane stuby pozwalają na wywołanie usługi w dwóch trybach: synchroniczny wykonanie kodu jest blokowane aż do otrzymania wyników z usługi: 2010-2012 Michał Wójcik 4
String ret = stub.sayhello(sayhello).get_return(); asynchroniczny usługa wywołania usługi zwraca sterowanie od razu a wyniki zostają asynchronicznie w osobnym wątku dostarczone do klasy callback: HelloServiceCallbackHandler callback = new HelloServiceCallbackHandler { @Override public void receiveresultsayhello(sayhelloresponse result) { System.out.println("Result: " + result.get_return()); } }; stub.startsayhello(sayhello, callback); Uwaga: wystąpienie błędu w synchronicznym wołaniu metody musi zostać obsłużone w tym samym miejscu co wołanie metody. W przypadku wołania asynchronicznego obsługę błędu zajmuje się klasa callback. 2010-2012 Michał Wójcik 5