Wst pę Modele powi za WS
Transkrypt
Wst pę Modele powi za WS
Katedra Architektury Systemów Komputerowych Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej mgr inż. Karol Bańczyk Technologie Internetowe Laboratorium nr 5. Globus Toolkit Temat: WebServices Resource Framework. Usługi z wieloma zasobami, własności zasobów. Wstęp Niniejsza instrukcja stanowi podzbiór informacji zawartych w punktach 3-6 doskonałego samouczka programistów Globus Toolkit autorstwa Borji Sotomayora, dostępnego pod adresem: http://gdp.globus.org/gt4-tutorial/ . Zaleca się przerobienie owego samouczka, zwłaszcza, gdy ujęcie tematu w niniejszym opracowaniu okaże się dla czytelnika zbyt skondensowane. Niniejsza instrukcja traktuje o tym, jak tworzyć i osadzać usługi sieciowe powiązane z zasobami na platformie Globus Toolkit. Za zarządzanie takimi parami WS-Resource odpowiada specjalny podsystem globusa implementujący specyfikację WebServices Resource Framework. Specyfikacja ta stała się standardem organizacji OASIS. Można o niej poczytać na stronach: OASIS WSRF Page oraz Globus WSRF Page . Najważniejszą przyczyną dla której owa specyfikacja powstała był fakt, że istniejący standard WebServices, doskonale nadający się do sieci usług o globalnym zasięgu, nie wypowiada się do problemu stanowości. Ten niedostatek uzupełnia właśnie WSRF, w którym mowa już nie o samych usługach sieciowych, ale raczej o parach: WebService-Resource. Zasoby posiadają własności (ResourceProperties), opisujące ich stan. Niniejsza instrukcja skupia się właśnie na tym, jak można stworzyć i umieścić na platformie globus toolkit usługę sieciową połączoną z zasobami oraz jak dostać się do własności owych zasobów. Modele powiązań WS-R Można wyróżnić 3 podstawowe modele powiązań usługi sieciowej z zasobami: 1. Implementacja usługi sieciowej oraz zasobu znajduje się w tej samej klasie. 2. Zasób i usługa sieciowa są różnymi klasami, zasób jest pojedynczym obiektem (Singleton). 3. Usługa sieciowa może działać w kontekście różnych zasobów. Szerszy opis przypadków 1 i 2 znajduj się w samouczku w punktach 3 i 4. Niniejszym zostanie szerzej przedstawiony przykład stworzony w zgodzie z trzecim modelem, najbardziej rozbudowanym z pośród wymienionych. Opis tego modelu można poprzeć niniejszym rysunkiem zaczerpniętym z samouczka: Obiekt klienta współpracuje z dwoma usługami sieciowymi, nazwanymi na rysunku: Factory Service i Instance Service. Rolą pierwszego z nich jest dostarczenie fasady pozwalającej stworzyć nowy zasób (wzorzec projektowy Factory) i wykorzystać go w powiązaniu z usługą na nim operującą, czyli właśnie Instance Service. Obiekt ResourceHome jest wykorzystywany przez fabrykę do stworzenia nowego zasobu, który jest modelowany przez klasę Resource. Dla rozpoznania tego modelu przedstawiony zostanie przykład usługi sieciowej obliczającą całkę na zadanym obszarze. Obszar będzie dla prostoty jednowymiarowy i będzie opisany przez pewną całkowitoliczbową funkcję f(n). Stworzenie i umieszcznie usługi sieciowej na zainstalowanym kontenerze globus toolkit składa się z następujących etapów: 1. Zdefiniowanie interfejsu usług sieciowych (w tym przypadku InstanceService i FactoryService). Interfejs definiuje się w języku nieco rozszerzonym na potrzeby stanowości języku WSDL. 2. Implementacja usługi w języku programowania (w tym przypadku będzie to Java). 3. Zdefiniowanie plików deskryptorów: WSDD i JNDI. 4. Stworzenie archiwum GAR (globus archive) zbierającego wcześniej wytworzone artefakty i wygenerowane na ich podstawie pieńki (stubs) w jednym miejscu. 5. Wdrożenie pliku archiwalnego na kontener globusa. 6. Stworzenie i uruchomienie pliku klienta. Interfejs i własności usługi Wszystkie plik wytwarzane w ramach tego opisu najlepiej pobrać z załączonego archiwum. Interfejs usługi sieciowej będzie obejmować dwie operacje: setRange(x1,x2), określającą zakres całkowania oraz integrate(), rozkazujacą dokonania całkowania. Stan zasobu, z którego będzie korzystać WS składać się będzie z czterech własności: x1, x2, state, integral. Pierwsze dwie opisują przedział całkowania, trzecia określa stan zasobu (przed całkowaniem, po całkowaniu, w trakcie całkowania, błąd), integral przechowuje informację o wartości całki, o ile stan wskazuje na to, że została obliczona. Interfejsy tworzonej usługi właściwej oraz fabryki w rozszerzonym języku WSDL przedstawione są niżej. Nie będą tutaj dokładnie opisywane szczegóły, zwłąszcza, że istnieje pełna analogia do tego, co opisane jest w samouczku w punkcie 3 oraz szczególnie w dodatku A1 http://gdp.globus.org/gt4tutorial/singlehtml/progtutorial_0.2.1.html#appendix_howto_wsdl . Plik Range.wsdl definiujacy usługę RangeService ma postać: <?xml version="1.0" encoding="UTF-8"?> <definitions name="RegionService" targetNamespace="http://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsrp="http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd" xmlns:wsrpw="http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft01.wsdl" xmlns:wsdlpp="http://www.globus.org/namespaces/2004/10/WSDLPreprocessor" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:import namespace= "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl" location="../../wsrf/properties/WS-ResourceProperties.wsdl" /> <!--============================================================ T Y P E S ============================================================--> <types> <xsd:schema targetNamespace="http://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance" xmlns:tns="http://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- REQUESTS AND RESPONSES --> <xsd:element name="setRegion"> <xsd:complexType> <xsd:sequence> <xsd:element name="x1" type="xsd:int"/> <xsd:element name="x2" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="setRegionResponse"> <xsd:complexType/> </xsd:element> <xsd:element name="integrate"> <xsd:complexType/> </xsd:element> <xsd:element name="integrateResponse"> <xsd:complexType/> </xsd:element> <!-- RESOURCE PROPERTIES --> <xsd:element name="X1" type="xsd:int"/> <xsd:element name="X2" type="xsd:int"/> <xsd:element name="State" type="xsd:string"/> <xsd:element name="Integral" type="xsd:int"/> <xsd:element name="RegionResourceProperties"> <xsd:complexType> <xsd:sequence> <xsd:element ref="tns:X1" minOccurs="1" maxOccurs="1"/> <xsd:element ref="tns:X2" minOccurs="1" maxOccurs="1"/> <xsd:element ref="tns:State" minOccurs="1" maxOccurs="1"/> <xsd:element ref="tns:Integral" minOccurs="1" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </types> <!--============================================================ M E S S A G E S ============================================================--> <message name="SetRegionInputMessage"> <part name="parameters" element="tns:setRegion"/> </message> <message name="SetRegionOutputMessage"> <part name="parameters" element="tns:setRegionResponse"/> </message> <message name="IntegrateInputMessage"> <part name="parameters" element="tns:integrate"/> </message> <message name="IntegrateOutputMessage"> <part name="parameters" element="tns:integrateResponse"/> </message> <!--============================================================ P O R T T Y P E ============================================================--> <portType name="RegionPortType" wsdlpp:extends="wsrpw:GetResourceProperty" wsrp:ResourceProperties="tns:RegionResourceProperties"> <operation name="setRegion"> <input message="tns:SetRegionInputMessage"/> <output message="tns:SetRegionOutputMessage"/> </operation> <operation name="integrate"> <input message="tns:IntegrateInputMessage"/> <output message="tns:IntegrateOutputMessage"/> </operation> </portType> </definitions> Plik Factory.wsdl definiujacy usługę FactoryService ma postać: <?xml version="1.0" encoding="UTF-8"?> <definitions name="FactoryService" targetNamespace="http://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--============================================================ T Y P E S ============================================================--> <types> <xsd:schema targetNamespace="http://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService" xmlns:tns="http://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:import namespace="http://schemas.xmlsoap.org/ws/2004/03/addressing" schemaLocation="../../ws/addressing/WS-Addressing.xsd" /> <!-- REQUESTS AND RESPONSES --> <xsd:element name="createResource"> <xsd:complexType/> </xsd:element> <xsd:element name="createResourceResponse"> <xsd:complexType> <xsd:sequence> <xsd:element ref="wsa:EndpointReference"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </types> <!--============================================================ M E S S A G E S ============================================================--> <message name="CreateResourceRequest"> <part name="request" element="tns:createResource"/> </message> <message name="CreateResourceResponse"> <part name="response" element="tns:createResourceResponse"/> </message> <!--============================================================ P O R T T Y P E ============================================================--> <portType name="FactoryPortType"> <operation name="createResource"> <input message="tns:CreateResourceRequest"/> <output message="tns:CreateResourceResponse"/> </operation> </portType> </definitions> Jeśli katalog rozpakowania dostarczonego archiwum to uznany zostanie za bieżący to przedstawione pliki znajują się odpowiednio w ./scheme/lab5/RangeService_instance/Range.wsdl i ./scheme/lab5/FactoryService/Factory.wsdl. Miejsce plików jest istotne, a zwłaszcza liczba zagłębień w stosunku do katalogu bieżącego. Należy dodatkowo stworzyć plik o nazwie namespace2package.mapping w katalogu bieżącym zawierający następujące mapowania przestrzeni nazw na pakiety zawierające klasy implementujące i stuby. http\://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance=org.pg.ti.lab5.stubs.RegionService_i nstance http\://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance/bindings=org.pg.ti.lab5.stubs.Region Service_instance.bindings http\://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance/service=org.pg.ti.lab5.stubs.RegionS ervice_instance.service http\://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService=org.pg.ti.lab5.stubs.FactoryService http\://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService/bindings=org.pg.ti.lab5.stubs.FactoryService .bindings http\://eti.pg.gda.pl/namespaces/ti/lab5/FactoryService/service=org.pg.ti.lab5.stubs.FactoryService. service Implementacja Wymagane jest, by klasy wchodzące w skład jednego archiwum GAR znajdowały się w pakiecie postaci nazwa1.nazwa2.nazwa3.impl. Wówczas deskryptory jndi i wsdd będą w pakiecie nazwa1.nazwa2.nazwa3. Na implementajcę skłądają się następujące klasy pakietu : FactoryService, RegionQNames, RegionResourceHome, RegionResource, RegionService, UniqueSequence i WorkerThread. Wszystkie zostały zawarte w pakiecie org.pg.ti.lab5.impl. Przed przystąpieniem do implementacji klas warto wygenerować pieńki (stubs), gdyż bez tego będzie niezręcznie tworzyć kod, który nie będzie się chciał skompilować. Z tego powodu należy w katalogu rozpakowanego archiwum wywołać polecenia: ./globus-build-service.sh -d org/pg/ti/lab5 -s schema/lab5/RegionService_instance/Region.wsdl -t stubs ./globus-build-service.sh -d org/pg/ti/lab5 -s schema/lab5/FactoryService_instance/Factory.wsdl -t stubs Spowoduje to wygenerowanie samych pieńków i pozwoli na kompilację tworzonych klas. Implementajca klas FactoryService, RegionQName, RegionResourceHome, RegionResource jest w pełni analogiczna do przykładu przedstawionego w samouczku w punkcie 5, więc nie będzie omawiana szczegółowo. Klasa UniqueSequence została użyta na potrzeby uzyskania unikalnych identyfikatorów kolejno tworzonych zasobów. Klasa WorkerThread została wprowadzona, by zademonstrować, jak zadania mogą być wykonywane w tle. Z obiektem RegionService jest skojrzaona prosta pula 10 wątków, które gotowe są do przyjmowania zleceń. W wypadku wywołania na metody integrate na serwisie RegionService próbuje on przydzielić zadanie całkowania zadanego obszaru całkowania jednemu z wolnych wątków. Gdy brak takiego wątku zgłaszany jest wyjątek. Całkowanie przeprowadza zasób ze stanu UNINTEGRATED przez stan INTEGRATING do stanu INTEGRATED, gdy proces został zakończony. Pozwoli do m.in. klientowi określić, czy zasób już jest gotowy do odczytu. Oto kod klasy implementującej usługę sieciową. package org.pg.ti.lab5.impl; import java.rmi.RemoteException; import org.globus.wsrf.ResourceContext; import org.pg.ti.lab5.stubs.RegionService_instance.Integrate; import org.pg.ti.lab5.stubs.RegionService_instance.IntegrateResponse; import org.pg.ti.lab5.stubs.RegionService_instance.SetRegion; import org.pg.ti.lab5.stubs.RegionService_instance.SetRegionResponse; import org.pg.ti.lab5.impl.WorkerThread; import org.pg.ti.lab5.impl.WorkerThread; public class RegionService { WorkerThread[] thread = new WorkerThread[10]; public RegionService(){ // inicjalizacja puli wątków for (int i=0; i< thread.length; i++){ thread[i] = new WorkerThread(); thread[i].start(); } } // pobieranie zasobu skojarzonego z danym wołaniem (kontekstem) private RegionResource getResource() throws RemoteException { Object resource = null; try { ResourceContext resourceContext = ResourceContext.getResourceContext(); System.out.println("resource key = " + resourceContext.getResourceKey()); resource = ResourceContext.getResourceContext().getResource(); } catch (Exception e) { e.printStackTrace(); throw new RemoteException("", e); } return (RegionResource) resource; } // ustawienie obszaru całkowania public SetRegionResponse setRegion(SetRegion setRegion) throws RemoteException{ System.out.println("setRegion(" + setRegion.getX1() +","+ setRegion.getX2() + ")"); RegionResource resource = getResource(); resource.setX1( setRegion.getX1() ); resource.setX2( setRegion.getX2() ); resource.setState(RegionResource.UNINTEGRATED); resource.setIntegral(0); return new SetRegionResponse(); } // wysłanie polecenie całkowania public IntegrateResponse integrate(Integrate integrate) throws RemoteException{ assignResourceToThread(); return new IntegrateResponse(); } // próba przydzielenia wątku całkującego do bieżącego zasobu synchronized private void assignResourceToThread() throws RemoteException { for (int i=0; i<thread.length; i++){ if ( thread[i].isWaitingForNewRequests()) { thread[i].performIntegration(getResource()); return; } } throw new RemoteException("No worker thread available"); } } Deskryptory wdrożenia W nadpakiecie pakietu impl zawierającego klasy implementacyjne powinny znaleźć się pliki wdrożeniowe wsdd oraz jndi. Ich postać w przypadku omawianego przykładu jest następująca: deploy-servier.wsdd: <?xml version="1.0" encoding="UTF-8"?> <deployment name="defaultServerConfig" xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Instance service --> <service name="ti/lab5/RegionService" provider="Handler" use="literal" style="document"> <parameter name="className" value="org.pg.ti.lab5.impl.RegionService"/> <wsdlFile>share/schema/lab5/RegionService_instance/Region_service.wsdl</wsdlFile> <parameter name="allowedMethods" value="*"/> <parameter name="handlerClass" value="org.globus.axis.providers.RPCProvider"/> <parameter name="scope" value="Application"/> <parameter name="providers" value="GetRPProvider"/> </service> <!-- Factory service --> <service name="ti/lab5/RegionFactory" provider="Handler" use="literal" style="document"> <parameter name="className" value="org.pg.ti.lab5.impl.FactoryService"/> <wsdlFile>share/schema/lab5/FactoryService/Factory_service.wsdl</wsdlFile> <parameter name="allowedMethods" value="*"/> <parameter name="handlerClass" value="org.globus.axis.providers.RPCProvider"/> <parameter name="scope" value="Application"/> <parameter name="instance" value="ti/lab5/RegionService"/> </service> </deployment> Wiele z parametrów wdro eniowych poznanych ju było przy okazji laboratoriów zwi zanych z serwerem AXIS. Na szczególn uwag zasługuje parametr “providers”, który dokonuje niejako wstrzykni cie implementacji metody do serwisu RegionService umo liwiaj cej pobranie informacji o własno ciach zasobu skojarzonego z usług . Mo liwe jest to równie dzi ki atrybutowi wsdlpp:extends="wsrpw:GetResourceProperty" zdefiniowanemu w pliku WSDL, stanowi cemu zarazem punkt rozszerzenia standardowego WSDL. deploy-jndi-config.xml: <?xml version="1.0" encoding="UTF-8"?> <jndiConfig xmlns="http://wsrf.globus.org/jndi/config"> <!-- Instance service --> <service name="ti/lab5/RegionService"> <resource name="home" type="org.pg.ti.lab5.impl.RegionResourceHome"> <resourceParams> <parameter> <name>resourceClass</name> <value>org.pg.ti.lab5.impl.RegionResource</value> </parameter> <parameter> <name>factory</name> <value>org.globus.wsrf.jndi.BeanFactory</value> </parameter> <parameter> <name>resourceKeyType</name> <value>java.lang.Integer</value> </parameter> <parameter> <name>resourceKeyName</name> <value>{http://eti.pg.gda.pl/namespaces/ti/lab5/RegionService_instance}RegionResourceKey</value> </parameter> </resourceParams> </resource> </service> <!-- Factory service --> <service name="ti/lab5/RegionFactory"> <resourceLink name="home" target="java:comp/env/services/ti/lab5/RegionService/home"/> </service> </jndiConfig> Plik JNDI wdra a obie usługi. Parametry dokonuj powi zania usługi z obiektem Home oraz z obiektem zasobu. Dodatkowo przekazywana jest informacja o typie klucza identyfikuj cego usług oraz o jego kwalifikowanej nazwie. W zeł resourceLink pozwala na odwołanie si do własno ci zdefiniowanej gdzie indziej w pliku, w tym wypadku do własno ci home usługi RegionService. Przypisana ona zostaje te usłudze fabryki. Plik GAR Gdy wszystkie pliki są już gotowe należy skorzystać ze skryptu globus-build-service.sh . Dla wygody najlepiej stworzyć plik build.mappings w katalogu bieżącym i wpisać w nim wiersz: factory,org/pg/ti/lab5,schema/lab5/RegionService_instance/Region.wsdl,schema/lab5/FactoryService/Factory. wsdl Pozwoli to utworzy archiwum GAR przez wywołanie komendy: ./globus-build-service.sh factory Gdy plik jest gotowy nale y jako u ytkownik globus (lub inny posiadaj cy uprawnienia) umie ci plik gar w kontenerze globusa poleceniem globus-deploy-gar ./org_pg_ti_lab5.gar oraz jako ten sam u ytkownik uruchomi kontener globusa: globus-start-container -nosec (-nosec tylko dla celów testowych). Program testowy Program testowy działa w nast puj cy sposób: Tworzy 5 niezale nych zasobów, ka demu przypisuj c inny zakres całkowania, nast pnie dla ka dego zasobu uruchamia obliczanie całki i sprawdza przy u yciu standardowego mechanizmu pobierania informacji o własno ciach zasobów, czy zadanie ju zostało wykonane, a je li tak, to podaje wynik. Oto kod klienta: package org.pg.ti.client; import java.rmi.RemoteException; import java.util.HashSet; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.rpc.ServiceException; import import import import import import import import import import import import import import import import import org.apache.axis.message.addressing.Address; org.apache.axis.message.addressing.EndpointReferenceType; org.apache.axis.types.URI.MalformedURIException; org.globus.wsrf.encoding.ObjectSerializer; org.globus.wsrf.encoding.SerializationException; org.pg.ti.lab5.impl.RegionQNames; org.pg.ti.lab5.stubs.FactoryService.CreateResource; org.pg.ti.lab5.stubs.FactoryService.CreateResourceResponse; org.pg.ti.lab5.stubs.FactoryService.FactoryPortType; org.pg.ti.lab5.stubs.FactoryService.service.FactoryServiceAddressingLocator; org.pg.ti.lab5.stubs.RegionService_instance.Integrate; org.pg.ti.lab5.stubs.RegionService_instance.RegionPortType; org.pg.ti.lab5.stubs.RegionService_instance.SetRegion; org.pg.ti.lab5.stubs.RegionService_instance.service.RegionServiceAddressingLocator; org.oasis.wsrf.properties.GetResourcePropertyResponse; org.oasis.wsrf.properties.InvalidResourcePropertyQNameFaultType; org.oasis.wsrf.properties.ResourceUnknownFaultType; public class Client { public static void main(String[] args) throws ServiceException, MalformedURIException, SerializationException, RemoteException, InterruptedException { FactoryServiceAddressingLocator factoryLocator = new FactoryServiceAddressingLocator(); RegionServiceAddressingLocator instanceLocator = new RegionServiceAddressingLocator(); String factoryURI = args[0]; EndpointReferenceType factoryEPR, instanceEPR; FactoryPortType regionFactory; // Get factory portType factoryEPR = new EndpointReferenceType(); factoryEPR.setAddress(new Address(factoryURI)); regionFactory = factoryLocator.getFactoryPortTypePort(factoryEPR); // Create resource and get endpoint reference of WS-Resource. // This resource is our "instance". RegionPortType[] regionService = new RegionPortType[5]; for (int i=0; i<5; i++) { CreateResourceResponse createResponse = regionFactory .createResource(new CreateResource()); instanceEPR = createResponse.getEndpointReference(); // Get instance PortType regionService[i] = instanceLocator.getRegionPortTypePort(instanceEPR); regionService[i].setRegion(new SetRegion( i*100 , (i+1) *100)); regionService[i].integrate(new Integrate()); } Set finished = new HashSet(); while ( true ) { for ( int i=0; i< regionService.length; i++) { RegionPortType pt = regionService[i]; if (finished.size() == 5) System.exit(0); if (finished.contains(new Integer(i))) continue; String String String String state = getResourceProperty(pt, RegionQNames.RP_STATE); x1 = getResourceProperty(pt, RegionQNames.RP_X1); x2 =getResourceProperty(pt, RegionQNames.RP_X2); integral =getResourceProperty(pt, RegionQNames.RP_INTEGRAL); if (state.equals("INTEGRATED")) { System.out.println("Integral for range ( " + x1 + ", " + x2 + ") = " + integral ); finished.add(new Integer(i)); } if ( state.equals("ERROR")) { System.err.println("Error while integrating range :( " + x1 + ", " + x2 + ")") ; finished.add((new Integer(i))); } System.out.println("resource[" +( i +1) + "].state=" +state); } Thread.sleep(1000); } } static String getResourceProperty(RegionPortType pt, QName qname) throws InvalidResourcePropertyQNameFaultType, ResourceUnknownFaultType, RemoteException{ GetResourcePropertyResponse resourcePropertyResponse = pt.getResourceProperty(qname); String value = resourcePropertyResponse.get_any()[0].getValue(); return value; } } Szczególn uwag nale y zwróci na metod getResourceProperty wykorzystuj c standardowego dostawc tej usługi wstrzykni tego w kod usługi sieciowej. S jeszcze 3 inne metody dost pu do usługi zasobów: SetResourceProperties, GetMultipleResourceProperties oraz QueryResourceProperties. Szczegółów nale y szuka w rozdziale 6 samouczka.