Wstęp Modele powiązań WS-R

Transkrypt

Wstęp Modele powiązań WS-R
Integracja usług w Internecie
laboratorium nr 5
Katedra Architektury Systemów Komputerowych
Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej
mgr inż. Karol Bańczyk
Globus Toolkit
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/gt4-
tutorial/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/Factory.wsdl -t stubs
Spowoduje to wygenerowanie samych pieńków i pozwoli na kompilację tworzonych klas.
Implementacja 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,schem
a/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
if (state.equals("INTEGRATED")) {
System.out.println("Integral for range ( " + x1 + ", " + x2 + ") = " + integral
);
}
}
}
state = getResourceProperty(pt, RegionQNames.RP_STATE);
x1 = getResourceProperty(pt, RegionQNames.RP_X1);
x2 =getResourceProperty(pt, RegionQNames.RP_X2);
integral =getResourceProperty(pt, RegionQNames.RP_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.
Kod klienta można skompilować w następujący sposób:
javac -classpath ./build/stubs/classes/:$CLASSPATH org/pg/ti/client/Client.java
a następnie uruchomić (po uprzednim uruchomieniu serwera) w następujący
sposób:
java -classpath ./build/stubs/classes/:$CLASSPATH org.pg.ti.client.Client
http://127.0.0.1:8080/wsrf/services/ti/lab5/RegionFactory

Podobne dokumenty