Download presentation
Presentation is loading. Please wait.
1
18. glava: Remote Method Invocation (RMI)
Mrežno računarstvo 18. glava: Remote Method Invocation (RMI)
2
Mreže imaju 2 fundamentalne primene:
Prva primena je premeštanje fajlova i podataka između hostova i tiče se FTP, SMTP, HTTP, NFS, IMAP, POP i mnogih drugih protokola Druga primena je omogućavanje jednom hostu da izvršava programe na drugom hostu. Tradicionalno, to rade Telnet, rlogin, RemoteProcedureCall (RPC) i mnogo database middleware-a. RMI (Remote Method Invocation) je primer druge primene mreža: izvršavanje programa na hostu udaljenom od lokalne mašine
3
RMI Delovi jednog programa izvršavaju se na lokalnom računaru, dok se drugi delovi istog programa izvršavaju na udaljenom hostu. RMI stvara iluziju da se ovaj distribuirani program izvršava na jednom sistemu sa jednim memorijskim prostorom koji sadrži sav kod i podatke korišćene na bilo kojoj od strana stvarne fizičke konekcije
4
Šta je Remote Method Invocation?
RMI dopušta da Java objekti na različitim hostovima međusobno komuniciraju na način sličan onome na koji komuniciraju objekti koji se izvršavaju na istoj VM: pozivanjem metoda objekata Udaljeni objekat (remote object) živi na serveru. Svaki udaljeni objekat implementira udaljeni interfejs (remote interface) koji određuje koji od njegovih metoda može biti pozvan od strane klijenata. Klijenti pozivaju metode udaljenog objekta skoro isto kao što pozivaju lokalne metode.
5
Primer Objekat koji se izvršava na lokalnom klijentu može proslediti upit bazi kao String argument metoda objekta baze koji se izvršava na udaljenom serveru da ga “zamoli” da sumira niz slogova. Server može vratiti rezultat klijentu kao double. Ovo je efikasnije nego download-ovati sve slogove i sumirati ih lokalno. Primer 2: Java-kompatibilni web serveri mogu implementirati udaljene metode (remote methods) koji dopuštaju klijentima da traže kompletan indeks javno dostupnih fajlova na sajtu. Ovo može dramatično smanjiti vreme koje server provodi popunjavajući zahteve web spider-a kao što je Google.
6
Sa programerske tačke gledišta, udaljeni objekti i metodi funkcionišu u velikoj meri kao lokalni objekti i metodi na koje smo navikli. Svi detalji implementacije su sakriveni. Samo importujemo jedan paket, potražimo udaljeni objekat u registry-ju (što je 1 linija koda), i obezbedimo da se hvata RemoteException kada pozivamo metode objekta. Od te tačke nadalje možemo koristiti udaljeni objekat skoro slobodno i jednostavno kao što koristimo objekat koji se izvršava na našem sopstvenom sistemu.
7
Apstrakcija nije savršena
Apstrakcija nije savršena. Remote method invocation je mnogo sporiji i manje pouzdan negoli regularan local method invocation. Stvari mogu poći, i polaze naopako sa remote method invocation koje ne utiču na local method invocation. (RemoteExceptions). Međutim, RMI pokušava da sakrije razliku između local i remote method invocation što je moguće više.
8
Udaljeni objekat Formalnije, udaljeni objekat je objekat sa metodima koji mogu biti pozvani sa druge VM u odnosu na onu na kojoj sam objekat živi, uopšteno, sa VM koja se izvršava na drugom računaru. Svaki udaljeni objekat implementira 1 ili više udaljenih interfejsa koji deklarišu koji metodi udaljenog objekta mogu biti pozvani od strane drugog sistema
9
Primer Pretpostavimo da je weather.centralpark.org PC konektovan na Internet u Central Park weather station, koji prati temperaturu, vlažnost vazduha, vazdušni pritisak, brzinu i smer vetra i slične informacije kroz konekcije sa raznim instrumentima, i treba da učini ove podatke dostupnim udaljenim računarima Java program koji se izvršava na tom PC-ju može ponuditi interfejs koji obezbeđuje tekuće vrednosti podataka o vremenu:
10
Weather.java (udaljeni interfejs)
import java.rmi.*; import java.util.Date; public interface Weather extends Remote{ public double getTemperature() throws RemoteException; public double getHumidity() throws RemoteException; public double getPressure() throws RemoteException; … }
11
Uobičajeno, ovaj interfejs je ograničen na druge programe koji se izvršavaju na istom PC-ju, zapravo u istoj VM. Međutim, remote method invocations dopuštaju da druge VM, koje se izvršavaju na drugim računarima, u drugim krajevima sveta, pozivaju ove metode kako bi dobile podatke o vremenu. Npr. Java program koji se izvršava na stallion.elharo.com može potražiti tekući Weather objekat u RMI registry na weather.centralpark.org Registry će mu poslati referencu na objekat koji se izvršava na VM na weather.centralpark.org Program na stallion.elharo.com može potom koristiti ovu referencu kako bi pozvao metod getTemperature(). Ovaj metod će se izvršiti na serveru u Central Park-u, ne na lokalnoj mašini.
12
Međutim, vratiće double vrednost lokalnom programu (koji se izvršava u Bruklinu).
Ovo je jednostavnije nego dizajnirati i implementirati novi soket-zasnovan protokol za komunikaciju između meteorološke stanice i njenih klijenata. Detalji uspostavljanja konekcija između hostova i transfera podataka su skriveni u RMI klasama.
13
Za sada, zamislili smo javni, svima dostupan, servis.
Međutim, postoje neki metodi za koje ne želimo da svako može da ih poziva Većina RMI aplikacija ima strogo ograničen skup dopuštenih korisnika. Sam RMI ne obezbeđuje nikakva sredstva ograničavanja kome je dopušten pristup RMI serverima. Ove mogućnosti mogu se dodati RMI programima pomoću Java Authentication and Authorization Service (JAAS).
14
Serijalizacija objekata
Kada se objekat prosledi Java metodu ili ga metod vrati, ono što je zaista preneseno je referenca na objekat. Referenca je dvostruki indirektni pokazivač na lokaciju objekta u memoriji. Prosleđivanje objekata između dve mašine zbog toga stvara neke probleme. Udaljena mašina ne može čitati šta je u memoriji lokalne mašine. Referenca koja je validna na jednoj mašini, besmislena je na drugoj.
15
*** Postoje dva načina za rešavanje ovog problema.
Prvi je da se objekat konvertuje u niz bajtova i ti bajtovi pošalju udaljenoj mašini. Udaljena mašina prima bajtove i rekonstruiše ih u kopiju objekta. Međutim, promene na kopiji se ne odražavaju automatski na originalni objekat. Drugi način je proslediti specijalnu udaljenu referencu na objekat. Kada udaljena mašina pozove metod za ovu referencu, poziv putuje natrag kroz Internet do lokalne mašine koja je originalno kreirala objekat. Promene učinjene na bilo kojoj mašini odražavaju se na oba kraja konekcije jer oni dele isti objekat.
16
*** Konvertovanje objekata u sekvencu bajtova je teže nego što se to čini na prvi pogled, jer polja objekta mogu biti reference na druge objekte; objekte na koje ova polja ukazuju takođe treba iskopirati kada se kopira taj objekat. A ovi objekti mogu pokazivati na neke druge objekte, koje takođe treba kopirati. Serijalizacija objekata je šema kojom se objekti mogu konvertovati u bajtove i proslediti drugoj mašini koja izgrađuje originalni objekat iz bajtova. Ovi bajtovi se takođe mogu upisati na disk i kasnije pročitati otuda, dopuštajući nam da sačuvamo stanje čitavog programa u jednom jedinom objektu
17
*** Iz bezbednosnih razloga, Java ima neka ograničenja na to koji objekti mogu biti serijalizovani. Svi primitivni tipovi mogu biti serijalizovani. “Neudaljeni” Java objekti mogu biti serijalizovani samo ako implementiraju java.io.Serializable interfejs Klase String i Component implementiraju ga Kontejnerske klase poput Vector<> su serijabilne (serializable) ako su takvi i svi objekti koje sadrže. Dalje, potklasa serijabilne klase je i sama serijabilna. Npr. java.lang.Integer i java.lang.Float su serijabilne jer je klasa iz koje su izvedene, java.lang.Number, takva.
18
*** Izuzeci, greške i drugi throwable objekti su uvek serijabilni.
Većina AWT i Swing komponenata, kontejnera i događaja je serijabilno Međutim, adapteri događaja, filteri slika i peer klase nisu Tokovi, čitači i pisači i većina drugih I/O klasa nije Wrapper klase tipova su serijabilne osim za Void Klase u paketu java.math su serijabilne Klase u java.lang.reflect nisu. Klasa URL jeste Međutim, Socket, URLConnection i većina drugih klasa u java.net nije
19
CORBA RMI nije jedina mogućnost kada se radi o distribuiranim objektnim sistemima. Njegovo najveće ograničenje je što se mogu pozivati samo metodi napisani u Javi. Šta ako već imamo aplikaciju napisanu u nekom drugom jeziku, npr. C++, i želimo da komuniciramo sa njom? Najuopštenije rešenje za distribuirane objekte je CORBA, the Common Object Request Broker Architecture. Corba dopušta da objekti napisani u različitim jezicima međusobno komuniciraju
20
RMI – kako funkcioniše Java krije mnoge stvari od nas. Međutim, ne škodi nikada da se razume kako stvari zaista funkcionišu Ključna razlika između udaljenih i lokalnih objekata je što su udaljeni objekti u drugoj VM. Uobičajeno, objekti argumenti se prosleđuju metodima i objekti povratne vrednosti bivaju vraćeni od metoda da referišu na nešto u određenoj VM. To se zove prosleđivanje reference. Međutim, ovakav pristup ne funkcioniše kada pozivajući i pozvani metod nisu u istoj VM. Različite VM mogu implementirati reference na potpuno različite i nekompatibilne načine
21
Koriste se 3 različita mehanizma za prosleđivanje argumenata i vraćanje rezultata udaljenih metoda u zavisnosti od tipa prosleđenih podataka. Primitivni tipovi (int, boolean, double, ...) se prosleđuju po vrednosti, kao i u pozivu lokalnih Java metoda Reference na udaljene objekte (tj. objekti koji implementiraju Remote interfejs) se prosleđuju kao udaljene reference koje omogućavaju da primalac pozove metode udaljenih objekata. Slično kao što se reference na lokalne objekte prosleđuju lokalnim Java metodima
22
Objekti koji ne mogu biti serijalizovani ne mogu biti prosleđeni udaljenim metodima.
Udaljeni objekti se izvršavaju na serveru, ali mogu biti pozvani objektima koji se izvršavaju na klijentu Neudaljeni, serijabilni objekti izvršavaju se na klijentskom sistemu.
23
*** Da bi se proces učinio što je moguće više transparentnim za programera, komunikacija između klijenta i servera je implementirana nizom slojeva: Server Program Client Program Skeleton Stub Remote Reference Layer Remote ReferenceL. Transpor Layer Transport Layer Programeru izgleda kao da se klijent direktno obraća serveru. Zapravo, klijent komunicira samo sa Stub objektom koji je zamena za stvarni objekat na udaljenom sistemu. Stub prosleđuje konverzaciju remote reference sloju, koji priča sa transport layerom...
24
Veći deo vremena mi o ovome ne moramo da mislimo više nego što mislimo o tome kako telefon prevodi naš glas u niz električnih impulsa koji se prevode nazad u zvuk na drugoj strani telefonskog poziva Cilj RMI-ja je da omogući da naš program prosledi argumente metodima i uzme povratne vrednosti od njih bez brige o tome kako se ti argumenti i povratne vrednosti prenose preko mreže. U najgorem slučaju, moraćemo da rukujemo još 1 dodatnom vrstom izuzetaka koje može izbaciti udaljeni metod
25
Registry Pre nego što pozovemo metod udaljenog objekta, neophodna nam je referenca na taj objekat. Da bismo je dobili, tražimo je od registry-ja po imenu. Registry je poput mini-DNS-a za udaljene objekte. Klijent se konektuje na registry i daje mu URL udaljenog objekta koji želi. Registry odgovara referencom na objekat koju klijent može koristiti da bi pozvao metode na serveru
26
Stub objekat U stvarnosti, klijent samo poziva lokalne metode u stub-objektu. Stub je lokalni objekat koji implementira udaljene interfejse udaljenog objekta; to znači da stub ima metode koji odgovaraju potpisima svih metoda koje udaljeni objekat eksportuje Zapravo, klijent misli da poziva metod udaljenog objekta, ali zapravo poziva ekvivalentni metod stub-a. Stub-ovi se koriste u VM klijenata umesto stvarnih objekata i metoda koji žive na serveru Korisno je razmišljati o stub-u kao o surogatu udaljenog objekta na klijentu.
27
Implementacija Većina metoda neophodnih za rad sa udaljenim objektima nalazi se u 3 paketa: java.rmi, java.rmi.server, java.rmi.registry Paket java.rmi definiše klase, interfejse i izuzetke koji će biti viđeni na strani klijenta Oni su nam neophodni kada pišemo programe koji pristupaju udaljenim objektima, ali sami po sebi nisu udaljeni objekti Paket java.rmi.server definiše klase, interfejse i izuzetke koji će biti vidljivi na strani servera. Ove klase se koriste kada se piše udaljeni objekat koji će biti pozivan od strane klijenata Paket java.rmi.registry definiše klase, interfejse i izuzetke koji se koriste za lociranje i imenovanje udaljenih objekata
28
Napomena U ovom poglavlju, kao i u Sun-ovoj dokumentaciji, serverska strana se uvek smatra “udaljenom”, a klijentska “lokalnom”. Ovo može biti zbunjujuće, posebno kada pišemo udaljeni objekat. Tada obično razmišljamo sa tačke gledišta servera, kome je klijent “udaljen”
29
Serverska strana Da bismo kreirali novi udaljeni objekat, prvo definišemo interfejs koji nasleđuje java.rmi.Remote interfejs. Remote je marker-interfejs koji nema sopstvenih metoda, njegova jedina svrha je da taguje udaljene objekte tako da mogu biti identifikovani kao takvi Jedna definicija udaljenog objekta je da je to instanca klase koji implementira Remote interfejs ili bilo koji njegov podinterfejs
30
Udaljeni interfejs Naš podinterfejs od Remote definiše koje metode udaljenog objekta klijenti mogu zvati. Udaljeni objekat može imati mnogo javnih metoda, ali samo oni deklarisani u udaljenom interfejsu mogu se pozivati od strane udaljenih klijenata. Ostali javni metodi mogu se pozivati samo unutar VM na kojoj objekat živi Svaki metod podinterfejsa mora deklarisati da izbacuje RemoteException. RemoteException je superklasa za većinu izuzetaka koji mogu biti izbačeni prilikom korišćenja RMI. Mnogi od ovih su povezani sa ponašanjem eksternih sistema i mreža i time su izvan naše kontrole
31
Primer: Fibonacci Jednostavan interfejs za udaljeni objekat koji računa Fibonačijeve brojeve proizvoljne veličine Fibonačijeve brojeve čini sekvenca koja počinje sa: 1, 1, 2, 3, 5, 8, 13, ... u kojoj je svaki broj suma prethodna dva. Prva dva broja se zadaju eksplicitno. Ovaj udaljeni objekat se može izvršavati na moćnom serveru kako bi računao rezultate za klijente manje snage Interfejs deklariše dva preklopljena (overloaded) metoda getFibonacci(), od kojih jedan uzima int kao argument, a drugi BigInteger. Oba metoda vraćaju BigInteger, jer Fibonačijevi brojevi vrlo brzo vrlo mnogo rastu. Složeniji udaljeni objekat može imati mnogo više metoda
32
Ništa u ovom interfejsu ne govori ništa o tome kako je izračunavanje implementirano. Npr. može biti izračunato direktno, korišćenjem metoda java.math.BigInteger klase. Može biti urađeno podjednako jednostavno efikasnijim metodima com.ibm.BigInteger klase. Može biti izračunato int-ovima za male vrednosti n, a BigInteger za velike. Svako izračunavanje može biti izvršeno neposredno ili može biti iskorišćen fiksirani broj niti kako bi se ograničilo opterećenje servera Izračunate vrednosti mogu biti keširane za brže dobijanje u budućim zahtevima, bilo interno ili u fajlu ili bazi podataka. Bilo šta ili sve od ovoga je moguće Klijent ne zna, i ne interesuje ga, kako server dolazi do rezultata sve dok je taj rezultat ispravan
33
Impl-klasa Sledeći korak je definisanje klase koja implementira ovaj udaljeni interfejs Klasa treba da bude izvedena iz java.rmi.server.UnicastRemoteObject bilo direktno ili indirektno (tj. da nasleđuje drugu klasu koja nasleđuje UnicastRemoteObject) Bez previše detaljisanja, UnicastRemoteObject obezbeđuje metode koji čine da RMI funkcioniše Posebno ova klasa radi tzv. “marshalling” i “unmarshalling” udaljenih referenci na objekat
34
Marshalling i Unmarshalling
Marshalling je proces kojim se argumenti i povratne vrednosti konvertuju u tok bajtova koji može biti poslat preko mreže Unmarshalling je obrnut proces: konverzija toka bajtova u grupu argumenata i povratnu vrednost.
35
Ako izvođenje klase iz UnicastRemoteObject nije podesno, npr
Ako izvođenje klase iz UnicastRemoteObject nije podesno, npr. jer bismo želeli da nasledimo neku drugu klasu, možemo eksportovati naš objekat kao udaljeni njegovim prosleđivanjem nekom od statičkih UnicastRemoteObject.exportObject() metoda: public static RemoteStub exportObject(Remote obj) throws RemoteException public static Remote exportObject(Remote obj, int port) throws RemoteException public static Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException
36
Oni kreiraju udaljeni objekat koji koristi naš objekat da bi odradio posao.
Ovo je slično kao što Runnable objekat može da se koristi kako bi dao niti ono što treba da radi, kada nije pogodno naslediti klasu Thread. Međutim, ovaj pristup ima manu jer sprečava korišćenje dinamičkih proksija u Java 1.5
37
Activatable Postoji 1 vrsta RemoteServer u standardnoj Java biblioteci: java.rmi.activation.Activatable (apstraktna klasa, izvedena iz RemoteServer) UnicastRemoteObject postoji dok se izvršava server koji ga je kreirao. Kada server umre, objekat zauvek nestaje Activatable objekti dopuštaju klijentima da se rekonektuju na servere u raznim trenucima između gašenja i restarta servera i pristupaju istim udaljenim objektima. Takođe, postoje statički Activatable.exportObject() metode koje pozivamo ako ne želimo da nasledimo klasu Activatable
38
Primer: FibonacciImpl
Klasa implementira udaljeni interfejs Fibonacci Ima konstruktor i 2 getFibonacci() metoda Jedino su getFibonacci() metodi dostupni klijentu jer su jedino oni definisani Fibonacci interfejsom Konstruktor se koristi na strani servera i nije dostupan klijentu FibonacciImpl() konstruktor samo poziva konstruktor superklase koji eksportuje objekat, tj. kreira UnicastRemoteObject na nekom portu i počinje da osluškuje konekcije. Konstruktor je deklarisan da izbacuje RemoteException jer UnicastRemoteObject konstruktor može izbaciti taj izuzetak
39
getFibonacci(int n) metod je trivijalan
getFibonacci(int n) metod je trivijalan. Prosto vraća rezultat konvertovanja svog argumenta u BigInteger i poziva drugog getFibonacci() metoda Drugi metod zapravo vrši izračunavanje. On koristi BigInteger kako bi omogućio izračunavanje proizvoljno velikih Fibonačijevih brojeva za proizvoljno veliki indeks. Ovo može trošiti mnogo CPU snage i ogromne količine memorije. Zbog toga možda želimo da to izračunavanje premestimo na server specijalizovan za tu vrstu izračunavanja umesto da ga izvršavamo lokalno.
40
Iako je getFibonacci() udaljeni metod, u njemu nema ničega što ga razlikuje od lokalnih metoda.
Ovo je jednostavan slučaj, ali čak i mnogo kompleksniji udaljeni metodi nisu algoritamski različiti od svojih lokalnih kopija. Jedina razlika – da je udaljeni metod deklarisan u udaljenom interfejsu, a lokalni metod nije – je potpuno eksterna za sam metod
41
Server: FibonacciServer
Dalje, treba da napišemo server koji čini Fibonacci udaljeni objekat dostupnim svetu Sve što on ima je main() metod. Počinje ulaskom u try-blok koji hvata RemoteException. Zatim konstruiše novi FibonacciImpl objekat i vezuje ga za ime “fibonacci” koristeći klasu Naming kako bi komunicirao sa lokalnim registry-jem. Registry prati koji su dostupni objekti na RMI serveru i imena kojima se oni mogu zahtevati. Kada se kreira novi udaljeni objekat, objekat dodaje sebe i svoje ime u registry Naming.bind() ili Naming.rebind() metodom. Klijenti potom mogu tražiti objekat po imenu ili dobiti listu svih udaljenih objekata koji su dostupni. Primetimo da ne postoji pravilo koje kaže da ime koje objekat ima u registry-ju mora da ima veze sa imenom klase. Npr. Mogli bismo nazvati ovaj objekat “Fred”. Zapravo, može postojati veći broj instanci iste klase, pri čemu su sve vezane u registry-ju, svaka sa različitim imenom. Nakon što se registruje, server štampa poruku na System.out signalizirajući da je spreman da prihvata udaljene pozive. Ako nešto krene naopako, catch-blok štampa jednostavnu poruku o grešci Iako se main() metod ovde završava prilično brzo, server će nastaviti da se izvršava, jer nedemonska nit je pokrenuta kada je FibonacciImpl vezan za registry. Ovim se završava serverski kod koji treba da napišemo
42
Kompajliranje stub-ova (ne treba od Java 1.5)
RMI koristi stub-klase da posreduju između lokalnih i udaljenih objekata. Svaki udaljeni objekat na serveru predstavljen je stub-klasom na klijentu. Stub sadrži informacije o Remote interfejsu (u ovom primeru, da Fibonacci objekat poseduje 2 getFibonacci() metoda) Java 1.5 može ponekad generisati ove stub-ove automatski kada su potrebni. U Java 1.4 i prethodnim, moraju se ručno kompajlirati stub-ovi za svaku udaljenu klasu. Čak i u Java 1.5 moraju se ručno kompajlirati stub-ovi za udaljene objekte koji nisu potklase od UnicastRemoteObject, već su eksportovani pozivom metoda UnicastRemoteObject.exportObject()
43
rmic Na sreću, ne moramo sami pisati stub-klase: one mogu biti generisane automatski od strane bajt koda udaljene klase koristeći rmic utility koji je sastavni deo JDK-a. Da bismo generisali stub-ove za FibonacciImpl udaljeni objekat, pokrenemo rmic na udaljenim klasama za koje želimo da generišemo stub-ove. Npr. rmic FibonacciImpl rmic čita .class fajl klasa koje implementiraju Remote interfejs i proizvodi .class fajlove za stub-ove neophodne za udaljeni objekat. Argument komandne linije za rmic je puno kvalifikovano ime klase udaljenog objekta (ovde je klasa u bezimenom paketu!!!) rmic podržava iste opcije komandne linije kao i javac kompajler, npr. -classpath i -d npr. ako klasa nije u classpath, možemo zadati lokaciju –classpath argumentom komandne linije. Sledeća komanda traži FibonacciImpl.class u direktorijumu test/clases: rmic -classpath test/classes FibonacciImpl
44
Pokretanje servera Sada smo spremni da pokrenemo server
Zapravo, dva servera treba da pokrenemo: sam udaljeni objekat (FibonacciServer u ovom primeru) i registry koji omogućava lokalnim klijentima da download-uju referencu na udaljeni objekat. Pošto server očekuje da komunicira sa registry-jem, prvo moramo pokrenuti registry. Postarati se da su sve stub i server klase u serverovom classpath i ukucati: rmiregistry & (za Linux) pod Windows-om, startuje se iz DOS prompta sa: start rmiregistry
45
U oba primera, registry se izvršava u pozadini.
registry pokušava da osluškuje na portu 1099, po default-u. Ako ne uspe, posebno sa porukom poput “java.net.SocketException: Address already in use”, onda neki drugi program koristi port 1099, moguće (ne nužno) drugi registry servis. Registry se može pokrenuti na drugom portu dopisivanjem broja porta: rmiregistry 2048 & Ako se koristi drugi port, neophodno je uključiti taj port u URL koji referiše na ovaj registry servis.
46
Konačno, spremni smo da pokrenemo server
To se čini na potpuno isti način kao i za bilo koju drugu klasu sa main() metodom: java FibonacciServer (klasa je u bezimenom paketu!!!) Sada su server i registry spremni da prihvataju pozive udaljenih metoda
47
Klijentska strana Sledeće pišemo klijenta koji se konektuje na ove servere kako bi napravio pozive udaljenih metoda Pre nego što regularni Java objekat može pozvati metod, neophodna mu je referenca na objekat čiji će metod zvati Pre nego što klijentski objekat može pozvati udaljeni metod, neophodna mu je udaljena referenca na objekat čiji će metod zvati. Program dohvata ovu udaljenu referencu iz registry-ja na serveru na kom se udaljeni objekat izvršava. On pretražuje registry pozivom lookup() metoda registry-ja. Tačna šema imenovanja zavisi od registry-ja; java.rmi.Naming obezbeđuje URL-zasnovanu šemu za lociranje objekata
48
Polja za hostname i port su uobičajena
Kao što se može videti u narednom kodu, ovi URL-ovi su dizajnirani tako da su slični sa http URL-ovima: Protokol je rmi file-polje URL-a određuje ime udaljenog objekta Polja za hostname i port su uobičajena Object o1 = Naming.lookup(”rmi://login.ibiblio.org/fibonacci”); Object o2 = Naming.lookup(”rmi://login.ibiblio.org:2048/fibonacci”);
49
Objekat dohvaćen iz registry-ja gubi informaciju o svom tipu
Objekat dohvaćen iz registry-ja gubi informaciju o svom tipu. Zato, pre korišćenja objekta, moramo ga kastovati u udaljeni interfejs koji udaljeni objekat implementira (ne u stvarnu klasu, koja je sakrivena od klijenata): Fibonacci calculator = (Fibonacci)Naming.lookup(”fibonacci”); Nakon što je referenca na objekat dobijena, i njen tip restauriran, klijent može koristiti referencu kako bi pozivao udaljene metode objekta sasvim isto kao kada koristi normalnu referencu da pozove metode lokalnog objekta. Jedina razlika je što mora hvatati RemoteException za svaki udaljeni poziv.
50
try{ BigInteger f56 = calculator. getFibonacci(56); System. out
try{ BigInteger f56 = calculator.getFibonacci(56); System.out.println(”The 56th Fibonacci number is ” + f56); BigInteger f156 = calculator.getFibonacci(new BigInteger(”156”)); System.out.println(”The 156th Fibonacci number is ” + f156); }catch(RemoteException ex){ System.err.println(ex); } Klasa se kompajlira na uobičajeni način.
51
Primetimo da zbog toga što se objekat koji Naming
Primetimo da zbog toga što se objekat koji Naming.lookup() vrati kastuje u Fibonacci, bilo Fibonacci.java bilo Fibonacci.class fajl mora biti dostupan na lokalnom hostu. Generalni zahtev kod kompajliranja klijenta je imati ili byte ili source code udaljenog interfejsa na koji se klijent konektuje. Do neke mere, ovo se može malo oslabiti, koristeći reflection API, ali se ipak mora znati bar nešto o API-ju udaljenog interfejsa. Veći deo vremena, ovo nije problem pošto su server i klijent napisani od strane istog programera ili tima
52
Pokretanje klijenta Postarati se da klijent poseduje: FibonacciClient.class Fibonacci.class i FibonacciImpl_Stub.class u svom class path Ako i klijent i server koriste Java 1.5 nije nam neophodna stub-klasa) Na klijentskom sistemu kucamo: java FibonacciClient rmi://host.com/fibonacci Klijent konvertuje argumente komandne linije u BigInteger objekte. Šalje te objekte preko žice udaljenom serveru. Server prima svaki od tih objekata, računa Fibonačijev broj za taj indeks i šalje BigInteger objekat nazad klijentu preko Interneta. Zapravo, moguće je izvršavati i klijent i server na istoj mašini, mada nije interesantno.
53
Loading Classes at Runtime
Sve što klijent zapravo treba da zna o udaljenom objektu je njegov udaljeni interfejs. Sve ostalo što mu je potrebno – npr. stub-klase – može biti učitano od web servera (ne RMI servera) u vreme izvršavanja koristeći class loader. Zapravo, ova mogućnost učitavanja klasa iz mreže je jedna od jedinstvenih mogućnosti Jave. Posebno je korisna u apletima. Web server može poslati browser-u aplet koji povratno komunicira sa serverom, npr. kako bi omogućio da klijent čita i piše fajlove na serveru. Međutim, kao i uvek kada se klase učitavaju od hosta kome potencijalno ne verujemo, one moraju biti proverene Security Manager-om.
54
Nažalost, iako su udaljeni objekti prilično jednostavni za upotrebu kada možemo da instaliramo neophodne klase u class path lokalnog klijenta, kada moramo dinamički da učitamo stub-ove i druge klase, teško je. Dohvatanje objekta lokalnog klijenta za download-ovanje udaljenih objekata sa servera zahteva jako preciznu manipulaciju. Sasvim mala greška sprečava pokretanje programa i samo najopštiji izuzetak se izbacuje da kaže programeru u čemu je pogrešio. Koliko je tačno teško naterati programe da rade zavisi od konteksta u kome se udaljeni objekti izvršavaju. Uopšteno, donekle je jednostavnije obraditi aplet klijente koji koriste RMI nego samostalne klijentske aplikacije Samostalne aplikacije su dopustive ako klijent može računati da ima pristup istim .class fajlovima kao i server. Samostalne aplikacije koje treba da učitaju te fajlove sa servera graniče se sa nemogućim.
55
Primer: FibonacciApplet
aplet klijent za Fibonacci udaljeni objekat ima istu osnovnu strukturu kao prethodni klijent koristi TextArea da prikaže poruku od servera umesto System.out rmi URL je izgrađen od apletovog codebase. Ovo pomaže da se izbegnu bezbednosni problemi koji nastaju kada aplet pokuša da otvori mrežnu konekciju sa hostom različitim od onoga sa koga potiče. RMI-zasnovani apleti svakako nisu izuzetak od uobičajenih restrikcija za mrežne konekcije
56
Primer: FibonacciApplet.html
jednostavan HTML fajl koji se može koristiti za učitavanje apleta u web browser-u. <html> <head> <title> RMI Applet </title> </head> <body> <h1>RMI Applet </h1> <p> <applet align=”center” code=”FibonacciApplet” width=”300” height=”100”> </applet> <hr/> </p> </body> </html>
57
Smestiti: FibonacciImpl_Stub. class FibonacciApplet
Smestiti: FibonacciImpl_Stub.class FibonacciApplet.html i FibonacciServer.class u isti direktorijum na našem web serveru. Dodati ovaj direktorijum u serverov class path i startovati rmiregistry na serveru Zatim pokrenuti FibonacciServer na serveru. Npr. rmiregistry & java FibonacciServer &
58
Osigurati da se oba programa izvršavaju na stvarnoj web server mašini
Osigurati da se oba programa izvršavaju na stvarnoj web server mašini. Kako bi prošli bezbednosne restrikcije apleta, i rmiregistry i FibonacciServer moraju da se izvršavaju na mašini koja predaje fajl FibonacciApplet.class web klijentima. Sada učitavamo FibonacciApplet.html u web browser sa klijenta.
59
Za aplikacije, mnogo je jednostavnije ako možemo da učitamo sve klase koje su nam neophodne pre pokretanja programa. Možemo učitati klase sa web servera koji se izvršava na istom serveru kao i udaljeni objekat, ako je potrebno. Da bismo to učinili, postavimo java.rmi.server.codebase Java sistemsko svojstvo (system property) na serveru (gde se udaljeni objekat izvršava) na URL na kom su .class fajlovi smešteni na mreži. Npr. da bismo zadali da se klase mogu naći na kucamo: java -Djava.rmi.server.codebase= FibonacciServer & Fibonacci server ready
60
Ako se klase nalaze u paketima, java. rmi. server
Ako se klase nalaze u paketima, java.rmi.server.codebase svojstvo pokazuje na direktorijum koji sadrži top-level com ili org direktorijum, pre nego direktorijum koji sadrži same .class fajlove I server i klijent će učitati .class fajlove sa ove lokacije ako ih prvo ne pronađu u lokalnom class path. Svaki klijentski program koji pišemo bi normalno morao da zna poprilično o sistemu sa kojim komunicira da bi uradio nešto korisno. Ovo obično uključuje bar da je udaljeni interfejs dostupan na klijentu u vreme kompajliranja i izvršavanja. Čak i ako koristimo reflection da bismo to izbegli, ipak moramo da znamo potpise i nešto o ponašanju metoda koje želimo da pozovemo.
61
RMI je izvršavanje 1 programa na većem broju mašina, a ne više programa na različitim mašinama koji međusobno komuniciraju prema tome, jednostavnije je ako obe strane konekcije imaju dostupan sav kod kada program započne izvršavanje
62
paket java.rmi sadrži klase koje vide klijenti (objekti koji pozivaju udaljene metode) i klijenti i serveri treba da importuju java.rmi ovaj paket sadrži 1 interfejs, 3 klase i pregršt izuzetaka Remote interfejs taguje objekte kao udaljene ne deklariše nijedan metod udaljeni objekti obično implementiraju podinterfejs od Remote koji deklariše neke metode. Metodi koji su tu deklarisani su metodi koji se mogu udaljeno pozivati 1 objekat može implementirati veći broj Remote interfejsa
63
klasa Naming java.rmi.Naming obraća se registry-ju koji se izvršava na serveru kako bi mapirao URL-ove poput rmi://login.ibiblio.org/myRemoteObject u određene udaljene objekte na određenim hostovima O registry-ju se može razmišljati kao o DNS-u za udaljene objekte. Svaki unos u registry-ju ima ime i referencu na objekat. Klijenti daju ime (preko URL), a dobiju referencu na udaljeni objekat rmi URL izgleda potpuno isto kao http URL osim što je šema rmi umesto http path deo URL-a je proizvoljno ime koje je server vezao za određeni udaljeni objekat, ne ime fajla
64
Najveći nedostatak je što iz bezbednosnih razloga (izbegavanje man-in-the-middle-napada) mora da se izvršava na istom serveru kao i udaljeni objekti. Ne može registrovati veći broj objekata na nekoliko različitih servera. Ako je ovo previše restriktivno, Java Naming and Directory Interface (JNDI) kontekst može ubaciti dodatni sloj indirekcije tako da veći broj RMI registry-ja može biti predstavljen kroz jedan direktorijum. Klijenti treba da znaju samo adresu glavnog JNDI direktorijuma. Ne treba da znaju adrese svih pojedinačnih RMI registry-ja koje JNDI menja.
65
metodi klase Naming klasa ima 5 javnih metoda: list() – lista sva imena iz registry-ja lookup() – za dati URL traži odgov. udaljeni objekat bind() – vezuje ime za određeni udaljeni objekat rebind() – vezuje ime za neki drugi udaljeni objekat unbind() – uklanja ime iz registry-ja
66
public static String[] list(String url) throws RemoteException, MalformedURLException
vraća niz String-ova, po jedan za svaki URL koji je trenutno vezan url argument je URL Naming registry-ja koji se pretražuje koristi se samo protokol, host i port, a path deo se ignoriše list() izbacuje MalformedURLException ako url nije validan rmi URL. RemoteException se izbacuje ako bilo šta drugo nije u redu, npr. registry nije dostupan ili odbija da dostavi zahtevanu informaciju Primer: program lista sva imena trenutno vezana u određenom registry-ju. To je ponekad korisno prilikom debagovanja RMI problema. Omogućuje nam da odredimo da li su imena koja koristimo imena koja server očekuje.
67
Metod izbacuje NotBoundException ako udaljeni server ne prepozna ime
public static Remote lookup(String url) throws RemoteException, NotBoundException, AccessException, MalformedURLException klijent koristi lookup() metod da bi dobio udaljeni objekat pridružen fajl-delu imena npr. kada je dat URL rmi://login.ibiblio.org:2001/myRemoteObject vratiće objekat vezan za myRemoteObject iz login.ibiblio.org na portu 2001 Metod izbacuje NotBoundException ako udaljeni server ne prepozna ime RemoteException ako udaljeni registry nije dostupan, npr. jer je mreža pala ili se ne izvršava registry servis na zadatom portu AccessException se izbacuje ako server odbije da potraži ime za određeni host Ako URL nije odgovarajući rmi URL, izbacuje se MalformedURLException
68
MalformedURLException ako url nije validan rmi URL
public static void bind(String url, Remote object) throws RemoteException, AlreadyBoundException, MalformedException, AcessException server koristi bind() metod da poveže ime, poput myRemoteObject sa udaljenim objektom Ako je to uspešno, klijenti će moći da dobiju stub udaljenog objekta iz registry-ja koristeći URL poput rmi://logib.ibiblio.org:2001/myRemoteObject MalformedURLException ako url nije validan rmi URL RemoteException ako registry nije dostupan AccessException (potklasa od RemoteException) ako klijentu nije dopušteno da vezuje objekte u registry-ju Ako je URL već vezan za lokalni objekat – AlreadyBoundException public static void unbind(String url) throws... .... rebind()...
69
Klasa RMISecurityManager
klijent učitava stub-ove od potencijalnog ”nepoverljivog” servera. U ovom smislu, odnos između klijenta i stub-a je donekle poput veze između browser-a i apleta. Iako je stub predviđen samo da radi marshalling argumenata i unmarshalling povratne vrednosti i šalje ih preko mreže, sa stanovišta VM, stub je samo još 1 klasa sa metodima koji mogu uraditi bilo šta. stub-ovi kreirani pomoću rmic ne bi trebalo da se ponašaju drugačije nego što je upravo opisano, ali nema razloga da neko ne može da ručno izmeni stub pa da on radi i ”užasne” radnje kao što su čitanje fajlova i brisanje podataka Java VM ne dopušta da se stub klase učitavaju preko mreže osim ako postoji SecurityManager objekat (kao i druge klase, stub klase se mogu uvek učitati iz lokalnog class path) Za aplete, standardni AppletSecurityManager zadovoljava ovu potrebu Aplikacije mogu koristiti klasu RMISecurityManager kako bi se zaštitile od loše kreiranih stub-ova. public class RMISecurityManager extends SecurityManager
70
u Java 1.1 ova klasa implementira policy koji dopušta da se klase učitaju sa serverovog codebase – što nije nužno isto što i server, i omogućuje neophodnu mrežnu komunikaciju između klijenta, servera i codebase 1.2 – ne dopušta čak ni to, previše restriktivna klasa, čak beskorisno 1.5 – Sun priznaje problem: ”RMISecurityManager implementira policy koja se ne razlikuje od one koju implementira SecurityManager” prema tome, RMI aplikacija treba da koristi klasu SecurityManager ili drugu SecurityManager implementaciju prilagođenu aplikaciji
71
Remote Exceptions u paketu java.rmi definisano je 16 izuzetaka
većina je izvedena iz java.rmi.RemoteException (a on je izveden iz java.io.IOException) AlreadyBoundException i NotBoundException su izvedeni iz java.lang.Exception Dakle, svi se ovi moraju hvatati 1 runtime exception: RMISecurityException, potklasa od SecurityException Udaljeni metodi zavise od mnogo stvari koje nisu pod našom kontrolom: npr. stanje mreže i drugih neophodnih servisa kao što je DNS. Prema tome, svaki udaljeni metod može da ne uspe: nema garancije da mreža neće pasti kada se pozove metod. Posledica toga je da svi udaljeni metodi moraju biti deklarisani tako da izbacuju RemoteException, a svi njihovi pozivi moraju biti u try-bloku Kada samo želimo da program proradi, najjednostavnije je da hvatamo RemoteException Robusniji programi treba da hvataju specifičnije izuzetke i reaguju na prikladan način
72
klasa RemoteException
klasa poseduje 1 javno polje detail public Throwable detail koje može sadržati stvarni izuzetak izbačen na strani servera, pa daje bliže informacije o tome šta ne valja umesto direktnog korišćenja polja detail, metod getCause() se koristi od 1.4 i nadalje da vrati ugnježdeni izuzetak: try{ // call remote method ... }catch(RemoteException ex){ System.err.println(ex.getCause()); ex.getCause().printStackTrace(); }
73
paket java.rmi.registry
Kako klijent kome je potreban udaljeni objekat locira taj objekat na udaljenom serveru? Preciznije, kako on dobija udaljenu referencu na objekat? Klijenti saznaju koji udaljeni objekti su dostupni vršeći upite nad registry-jem servera. Mogu dobiti reference na te objekte klasa java.rmi.Naming služi za interakciju sa registry-jem Interfejs Registry i klasa LocateRegistry omogućavaju klijentima da dobiju udaljene objekte sa servera po imenu RegistryImpl je potklasa od RemoteObject koja povezuje imena i određene RemoteObject objekte Klijenti mogu koristiti metode klase LocateRegistry kako bi dobili RegistryImpl za određeni host i port ...
74
LocateRegistry klasa, primeri korišćenja
Npr. udaljeni objekat koji želi da sebe učini dostupnim klijentima, mogao bi da uradi sledeće: Registry r = LocateRegistry.getRegistry(); r.bind(”MyName”, this); Udaljeni klijent koji želi da pozove ovaj udaljeni objekat može onda reći: Registry r = LocateRegistry.getRegistry(”thehost.site.com”); RemoteObjectInterface tro = (RemoteObjectInterface) r.lookup(”MyName”); tro.invokeRemoteMethod();
75
LocateRegistry, createRegistry() metodi
kreiraju registry i pokreću ga da osluškuje na zadatom portu. Svaki može izbaciti RemoteException: public static Registry createRegistry(int port) throws RemoteException public static Registry createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException
76
paket java.rmi.server najsloženiji od svih RMI paketa
sadrži sredstva za izgradnju udaljenih objekata te ga koriste objekti čije će metode klijenti pozivati 6 izuzetaka, 9 interfejsa, klasa (u zavisnosti od Java verzije) Na sreću, samo nekoliko od njih nam je potrebno da bismo pisali udaljene objekte Bitne klase su RemoteObject (osnova za sve udaljene objekte), RemoteServer (izvedena iz RemoteObject), UnicastRemoteObject (izvedena iz RemoteServer) Svi udaljeni objekti koje pišemo će verovatno ili koristiti ili naslediti UnicastRemoteObject Klijenti koji pozivaju udaljene metode, ali sami po sebi nisu udaljeni objekti, ne koriste ove klase, pa samim tim ne moraju da importuju java.rmi.server
77
klasa RemoteObject apstraktna
tehnički, udaljeni objekat je instanca proizvoljne klase koja implementira Remote interfejs. U praksi, većina udaljenih objekata su instance potklasa od RemoteObject statički metod RemoteObject.toStub(): public static Remote toStub(Remote ro) throws NoSuchObjectException konvertuje dati udaljeni objekat u ekvivalentan stub objekat za korišćenje u klijentskoj VM, što može biti od pomoći da dinamički generišemo stub-ove iz servera, bez korišćenja rmic
78
klasa RemoteServer apstraktna je i ona
njena najčešće korišćena potklasa je UnicastRemoteObject metod za lociranje klijenta sa kojim komuniciramo: public static String getClientHost() throws ServerNotActiveException vraća String koji sadrži hostname klijenta koji je pozvao metod koji se trenutno izvršava. Metod izbacuje ServerNotActiveException ako tekuća nit ne izvršava udaljeni metod Logging: za svrhe debagovanja, ponekad je korisno videti pozive koji su izvršeni na udaljenom objektu i njegove odgovore public static void setLog(OutputStream out) null kao argument isključuje logovanje Primer. da bismo videli sve pozive na System.err pišemo myRemoteServer.setLog(System.err); Ako želimo da dodamo ekstra informacije onima koje daje klasa RemoteServer, možemo dohvatiti PrintStream loga metodom public static PrintStream getLog() Kada ga dobijemo, možemo njime pisati svoje dodatne komentare u log: PrintStream p = RemoteServer.getLog(); p.println(”There were ” + n + ” total calls to the remote object”);
79
klasa UnicastRemoteObject
Da bismo kreirali udaljeni objekat, nasleđujemo UnicastRemoteObject i deklarišemo da naša potklasa implementira neki podinterfejs od java.rmi.Remote Metodi interfejsa obezbeđuju funkcionalnost specifičnu za klasu, dok metodi od UnicastRemoteObject rukuju opštim zadacima udaljenog objekta poput marshalling-a i unmarshalling-a argumenata i povratnih vrednosti. Sve se ovo odvija iza scene. Kao programer aplikacije, mi ne moramo da brinemo o tome.
80
UnicastRemoteObject se izvršava na jednom hostu, koristi TCP sokete za komunikaciju i ima udaljene refrence koje ne ostaju validne između restartovanja servera. 3 protected konstruktora Kada pišemo potklasu od UnicastRemoteObject, zovemo jedan od njih, bilo eksplicitno bilo implicitno, u prvoj liniji svakog konstruktora naše potklase. Sva 3 konstruktora mogu izbaciti RemoteException ako udaljeni objekat ne može biti kreiran.
81
Konstruktor bez argumenata kreira UnicastRemoteObject koji osluškuje na anonimnom portu izabranom u vreme izvršavanja Server osluškuje na anonimnom portu. Normalno, ovakva situacija je besmislena jer je nemoguće da klijenti lociraju server (pominjano u poglavljima 9 i 10). U ovom slučaju, klijenti lociraju server korišćenjem registry-ja koji prati dostupne servere i portove na kojima oni osluškuju. Loša strana osluškivanja na anonimnom portu je što firewall često blokira konekcije na tom portu. Preostala 2 konstruktora osluškuju na zadatom portu, pa možemo tražiti od mrežnih administratora da dozvole saobraćaj na tim portovima kroz firewall Ako mrežni administratori nisu kooperativni, moramo da koristimo HTTP tunneling ili proxy server ili obe te stvari exportObject() metodi...
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.