Sunteți pe pagina 1din 8

Programare Java Lucrarea de laborator Nr.

TEHNOLOGIA JAVA RMI


n tehnologia Java, apelul procedurilor la distanta se numeste RMI (Remote Method Invocation) si este implementata n pachetul java.rmi . Multe din aplicatiile distribuite se bazeaza pe modelul client-server. n acest model, un proces, numit server, ofera servicii mai multor altor procese, denumite clienti. n fiecare statie se pot executa mai multe procese server, multiple procese client precum si combinatii ale acestora. Acest model se bazeaza pe transferul de mesaje : clientul trimite un mesaj catre server, continnd o cerere de serviciu, iar serverul raspunde clientului, caruia i trimite de asemenea un mesaj. Acest model de programare este destul de incomod, deoarece programul trebuie sa prevada operatii de transfer de mesaje explicite (operatii sendreceive), sincronizarea acestora, tratarea erorilor, etc. De aceea a fost dezvoltata si o alta metoda de programare distribuita care, desi foloseste tot transferul de mesaje ntre statii, ofera o interfata de programare mai simpla; aceasta metoda se numeste apelul de procedura la distanta (RPC - Remote Procedure Call). Mecanismul de apel de procedura la distanta (RPC) a fost introdus n anul 1984 de Birell si Nelson si apoi a fost si este intens utilizat att n dezvoltarea sistemelor de operare ct si a componentelor software distribuite. Ideea acestui mecanism este de a permite unui program sa apeleze proceduri localizate n alte statii (proceduri la distanta) n acelasi mod cu apelul unor proceduri locale, adica sa fie asigurata transparenta apelurilor la distanta. Acest mecanism consta n ncorporarea n fiecare dintre procesele comunicante (procesul client si procesul server) a unui nucleu de apeluri (surogat, radacina - stub) care intercepteaza apelurile si raspunsurile, prelucrndu-le astfel nct sa asigure toate operatiile necesare de mpachetare/despachetare parametri si rezultate si de transfer a mesajelor care realizeaza executia procedurii la distanta. (Fig. 6.1).

Aplicatie Client Program Client

Aplicatie Server Program Server

Stub (Proxy)

Skeleton (Stub)

Sistem de Operare +Hardware

Sistem de Operare +Hardware

Fig. 6.1. Mecanismul de executie RPC

Pasii executati la apelul unei proceduri la distanta pot fi prezentati pe scurt astfel: Programul client apeleaza (local) nucleul de apeluri client (surogat - stub, proxy), pasndu-i acestuia parametrii functiei la distanta. Nucleul de apeluri client (stub) mpacheteaza parametrii primiti, construieste un mesaj pe care l transmite catre nucleul de apeluri al serverului (surogat - skeleton, stub ) prin intermediul subsistemului IO al sistemului de operare.

63

Nucleul de apeluri server (skeleton) despacheteaza parametrii si apeleaza local functia din server. Serverul executa functia apelata si returneaza rezultatul nucleului de apeluri server. Nucleul de apeluri server (skeleton ) mpacheteaza rezultatul, construieste un mesaj, pe care l transmite catre nucleul de apeluri al clientului (stub) prin intermediul al sistemului de operare si al retelei de interconectare. Nucleul de apeluri client ( stub ) despacheteaza rezultatul si-l returneaza programului client apelant.

Mecanisme RPC sunt oferite n mai multe forme ; exista mecanisme RPC oferite de sistemele de operare (Windows, Unix) si accesibile n programe prin apeluri de functii din bibliotecile de sistem. Alte mecanisme RPC s-au dezvoltat pe baza unor sta ndarde si cu implementari oferite de diferite firme producatoare de software, deoarece programarea prin componente reutilizabile ca si programarea distribuita se bazeaza pe mecanismul RPC. La nivelul unei aplicatii distribuite se considera, de regula, clie nt acel program care ofera unui utilizator (operator) posibilitatea de a lansa diferite operatii, n general prin intermediul unei interfete grafice, n timp ce serverul (sau serverele) nu au, de regula integfata grafica, deoarece nu sunt sub controlul unui utilizator ci raspund la apeluri ale programelor clienti. Acest lucru nu nseamna ca un program client nu va putea raspunde unei cereri (deci sa ndeplineasca functie de server), sau ca un program server nu va putea apela la servicii de la alte servere (sau chiar de la proprii clienti). Modul de comunicare ntre aceste entitati variaza destul de mult n tehnologiile de programare oferite de diferite firme de software. Tehnologiile care ofera posibilitatea de programare distribuita n retele de calculatoare asigura o intermediere ntre aplicatii si sistemul de operare definind un nivel intermediar software, cunoscut sub numele de middleware. n momentul actual se acorda o atentie deosebita dezvoltarii software-ului middleware, n care sunt implicate nu numai mari firme (Microsoft, Sun) dar si organizatii si grupuri de firme, universitati, cercetatori de renume. Tehnologiile Microsoft COM, Java RMI, CORBA (Common Object Request Broker Architecture , standard propus de OMG - Object Management Group ) sunt cele mai cunoscute sisteme middleware care permit dezvoltarea aplicatiilor distribuite folosind componente software. Toate aceste tehnologii se bazeaza pe mecanismul RPC (Remote Procedure Call), implementat n modalitati specifice. Folosind facilitatile oferite de un sistem middeware, dezvoltarea aplicatiilor distribuite este mult mai rapida si eficienta, beneficiind de suport pentru crearea si activarea serverelor, mpachetarea/despachetarea parametrilor metodelor si transferul acestora pe reteaua de interconectare, lansarea si tratarea exceptiilor si multe altele. De fapt, este aproape de neconceput dezvoltarea unei aplicatii distribuite de la zero, mare parte din problemele legate de programarea distribuita fiind deja rezolvate si oferite ca module reutilizabile de diferitele tehnologii de programare actuale. Termenii folositi n tehnologia RPC difera n diversele ei abordari, desi au aceeasi semnificatie : n Java RMI se folosesc termenii stub si skeleton pentru nucleul de apel client, respectiv server; n Microsoft COM se folosesc termenii proxy si stub pentru nucleul de apel client, respectiv server. O aplicatie Java RMI consta din doua programe separate: un server si un client care ruleaza pe masini virtuale diferite (posibil si pe statii diferite) si comunica prin intermediul unei interfete la distanta (remote interface). n mod tipic, serverul creaza obiecte care implementeaza metodele interfetei la distanta (obiecte la distanta, remote objects), face cunoscute referintele acestor obiecte (prin intermediul unui serviciu specializat) si asteapta apelurile clientilor a metodelor la distanta. n mod tipic, un client obtine referinta unui obiect la distanta (tot prin intermediul unui serviciu) si invoca metodele interfetei la distanta implementate de obiectul respectiv. Din aceasta scurta descriere rezulta aspectele de baza n tehnologia Java RMI: definirea interfetelor la distanta, localizarea obiectelor la distanta, comunicatia clientului cu obiectele la distanta.

64

6.1

INTERFETE LA DISTANTA

Orice metoda care poate fi invocata la distanta trebuie sa fie definita ntr-o interfata la distanta. n alte tehnologii de apel a procedurilor la distanta (cum sunt tenhologiile COM sau CORBA) se foloseste un limbaj special de descriere a interfetelor, numit limbaj IDL (Interface Description Language ). n tehnologia RMI interfetele la distanta se definesc chiar n limbajul Java (care contine tipul interface). n Java RMI o interfata la distanta este o interfata care extinde interfata java.rmi.Remote. De asemenea este necesar ca fiecare metoda a interfetei la distanta sa declare exceptia java.rmi.RemoteException n clauza throws, pe lnga alte exceptii specifice aplicatiei. De exemplu, interfata unei aplicatii de tip Hello va fi definita n modul urmator:
// Fisier Hello.java - Interfata aplicatiei package hello; import java.rmi.*; public interface Hello extends java.rmi.Remote{ String sayHello() throws java.rmi.RemoteException; }

Interfata Hello va fi asamblata n package-ul hello si contine o singura metoda, sayHello() , care returneaza un String. Obiectele la distanta sunt create n server si vor implementa metodele interfetei remote corespunzatoare.

6.2

CREAREA UNUI SERVER RMI

Clasa unui obiect la distanta trebuie sa implementeze o interfata la distanta si sa extinda clasa
java.rmi.server.UnicastRemoteObject . De asemenea, aceasta clasa trebuie sa defineasca un

constructor implicit pentru obiectul la distanta si sa implementeze fiecare metoda definita n interfata la distanta. Aceeasi clasa poate sa prevada si restul de operatii necesare sa fie efectuate de server, si anume: Crearea unui administrator de securitate (security manager); Crearea unui obiect la distanta; nregistrarea obiectului la distanta printr-un serviciu de nregistrare.

Aceste operatii se pot efectua n functia main(). Serverul pentru aplicatia Hello va arata n felul urmator:
// Fisier HelloServer.java - serverul aplicatiei package hello; import java.rmi.*; import java.rmi.server.*; import java.util.*; public class HelloServer extends UnicastRemoteObject implements Hello { // Constructorul implicit public HelloServer() throws RemoteException{ super(); } // Implementarea metodei la distanta public String sayHello() throws RemoteException{ String message = "Hello RMI World!"; return message; } public static void main(String [] args){ // Crearea unui administrator de securitate if (System.getSecurityManager() == null)

65

System.setSecurityManager(new RMISecurityManager()); // Crearea unui obiect de implementare a interfetei HelloServer remoteObject = null; try { remoteObject = new HelloServer(); } catch (Exception ex) { ex.printStackTrace(); } // nregistrarea obiectului remote n serviciul rmiregistry try { Naming.rebind( "rmi://localhost/HelloRMI",remoteObject ); System.out.println( "HelloServer : Inregistrare...Ok" ); } catch( Exception ex ) { ex.printStackTrace(); } } }

Constructorul implicit al clasei obiectelor la distanta trebuie sa prevada n clauza throws exceptia RemoteException. Implementarea metodei sayHello() este foarte simpla: ea returneaza un String care contine sirul de caractere "Hello RMI World!". Crearea unui obiect la distanta este, de asemenea foarte simpla: obiectul este o instanta a clasei care implementeaza interfata la distanta. n aplicatiile RMI trebuie sa fie definita politica de securitate, att pentru accesul stub-ului si al skeleton-ului la resursele calculatorului, ct si pentru ncarcarea claselor programului. n lipsa unui administrator de securita te, nu se pot ncarca clasele dect din sistemul de fisiere local. Se poate folosi ca administrator de securitate java.rmi.RMISecurityManager iar permisiunile pe care acesta le acorda executiei se stabilesc prin intermediul propietatii java.security.policy. Aceasta proprietate se seteaza la lansarea n executie a programului, asa cum se va vedea ntr-o sectiune urmatoare.

6.3

NREGISTRAREA SI REGASIREA OBIECTELOR LA DISTANTA

Pentru ca un client sa apeleze o metoda la distanta, trebuie sa detina referinta surogatului n client (stub-ul) al obiectului care implementeaza interfata si metoda respectiva. n tehnologia Java RMI, o astfel de referinta se obtine prin intermediul unui serviciu, numit rmiregistry care realizeaza o corespondenta ntre un nume al obiectulu i la distanta (nume care se alege de comun acord ntre server si client) si informatia de acces la acesta. Serviciul rmiregistry contine o tabela n care se nregistreaza fiecare obiect la distanta creat ntrun server; n exprimarea curenta se spune ca se nregistreaza serverul, ceea ce este destul de adevarat, mai ales daca s-a folosit aceeasi clasa pentru obiectul la distanta si server, ca n exemplul de mai sus, clasa HelloServer . nregistrarea obiectelor (ca si regasirea referintelor la acestea) se realizeaza folosind functii statice ale clasei Naming din pachetul java.rmi. Metodele clasei Naming au unul din argumente un String care contine adresa URL a serviciului rmiregistry si numele (name) obiectului remote: rmi://host:port/name. Adresa servic iului rmiregistry este data prin numele protocolului (rmi ), numele statiei (host) si numarul portului (port) pe care acest serviciu accepta apeluri de la servere si clienti. Acesti parametri sunt optionali: numele protocolului folosit poate sa lipseasca si atunci se considera protocolul implicit (rmi); numele statiei poate sa lipseasca si se considera statia locala (localhost); de asemenea, numarul portului poate sa lipseasca si atunci se considera portul implicit 1099.

66

Legarea (binding ) numelui unui obiect la distanta este o nregistrare a acestui nume (conventional, stabilit de comun acord ntre server si clienti), astfel nct acest obiect sa poata fi ulterior regasit si accesat (de un client). nregistrarea obiectelor la distanta se face printr-una din metodele Naming.bind() sau Naming.rebind(). Aceste metode au aceleasi argumente: primul argument este un obiect String care contine adresa URL a serviciului rmiregistry si numele obiectului remote; cel de-al doilea argument este referinta obiectului de implementare (creat n server). n exemplul dat, functia rebind() nregistreaza numele HelloRMI pentru obiectul de implementare a interfetei Hello (cu referinta remoteObject n programul server) n serviciul rmiregistry care ruleaza pe statia locala ( localhost). Aici, termenul de statie locala are sensul ca serviciul rmiregistry si programul server care l apeleaza prin functia rebind ruleaza pe aceeasi statie. Singura diferenta cele doua functii de nregistrare (bind si rebind) este aceea ca functia rebind permite refolosirea unui nume deja nregistrat. Un client obtine o referinta prin care poate invoca o metoda a unui obiect la distanta prin apelul metodei Naming.lookup() care are ca argument adresa URL a serviciului rmiregistry si numele obiectului cautat. Aceasta metoda returneaza o referinta de tip Remote (interfata de baza a tuturor interfetelor la distanta) care poate fi converita explicit ( downcast) n referinta la interfata la distanta implementata de obiectul respectiv. Pentru exemplul dat, gasirea referintei obiectului la distanta se obtine astfel:
String registryHost = "141.85.107.129"; // statia serviciul rmiregistry Hello remote=(Hello)Naming.lookup("rmi://"+registryHost+"/HelloRMI");

Ceea ce obtine clientul prin apelul metodei lookup este referinta la stub-ul (surogatul, reprezentantul) obiectului la distanta, si metodele acestuia pot fi invocate la fel ca metodele obiectelor locale. Tot restul operatiilor de comunicatie implicate de apelul unei metode la distanta sunt rezolvate n mod transparent pentru programator, prin metodele claselor RMI incluse n stub-ul si skeleton-ul creat pentru fiecare interfata la distanta.

6.4

CREAREA UNUI CLIENT RMI

Un client RMI trebuie sa obtina referinta la obiectul la distanta (de fapt obtine referinta la reprezentantul acestuia, stub-ul) prin apelul metodei Naming.lookup(), dupa care poate apela metoda la distanta, la fel ca o metoda obisnuita (locala). Programul client al aplicatiei Hello arata n felul urmator:
// Fisier HelloApp.java - Clientul aplicatiei package hello; import java.rmi.*; public class HelloApp{ public static void main(String []args){ String registryHost = "141.85.107.129"; try{ Hello remote = (Hello) Naming.lookup( "rmi://" + registryHost + "/HelloRMI" ); String message = remote.sayHello(); System.out.println(message); } catch (Exception ex){ ex.printStackTrace(); } } }

67

n aplicatiile RMI comunicatia ntre client si server are loc numai dupa ce s-a nregistrat un obiect la distanta (de catre server) n serviciul rmiregistry si s-a obtinut o referinta la acesta (de catre client) (Fig. 6.2).
Server
rebind()

rmiregistry Client
lookup()

Fig. 6.2 Comunicatia server-client-serviciu rmiregistry.

Cele trei componente (serverul, clientul si serviciul rmiregistry) pot sa ruleze pe aceeasi statie sau pe statii diferite, n orice combinatie.

6.5

COMPILAREA SI EXECUTAREA UNEI APLIC ATII RMI

O aplicatie RMI ncepe cu definitia interfetei la distanta (interfata Hello , n exemplul de mai sus), care contine prototipurile metodelor la distanta. Urmatoarea etapa este scrierea programului server. Este posibil (si mai simplu) ca sa fie folosita aceeasi clasa ca si clasa principala a serverului (care contine functia main()) si, n acelasi timp implementarea interfetei la distanta. n final se scrie programul client. Daca cele trei fisiere sursa sunt plasate n acelasi director, atunci compilarea tuturor fisierelor se face cu comanda:
javac *.java -d .

Optiunea de director (-d .) plaseaza toate fisierele compilate ntr-un subdirector al directorului curent cu numele package-ului (hello). Pentru crearea stub-ului si a skeleton-ului se foloseste un utilitar din distributia Java, numit rmic. Acest utilitar primeste ca parametru n linia de comanda numele unei clase care implementeaza o interfata remote (HelloServer n exemplul dat) si creeaza stub-ul si skeleton-ul corespunzator n doua fisiere (de tip class ) care au ca acelasi nume ca si clasa respectiva cu sufixul _Stub si respectiv _Skeleton. Pentru exemplul dat, invocarea compilatorului rmic va arata astfel:
rmic hello.HelloServer

Dupa executia acestuia, n subdirectorul hello se vor gasi toate fisierele compilate, si anume:
Hello.class , HelloApp.class, HelloServer.class (clase generate de comanda java *.java) si HelloServer_Stub.class, HelloServer_Skeleton.class (clase generate de compilatorul rmic ).

Pentru executia aplicatiei, se porneste mai nti serviciul rmiregistry cu comanda (n Windows):
start rmiregistry

Pornirea serverului se face cu comanda :


java -Djava.security.policy = AllPolicy.policy hello.HelloServer

Optiunea -Djava.security.policy seteaza proprietatea de politica de securitate a programului, furniznd numele unui fisier (n acest caz, AllPolicy.policy) care contine permisiunile acordate executiei programului. n acest caz simplu de test se pot acorda toate drepturile de acces la resurse si fisierul Allpolicy.policy contine urmatoarele linii:
grant { permission java.security.AllPermission; };

68

n functie de cerintele programelor, fisierul de politica de securitate poate sa acorde numai permisiunile strict necesare. O data serverul pornit, el ramne n asteaptarea cererilor de la clienti si le executa. Dupa ce serviciul rmiregistry si serverul au fost pornite, se poate porni clientul cu comanda:
java -Djava.security.policy = AllPolicy.policy hello.HelloApp

La executia unui client, acesta invoca metoda sayHello() de pe server, primeste ca rezultat un String , pe care il afiseaza. Pe ecranul consolei clientului se va afisa: Hello RMI Wworld! n exemplul prezentat s-a considerat ca toate clasele sunt ncarcate din sistemul de fisiere local, att pentru server ct si pentru client. Este posibil ca la client sa existe doar fisierul clasei principale, iar celelalte fisiere (de stub si skeleton) sa fie ncarcate dinamic (n cursul executiei) de pe alta statie, daca se defineste locatia acestora prin proprietatea codebase.

EXERCITII
6.1 Creati o aplicatie RMI asemanatoare cu aplicatia Hello descrisa mai sus si realizati toate etapele de compilare si executie. Folositi denumiri individualizate pentru server si client (insernd propriul nume n denumirea fisierelor si a claselor, de exemplu PopescuHelloServer.java). Acest lucru va permite ntelegerea mai buna a conventiilor de nume folosite n tehnologia Java RMI si, de asemenea, nregistrarea simultana a mai multelor servere la acelasi serviciu de registri RMI (rmiregistry ). 6.2 n interfata la distanta adaugati o noua metoda astfel nct serverul sa raspunda la salut (primeste un nume si returneaza un sir de caractere -String- de forma Salut nume de la!, unde la sfrsitul salutului serverul insereaza propriul nume). Implementati aceasta metoda n server si apelati-o din client. 6.3 n reteaua din laborator realizati comunicatii ntre diferite servere si clienti RMI. Pentru aceasta modificati programul client astfel nct acesta sa contina o interfata grafica care sa permita selectarea serverului cu care doreste sa comunice, introducerea si modificarea numelui de salut si afisarea raspunsului. 6.4 Creati o aplicatie RMI n care serverul returneaza clientilor un numar aleator, obtinut de la un generator de numere pseudo-aleatoare unic, definit n server. Pentru aceeasi valoare de initializare a generatorului (seed ) urmariti secventa primelor cteva numere aleatoare primite de un singur client care apeleaza serverul cu cele primite de mai multi clienti care se conecteaza la server. 6.5* Executati n retea aplicatia BINGO descrisa n Tutorialul de la Sun. n directorul together al tutorialului se gasesc sursele aplicatiei si descrierea ei. Ceea ce mai trebuie facut este compilarea modulelor aplicatiei, distribuirea acestora si lansarea n executie. 6.6* Creati o aplicatie RMI pentru o aplicatie de conversatie ntre mai multi utilizatori (CHAT), ncercnd sa obtineti aceeasi functionare ca cea descrisa n exercitiul 5.8 din lucrarea precedenta. Binenteles, modalitatile de a obtine aceasta functionare difera de cele recomandate la exercitiul precedent. 6.7* Modificati aplicatia de mai sus astfel nct sa obtineti o conversatie doar ntre doi dintre utilizatorii conectati la un moment dat la server. La conectarea la server, fiecare utilizator primeste lista tuturor utilizatorilor deja conectati si selecteaza unul dintre acestia pentru a comunica. Din acel moment, discutia va avea loc numai cu utilizatorul ales, pna la deconectare. n acelasi timp, alte perechi de utilizatori pot comunica ntre ei.

69

70