Sunteți pe pagina 1din 75

ADNOTARE

Cuvinte cheie: Java, Server, Client, URL, RMI, JSP, JSF, applet.
Limbajul Java a aparut datorită necesităţii rezolvării problemelor actuale ale programării.
Deşi a apărut doar de câţiva ani, limbajul Java este prezent deja în peste 200.000 de pagini de
Web, are peste 400.000 de programatori care-l utilizează şi peste 40% dintre aplicaţiile
dezvoltate, în special cele dedicate comerţului electronic. Pentru a întelege ce înseamnă Java,
trebuie avută în vedere tendinţa Internet-ului de a deveni un bun de folosinţă comun, o piaţă
imensă, un teren electronic de desfăşurare a afacerilor, ceea ce a focalizat interesul
cercetătorilor şi firmelor de specialitate, precum şi utilizarea tot mai frecventă a soluţiilor de tip
Intranet în cadrul întreprinderilor de toate marimile. Coincidenţa apariţiei Java cu fenomenul
legat de Internet, Extranet, Intranet, a facut din el un instrument fundamental al dezvoltării
tehnologiei informaţie.
Teza constă din Introducere, patru capitole, concluzii. În primul capitol este prezentată
informaţia referitoare la utilizarea actuală a reţelelor şi deasemenea este redată prezentarea
limbajului Java, scurt istoric, noţiuni generale , caracteristici. În al doilea şi al treilea capitol s-a
studiat mai aprofundat arhitecturile Java pentru programarea în reţea şi web. Deasemea sunt
făcute şi unele comparaţii cu alte tehnologii de ultimă generaţie, prezentând avantaje şi
dezavantaze de partea fiecăreia. Al patrulea capitol prezintă aplicaţia web realizată în cadrul
tezei. Descrierea aplicaţiei, crearea utilizând limbajul Java, descrierea framework-ului folosit şi a
funcţionalităţilor.
Principalele obiective ale lucrării sunt:
• Studierea arhitecturilor Java de programare a reţelelor şi perspectivele oferite de aceste
tehnologii în dezvoltarea lor .
• Crearea unei aplicaţii web pentru un magazin de cărţi, stocarea şi prelucrarea datelor
privind managementul vânzării cărţilor.

1
CUPRINS

ADNOTARE..................................................................................................................................................................1
CUPRINS.......................................................................................................................................................................2
INTRODUCERE............................................................................................................................................................3
CAPITOLUL I................................................................................................................................................................4
Reţelele de calculatoare şi Java.......................................................................................................................................5
1.1 Reţele de calculatoare……………………………..……………………………………………………………. ...5
1.2 Java………………………………………………...………………………………………………………………7
1.2.1 Ce este Java ?.........................................................................................................................................................7
1.2.2 Evoluţia limbajului Java………………………..………………………………………………………………..8
1.2.3 Java : un limbaj compilat şi interpretat……..............................…………………………………………………8
1.2.4 Java şi conceptele programării orientate pe obiecte…………...............................………………………………
9
1.2.5 Caracteristicile de bază al limbajului Java…………………...............................………………………............10
1.2.6 Structura limbajului Java………………………………………………………..………………………...........11
CAPITOLUL II.............................................................................................................................................................12
2. INTERNETUL şi TEHNOLOGII WEB...................................................................................................................12
2.1. Internetul................................................................................................................................................................12
2.2 Tehnologii WEB……………………………………………………………………………….............................13
2.2.1 Java versus .NET…………………………………………………………………….........................................13
2.2.2 .NET a învăţat de la Java………………………………………………………………….................................14
2.2.3 .Net versus Java: criterii de comparaţie……………………………………………………...............................14
2.2.4 Schimbările ulterioare sunt scumpe…………………………………………………………………………….16
2.3. Java şi programarea WEB………………………………………………………………………………………..18
2.3.1 JSP……………………………………………………………………………………........................................18
2.3.2 JSF………………………………………………………………………………………....................................19
2.3.3 MySQL……………………………………………………………………………….......................................22
2.3.4 Arhitectura Tomcat……………………………………………………………………………………………..23
Capitolul III……………………………………………………………………………………...................................25
3.1. Socluri. Modelul client server……………………………………………………………................................... 25
3.2 URL…………………………………………………………………………………………................................ 31
3.3 Elemente de programare distribuită prin invocare de metode la distanţă. RMI.....................................................33
Capitolul IV…………………………………………………………………………………………………………..58
4.1 Magazinul electronic (E-shop)……………………………………………………………………………………58
4.2 Aplicaţia E-Shop.....................................................................................................................................................61
CONCLUZII.................................................................................................................................................................70

Introducere
Reţelele de calculatoare permit accesarea unor baze informaţionale cu localizări
geografice diverse şi constituie un mediu de comunicare între persoanele aflate la distanţă. Într-o
instituţie sau firmă cu mai multe compartimente, instalarea unei reţele de calculatoare facilitează
schimbul si corelarea informaţiilor (între diverse departamente sau în cadrul aceluiaşi
departament). Importanţa reţelelor de calculatoare ca medii de comunicare va creşte tot mai mult
în viitor.

2
Reţelele de calculatoare asigură partajarea resurselor de calcul fizice şi logice, astfel încât
programele, echipamentele şi mai ales datele să fie disponibile pentru orice utilizator conectat la
reţea, indiferent de localizarea lui. Această facilitate este foarte importantă în cadrul unei firme
fiindcă permite, de exemplu, mai multor persoane aflate în puncte geografice diferite, să
întocmească împreună un raport. O schimbare efectuată de un angajat într-un document poate fi
vizibilă instantaneu si celorlalţi angajaţi. Astfel, colaborarea dintre grupuri de oameni aflaţi la
distanţă devine foarte simplă. Practic, un utilizator cu orice localizare geografică (acoperită de
reţea) poate utiliza datele ca si când ar fi locale. Această caracteristică atinge scopul reţelelor,
formulat plastic, de "distrugere a tiraniei geografice".
Java este unul dintre cele mai utilizate limbaje de programare in zilele
noastre, datorita unor avantaje de necontestat. Printre acestea putem menţiona:
securitate, independenţa de platforma, limbaj intuitiv, bine structurat şi, bineinţeles, opensource.
Java este un mediu de programare ce oferă utilizatorului cadrul necesar şi uneltele necesare
pentru dezvoltarea aplicaţiilor Java. Java este o tehnologie ce oferă suport dezvoltării de aplicaţii
distribuite, independente de platformă.
Programele Java pot rula pe diferite tipuri de platforme, cu condiţia ca pe aceste platforme să fie
instalată o maşină virtuală Java deasupra platformei respective. Avantajul limbajului Java,
comparativ cu alte limbaje de programare este conexiunea strânsă cu tehnologia Internet.
Teza cuprinde 4 capitole, a căror obiectiv principal este sistematizarea şi îmbogăţirea
cunoştinţelor teoretice despre tehnologiile aduse de limbajul Java pentru programarea reţelelor
de calculatoare.
Dezvoltarea aplicaţiilor de reţea este un subiect complex care implică un set variat de
tehnologii ce oferă soluţii diverse pentru realizarea comunicării între calculatoare. Teza şi-a
propus să treacă într-o primă faza în revistă aceste tehnologii oferite de limbajul Java,
compararea lor cu alte limbaje de programare şi descrierea unor avantaje şi dezavantaje faţă de
aceste tehnologii. Odată ce s-a făcut o analiză a problemelor-soluţiilor din domeniu, s-a trecut la
partea practică a tezei şi anume realizarea unui proiect pe web, folosind tehnologiile oferite din
plin de Java în acest domeniu cum ar fi JSP, JSF, web servicii şi altele, precum şi lucrul cu baze
de date folosind My SQL.

CAPITOLUL I
Reţelele de calculatoare şi Java

3
1.1 Reţele de calculatoare

Folosirea reţelelor de calculatoare, în raport cu sistemele mari de calcul, au un cost redus


sistemele mari de calcul sunt cam de 10 ori mai rapide decât calculatoarele personale dar costă
de aproximativ 1000 de ori mai mult. Astfel, a apărut un model de reţea în care fiecare utilizator
să poată dispune de un calculator personal iar datele de reţea să fie păstrate pe unul sau mai
multe servere partajate (folosite în comun). Modelul se numeşte client-server iar utilizatorii săi
sunt numiţi clienţi. Se poate spune că pe maşina client se desfăşoară procesul client, care
lansează o cerere pe maşina server (de care este legată). Mesajul "cerere" este prelucrată de
procesul server, de pe maşina server, iar răspunsul este furnizat procesului client, sub forma unui
mesaj de răspuns. Uzual, numărul de clienţi este mare iar numărul de servere este mic. Din punct
de vedere soft, modelul client-server presupune existenţa unui program "server" care acceptă şi
rezolvă cereri de la diverse procese / programe "client" (acestea se execută, se pot executa pe alte
masini decât procesul server).
Reţelele asigură o fiabilitate mare prin accesul la mai multe echipamente de stocare
alternative (de exemplu, fişierele pot fi copiate pe două sau trei calculatoare astfel încât, dacă
unul din ele nu este disponibil, să fie utilizate copiile fişierelor). Dacă un procesor se defectează,
sarcina sa poate fi preluată de celelalte, astfel încât activitatea să nu fie întreruptă ci dusă la bun
sfârşit, chiar dacă cu performanţe reduse. Acest lucru este esenţial pentru activităţi strategice din
domeniile militar, bancar, controlul traficului aerian, siguranţa reactoarelor nucleare etc.
O reţea de calculatoare poate să se dezvolte în etape succesive, prin adăugare de noi
procesoare: pe măsură ce se face simţită această necesitate, se pot introduce noi calculatoare
server sau client. Prin comparaţie, performanţele sistemelor de calcul mari, centralizate, nu se pot
îmbunătăţi decât prin înlocuirea cu un sistem mai mare, operaţie care produce neplăceri
utilizatorilor şi implică costuri mari.
Se poate concluziona că utilizarea reţelelor de calculatoare de către instituţii şi firme, în
locul sistemelor de calcul mari care să folosească terminale (răspândite în anii '70 şi la începutul
anilor '80), este motivată economic şi tehnologic. Reţelele de calculatoare personale au devenit
populare în anii '80, în momentul în care dezvoltarea lor tehnologică le-a făcut foarte avantajoase
sub aspectul raportului preţ/performanţă.

În anii '90, reţelele de calculatoare au început să furnizeze inclusiv servicii la domiciliu, pentru
persoane particulare.
Noile aplicaţii de acces la Internet sunt extrem de prietenoase, astfel încât încep să fie
utilizate nu numai în sferele de cercetare, industriale sau comerciale, în care aduc o îmbunătăţire

4
calitativă a proceselor de prelucrare şi transmitere a informaţiei, ci şi de către publicul larg,
pentru care se deschide astfel accesul la Internet. Aceste facilităţi se referă la:
1.accesul la baze informaţionale aflate la distanţă
2.comunicare între persoanele conectate la o reţea de calculatoare
3.divertisment interactiv.

1. Prin intermediul reţelelor de calculatoare se pot accesa informaţii de natură diversă.

Cea eficientă mai modalitate de consultare a informaţiilor din domenii diverse este
sistemul World Wide Web, creat la CERN (Geneva). Aceste informaţii aparţin unor domenii
foarte variate: artă, afaceri, politică, sănătate, istorie, recreere, ştiinţă, sport, călătorii, hobby-uri
etc.
În unele cazuri, se pot realiza nu numai consultări, ci, prin procedee interactive, se pot
realiza acţiuni care uzual ar fi necesitat prezenţa fizică a persoanei într-un anumit loc (plăţi,
rezervări de bilete, cumpărături etc). Un asemenea exemplu de domeniu, care este tot mai mult
transformat de progresul electronic, este cel bancar. Se vorbeşte din ce în ce mai mult de banking
virtual - băncile pun la dispoziţie produse (în special soft) prin care serviciile specifice îmbracă o
formă nouă, electronică. Oamenii îşi pot plăti taxele sau îşi pot administra conturile la distanţă,
prin metode electronice. Mii de firme îşi pun la dispoziţie cataloagele pentru consultări on-line
astfel încât practica de a face cumpărături la domiciliu, prin metode electronice, devine tot mai
răspândită. În acest sens, comerţul electronic a evoluat foarte mult, dezvoltând, prin mijloace
electronice, anumite direcţii specifice: marketing, management, plăţi digitale, securitatea
tranzacţiilor.
Presa începe să fie tot mai mult disponibilă direct, electronic. Mai mult, ea devine tot mai
personalizată: o persoană va putea comunica unui ziar subiectele sale de interes astfel încât să-i
fie trimise doar articolele legate de acestea. Pasul următor va fi crearea de biblioteci digitale cu
reviste, publicaţii ştiinţifice etc. Trecerea de la cărţile tipărite la cărţile electronice poate fi
comparată cu trecerea, în evul mediu, de la manuscrise la tipărituri.

În ultimii ani, se dezvoltă din ce în ce mai mult forme de educaţie la distanţă (învăţământ
electronic, care utilizează cel mai adesea facilităţile sistemului World Wide Web).

2. Poşta electronică sau e-mail-ul este un sistem de comunicare electronică bazat pe mesaje
scrise, care se adaugă astăzi la mijlocul clasic de comunicare verbală, prin intermediul
telefonului, vechi de mai bine de 100 de ani. Menţionăm aici faptul că între facilităţile poştei

5
electronice este inclusă şi posibilitatea ca anumite mesaje să fie trimise unui întreg grup de
persoane. Mesajele electronice conţin deja în mod curent secvenţe audio si video.
Dialogul direct on-line (aproape instantaneu) sau în timp real, implementat prin
mecanisme de tip talk, chat, se va extinde de la varianta textuală, scrisă, pentru a permite
utilizatorilor să se vadă sau să se audă unul pe celălalt. Această tehnologie face posibile
întâlnirile în timp real, numite videoconferinţe, între persoane aflate în poziţii geografice diferite.
Întâlnirile virtuale pot fi folosite pentru educaţie la distanţă, sfaturi medicale, întâlniri de afaceri
sau politice. Comunicaţiile vor prelua din ce în ce mai mult anumite tipuri de servicii realizate
deocamdată prin intermediul transporturilor, aşa cum poşta electronică a înlocuit, în mare
măsură, scrisorile obişnuite.
Deja s-au format grupuri mondiale de interes pe anumite domenii prin subscrierea la
facilităţle de informare şi comunicare oferite de grupurile de ştiri şi se pare că întreaga omenire
va fi antrenată în asemenea tipuri de comunicaţii, pe diverse tipuri de subiecte.

3. Divertismentul reprezintă la ora actuală o industrie în plină dezvoltare, în care se dezvoltă noi
tehnologii. Aplicaţia cu cel mai mare succes până acum este video-ul la cerere, prin care se va
putea selecta orice film sau program de televiziune iar acesta să apară imediat pe ecran. Filmele
viitorului, prevăzute cu scenarii alternative, ar putea deveni interactive iar spectatorul să joace un
rol activ în desfăşurarea acţiunii. Spectacolele de televiziune se vor putea desfăşura şi ele
interactiv, cu contribuţia directă a telespectatorilor.
Un domeniu al divertismentului care a înregistrat un succes uriaş şi al cărui viitor se
prevede la fel de promiţător este industria jocurilor. Există deja jocuri pentru mai multe persoane
cu simulare în timp real. Realitatea virtuală, creată prin animaţie tridimensională de calitate, va
putea deveni partajată.
Toate aceste aplicaţii noi sunt posibile prin tehnologiile moderne de comunicare, bazate pe reţele
de calculatoare.

1.2 Java

1.2.1 Ce este Java ?

 este un limbaj de programare dezvoltat de JavaSoft, companie în cadrul


firmei Sun Microsystems.

6
 este complet orientat pe obiecte si ofera posibilitatea reala de refolosire a
codului (care este de fapt promisiunea făcută la apariţia programării
orientate pe obiecte).

 este neutru din punct de vedere arhitectural, cu alte cuvinte Java este un
limbaj independent de platforma de lucru, aceeaşi aplicaţie rulând, fara
nici o modificare, pe sisteme diferite cum ar fi Windows, UNIX sau
Macintosh, lucru care aduce economii substanţiale firmelor care dezvolta
aplicaţii pentru Internet.

 limbajul Java este modelat dupa C şi C++, trecerea de la C, C++ la Java


facându-se foarte uşor.

 elimina sursele frecvente de erori ce apar în programare prin eliminarea


pointerilor, administrarea automata a memoriei şi eliminarea fisurilor de
memorie printr-o procedura de colectare a “gunoiului” care ruleaza în
fundal;

 este cel mai sigur limbaj de programare disponibil în acest moment,


asigurând mecanisme stricte de securitate a programelor concretizate
prin: verificarea dinamica a codului pentru detectarea secvenţelor
periculoase, impunerea unor reguli stricte pentru rularea programelor
lansate pe calculatoare aflate la distanţă (acestea nu au acces la reţeaua
locala, la fişierele stocate în sistemul local şi nu pot lansa în executie
programe locale), etc.

 permite creearea unor documente Web îmbunataţite cu animaţie şi


multimedia.

 a fost proiectat pentru a fi folosit în medii distribuite şi sisteme deschise.

1.2.2 Evoluţia limbajului Java


In 1991, firma SUN, mergând pe direcţia dezvoltarii sistemelor deschise de
lucru în reţea, a creat un proiect de lucru numit Green, care avea drept scop
punerea la punct a unor procesoare care să poata rula pe diferite tipuri de
aparate şi punerea la punct a unui sistem care să poata rula pe platforme
diferite. Planul iniţial prevedea dezvoltarea proiectului în C++, dar au aparut
foarte multe probleme în încercarea de dezvoltare a compilatorului de C++.
Ca urmare, James Gosling, membru al grupului Green, a început sa lucreze

7
la dezvoltarea unui nou limbaj, numit Oak, care, mai târziu, avea sa se
numeasca Java. De asemenea grupul Green avea sa-şi schimbe numele întâi
în FirstPerson, apoi în JavaSoft.
Abia dupa ce a fost înfiinţată compania Netscape Communications
Corporation, cei de la JavaSoft s-au orientat către Internet si Web, mediul
multiplatformă distribuit al reţelei Internet fiind perfect pentru testarea
proiectului.
In prezent licenţa pentru tehnologia Java a fost acordata unor firme
precum IBM, Microsoft, Sillicon Graphics, Adobe şi Netscape.

1.2.3 Java : un limbaj compilat şi interpretat


In funcţie de modul de execuţie al programelor, limbajele de programare se
împart în doua categorii :

• interpretate : instrucţiunile sunt citite linie cu linie de un program


numit interpretor şi traduse în instrucţiuni maşina; avantaj :
simplitate; dezavantaje : viteza de executie redusa

• compilate : codul sursa al programelor este transformat de


compilator într-un cod ce poate fi executat direct de procesor;
avantaj : executie rapida; dezavantaj : lipsa portabilitaţii, codul
compilat într-un format de nivel scăzut nu poate fi rulat decât pe
platforma pe care a fost compilat.

Programele Java pot fi atât interpretate cât şi compilate.


Cod sursa Java →(compilare)→ Cod de octeţi

Codul de octeţi este diferit de codul maşina. Codul maşina este


reprezentat de o succesiune de 0 si 1; codurile de octeţi sunt seturi de
instrucţiuni care seamana cu codul scris în limbaj de asamblare.
Codul maşina este executat direct de către procesor şi poate fi folosit
numai pe platforma pe care a fost creat; codul de octeţi este interpretat de
mediul Java şi de aceea poate fi rulat pe orice platforma care foloseşte
mediul de execuţie Java → neutralitatea limbajului Java din punct de vedere
arhitectural.

8
Cum este rulat un program Java ? Interpretorul Java transformă codul
de octeţi într-un set de instrucţiuni maşina, întârzierea interpretarii fiind însă
foarte mica datorită asemanarii dintre codul de octeţi şi limbajul de
asamblare şi din acest motiv execuţia se face aproape la fel de repede ca în
cazul programelor compilate.
Cum este obţinuta neutralitatea arhitecturală a limbajului Java ? Cu
alte cuvinte, cum este posibilă portarea codului de octeţi pe calculatoare
diferite? Truc : codul sursa este compilat nu pentru calculatorul pe care se
lucrează ci pentru un calculator inexistent, acest calculator imaginar fiind
numit Maşina virtuală Java (Java Virtual Machine). Interpretorul acţionează
apoi ca un intermediar între Maşina virtuală Java şi maşina reală pe care este
rulat programul.

Aplicaţia utilizatorului
Obiecte Java
Maşina virtuală Java
UNIX Windows Macintosh
Sisteme de operare

1.2.4 Java şi conceptele programării orientate pe obiecte


Limbajul Java este urmatorul pas logic în domeniul limbajelor de programare
şi se bazează pe cel mai popular limbaj de programare al momentului C++.
În Java se pot obţine programe cu aspectul şi comportarea programelor C++,
dar beneficiind de avantajele oferite de un limbaj proiectat special pentru
POO. Java renunţă complet la programarea procedurala specifică C-ului şi vă
obligă să folosiţi conceptele solide ale POO.
Conceptele programării orientate pe obiecte cuprind :

• Obiectele
• Încapsularea şi transmiterea de mesaje
• Clasele
• Bibliotecile (numite pachete, în Java)
• Moştenirea
• Modificatorii de acces

9
Obiectele :
unitatea elementară a POO
starea obiectului este dată de variabile de instanţă
comportamentul obiectului este dat de metode
uşor de refolosit, actualizat, întreţinut
Încapsularea şi transmiterea de mesaje :
Clasele :
încapsuleaza obiecte
o singură clasă poate fi folosită pentru instanţierea mai multor obiecte
Pachetele: colecţie de clase înrudite
Moştenirea : permite
extinderea funcţionalitaţii unor clase existente
refolosirea codului
Modificatorii de acces : controleaza accesul la metodele şi variabilele
obiectelor. Acestea pot fi :
1. Private - accesibile doar obiectelor din aceeaşi clasă
2. Protejate - accesibile obiectelor din aceeaşi clasă şi din
subclasele clasei respective
3. Prietenosase (default) - (nivelul de accesibilitate prestabilit)
accesibile tuturor claselor din pachetul curent
4. Publice - accesibile tuturor claselor din orice pachet

1.2.5 Caracteristicile de bază al limbajului Java


A. Folosirea în medii de reţea distribuite
Java a fost proiectat pentru un mediu complex cum este Internetul şi de
aceea trebuie să poată rula pe platforme eterogene distribuite. Acest lucru
este posibil deoarece :

• este neutru din punct de vedere arhitectural = programele pot fi rulate


pe orice platformă care are instalat mediul Java

• are un grad ridicat de portabilitate = conţine obiecte care pot fi folosite


pe platforme eterogene şi respectă standardele IEEE (Institue of Electrical
and Electronics Engineers) pentru structurile de date (folosirea întregilor,
a numerelor în virgulă mobilă, a şirurilor, etc)

10
• este distribuit = poate folosi atât obiecte memorate local cât şi obiecte
stocate pe calculatoare aflate la distanţă

• este compatibil cu mediile de lucru în reţea (poate fi utilizat în reţele


complexe) şi acceptă direct protocoalele de reţea obişnuite cum ar fi FTP
şi HTTP

B. Asigurarea performanţei ridicate

• compilatorul şi sistemul de execuţie ofera o viteză ridicată rulării


programelor

• are încorporate posibilităţi de execuţie multifir (rularea simultană a mai


multor procese) folosind un sistem de acordare de priorităţi proceselor ce
trebuie executate. Printre procesele care rulează în fundal sunt cele de
“colectare a gunoiului” şi de gestionare a memoriei.

C. Refolosirea codului şi fiabilitatea

• Java este un limbaj dinamic, lucru asigurat prin întârzierea legării


obiectelor şi legarea dinamică a claselor în timpul execuţiei, ceea ce
împiedică apariţia erorilor în cazul schimbării mediului de lucru după
compilarea programului sursă.

• Fiabilitatea este asigurată prin eliminarea pointerilor, prin folosirea


verificării dinamice a limitelor şi prin gestionarea automată a memoriei,
înlăturându-se posibilitatea fisurilor şi violărilor de memorie. O altă cale
de evitare a erorilor este verificarea structurilor de date atât la compilare
cât şi în timpul execuţiei.

D. Asigurarea securităţii

• Interzice accesul la stiva sistemului, la zona liberă de memorie şi la


secţiunile protejate de memorie

• Verifică validitatea codului semnalând următoarele:


 Violările de acces
 Conversiile ilegale de date
 Valori şi parametri incorecţi

11
 Modificarea claselor sau folosirea incorectă a acestora
 Depăşirea stivei în partea superioară sau inferioară
 Activităţi suspecte sau neautorizate

1.2.6 Structura limbajului Java


Aplicaţii şi miniaplicaţii

 miniaplicaţie (applet) = program Java creat pentru a fi folosit în sistemul


WWW. Applet-urile necesită un program de vizualizare extern : browser
Web sau un program specializat de vizualizare (applet viewer).

 aplicaţie (app) = program Java care poate fi rulat independent.

CAPITOLUL 2

2. INTERNETUL şi TEHNOLOGII WEB .

2.1. Internetul
Internet (Internetware system) reprezintă un ansamblu de reţele de calculatoare interconectate
care a luat o amploare deosebită în ultimii ani. Internet reprezintă un instrument de acces la
cantităţi imense de informaţii distribuite în toată lumea. Prin intermediul Internet-ului se pot
transfera fişiere între calculatoare situate la distanţe foarte mari.
Internetul sau reţeaua mondială de reţele devine din ce în ce mai popular, cunoscând o
creştere exponenţială a numărului de calculatoare interconectate. Tehnologia şi aplicaţiile de pe
Internet se extind extrem de rapid, captând o atenţie deosebită, deoarece Internet-ul este un
mediu excitant de comunicaţie, un instrument pentru facilitarea afacerilor şi un debuşeu
comercial, într-o măsură mult mai mare decât au fost radioul şi televiziunea cu ani în urmă.

12
Noţiunea de internet (cu i mic) constituie o colecţie de reţele separate fizic şi care sunt
interconectate pentru a forma o singură reţea logică, iar Internet (cu I mare) reprezintă reţeaua
globală ce leagă toate reţelele, într-o reţea unică mondială. Internetul este un conglomerat
complex de arhitecturi, componente fizice şi sisteme de operare. Componentele sunt de unu-la-
unu.

Pe de altă parte Internetul este un complex univers virtual unde sunt accesibile informaţii
despre orice subiect imaginabil; ştiinţă, muzică, religie, politică, finanţe, umor etc.. Este de
înţeles preocuparea de a organiza această incredibilă masă de informaţii şi de concepere a unor
instrumente pentru regăsirea informaţiilor.
Internet foloseşte o metodă de adresare bazată pe sistemul de denumire al domeniilor.
Există posibilitatea includerii într-o adresă a mai multor nivele de domenii (domenii, instituţii,
departament, calculator). Domeniile de pe nivelul cel mai (înalt) general pot fi de natură
organizaţională sau geografică. Exemple de domenii organizaţionale: com (entităţi comerciale),
edu (instituţii educaţionale), gov (instituţii guvernamentale), etc. Exemple de coduri de denumiri
geografice: it (Italia), ro (România), etc.

2.2 Tehnologii WEB

2.2.1 Java versus .NET

Abstract:

J2EE şi .NET sunt platformele viitorului. Dar care platforma i se potriveşte cui? Sau:
„Cine vrea să cheltuiască bani pe produse Java?”
O privire comparativa asupra tehnologiilor Java si .Net, singurele alternative profesionale
pentru dezvoltarea de aplicatii in mediul de afaceri. Dupa succesul inregistrat de Java in ultimii
zece ani, Microsoft incearca sa introduca pe piata .Net, o creatie proprie si proprietara, care sa
concureze tehnologia Java. Este .Net cu adevarat o alternativa? Si daca da, pentru cine?
Evolutia ingineriei software in ultimii 5 ani a minimalizat utilizarea limbajelo 4GL, asa cum
limbaje ca Smalltalk au fost inlocuite de Java, iar conceptul de „fat client” a fost înlocuit de o
arhitectură multinivel. In compensatie s-au impus diferite tehnologii web si XML (Extended
Markup Language). Iniţiative de tip middleware cum ar fi Distributed Computing Environment

13
(DCE) sau Common Object Request Broker Architecture (CORBA) sunt înlocuite treptat cu
infrastructuri tehnice de mare complexitate. Astăzi au rămas în esenţă numai două platforme
tehnologice pentru aplicaţii noi: Java 2 Enterprise Edition (J2EE) şi Microsoft .NET.
Pentru a lua o decizie corectă pentru viitor, utilizatorii trebuie să ia în considerare două criterii
importante:
- potenţialul de dezvoltare şi comprehensibilitate susţinut de o anumită
platformă
- oferta de soluţii proprii ale platformei, necesare pentru a se menţine pe
piaţă.
Limbajul Java a cunoscut o dezvoltare deosebită în ultimii cinci ani, de la un„capriciu” al
împătimiţilor pentru limbajele orientate obiect la o tehnologie larg răspândită. Această evoluţie
se datorează mai puţin farmecului limbajului şi mai mult fortei platformei tehnice asociate.
Recent şi Microsoft oferă o platformă tehnologică asemănătoare. Cei din Redmond au început cu
Distributed InterNet Architecture (DNA), care avea însă multe defecte.
Pe lângă problemele cu registrul şi conflictele de la nivelul DLL-urilor, a apărut
conceptul de model obiect componentă (COM), care a devenit prea complex din cauza
suportului pentru diferite limbaje. De asemenea procesarea distribuită cu soluţii DCOM pe baza
conceptului Microsoft RPC şi a registrului Windows nu s-a dovedit a fi compatibilă cu
Internetul.

2.2.2 .NET a învăţat de la Java

Începând cu .NET, Microsoft a realizat o importantă schimbare faţă de DNA,compania


lui Bill Gates deschizând problema tehnologiei predecesoare. La capitolul arhitectură şi
funcţionalitate .NET şi J2EE sunt foarte asemănătoare, dar Microsoft oferă o soluţie tehnică mai
modernă, prin implementarea tehnologiilor web şi a limbajului XML. De asemenea, noul limbaj
C# si maşina virtuală (CLR) sunt idei provenite din Java. Există şi alte diferenţe de importanţă
strategică:
1. J2EE nu este un produs, ci o specificaţie, pentru care diferite companii oferă produse.
Aplicaţiile sunt independente de proprietarul suportului middleware. Astfel, companiile obţin nu
numai o independenţă faţă de un anumit furnizor, dar pot să-şi dezvolte propriile platforme
tehnologice. .NET este o colecţie de produse ale unui singur producător şi rulează numai
împreună cu Windows. Se asigură integrarea diferitelor componente şi utilizarea unor
caracteristici speciale ale sistemului de operare Windows.

14
2. J2EE este independent de conceptul de sistem de operare. Portabilitatea este asigurată de Java
Runtime Environment, iar serverul de aplicaţii si alte produse middleware pot fi programate in
funcţie de sistemul de operare. Pe lângă aceste aspecte, mai există şi alte criterii importante în
luarea unei decizii în privinţa acestor două tehnologii, cum ar fi nivelul de comprehensibilitate si
dezvoltare, ceea ce analiştii de la Gartner numesc „completeness of vision”. Avantajul J2EE
constă în existenţa interfeţelor API (Application Programming Interface), care creează o
independenţă tehnologică a aplicaţiilor. Aceasta facilitează dezvoltarea ulterioară a tehnologiei
cu efecte secundare reduse. Modelul componentelor Java este mai metodic şi mai elaborat, iar
arhitectura bazată pe conectori oferă baza pentru o mai mare interoperabilitate decit facilitatile
corespondente in tehnologia .Net.

2.2.3 .Net versus Java: criterii de comparaţie

Înainte de a lua o decizie, responsabilul IT trebuie să mai treacă sub lupă şiimplementarea
tehnică a infrastructurii informatice respective. Sub acestaspect .NET posedă câteva avantaje,
deoarece utilizează de la începuttehnologii moderne cum ar fi XML şi serviciile web. Prin
dezvoltarea proprieimaşini virtuale Microsoft rezolvă problemele datorate interpretorului din
Java.Multe functionalităţi ale sistemului de operare Windows pot fi utilizate direct,cum ar fi
serverul web IIS, Active Directory, OLEDB şi Windows LoadBalancing. Cuplarea eficientă cu
sistemul de operare este cauzaperformanţelor îmbunătăţite ale aplicaţiilor .NET, comparativ cu
cele ale aplicaţiilor J2EE, deşi este dificil de estimat obiectivitatea testelor respective.Totuşi
performanţele pot varia, astfel performanţele maşinii virtuale Java pe acelaşi suport hardware
variază cu un factor egal cu trei, iar această variaţie e chiar mai mare pentru serverele de aplicaţii
Java. Experienţa arată ca produsele software complexe au nevoie de ani de zile pentru a fi
dezvoltate. Asta se întâmplă cu bazele de date, cu aplicaţiile de monitorizare a tranzacţiilor sau
cu aplicaţiile Java, ceea ce face ca dezvoltarea unui nou produs construit pe un nucleu de
componente mai vechi să nu constituie un dezavantaj. Produsele J2EE au căpătat în timp un grad
acceptabil de maturizare. Pentru .NET experienţa practicilor în dezvoltarea aplicaţiilor proprii
lipseşte, pentru a face o comparaţie.

15
Dincolo de criteriile de performanţă, managerii IT trebuie să ţină cont de eficienţa platformei şi
de productivitatea furnizată în dezvoltarea aplicaţiilor. Dacă se măsoară productivitatea numai pe
baza „numărului de linii de cod”, .NET prezintă avantaje clare in faţa J2EE. Crucial este însă cât
dintre aceste linii de cod trebuie sa fie scrise la mână. Aici intervine atât procesul automatizat de
dezvoltare cat şi inteligenţa mediului de dezvoltare software. În Java există diferenţe
semnificative între uneltele de dezvoltare, care sunt subliniate de furnizori în campaniile lor de
marketing. IDE (Integrated Development Environment) cum ar fi Jbuilder, Forte si mai nou
ECLIPSE oferta suport optimal pentru dezvoltare, debug si versionare de proiecte oricit de
complexe, lasind totusi programatorului intregul control si transparenta perfecta fata de codul
Java rezultat. Uneltele „Visual Studio .NET” de la Microsoft pot fi comparate cu cele mai
eficiente medii de dezvoltare din Java. Costurile cu licenţele şi cu întreţinerea sunt un factor ce
nu trebuie neglijat în luarea deciziei pentru sau contra unei tehnologii. Costurile soluţiilor J2EE
ale unor furnizori ca IBM sau BEA sunt transferate în categoria mainframe-urilor.
Nu trebuiesc insa uitate ofertele open-source cu preţ zero, care necesită doar puţin curaj
în implementare. Forte, Turbine, Struts, Cactus, Junit, Eclipse – sunt doar citeva nume de
frameworkuri, module sau unelte gratuite care nu mai au nevoie de nici o recomandare
suplimentare in lumea programatorilor si a inginerilor de software. Pe scara preţurilor de la
gratuit la scump, Microsoft .NET este aşezat undeva pe la mijloc. Mai apar şi cheltuieli cu
personalul calificat care să opereze o infrastructură atât de complexă. Mâna de lucru este scumpă

16
şi comparabilă pentru ambele tehnologii. Trebuie avut in vedere ca J2EE si Java sunt insa pe
piata de citiva ani de zile, fapt care a „produs” deja mina de lucru experimentata. Tehnologia
.Net este in stadiul de nou-nascut, iar specialistii in acest domeniu abia se formeaza.
Pentru a analiza dacă o tehnologie sau un concept este complet, trebuie luat în
considerare dacă ofertantul continuă să susţină şi să dezvolte propria tehnologie pe piaţă. Luind
in considerare valoarea strategica a acestor tehnologii, care sunt momentan singurele in masura
sa sustina dezvoltarea de aplicatii de tip B2B sau B2E, este foarte putin probabil sa nu se
gaseasca investori pentru ambele linii de dezvoltare, indiferent de situatia financiara a creatorilor
lor.
Furnizorii de tehnologie Java sunt capabili să sfideze puterea de dezvoltare simarketing a
celor de la Microsoft. Pentru ei aceasta este de fapt o strategie de supravieţuire. Dar ei nu depind
în mod necesar de existenţa companiei Sun. În cazul insolvabilităţii companiei Sun, rolul său
poate fi transferat altei companii. Grupul de producători de soluţii Java şi-a împărţit capacitatea
de producţie. Orice produs Java este dezvoltat în paralel de 6-8 producători. Astfel există
aproximativ 40 de producători de servere de aplicaţii. Dar competiţia accelerează si
diversificarea ideilor. Nici puterea de inovaţie a comunităţii open-source nu trebuie omisă.
Proiecte ca Apache arată gradul de dezvoltare de produse eficiente open-source.

2.2.4 Schimbările ulterioare sunt scumpe

Vizualizarea situaţiei actuale nu este uneori suficientă în luarea deciziilor. Companiile


investesc milioane de Euro în infrastructură şi în aplicaţii noi. Dacă o platformă tehnologică a
fost aleasă, costurile generate de modificare sau inlocuire ulterioara sunt foarte mari. Studiul
Gartner arată că apariţia Microsoft .NET va produce mutaţii la nivelul comunităţii Java, dar nu
va înlocui Java. Este insa improbabil ca Java să rămână dominant în aşa măsură încât .NET să nu
obţină procente din piaţă. Miile de documente descărcate de pe Internet arată un interes activ
in .NET. Tinind cont si de eforturile de marketing si vinzari depuse de Microsoft pentru
introducerea pe piata a alternativei tehnologice .Net, este probabil că cele două platforme
tehnologice vor coexista în viitor.
Multe companii au sesizat ca Microsoft .NET reprezintă un mare pas înainte, dar nu au
motive să renunţe la Java. Cine a investit deja în Java găseşte puţine motive să o schimbe şi să
treacă la .NET. .NET nu oferă chiar atât de multe avantaje până la urmă.

Potenţiali clienţi sau o posibilă impărţire a pieţei între Java şi .Net


Mai rămân companiile care nu s-au decis încă în care din cele două tehnologii vor investi.
Aici mai degrabă obiective strategice vor afecta decizia. Companiile mai mici, cele care dispun

17
de echipamente cu procesoare Intel ieftine si cu sisteme de operare Windows, vor opta pentru
.NET pentru noile aplicaţii. Companiile mari, ce dispun de sisteme mainframe dotate cu sisteme
Unix vor opta pentru o platformă ce rulează pe aceste mainframe-uri, aceasta fiind J2EE. Pentru
mulţi dintre utilizatori, inventarea limbajului Java a fost un eveniment. Dacă ei au trebuit să
testeze în trecut propriile aplicaţii pe mai multe sisteme de operare, acum ei le testează pe
implementarea standard de la Sun, cu eventuale teste adiţionale pe medii de producţie dezvoltate
de IBM, BEA sau Oracle.
Dar şi .NET atrage producătorii de software. Aceasta depinde de infrastructura clientului
respectiv. Dacă o companie cumpără o aplicaţie Java, atunci (cel puţin în prezent), trebuie
utilizat şi un mediu J2EE ce depinde de extensiile stabilite de fabricant. Prin cumpărarea mai
multor pachete software o companie ajunge să posede mai multe servere de aplicaţie. Cu .NET o
infrastructură pentru toate aplicaţiile este suficientă. Se mai pune doar intrebarea daca .Net
asigura si calitatea de care este nevoie in mediul de afaceri, Microsoft avind pina la acest
moment experiente (nu totdeauna laudabile) doar in mediul utilizator (home office sau
consumer).
Cerinţele legate de cunoştinţele dezvoltatorilor de aplicaţii sunt comparabile. În afara de
limbajul şi uneltele specifice, mai trebuie stăpânite cunoştinţe despre programarea orientată pe
obiecte, arhitectura bazată pe straturi, design de componente şi implementare iterativă. Cei care
au dezvoltat aplicaţii Microsoft în trecut pot trece uşor la .NET. Totuşi, un dezvoltator „clasic”
care a implementat în trecut în Visual Basic soluţii bazate pe „fat client” ar putea întâmpina
dificultăţi în implementarea cu .Net. În plus VB.NET nu mai este identic cu vechiul Visual
Basic.
Aceleaşi probleme apar şi la migrarea programelor Microsoft vechi la .NET. Pentru unele
module se oferă asistenţi de migrare, dar aceasta este valabil numai dacă aplicaţiile vechi s-au
dezvoltat pe o arhitectură pe trei nivele, pe bază de componente. Deoarece tendinţa merge către
achiziţionarea de software în loc de dezvoltare internă, companiile au puţine şanse să primească
tehnologie omogenă. Astfel încât se creează un mixaj de soluţii, pentru mainframe, PC, aplicaţii
Java şi .NET, prioritatea fiind abilitatea de a integra platforme eterogene.
Pentru sarcinile de integrare între tehnologii se poate utiliza XML sau serviciile web, care
sunt suportate atât de Java cât şi de .NET. Chiar şi aplicaţiile mainframe pot fi integrate cu un
anumit cost. Cea mai mare rezistenţă la integrarea cu alte programe o vor avea aplicaţiile din era
„fat client”, adică aplicaţiile Microsoft cu tehnologii mai vechi.

2.3. Java şi programarea WEB


2.3.1 JSP
18
2.3 .1.1 Introducere în JSP.
Java Server Pages sau, pe scurt, JSP este o solutie oferita de Sun Microsystems pentru
dezvoltarea aplicatiilor web. JSP permite programatorilor includerea de cod Java in pagini web, oferind

suport pe partea de server. JavaServer Pages face parte din familia Java şi reprezintă o
tehnologie care permite crearea de aplicaţii Web independente de platformă. JSP separă
interfaţa utilizator de conţinutul generat dinamic permiţând schimbarea întregului şablon al site-
ului WEB fără a altera informaţiile afişate. Tehnologia utilizează marcatori XML şi scripturi
scrise în limbajul de programare Java pentru a încapsula logica aplicaţiei care generează
conţinutul paginilor WEB. JSP-urile sunt o extensie a tehnologiei Java Servlet. Servlet-urile sunt
independente de platformă 100% şi reprezintă module la nivel de server care se integrează în
cadrul unei aplicaţii Web şi care pot fi utilizate pentru a extinde capabilităţile unui server WEB.
Tehnologia JSP şi servlet-urile oferă o alternativă pentru crearea aplicaţiilor WEB faţă
de alte limbaje de scripting/programare a aplicaţiilor WEB, oferind independenţă de platformă,
performanţă, separarea logicii aplicaţiei de partea de interfaţă utilizator, administrare uşoară şi
extensibilitate.
Principalul avantaj al JSP-urilor consta in introducerea template-urilor de continut
static (posibil de creat in formate non-HTML: WML, XML) care pot fi realizate de dezvoltatori
specializati in proiectarea interfetelor Web. Deoarece insa partea de prelucrare a informatiei necesara
generarii de continut dinamic este mai greu de scris in JSP, si este preferabil sa fie separata pentru a
fi scrisa de programatori Java, s-a trecut rapid de la lucrul exclusiv cu pagini JSP (arhitectura numita
“model-0”) la delegarea sarcinilor de stocare si prelucrare catre coduri Java care pot fi clase
Java clasice (POJO – Plain Old Java Objects) sau componente JavaBeans.
Arhitectura conţine elementele de bază necesare funcţionării aplicaţiei,
fiind prezentate componentele la nivel generic. Clienţii, prin intermediul unui
navigator Internet, accesează pagini JSP care conţin cod Java executat pe
maşina virtuală Java (JVM) de pe sever. Rezultatele prelucrărilor efectuate
sunt trimise clientului în format HTML prin serverul Web. Fişierele JSP sunt
transformate de către procesorul JSP în fişiere sursă Java, care conţin pe
lângă codul existent în fişierele JSP şi secvenţe de cod propriu motorului JSP.
Un servlet este un program Java care rulează în cadrul serverul Web sau al
servelor de aplicaţii şi funcţionează ca un strat de mijloc între cererile
provenite de la clienţi şi aplicaţii sau baze de date existente pe partea de
server. J2EE (Java 2 Platform, Enterprise Edition) defineşte un standard
pentru dezvoltarea aplicaţiilor de întreprindere multi-strat. Aplicaţiile de
întreprindere sunt simplificate prin utilizarea de componente modulare

19
standardizate, având un set complet de servicii care preiau o parte din
funcţionalitatea aplicaţiilor, astfel încât atenţia se va concentra la partea de
business.
Platforma J2EE utilizează platforma J2SE (Java2 Platform, Standard
Edition), în plus faţa
de aceasta oferă suport pentru:
- Java Servlets API ;
- tehnologia JSP;
- componente EJB (Enterprise JavaBeans);
- conectivitate la baze de date;
- tehnologia XML;

2.3.1.2 Despre obiecte implicite şi explicite


JSP operează cu obiecte implicite şi explicite. Sunt nouă obiecte implicite. Iată-le:
application (aplicaţia), config (configurarea), exception (tratarea excepţiilor, erorilor), out
(scrierea în pagina curentă a unui flux de caractere), page (pagina), pageContext (contextul
paginii), request (cererea), response (răspunsul) şi session (sesiunea). Aţi observat în exemplele
date până acum directiva import. Cu ea anunţam JVM că avem nevoie de o serie de clase.
Clasele „produc” obiecte. Fiecare clasă are cel puţin unul sau mai multe metode pe post de
constructori, care servesc la crearea obiectului. Spunem: se instanţiază obiectele!
În cazul obiectelor implicite, maşina virtuală Java este aceea care instanţiază din oficiu.
În cazul propriilor noastre clase sau a sutelor de clase, care nu sunt abstracte şi aparţin unuia
dintre pachetele Java, se recurge la operatorul de instanţiere new. Maşina virtuală Java importă
în mod automat patru pachete de bază. Un pachet conţine un set de clase aşezate într-o ordine
ierarhică. Ele sunt: java.lang.*, javax.servlet*, javax.servlet.jsp* şi javax.servlet.http*.

2.3.2 JSF
2.3.2.1 Introducere în JSF.
JSF (Java Server Faces) este o tehnologie opensource ce a apărut în
anul 2001, cu ajutorul căreia putem dezvolta interfeţe Web. JSF-ul are la
bază şablonul MVC (Model View Controller), ceea ce presupune separarea
interfeţei cu utilizatorul, a părţii de business logic, şi a modelului. JSF-ul pune
la dispoziţia programatorilor o serie de componente JSF standandard, ce vor
fi transpuse în elemente de interfaţă.

20
Puterea acestui framework se bazează tocmai pe flexibilitatea acestor
componente, care pot fi reutilizate, şi (şi mai important) pot fi extinse pentru
a da viaţă unei aplicaţii web conform cu cerinţele utilizatorilor săi. Putem sa
ne punem întrebarea: De ce să folosim JSF în locul JSP-ului, sau în locul unui
alt framework precum Strut sau Spring? Pentru a dezvolta o aplicaţie web
simplă, care nu necesită o interacţiune complexă cu utilizatorul putem alege
JSP în combinaţie cu JSTL (JSP Standard Tag Library). Dar, în caz contrar, JSF-
ul este o alegere mult mai potrivită datorită componentelor pe care le pune
la dispoziţia programatorului, acesta putându-se concentra pe dezvoltarea
aplicaţiei. Dezvoltatorul nu trebuie să ştie neapărat detaliile din spatele unei
componente JSF, modul de utilizare a acestora permiţând acest lucru.
Majoritatea IDE-urilor au dezvoltat suport pentru creearea de aplicaţii JSF în
mod vizual. Exemple de astfel de IDE-uri sunt: NetBeans, Eclipse, JDeveloper.
Un aspect important al aplicaţiilor web de care JSF-ul ţine cont este salvarea
şi reîncărcarea stării unei pagini web. Un exemplu tipic este cel al coşului de
cumpărături online. Starea fiecărei pagini trebuie salvată până când
utilizatorul a terminat de cumpărat (între cereri multiple). JSF-ul se ocupă de
acest lucru cu ajutorul clasei StateManager, care salvează şi recuperează
starea unui anumit view. Există două alternative pentru a face acest lucru: la
nivelul clientului sau la nivelul serverului.

2.3.2.2 Componente JSF.


Componentele JSF se gasesc la nivelul View-ului. Astfel, View-ul este
construit din grupuri de componente, păstrate într-o ierarhie de tip arbore,
permiţându-se accesul la o anumită componentă pe baza unui index.
O componentă JSF reprezintă un grup de clase ce interacţionează între ele,
punând la dispoziţia programatorului cod reutilizabil pe partea de interfaţă
cu utilizatorul. Sarcinile unei componente în general sunt: generarea de cod
pe partea de client (de exemplu html), validarea inputurilor şi conversia de
date.
După cum am menţionat mai sus, JSF-ul pune la dispoziţia
programatorilor o serie de componente standard, precum componente ce
generează cod pe partea de client şi componente ce oferă suport pentru
validare sau conversie de date. Un exemplu de componentă este UIInput

21
care face parte din componentele JSF standard. Această componentă pune la
dispoziţie elementul html input text, cu ajutorul renderului HtmlInputText,
sau al renderelui HtmlInputHidden etc. Alte componente standard sunt:
UIData, UIColumn, UICommand, UIForm, UIGraphic etc. Pe lângă aceste
componentente standard, există o serie de alte implementări, care mai de
care mai puternice şi mai complicate. Printe acestea enumerăm: MyFaces,
RichFaces, IceFaces etc.

2.3.2.3 Dezvoltarea de componente JSF proprii


Înainte de a dezvolta o componenta JSF proprie trebuie sa cercetăm
daca nu cumva există deja o componenta ce oferă funcţionalitatea de care
avem nevoie. Astfel, în multe cazuri vom descoperi că este suficient să
extindem funcţionalitatea unei componente deja existente. Dar, dacă nu
găsim componenta pe care o căutăm, atunci va trebui să o dezvoltăm noi
înşine. În cazul unor aplicaţii web care necesită o mare dinamicitate în
interacţiunea cu utilizatorul vom constata că uneori este nevoie de acest
lucru, deşi multe companii software se întrec în a implementa componente
JSF cât mai puternice.
Un exemplu concret este următorul: o componentă care iterează o lista
de elemente, le afişează şi care trebuie să facă o operaţie de drag&drop în
interiorul său, şi de asemenea în interiorul altor componente de acelaşi tip.
În urma cercetarilor am constatat că există o singură componentă care oferă
doar o parte din funcţionalitatea cerută, componentă pusă la dipoziţie de
IceFaces, dar care nu funcţiona în mod corespunzător. Având în vedere
aceasta şi faptul că acea componentă permitea drag&drop doar în interiorul
ei, singura variantă rămasă a fost dezvoltarea unei componente JSF proprii,
care trebuia să extindă UIData, ce oferă suport pentru iterarea şi afişarea
elementelor unei liste.
Am ales aceasta variantă pentru că, deşi, ca complexitate, este destul de
dificilă crearea şi menţinerea unei astfel de componente, aceasta va fi foarte
usor de reutilizat în interiorul oricărei pagini JSF, prin simpla scriere a unui
tag şi prin definirea unor atribute.

2.3.2.4 Structura unei componente JSF


O componentă JSF este alcatuită din următoarele elemente:
22
o clasă de tipul UIComponent (derivată din UIComponentBase sau extinsă
dintr-o altă componentă, cum ar fi HtmlOutputText. Aceasta are rolul de a
accesa date de pe partea de model
una sau mai multe clase Render: se ocupă cu generarea componentei pe
partea de client, şi cu conversia datelor introduse de utilizator în valori pe
care componenta să le poată înţelege. Acesta este opţional, sarcinile
acestuia pot fi îndeplinite şi de către clasa componentă. Totuşi varianta
folosirii rederelor este mai bună pentru că acestea permit componentei să
lucreze independent de codul generat pe partea de client. Un alt avantaj ar fi
acela că pentru o aceaşi componentă se poate genera cod diferit pe partea
de client. Un exemplu este cel al componentei UIInput care are următoarele
rendere: HtmlInputText, HtmlInputTextarea, HtmlInputHidden etc.
clasa Tag: o clasă handler care permite reutilizarea componentei în interiorul
paginilor JSP.
fişier .tld (Tag Library Descriptor): permite asocierea clasei handler cu un tag
JSP, pentru că JSF-ul trebuie să urmeze regulile JSP-ului.
De fiecare dată când un tag este deschis, va fi apelată metoda
encondeBegin a componentei asociate, iar atunci când un tag este închis va
fi apelată medota encodeEnd. Metoda encodeChildren va procesa copiii
componentei dacă getRenderChildren returnează true. Acest lucru este de
reţinut mai ales pentru începători.

2.3.2.5 Fazele vieţii JSF-ului (The JSF life cycle)


Pentru o înţelegere mai în amănunt a modului în care funcţionează o
componentă JSF (şi deci pentru a fi capabili să implementăm una) va trebui
să înţelegem fazele vieţii JSF-ului. De aceea vom face o scurtă prezentare a
acestora. Fiecare cerere sau răspuns care implică JSF parcurge nişte faze.
Clientul face o cerere HTTP pentru o pagină, serverul răspunde, deci lucrurile
seamănă cu ce se întamplă la nivelul unei pagini JSP. Dar, datorită puterii
JSF-ului, tratarea unei cereri se face cu ajutorul unor servicii suplimentare.
Când clientul trimite o cerere, JSF-ul trebuie să îndeplinească mai multe
sarcini cum ar fi validarea datelor şi conversia acestora. Acestea fac parte
din fazele vieţii JSF-ului. Numele acestor faze le vom prezenta în engleză:

23
Restore View: atunci când este făcută o cerere pentru o pagina JSF. În timpul
acestei faze, JSF-ul construieşte/reconstruieşte view-ul paginii şi îl salvează
într-o instanţă FacesContext.
Apply Request Values: se apelează după construirea arborelui de
componente.
Validation: în timpul acestei faze, fiecare componentă procesează toţi
validatorii înregistraţi.
Update Model: se realizează actualizarea datelor pe partea de model pentru
a corespunde cu datele de pe partea de componentă.
Invoke Application: procesarea action-urilor şi a actionListenere-lor.
Render Response: generarea răspunsului pentru client şi salvarea stării.

2.3.3 MySQL.
MySQL este un sistem de gestiune a bazelor de date relaţional, produs
de compania suedeză MySQL AB şi distribuit sub Licenţa Publică Generală
GNU. Este cel mai popular SGBD open-source la ora actuală, fiind o
componentă cheie a stivei LAMP (Linux, Apache, MySQL, PHP).
Deşi este folosit foarte des împreună cu limbajul de programare PHP, cu
MySQL se pot construi aplicaţii în orice limbaj major. Există multe scheme
API disponibile pentru MySQL ce permit scrierea aplicaţiilor în numeroase
limbaje de programare pentru accesarea bazelor de date MySQL, cum are fi:
C, C++, C#, Borland Delphi, Java, Perl, PHP, Python, FreeBasic, etc., fiecare
dintre acestea folosind un tip spefic API. O interfaţă de tip ODBC denumită
MyODBC permite altor limbaje de programare ce folosesc această interfaţă,
să interacţioneze cu bazele de date MySQL cum ar fi ASP sau Visual Basic. În
sprijinul acestor limbaje de programare, unele companii produc componente
de tip COM/COM+ sau .NET (pentru Windows) prin intermediul cărora
respetivele limbaje să poată folosi acest SGBD mult mai uşor decât prin
intermediul sistemului ODBC. Aceste componente pot fi gratuite (ca de
exemplu MyVBQL) sau comerciale.
Licenţa GNU GPL nu permite încorporarea MySQL în softuri comerciale; cei
care doresc să facă acest lucru pot achiziţiona, contra cost, o licenţă
comercială de la compania producătoare, MySQL AB.
MySQL este componentă integrată a platformelor LAMP sau WAMP
(Linux/Windows-Apache-MySQL-PHP/Perl/Python). Popularitatea sa ca
24
aplicaţie web este strâns legată de cea a PHP-ului care este adesea combinat
cu MySQL şi denumit Duo-ul Dinamic. În multe cărţi de specialitate este
precizat faptul ca MySQL este mult mai uşor de invăţat şi folosit decât multe
din aplicaţiile de gestiune a bazelor de date, ca exemplu comanda de ieşire
fiind una simplă şi evidentă: „exit” sau „quit”.
Pentru a administra bazele de date MySQL se poate folosi modul linie de
comandă sau, prin descărcare de pe internet, o interfaţă grafică: MySQL
Administrator şi MySQL Query Browser.
MySQL poate fi rulat pe multe dintre platformele software existente: AIX,
FreeBSD, GNU/Linux, Mac OS X, NetBSD, Solaris, SunOS, Windows
9x/NT/2000/XP/Vista.

2.3.4 Arhitectura Tomcat.


2.3.4 .1 Apache Tomcat.
Serverul Web de la Apache realizat în cadrul proiectului Jakarta, numit
Tomcat, reprezintă o implementare de referinţă oficială a specificaţiilor
servlet şi JSP.
El include un server Web, astfel încât poate fi utilizat drept container de sine
stătător pentru a testa servlet-uri şi JSP-uri.
Tomcat poate fi configurat şi pentru a servi drept container pentru servlet-uri
şi JSP-uri utilizat ca extensie a unor servere Web populare cum ar fi Apache
HTTP Server de la Apache Software Foundation sau Internet Information
Services (IIS) de la Microsoft.
Tomcat este integrat în implementarea de referinţă de la Sun Microsystems
inclusă în platforma Java pentru e-business numită Java 2 Enterprise Edition
(J2EE).

2.3.4.2 Instalarea serverului Web Tomcat de la Apache.


Mediul de lucru :
Pentru a realiza programare pe Internet folosind Java, avem nevoie de urmatoarele unelte:
1- server web Apache Tomcat, folosim versiunea 6.0.16 care se obţine prin download de la
adresa http://tomcat.apache.org/
2- mediu eclipse echipat cu pluginul Eclipse WTP
Instalarea mediului de lucru:

25
1. se obţine kitul Tomcat de la adresa http://tomcat.apache.org/
2. se instaleaza acest kit. La instalare putem instala optional exemplele. In mod necesar, instalăm
Tomcat ca şi un serviciu (se selectează opţiunea service în ecranul „Choose Components”.
Selectăm o cale de instalare, de exemplu C:\Java\Tomcat6.0. Păstrăm portul de instalare 8080 şi
introducem o parolă de admin. LA instalare selectăm o platformă JRE. E de preferat să se
selecteze aceaşi platformă care este utilizată în Eclipse.
3. LA finalizarea instalării Tomcat, se porneşte serviciul de web. Verificăm funcţionarea acestui
serviciu. La o funcţionare corectă, în bara de taskuri care rulează în background trebuie să apară
icoana pentru Tomcat, marcată cu butonul verde. De asemenea, apelăm din browser adresa
http://localhost:8080/ care trebuie sa ne ducă la pagina iniţială Tomcat de pe calculatorul curent.
4. În cele ce urmează se configurează eclipse pentru WTP. În Eclipse se lansează meniul
Help/Software updates/Find and Install. Se selectează „Search for new features to install”. Se
selectează opţiunea Web Tools Platform updates. Pentru că avem nevoie de Eclipse DTP, dacă în
ecranul pentru alte unelte nu se gaseşte acest plugin, se introduce site-ul eclipse DTP pentru
update prin „new Remote Site”. Pentru DTP se va introduce următoarea adresa de web:
http://download.eclipse.org/datatools/downloads/drops/N_updates
5. În următorul ecran se selectează doar WTP şi apoi se apasă butonul „Select required” pentru a
se selecta pentru instalare toate uneltele solicitate de WTP. 6. Se finalizează instalarea lăsând
Eclipse să downloadeze şi instaleze componentele necesare.
7. Se instalează serverul Tomcat în Eclipse:
În meniul Window/Preferences/Servers/InstalledRuntimes selectăm Add. Apoi Selectăm din
lista Apache Tomcat 6.0 şi se selectează directorul de instalare Tomcat.

Capitolul III
26
Aplicaţii de reţea în Java. Socluri. URL. RMI

Clasele din pachetul java.net se împart în doua categorii, clase pentru socluri şi clase care
lucrează cu URL (Uniform Resource Locators). Soclurile Java facilitează accesul la protocoalele
standard utilizate în comunicarea între calculatoarele gazdă de pe Interent.

3.1. Socluri. Modelul client server.

3.1.1 Protocoale

Înainte să intrăm în detaliile posibilitaţilor oferite de limbajul Java pentru scrierea


aplicaţiilor de reţea trebuie să cunoaştem nişte lucruri despre reţeaua Internet. Internetul
funcţionează pe un sistem de protocoale numit TCP/IP (Transport Control Protocol/Internet
protocol)

Aceste protocoale stabilesc regulile cu ajutorul cărora două calculatoare comunică între
ele. Protocoalele sunt standarde de care se ocupă IETF ( Internet Engineering Task Force). Java
implementează protocoalele de nivel superior al stivei de protocoale TCP/IP. Astfel facilitează
utilizarea protocoalelor HTTP (HyperText Transfer Protocol) şi FTP( File Transfer Protocol).
Astfel programatorul va utiliza nişte clase şi interfeţe predefinite, fără a cunoaşte detaliile de
implementare a acestora. Nu trebuie să cunoaştem structurile de date utilizate de acest sistem de
protocoale, nici metodele utilizate pentru transmiterea şi recepţionarea secvenţelor de octeţi.

3.1.2 Modelul client server

27
Serverul este o aplicaţie care oferă servicii clienţilor sosiţi prin reţea. Serverele oferă o
gamă variată de servicii. Serverul cel mai cunoscut este serverul Web, care furnizează
documentele cerute de către clienţi. Un alt serviciu cunoscut este poşta electronică, care
utilizează protocoalele SMPT (Simple Mail Transfer Protocol) şi IMAP4 (Internet Mail
Access Protocol). Pe principiul client-server funncţionează şi protocoalele NFS (Network
File Service) şi FTP sau serviciul de nume de domenii DNS (Domain Name Service) şi
serviciul de informaţii despre reţea NIS (Network Information Services). Trebuie să amintim
şi serviciul care permite logarea la un calculator aflat la distanţă: TELNET şi RLOGIN.
Putem trage concluzia că arhitectura client-server este instrumentul de baza în dezvoltarea
aplicaţiilor de reţea.
Clientul este o aplicaţie care utilizează serviciile oferite de către un server. Pentru a putea
realiza acest lucru, clientul trebuie să cunoască unde se află serverul în reţea şi cum trebuie
comunicat cu acesta şi ce servicii oferă. Deci dacă un client doreşte o comunicare cu
serverul, trebuie să cunoască trei lucruri:

• adresa server
• portul server utilizat pentru comunicare
• protocolul de comunicaţie utilizat de server

Dacă aceste date ne stau la dispoziţie, putem realiza comunicaţia cu serverul.

3.1.3 Porturi şi socluri

Porturile şi soclurile reprezintă mecanismul prin care se realizează legatura cu un server.


Porturile reprezintă o poartă la care sunt primiţi clienţii pentru un anumit serviciu. De exemplu la
aceeaşi adresă se pot oferi diferite servicii, acestea oferindu-se la porturi diferite. Acelaşi
calculator (cu o singură adresa IP) poate să ne ofere oricate servicii doreşte. Clienţii care
apelează la serviciile acestui calculator vor utiliza aceeaşi adresă, indiferent la care serviciu
apelează, şi toţi clienţii care doresc utilizarea unui anumit serviciu vor utiliza acelaşi port. Un
numar de port este un numar întreg din intervalul 1-9999. IETF defineşte serviciile oferite pe
porturile 1-1024. De obicei serviciile HTTP sunt oferite la portul 80, cele de FTP la portul 21,
Telnet la 23 etc.

Un soclu este de fapt un nod abstract de comunicaţie. Soclurile reprezintă o interfaţă de nivel
scazut pentru comunicarea in reţea. Soclurile permit comunicarea între procese aflate pe acelaşi
calculator sau pe calculatoare diferite din reţea. Mecanismul de socluri a fost definit prima data
in BSD UNIX. Java suportă trei tipuri de socluri. Clasa Socket utilizează un protocol orientat pe

28
conexiune (TCP), clasa DatagramSocket utilizează protocolul UDP la nivelul transport, care este
un protocol neorientat pe conexiune. O altă variantă a DatagramSocket este MulticastSocket
utilizat pentru a trimite date deodata la mai mulţi receptori. Soclurile utilizează fluxuri de date
(streamuri) pentru a trimite şi a recepţiona mesaje.

3.1.3 Modelul de comunicaţie orientat pe conexiune.


Clasele Socket şi ServerSocket

Acest model se bazează pe protocolul TCP. Într-o aplicaţie reţea întotdeauna avem două
parţi: o parte client care iniţializează conversaţia şi trimite cereri, şi o parte server care primeşte
cererile şi răspunde la acestea. Clientul întotdeauna crează un soclu pentru a iniţia conversaţia şi
trebuie să cunoască serverul căruia adresează cererea, iar serverul trebuie să fie pregatit pentru a
recepţiona aceste cereri. În momentul recepţionării mesajului crează un soclu pe partea
serverului, soclu care va facilita deservirea clientului. Atât pe partea de client cât şi pe partea de
server se utilizează câte un obiect de tip Socket pentru comunicare. Pe partea de server mai
trebuie să creăm un obiect de tip ServerSocket, care are sarcina primirii conexiunilor şi
acceptarea acestora.

Figura 1. Arhitectura Client-Server

29
Clientul trebuie să cunoască două lucruri despre server: numele serverului (utilizat pentru
determinarea adresei IP al serverului) şi numărul portului la care acesta ascultă cererile clienţilor.
Acelaşi calculator gazdă poate oferi mai multe servicii, deci poate găzdui mai multe procese de
tip server. De exemplu poate fi server Mail, server FTP, server HTTP, dar aceste aplicaţii
lucrează cu diferite porturi, deci cererile adresate acestor servere vor fi recepţionate pe diferite
porturi.
Privind modalitatea de deservire a clienţilor serverul prin construcţie poate fi server paralel
(concurent) şi server secvenţial.

Figura 2. Server paralele şi Server secvenţial.


Serverul concurent permite deservirea în paralel a mai multor clienţi. Aceasta paralelitate se
poate realiza prin crearea a mai multor procese fiu, câte unul pentru fiecare client sau prin
crearea de fire de execuţie pentru deservirea fiecărui client în Java noi vom utiliza cea de a doua
modalitate. De obicei utilizăm server cu arhitectura paralela pentru servicii la care deservirea
unui client durează în timp.
In general o aplicaţie server trebuie să execute următorii paşi:

1. Serverul alocă un port de comunicare care va fi cunoscut de către clienţi


2. Cât timp ( mai sunt clienţi la port )
{
stabilire conexiune cu client ( creare soclu )
deservire client ( flux de intrare, flux de ieşire )

30
eliberare conexiune ( eliberare soclu )
}
O aplicatie client executa urmatoarele:
1. Alocă un port de comunicare
2. Se conectează la server la portul cunoscut de dinainte
3. Se stabileşte o conexiune prin care se trimit şi se citesc date (soclu + fluxuri)

Clasa Socket

Constructori:
Socket(InetAddress address, int port)
Crează un soclu şi care se conectează la adresa IP specificat prin obiectul
InetAddress şi portul specificat prin parametrul port.

Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

Crează un soclu şi care se conecteaza la adresa IP specificat prin obiectul InetAddress şi portul
specificat prin parametrul port. Ultimii doi parametri reprezintă adresa clientului şi portul pe care
acesta comunică .
Socket(String host, int port)
Crează un soclu şi care se conectează la calculatorul host pe portul specificat prin
parametrul port.

Socket(String host, int port, InetAddress localAddr, int localPort)


Crează un soclu şi care se conectează la calculatorul host pe portul specificat prin
parametrul port. Ultimii doi parametri reprezintă adresa clientului şi portul pe care acesta
comunica.

Metode principale:

void close()
Închide soclul.
InetAddress getInetAddress()
Returnează adresa la care soclul este conectat
InputStream getInputStream()
Returnează un stream de intrare pentru soclu.

31
InetAddress getLocalAddress()
Returnează adresa pe care soclul este creat.
int getLocalPort()
Returnează numărul portului local.
OutputStream getOutputStream()
Returneză un stream de ieşire pentru soclu.
int getPort()
Returnează portul la care soclul este conectat.

Clasa ServerSocket

Constructori:
ServerSocket(int port)
Crează un soclu server pe portul specificat.

ServerSocket(int port, int backlog)


Crează un soclu server pe portul specificat. Al doilea parametru indică lungimea cozii de
aşteptare.

Metode principale:
Socket accept()
Ascultă conexiunile şi le acceptă.
void close()
Închide soclul.
InetAddress getInetAddress()
Returnează adresa locală al soclului server.
int getLocalPort()
Returnează portul la care serverul aşteaptă conexiunile.

3.2 URL

3.2.1 Modelul de comunicaţie neorientat pe conexiune. Clasele DatagaramSocket şi


DatagramPacket

Trimiterea unei datagrame este similară cu trimiterea unei scrisori prin serviciul poştal. În cazul
trimiterii unei scrisori avem nevoie de un plic pe care scriem adresa destinatarului şi după aceea
punem scrisoarea în plic şi o aruncăm într-o cutie poştală. Analog la trimiterea unei datagrame

32
trebuie sa cunoaşten adresa şi portul calculatorului caruia îi este adresată datagrama, după care
putem să punem datele în datagrama şi să le trimitem. Datagramele utilizează la nivelul
transportului protocolul UDP. Acest protocol este unul nesigur, neorientat pe conexiune. Nu se
face confirmare în cazul recepţionării acestor datagrame. Nici calea urmată de aceste datagrame
nu se cunoaşte de dinainte. De aceea dacă trimitem la acelaşi destinatar mai multe datagrame,
unul după altul, nu putem fi siguri nici în ordinea primirii acestor datagrame. Din cauza că
protocolul nu necesită confirmarea sosirii datagramelor este un protocol rapid şi se utilizează în
cazul serviciilor unde nu este nici o nenorocire dacî se pierde un pachet-doua (DNS utilizează
UDP).
Descrierea claselor principale:
Clasa DatagramPacket:

Constructori:

DatagramPacket(byte[] buf, int length)


Construieşte un obiect de tip DatagramPacket pentru primirea unui pachet de lungime length

DatagramPacket(byte[] buf, int length, InetAddress address, int port)


Construieşte un obiect de tip DatagramPacket pentru trimiterea unui pachet de lungime
length pe un port specificat, la un host specificat

DatagramPacket(byte[] buf, int offset, int length)


Construieşte un obiect de tip DatagramPacket pentru primirea unui pachet de lungime length,
specificand un offset în buffer

DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
Construieşte un obiect de tip DatagramPacket pentru trimiterea unui pachet de lungime length
pe un port specificat, la un host specificat, specificand şi un offset

Metode:
InetAddress getAddress()
Returnează adresa IP al calculatorului de la care se primişte sau la care se trimite datagrama
byte[] getData()
Returnează şirul de octeţi care se trimite sau care se primeşte
int getLength()
Returnează lungimea datelor care se trimit sau care se primesc
int getOffset()

33
Returnează offsetul datelor care se trimit sau care se primesc
int getPort()
Returnează numarul portului calculatorului la distanţă la care se trimit datele sau de la care se
primesc datele
void setAddress(InetAddress iaddr)
Setează adresa.
void setData(byte[] buf)
Setează bufferul pentru pachet
void setData(byte[] buf, int offset, int length)
Setează bufferyl pentru pachet
void setLength(int length)
Setează lungimea pachetului.
void setPort(int iport)
Setează portul..

Clasa DatagramSocket

Constructori:

DatagramSocket()
Construieşte un soclu şi leaga la un port liber pe calculatorul local.
DatagramSocket(int port)

Construieşte un soclu şi leagă un port specificat pe calculatorul local.

DatagramSocket(int port, InetAddress laddr)

Construieşte un soclu şi leagă la adresa şi portul specificat

Metode:

void close()
Inchide soclul.

34
void connect(InetAddress address, int port)
Conectează soclul la o adresă şi port la distanţă.
void disconnect()
Deconectează soclul.
InetAddrress getInetAddress()
Returnează adresa la distanţa la care soclul este conectat.
InetAddress getLocalAddress()
Returnează adresa locală la care soclul este conectat.
int getLocalPort()
Returnează portul local la care soclul este legat.
int getPort()
Returnează portul la distanţa la care soclul este legat.
void receive(DatagramPacket p)
Primire de datagrama prin acest soclu.
void send(DatagramPacket p)
Trimitere de datagrama prin acest soclu
.

3.3 Elemente de programare distribuită prin invocare de metode la distanţă. RMI

Mecanismul RMI (Remote Method Invocation) furnizează o modalitate prin care este
posibilă execuţia unei aplicaţii distribuite pe mai multe maşini virtuale Java, permiţând ca un set
de calculatoare să poată colabora (să transfere date şi cod) pentru rezolvarea unui task comun.
Paradigma RMI a preluat o serie de concepte din modelul clasic RPC (Remote Procedure Call)
adaptate pentru sisteme obiectuale, astfel un obiect “client” poate să apeleze o metodă a unui
obiect “server” aflat la distanţă, concept extins cu alte facilităţi specifice programării distribuite
obiectuale, cele mai importante fiind sistemul de numire a entităţilor, colectorul de deşeuri,
încărcarea dinamică a claselor, oferind astfel o modalitate elegantă de soluţionare a diverselor
probleme specifice programării distribuite, pentru medii Java.

3.3.1. Concepte

În aplicaţiile distribuite atât datele (stocate separat) cât şi codul (procesoare multiple în
sistem), respectiv utilizatorii (comunica şi interacţionează) pot fi distribuiţi. RMI este un sistem

35
de programare obiectual, distribuit construit în platforma Java, facilitate ce permite interacţiuni
între obiecte care rulează pe maşini virtuale Java distribuite în reţea. Spre deosebire de
programarea complexă, bazată pe socketuri, mecanismul RMI oferă un context de programare
distribuită flexibil şi relativ simplu, reprezentând mecanismul suport pentru diverse alte modele
de dezvoltare a aplicaţiilor distribuite Java

Mecanismul a fost adăugat în platforma Java JDK 1. 1 din nevoia unui suport pentru
dezvoltarea aplicaţiilor distribuite bazate pe obiecte Java. Deşi la o simplă analiză, sistemul RMI
poate părea un alt mecanism de apel al procedurilor la distanţă (tip RPC), el reprezintă o soluţie
evoluţionară, un sistem care diferă de celelalte în setul de prezumţii despre sistemul distribuit pe
care operează, în modelul de programare şi capabilităţile oferite dar şi în modul în care
mecanismul interacţionează cu sistemul distribuit. RMI permite crearea unei referinţe la un
obiect care aparţine unui proces de pe un alt calculator şi invocarea de metode ale obiectului ca şi
cum acesta ar fi local. În loc să fie necesară definirea unui protocol de transfer de mesaje şi un
format al datelor transmise între procesele aplicaţiei distribuite, se foloseşte interfaţa Java ca
protocol, iar argumentele metodei exportate devin formatul datelor transmise.
Un sistem de programare a aplicaţiilor distribuite trebuie să ofere dezvoltatorului de aplicaţii
următoarele facilităţi:
 localizarea obiectelor la distanţă- aplicaţiile folosesc diverse mecanisme pentru a obţine
referinţele obiectelor remote (serviciul de nume rmiregistry sau transferul referinţelor la
obiecte ca parte a operaţiei solicitate)
 comunicare cu obiectele remote - detaliile comunicării sunt gestionate de RMI, pentru
programator comunicaţia remote este similara unei invocări de metode locale
 încărcarea codului intermediar al clasei pentru obiecte transferate ca parametri sau valori
întoarse. Deoarece permite ca apelantul să transfere obiecte, RMI integrează mecanismele
necesare încărcării codului obiectului şi transmiterea datelor.
Serverul apelează un sistem de localizare a obiectelor (registry) pentru a asocia un nume cu
un obiect remote, astfel clientul va căuta obiectul după nume în registry şi apoi va invoca
metoda. Pot fi utilizate servere Web pentru a încărca codul intermediar al claselor Java client-
server pentru obiectele aplicaţiei dacă este necesar folosind orice protocol de tip URL suportat de
platforma Java.

Cele mai importante avantaje oferite de mecanismul RMI sunt:


 este orientat obiect: RMI poate transfera obiecte ca parametri de apel a metodelor
remote, dar şi ca valori returnate. Astfel se pot transfera ca şi argumente pentru

36
metode diverse obiecte complexe (tabela de hashing) (în sistemele RPC, la client
obiectul necesită descompunere în tipuri primitive, transferul lor şi apoi refacerea
obiectului la server)
 oferă cod portabil: RMI e portabil referitor la orice JVM
 integrează un colector de deşeuri distribuit (Garbage Collector) oferind astfel
suport pentru gestionarea referinţelor la obiectele distribuite
 integrează mecanisme de securitate: RMI foloseşte controlerul de securitate
integrat JVM pentru a proteja sistemele de applet-uri maliţioase sau cod destructiv
 oferă suport pentru procesare paralela şi comportament mobil: RMI poate să
schimbe ‘comportamentul’, adică implementările claselor, de la client la server şi
invers

3.3.2. Arhitectura RMI

Arhitectura sistemului RMI integrează 3 niveluri: stratul stub/skeleton, stratul de referinţe la


distanţă şi stratul de transport, fiecare nivel software fiind delimitat de o interfaţă şi un
protocol specifice, fiind independent de celelalte şi posibil înlocuibil cu o implementare
alternativă. Pentru interacţiunile la distanţă sunt folosite două tehnici astfel: pentru a
realiza transmiterea transparentă a unui obiect între spaţii de adrese diferite, e folosită
tehnica de serializare a obiectului, iar pentru a permite clientului apelul metodelor la
distanţă e utilizată tehnica de încărcare dinamică a unui intermedia de acces (stub) ce
implementează acelaşi set de interfeţe la distanţă ca şi obiectul.

3.2.2. 1. Descrierea funcţionalităţii straturilor sistemului RMI:

37
Stratul Stub/Skeleton - stratul stub este la client, iar stratul skeleton e la server,
comportându-se asemenea unor proxy. JVM permite doar invocarea de metode locale, astfel o
cerere de invocare a unui obiect de la distanţă parcurge straturile sistemului RMI în ambele
sensuri, presupunând folosirea unui stub pentru obiectul de la distanţă şi a unei căi spre acel
obiect.

Acest strat defineşte interfaţa dintre aplicaţie şi restul sistemului RMI, nu se ocupă cu
detalii de transport, dar transmite datele spre stratul de referinţă la distanţă via abstractizarea
numită stream-uri, bazat pe mecanismul de serializare, ce permite transmisia obiectelor Java
între diferite spaţii de adrese.
Un stub pentru un obiect remote este proxy-ul la client al acelui obiect, el implementează
toate interfeţele care sunt suportate de obiectul remote, fiind reponsabil pentru:
 iniţierea unui apel spre obiectul remote (prin apelul stratului de referinţă la distanţă)
 ordonantarea argumentelor într-un stream marshall (argumente sunt obţinute de la
stratul de referinţă la distanţă)
 informarea stratului de referinţă la distanţă de faptul că apelul este necesar
 reconversia valorii de return sau a excepţiei dintr-un stream marshall
 informarea stratului de referinţă la distanţă de faptul că apelul a fost efectuat

Un skeleton pentru un obiect remote este o entitate în server care conţine metode ce
efectuează apelurile spre implementarea obiectului remote. Această entitate este responsabilă cu:
 reconversia argumentelor din stream-ul marshall
 efectuarea apelului spre implementarea obiectului remote
 ordonantarea valorii de return a apelului sau a excepţiei în stream-ul marshall

Obiec Obiec
t t
client server

Stub/skeleton Stub/skeleton

Referinta Referinta
remote remote

Transport Transport

Masina virtuala locala Masina virtuala remote

Figura 3. Arhitectura RMI.


38
Clasele de tip stub -skeleton sunt generate la runtime şi sunt încărcate dinamic pe măsură ce este
necesar.
Stratul de referinţă la distanţă integrează comportamentul referinţei la distanţă a obiectului,
se ocupă cu interfaţa de nivel jos a stratului de transport şi cu gestionarea unui protocol specific
de referinţă la distanţă independent de stub-rile clienţilor şi skeleton-ii serverelor. Fiecare
implementare de obiect remote îşi alege propria sa subclasă de referinţă care va opera în locul ei,
diferite protocoale de invocare pot fi utilizate la nivelul acestui strat, ca de exemplu:
 invocare punct la punct unicast
 invocare a grupurilor de obiecte replicate
 suport pentru o strategie specifică de replicare
 suport pentru o referinţă persistentă spre obiectul remote
 strategii de reconectare

Stratul de referinţa la distanţă are două componente care cooperează astfel: componenta
client conţine informaţii specifice despre server-ul remote şi comunică via strat transport cu
componenta server.

Stratul de transport se ocupă de stabilirea conexiunii şi managementul acesteia, precum şi


de identificarea obiectului la distanţă. În general stratul de transport este responsabil pentru:

 realizarea conexiunii spre spaţiul de adrese îndepărtat


 managementul conexiunilor, monitorizarea stării conexiunii
 aşteptarea de apeluri şi realizarea unei conexiuni pentru un apel cerut de client
 păstrarea unei tabele de obiecte remote care exista în spaţiul de adrese
 localizarea dispecerului pentru destinaţia unui apel la distanţă şi transmiterea
conexiunii
Reprezentarea concretă a referinţei unui obiect remote constă dintr-un capăt de conexiune
şi un identificator de obiect, reprezentare numită “referinţa vie” (live reference). Fiind dată o
asemenea reprezentare pentru un obiect remote, un transportor poate folosi capătul de conexiune
pentru realizarea unei conexiuni la spaţiul de adrese în care se găseşte obiectul remote.
Transportorul conţine 4 abstracţii de bază:
 capăt de conexiune - abstractizarea unui spaţiu de adrese sau a unei JVM, pentru un
capăt de conexiune se poate obţine o instanţă specifică pentru transport

39
 canal - abstractizarea pentru calea dintre două spaţii de adrese, responsabil pentru
managementul conexiunilor între spaţii de adrese locale şi spaţiul de adrese remote
pentru care este definit canalul.
 conexiune - abstractizare pentru transferul datelor
 abstracţia de transport controlează canalele. Fiecare canal e o conexiune virtuală între
2 spaţii de adrese, într-un transport poate exista un singur canal pentru fiecare pereche
de spaţii de adrese, abstracţia de transport fiind responsabilă pentru acceptarea
apelurilor de pe conexiunile care se stabilesc spre spaţiul de adrese şi pentru pasarea
acestui apel spre straturile superioare din sistem.
 pentru acelaşi transport pot exista mai multe implementări (TCP-UDP pentru aceeaşi
maşina virtuală).

3.3.2.2 Mecanisme RMI

Modelul de obiecte distribuite. Numim obiect depărtat un obiect care oferă metode
apelabile de la distanţă, obiectele la distanţă sunt exemple ale unor clase ce implementează
metodele unor interfeţe la distanţă În terminologia client/server, obiectul depărtat îl vom numi
server, iar obiectul care invocă o astfel de metodă îl vom numi client.
Localizarea obiectelor la distanţă este realizată prin intermediul unui server de nume
(registrator - rmiregister), care stochează referinţe tip URL către obiecte la distanţă (protocolul
din URL poartă numele rmi). Serviciul de nume necesită următorul set de funcţiuni: introducere
de asocieri nume – obiect, căutări de asocieri, modificări / ştergeri de asocieri, listarea asocierilor
existente la un moment dat.
Interfaţa la distanţă. Legătura între server şi client este realizată prin intermediul unei
interfeţe de acces la distanţă. Definirea unei astfel de interfeţe trebuie să verifice următoarele
condiţii:
 trebuie declarată public
 trebuie să extindă interfaţa java. rmi. Remote
 fiecare metodă din interfaţa la distanţă trebuie să declare posibilitatea de a arunca
(throws) excepţia java. rmi. RemoteException
Implementarea interfeţei la distanţă respectă următoarele etape:
 obiectul server extinde java. rmi. server. UnicastRemoteObject şi implementează
interfaţa la distanţă
40
 se specifică constructorul obiectului server (si excepţia java. rmi. RemoteException)
 pentru obiectul server trebuie să se definească şi să se instaleze un manager de
securitate (pentru Java 2 acesta este RMISecurityManager).
 constructorul obiectului server foloseşte, printre altele, un fişier în care să se specifice
“politica de securitate” adoptată de către server (identificarea numelui acestui fişier
este realizată prin stringul atribuit variabilei java. security. policy la lansarea
serverului, fie prin: System. setProperty()).
 se înregistrează obiectul server la serverul de nume (rmiregister) sub numele dorit
(java. rmi. Naming. bind() sau java. rmi. Naming. rebind()).
 se implementează metodele apelabile de la distanţă (interfeţe la distanţă).

Serializare. Pentru transmiterea efectivă la distanţă a parametrilor şi a rezultatelor, RMI


foloseşte mecanismul de serializare (Object Serialization Protocol), protocol ce se bazează pe
mecanismul obişnuit de serializare, la care se adaugă un mecanism de adnotare a claselor.
Stub-ul şi skeleton-ul se ocupă cu detaliile de reţea (împachetarea şi despachetarea
parametrilor şi a valorilor returnate de către metode apelabile la distanţă) transformând parametri
şi valorile returnate în fluxuri de octeţi ce pot fi transmise prin reţea
Mecanismul prin care un obiect este transformat într-un flux de octeţi, şi mai apoi
reconstituit, se numeşte serializare, fiind deosebit de util pentru RMI şi alte aplicaţii în reţea. În
Java, orice obiect care implementează interfaţa java. io. Serializaile poate fi transformat într-un
flux de octeţi şi mai apoi reconstituit din acesta. Această interfaţă nu adaugă nici o metodă
necesar a fi implementată, ea este o interfaţă ataşabilă ce poate fi utilizată pentru a permite
serializarea claselor, în acest mod pot fi transferate obiecte complexe Java în reţea, fie ca
argumente ale unei metode, fie ca valori returnate.
Orice tip pe care îl folosim ca parametru sau valoare returnată la apelul unei metode la
distanţă trebuie să fie serializabil. Cerinţe de serializare a unei clase sunt:
 să posede un constructor public fără parametri, necesar pentru deserializarea corectă a
obiectelor
 să nu conţină referinţe la obiecte ce nu sunt serializabile (Java nu poate determina
complet dacă un obiect este sau nu serializabil în timpul compilării astfel dacă o dată
membră a unui obiect nu poate fi serializată, atunci obiectul în sine nu poate fi
serializat).

Obiecte exportabile prin RMI. Orice argument sau valoare returnată folosită într-un
apel RMI trebuie să fie serializabilă. RMI va serializa transparent obiectele (sau tipurile
41
primitive de date) trimise ca parametri sau returnate de metodele apelabile la distanţă. Spre
deosebire de apelurile locale, care transmit referinţe la obiecte, RMI copiază argumentele şi
valorile returnate de metodele la distanţă, astfel semantica transmiterii acestor valori este
“transmitere prin valoare”. Spre exemplu avem un obiect server, exportabil, care are o metodă
apelabilă la distanţă, metodă ce întoarce o referinţa la însăşi obiectul server în sine (this). În
cazul serverului, this se referă la însăşi instanţa actuala a serverului care este o entitate în maşina
virtuală Java locală. Daca această metodă este apelata de către client care rulează în alta maşină
virtuală Java, acesta client lucrează cu stub-ul ca un mod de a reprezenta serverul (proxy pentru
obiectul server), deci în momentul în care serverul întoarce printr-o anumită metodă o referinţă la
el însuşi, clientul primeşte o referinţă la stub-ul serverului.
Metodele apelabile la distanţă verifica parametri şi valorile returnate care implementează
interfaţa Remote. De fiecare dată când este întâlnit un astfel de obiect exportabil, el este înlocuit
transparent cu stub-ul asociat lui. În momentul în care serverul întoarce o referinţă la el însuşi, în
urma apelului unei anumite metode, RMI converteşte serverul la stub-ul său pentru ca clientul să
îl poată folosi. Acest mod transparent de a schimba argumente asigură invizibilitatea stub-ului
atât în server cât şi în client. Atât serverul cât şi clientul au iluzia că lucrează cu obiecte locale,
fiindcă chiar şi referinţa this poate fi folosită prin RMI între mai multe maşini virtuale Java.
Astfel obiectele exportabile, apelabile la distanţă sunt transmise prin referinţă ca într-un
apel Java normal. Când transmitem un obiect la distanţă ca argument sau valoare returnată de
către o metodă la distanţă, se primeşte o referinţă a obiectului la distanţă ce poate fi utilizata atât
în server cât şi în client. Transmiterea unui obiect la distanţă nu se realizează prin copierea
întregului obiect, ci doar stub-ul, care poate fi gândit ca o referinţă la obiectul la distanţă. Un
stub este serializabil, ceea ce înseamnă că poate fi transmis într-un apel de metodă la distanţă ca
orice alt obiect Java neexportabil (adică prin valoare).

Adnotarea claselor în RMI. Adnotarea claselor denotă mecanismul prin care în fluxul
de date serializat se adaugă şi o adresă de unde se poate obţine la nevoie codul binar Java al
clasei respective, mecanism fundamental pentru implementarea transferului de comportament în
RMI.
Pentru a realiza adnotarea unei clase la scriere (serializare) în loc să se utilizeze un obiect
instanţiat direct din ObjectOutputStream se utilizează un obiect instanţiat din clasa derivată
MarshalOutputStream, în care se defineşte metoda annotateClass(). Pentru a încărca clasele
adnotate (operaţia inversă serializării) se utilizează un obiect instanţiat din MarshalInputStream
care derivă din ObjectInputStream şi care defineşte metoda resolveClass(). Adresa cu care se
face adnotarea se transmite sub forma unui URL.

42
La împachetarea argumentelor pentru RMI (marshalling) se utilizează pentru fiecare
obiect argument metoda annotateClass() care testează dacă o clasă este locală sau a fost adusă de
un încărcător (loader) de la distanţă. În acest caz (de un URLClassLoader spre exemplu), se
interoghează încărcătorul respectiv asupra adresei de origine şi se adnotează cu aceasta clasa, în
caz contrar, RMI nu poate determina adresa pe baza originii clasei (de exemplu, o clasă încărcată
local din CLASSPATH). Pentru a adnota astfel de clase RMI are nevoie de o adresă dată explicit
prin intermediul proprietăţii java. rmi. server. codebase, proprietate ce permite chiar specificarea
mai multor adrese alternative. Dacă această proprietate este însă vidă, atunci clasele nu vor fi
adnotate, iar cel care le receptează trebuie să determine prin alte mijloace adresa de la care le
poate încărca.

rmiregister

3 3
Naming. 0 Naming.
rebind LocateRegistry lookup
(optional)

obiect obiect
server client

1
1
java. security. java. security.
2 policy 4
policy
apel metoda 2
setSecurityManag (obiect) setSecurityManag.

Figura 4. Scenariul utilizării


RMI

Rezolvarea claselor în RMI. "Rezolvarea" unei clase înseamnă obţinerea codului


corespunzător metodelor sale. La despachetarea argumentelor (unmarshalling) se apelează pentru

43
fiecare descriptor de clasă metoda resolveClass() din MarshalInputStream, responsabilă cu
încărcarea claselor necesare pentru instanţierea obiectului.
Înainte de a preciza strategia de rezolvare a claselor, este necesară specificarea modului
în care se poate obţine codul binar al clasei, astfel există trei metode posibile:
 pe baza adnotării aferente clasei transmisă prin RMI Wire Protocol
 pe baza unei proprietăţi globale pentru toate clasele recepţionate fără adnotare
 prin intermediul unui încărcător special.
Proprietatea globală care poate fi interogată este tot java. rmi. server. codebase. Se
observă că această proprietate oferă o adnotare automată a claselor ce nu prezintă una explicită
atât la transmiterea cât şi la recepţionarea fluxului serializat, mecanism numit adnotare implicită.
Încărcătorul special menţionat poartă denumirea de încărcător contextual (context class loader).
Acest mecanism este specific Java 2 şi este foarte flexibil deoarece pentru fiecare fir de execuţie
se poate specifica un încărcător contextual diferit. La instanţierea unui nou fir de execuţie, acesta
moşteneşte încărcătorul contextual al părintelui.

Etapele de rezolvare a claselor sunt:


 modalitatea "clasică" de rezolvare care se aplică tuturor claselor
serializate, presupune căutarea în stivă (prin intermediul unei metode native) a
unei clase cu încărcătorul definitor (defining class loader) nenul. Dacă există,
acest încărcător este invocat pentru a rezolva clasa serializată.
 se testează dacă clasa este adnotată, dacă nu este se va folosi drept
adnotare implicită java. rmi. server. codebase (comportament ce poate fi forţat
chiar dacă clasa este adnotată în fluxul serializat, cu condiţia ca proprietatea
globală java. rmi. server. useCodebaseOnly să aibă valoarea true), insa pentru ca
adnotarea să fie luată în consideraţie este necesar să fie activ un manager de
securitate.
 se presupune activ un manager de securitate, ordinea în care se încearcă
rezolvarea este întotdeauna: adnotarea şi apoi încărcătorul contextual. Evident, în
absenţa unui manager de securitate se va încerca direct încărcătorul contextual, iar
dacă acesta eşuează se va afişa un mesaj explicit ce avertizează utilizatorul că
adnotarea nu a fost luată în considerare.

Astfel proprietatea java. rmi. server. codebase poate fi utilizată pentru adnotare atât de
către cel care transmite clasele cât şi de cel care le recepţionează, insa este necesara stabilirea
unei politici adecvate în acest sens. Să presupunem că dorim să realizăm o aplicaţie, în care un

44
server transmite un comportament care va fi executat de către clienţi. Există trei posibilităţi şi
anume:
 setarea proprietăţii codebase doar la client, astfel clasele vor sosi fără vreo
adnotare la acesta şi se va folosi adnotarea implicită.
 setarea proprietăţii codebase doar la server, atunci clasele vor sosi direct adnotate.
 setarea proprietăţii codebase şi la client şi la server, atunci clasele vor sosi
adnotate de pe server, iar adnotarea implicită a clientului va fi ignorată. Se
observă că în acest scenariu transferul va funcţiona indiferent unde se specifică
proprietatea codebase.
Să presupunem însă că dorim să ne conectăm cu clientul la mai multe servere simultan şi
că nu toate serverele au codul comportamentului la aceeaşi adresă. În această ipoteză clientul
trebuie să primească cod de la fiecare server, iar adnotările trebuie să fie specifice fiecărui server,
caz în care este utila a doua soluţie, în care fiecare server va adnota corespunzător fluxul său de
date, astfel încât clientul să poată obţine fiecare comportament de la sursa corespunzătoare.

Încărcătorul contextual. Principalul dezavantaj al utilizării proprietăţii codebase


provine din faptul că evaluarea acesteia se face o singură dată în momentul iniţializării RMI.
Practic aceasta înseamnă că proprietatea trebuie să primească valoarea corespunzătoare la
lansarea în execuţie (de exemplu, prin linia de comandă) sau imediat după lansarea în execuţie,
înainte de execuţia oricărui apel RMI, sau de exportarea vreunui obiect.
În anumite condiţii această restricţie poate să ridice probleme delicate. Să presupunem că
scriem o bibliotecă ce utilizează RMI şi transferul de comportament. Aplicaţia client care
utilizează această bibliotecă poate utiliza la rândul său RMI, nu neapărat direct, ci prin
intermediul altei biblioteci. Dacă şi clientul şi biblioteca setează proprietatea codebase la valori
diferite aplicaţia va funcţiona eronat. Chiar dacă se adaugă valori la codebase (în loc să se
rescrie), tot pot apare probleme legate de momentul în care RMI va evalua proprietatea.
În astfel de situaţii este util încărcătorul contextual. Firul de execuţie curent este
întotdeauna interogat cu privire la încărcătorul contextual când este necesar transferul de cod,
deci modificările care apar pe parcursul execuţiei programului vor fi tratate corect de RMI.
Trebuie să subliniem că, în absenţa unui manager de securitate, încărcătorul contextual va
fi apelat ori de câte ori este necesar transferul de cod. În caz contrar, încărcătorul contextual va fi
utilizat doar pentru clasele ce sosesc fără o adnotare de la sursă.
Fiind specific fiecărui fir de execuţie, încărcătorul contextual rezolvă problema pe care o
ridica utilizarea proprietăţii codebase la destinaţie - imposibilitatea primirii de comportament din
surse multiple. Tot ceea ce trebuie să facem este să recepţionăm comportament din surse diferite

45
pe fire de execuţie distincte. Concret, metodele de setare şi obţinere a încărcătorului contextual
se găsesc la nivelul clasei Thread şi sunt:

ClassLoader getContextClassLoader() void setContextClassLoader(ClassLoader cl)

Încărcătorul contextual poate fi setat doar la destinaţia comportamentului. Din acest motiv,
utilizarea sa este mai puţin directă. Trebuie să trimitem mai întâi de la sursa comportamentului
adresa de unde se pot obţine clasele. Asta se poate realiza printr-un apel RMI care să nu implice
transfer de cod.
Mecanismul de reflecţie. Începând cu Java 1. 2. facilităţile de reflecţie au fost utilizate
pentru a proiecta un distribuitor generic al cererilor de obiecte cu scopul de a evita skeletoanele.
Proxiurile la client sunt generate folosind compilatorul rmic din clasele server compilate şi nu
din definiţiile interfeţelor remote.

3.3.2.3 Clase şi interfeţe RMI

Clase şi interfeţe client. În dezvoltarea părţii de client a unei aplicaţii/applet se utilizează


interfaţa Remote şi clasele RemoteException şi Naming. alături de o serie de excepţii derivate
din RemoteException şi clasa RMISecurityManager utilizată la încărcarea claselor stub în
aplicaţii.
Clasa Naming constituie mecanismul prin care clienţii pot obţine referiri la obiectele la
distanta (ea este folosită şi de server pentru înregistrarea obiectelor cu rol de server la distanţă),
localizarea obiectelor la distanţă are la bază mecanismul URL, clasa are doar metode statice şi nu
defineşte constructori, metodele sale uzuale sunt lookup (), String(), bind(), rebind() unbind()
utilizate pentru înregistrarea serverelor.

Clase şi interfeţe server. Exceptând clasa RMISecurityManager care se găseşte în


pachetul java. rmi, toate celelalte clase şi interfeţe utilizate în programele server se găsesc în
pachetul java. rmi. server.

Clasa remoteObject reimplementează metodele hashcode şi equals ale clasei Object


pentru a permite memorarea referirilor de obiecte la distanţă în tabele de hasing şi compararea

46
acestor referiri. Constructorii protected RemoteObject() şi protected RemoteObject(RemoteRef
newref) creează un obiect la distanţă iniţializat cu referirea specificată.
Clasa RemoteServer este o superclasă pentru implementări de servere şi oferă o gamă
variată de semantici pentru referirile la distanţă. Toate metodele clasei sunt statice. Metoda
getClient-Host apelata dintr-un fir de execuţie aflat în cursul tratării unui apel de metodă la
distanţă returnează numele calculatorului pe care rulează clientul, iar celelalte metode stabilesc
identitatea fluxului utilizat la crearea unui jurnal de apeluri la server.

package java. rmi. server;


public abstract class RemoteServer extends RemoteObject{
protected RemoteServer();
protected RemoteServer (remoteRef ref);
public static String getClientHost()
public static void setLog(java. io. OutputStream out);
public static java. io. PrintStream getLog();
}

Clasa UnicastRemoteObject. Această clasa derivă din RemoteServer şi oferă suport


pentru referiri punct la punct la obiecte active bazat pe fluxuri TCP. Astfel serverele derivate vor
fi nereplicate, iar referirile la ele vor fi doar pe durata de viaţă a procesului ce l-a creat.

package java. rmi. server;


public class UnicastRemoteObject extends RemoteServer {

protected UnicastRemoteObject()
protected UnicastRemoteObject(int port)
protected UnicastRemoteObject(int port, RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
public Object clone()
public static RemoteStub exportObject(java. rmi. Remote obj)
public static Remote exportObject(java. rmi. Remote obj, int port)
public static Remote exportObject(Remote obj, int port, RMIClientSocketFactory
csf, RMIServerSocketFactory ssf)
public static boolean unexportObject(java. rmi. Remote obj,
boolean force)

47
}

Clasa RMI SecurityManager. În absenţa managerului de securitate, RMI nu va putea


încărca clasele stub decât din sistemul local de fişiere (CLASSPATH). Managerul de securitate
permite aplicaţiei să determine înaintea oricărei operaţii potenţial periculoase dacă ea se va
efectua prin încărcătorul de clase sau din sistemul local, astfel aplicaţia poate autoriza sau
dezautoriza operaţia. Dacă operaţia nu e permisă se va genera excepţia SecurityException.

Majoritatea metodelor au nume care încep cu check iar utilizarea lor se face după
următoarea schemă:
SecurityManager security=System. getsecurityManager();
if (security !=null){
Security. checkxxx(argument, …);
}

Câteva metode din Clasa RMISecurityManager sunt:

 public synchronized void checkAccess (Thread t) throws RMISecurityException -


stuburile nu pot modifica argumentul Thread
 checkCreateClassLoader () – stuburile nu pot crea incarcătoare şi nici să execute
metodele clasei ClassLoader
 checkpropertiesAccess() (String key) – stuburile nu pot accesa lista de proprietăţi
a sistemului ci doar cele etichetate ca accesibile
 checkListen(int port) – stuburile nu pot asculta la nici un port
 checkConnect(String host, int port, Object context) clasele încărcate pot face
conectări dacă sunt apelate prin transportul RMI.

Clasa RMIClassLoader – este un utilitar poate fi folosit de aplicaţii pentru a încarca


clase de la un URL. Metodele sale sunt:

 public static class loadClass(String name) – foloseşte proprietatea java. rmi.


server. codebase pentru a setermina URL –ul de la care se încarcă
 public static synchronized Class LoadClass(URL codebase, String name)

48
 public static Object getSecurityContext(ClassLoader loader) – returnează
contextul de securitate

Procesele server trebuie să declare mediului de execuţie RMI localizarea claselor stuburi
şi parametri/valori returnate ce vor fi disponibile clienţilor prin această proprietate.

Interfaţa LoaderHandler – este implementată de o clasa LoaderHandler, iar metodele


sale sunt folosite de RMIClassLoader pentru efectuarea operaţiilor sale.
Clasa abstractă RMI SocketFactory – specifică modul în care transportul RMI trebuie să
obţina socketuri. Specificarea clasei este următoarea:

package java. rmi. server;


public abstract class RMISocketFactory
implements RMIClientSocketFactory, RMIServerSocketFactory
{
public abstract Socket createSocket(String host, int port)
public abstract ServerSocket createServerSocket(int port)
public static void setSocketFactory(RMISocketFactory fac)
public static RMISocketFactory getSocketFactory() {. . . }
public static void setFailureHandler(RMIFailureHandler fh) {. . . }
public static RMIFailureHandler getFailureHandler() {. . . }
}

Serviciul de înregistrare a obiectelor (de nume)

Pachetul java. rmi. registry conţine două interfeţe Registry şi RegistryHandler precum şi
clasa LocateRegistry ce realizează serviciul de înregistrare şi regăsire a obiectelor la distanţă
folosind nume simple. E permis ca fiecare process server să îşi definească propriul registru de
obiecte sau să folosească un singur registru pentru un host. Registrul este un obiect la distanţă la
rândul său.
Interfaţa registry specifică metodele de căutare, legare, relegare, ştergere şi listare a
conţinutului unui registru. Operaţii bind/rebind/unbind sunt premise doar dacă solicitanţii sunt pe
acelaşi host ca şi serverul însă operaţia lookup este permisă de oriunde.

49
Clasa LocateRegistry - conţine metodele statice ce returnează o referinţă la un registru, o
metodă de creare registru, referinţele returnate sunt referinţe la un stub la distanţă al registrului.

package java. rmi. registry;


public final class LocateRegistry {
public static Registry getRegistry()
public static Registry getRegistry(int port)
public static Registry getRegistry(String host)
public static Registry getRegistry(String host, int port)
public static Registry getRegistry(String host, int port, RMIClientSocketFactory
csf)
public static Registry createRegistry(int port)
public static Registry createRegistry(int port, RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
}

Metodele tip get returnează referiri al registrul hostului curent şi pentru portul specificat
(portul pentru Registry este 1099). Metoda CreateRegsitry creează şi exportă un registru pe
hostul local, registru ce implementează un serviciu de nume simplu, în care numele unui obiect
la distanţă (String) este asociat unei referinţe la distanţă. Legăturile astfel create sunt valabile
doar pentru activarea curentă a registrului.
Interfaţa RegistryHandler este utilizată pentru legătura cu o implementare particulară a
serverului de nume astfel:

public interface RegistryHandler{


Registry regitsryStub(String host, int port)
Registry registryImpl(int port)
}

Clase şi interfeţe pentru stuburi şi skeletoane

Clasa RemoteStub – este superclasa comună stuburilor, ea oferă un cadru ce permite


implementarea unor semantici diferite pentru referire la distanţă.

package java. rmi. server;

50
public abstract class RemoteStub extends java. rmi. RemoteObject {
protected RemoteStub() {. . . }
protected RemoteStub(RemoteRef ref) {. . . }
protected static void setRef(RemoteStub stub,
RemoteRef ref) {. . . }
}

Clasa RemoteCall – este abstracţiunea utilizată de stuburi şi skeletoane pentru a transfera


un apel la un obiect remote şi are următoarea specificare:

package java. rmi. server;


import java. io. *;

public interface RemoteCall {


ObjectOutput getOutputStream() throws IOException;
void releaseOutputStream() throws IOException;
ObjectInput getInputStream() throws IOException;
void releaseInputStream() throws IOException;
ObjectOutput getResultStream(boolean success) throws IOException,
streamCorruptedException;
void executeCall() throws Exception;
void done() throws IOException;
}

Primele metode referă fluxurile de obiecte prin care se realizează serializarea


argumentelor, metoda GetResultStream returnează un flux de ieşire, după ce marchează în antet
informaţie referitoare la succesul apelului, obţinerea fluxului cu rezultate trebuie să reuşească o
singură dată pentru fiecare apel. Metoda ExecuteCall conţine ceea ce este necesar pentru
efectuarea apelului, iar done eliberează resursele după terminarea apelului remote. Versiunile
post JDK 1. 2. au depreciate această interfaţă în favoarea utilizării metodei invoke.
Interfaţa RemoteRef – defineşte un descriptor (handle) pentru un obiect la distanţă,
fiecare stub integrează câte un exemplar RemoteRef ce conţine reprezentarea concretă a
referinţei. Metoda NewCall permite crearea unui obiect de apel adecvat pentru un nou apel de

51
metodă la distanţă obj. Tabloul de operaţii op conţine operaţiile disponibile asupra obiectului la
distanţă iar num este un indice în acest tablou prin care este indicată operaţia apelului curent.

package java. rmi. server;


public interface RemoteRef extends java. io. Externalizable {

Object invoke(Remote obj, java. lang. reflect. Method method, Object[] params, long
opnum) throws Exception;
RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
long hash) throws RemoteException;
void invoke(RemoteCall call) throws Exception;
void done(RemoteCall call) throws RemoteException;
String getRefClass(java. io. ObjectOutput out);
int remoteHashCode();
boolean remoteEquals(RemoteRef obj);
String remoteToString();
}
Interfaţa ServerRef reprezinta descriptorul de server pentru implementarea unui obiect la
distanţă. Metoda exportObject caută sau creează un obiect stub client pentru implemenetarea
obiectului Remote obj. Astfel server este obiectul server la distanţă pentru implementare poate fi
identic cu obj), iar data conţine informaţiile necesare exportării obiectului.

package java. rmi. server;


public interface ServerRef extends RemoteRef {

RemoteStub exportObject(java. rmi. Remote obj, Object data)


throws java. rmi. RemoteException;
String getClientHost() throws ServerNotActiveException;
}

Interfaţa Skeleton este utilizată în implementarea skeletoanelor generate de compilatorul


rmic. Metoda dispatch deordonanţează argumentele din fluxul de intrare obţinut de la obiectul
call, apelează metoda opnum pe implementarea efectiva a obiectului obj şi ordonanţează
valoarea returnată.

52
package java. rmi. server;
public interface Skeleton {
void dispatch(Remote obj, RemoteCall call, int opnum, long hash)
throws Exception;
Operation[] getOperations();
}

Clasa Operation – menţine descrierea unei metode pentru un obiect la distanţă


public class Operation{
public Operation (String op);
public String getOperation();
pub;ic String toString();
}

Clasele şi interfaţa pentru colectorul de deşeuri

Într-un sistem distribuit, la fel ca într-un sistem local, este de preferat a se şterge automat
acele obiecte remote care nu mai sunt referenţiate de nici un client. Astfel, programatorul e
eliberat de sarcina neplăcuta de a tine evidenţa obiectelor remote client. RMI foloseşte un
algoritm de garbage collection bazat pe numărarea referinţelor.
Pentru a implementa algoritmul garbage collection, RMI runtime ţine evidenta a tuturor
referinţelor active din fiecare JVM, astfel când o referinţă activă intră într-o maşină virtuală
JVM, contorul sau de referinţă e incrementat. Pe măsură ce referinţe active sunt găsite
nereferenţiate de JVM, contorul asociat este decrementat. Când ultima referinţă a fost ştearsă un
mesaj de nereferenţiere este trimis la server. Protocolul este destul de complex, pentru că se ţine
seama mai ales de menţinerea ordonării mesajelor de referenţiere şi dereferenţiere, astfel încât
obiectul să nu fie prematur colectat.
Interfaţa DGC (Distributed Garbage Collector) este utilizată în server de algoritmul
distribuit de colectare a deşeurilor şi implementează metodele dirty şi clean. Un client apelează
dirty atunci când deordonanţează o referire la distanţă iar dacă nu mai are referiri la distanţă va

53
apela clean. Referirile la obiectele la distanţă sunt împrumutate (lease) de către clienţi pe
perioade specificate ce încep în momentul primirii apelului dirty. Este responsabilitatea
clientului să reînnoiască împrumuturile înainte de expirare, altfel se presupune că obiectul nu
mai e referit. Un obiect conţine un identificator unic al clientului, (VMID) pentru fiecare obiect
la distanţă exportat în maşina locală colectorul (GC) menţine o listă de referiri (identificatori ai
clienţilor ce au referit obiectul). Este necesar un singur apel la dirty pentru fiecare obiect chiar
dacă clientul deţine mai multe referinţe pentru acel obiect. Descrierea sucintă a claselor:
1. Clasa Lease conţine VMID şi o durată de împrumut
2. Clasa ObjID identifică unic obiectele remote pentru fiecare maşină virtuală, acesta
conţine un număr de obiect şi un identificator al spaţiului de adrese. Clasa Objid
reimplementează metodele hashCode, equals şi toString
3. Clasa UID creează identificatori unici pentru hostul pe care s-au generat pentru a
permite identificarea spaţiului de adrese.
4. Clasa VMID oferă identificatori unici universali în raport cu toate maşinile JVM(UID
şi adresa de host)
In cazul în care în reţea apare o partiţionare forţată între clienţi –servere e posibil să apară
referinţe invalide fiind astfel necesare mecanisme suplimentare pentru gestionarea lor corectă.

3.3.2.4 Alte mecanisme RMI

Fluxul de date, flux de cod. Transfer de comportament Java

O aplicaţie care doreşte să transfere comportament va utiliza două fluxuri de informaţie:


fluxul de date (transmis prin RMI Wire Protocol) şi fluxul de cod binar Java.
Fluxul de date: RMI Wire Protocol. Funcţionarea RMI se bazează pe protocolul RMI
Transport Protocol care realizează implementarea fluxului de date între apelant şi apelat
(protocol de nivel aplicaţie), el încapsulând celelalte protocoale folosite. Protocolul în sine este
suficient de flexibil ca să pară transparent pentru programatori, el implementează trei tipuri de
conexiuni: directe, multiplexate şi încapsulate, în mod implicit atât conexiunile directe cât şi cele
multiplexate se efectuează peste TCP.
Conexiunile directe pot fi utilizate atunci când nu există restricţii de securitate la nivelul
maşinii virtuale a serverului şi nici la nivelul reţelei. Conexiunile multiplexate sunt utile atunci

54
când se doreşte exportarea unor obiecte dintr-un applet (exportarea este acţiunea prin care un
obiect devine invocabil de la distanţă).
Conexiunile încapsulate se utilizează atunci când clientul se află într-un intranet protejat
de un firewall care limitează accesul către exterior. Pentru conexiunile încapsulate clientul
împachetează apelul într-o cerere HTTP POST, răspunsul obiectului apelat fiind împachetat la
rândul său într-un răspuns HTTP.
Pentru a transmite cererea sunt disponibile două metode:
 Acces direct - se încearcă adresarea acesteia direct către portul pe care
ascultă obiectul de pe server, dacă firewall-ul lasă să treacă cereri HTTP către
porturi arbitrare, atunci această metodă va reuşi, iar obiectul va fi apelat direct. În
caz contrar, se trimite cererea către portul 80 al serverului, în speranţa că firewall-
ul permite conexiuni către porturi HTTP standard.
 Acces indirect – e necesar ca pe maşina pe care se găseşte obiectul apelat
să ruleze un server Web care să poată executa un anume program CGI (java-rmi.
cgi). Acest program va citi antetul cererii POST şi pe baza acestuia va înainta
cererea către portul pe care ascultă obiectul apelat.
Prin conexiunea stabilită prin una din aceste metode sunt transmise invocările la distanţă
şi obţinute rezultatele. Prin intermediul primelor două tipuri de conexiune se pot transmite mai
multe apeluri, însă conexiunea încapsulată permite un singur apel, după care trebuie efectuată o
nouă conexiune.

Transfer de cod (comportament). Pentru a încapsula fluxul de cod binar se pot folosi
protocoalele Internet pentru transferul de fişiere suportate de maşina virtuală Java (FTP, HTTP).
Nu este nevoie de un server Web pentru a testa transferul de cod, fiind posibilă folosirea oricărui
protocol pentru care există un handler instalat, bayat pe faptul că RMI foloseşte un
URLClassLoader pentru a transfera codul binar al claselor ce prezintă adnotare.

Redefinirea socketurilor RMI

O facilitate deosebit de utilă este aceea de a permite utilizatorului să redefinească


mecanismul de generare al socketurilor folosite de implementarea RMI, fapt ce permite
integrarea de capabilităţi speciale pentru situaţiile în care se impune o anumită politică de
securitate în reţea şi trebuie să existe control asupra porturilor utilizate de RMI. Aceasta este

55
realizata prin modificarea fluxului de date transmis (cum ar fi utilizarea RMI peste protocolul de
transmisie securizata SSL -Secure Sockets Layer) asigurând astfel prin criptare securitatea
comunicaţiilor prin utilizarea unui mecanism specific numit Custom RMI Socket Factory.
Disponibil în JDK 1. 1, RMISocketFactory face posibilă construirea unei “fabrici” care
să producă socketuri, însă odată instanţiata “fabrica” aceasta putea produce numai socketuri de
acelaşi tip. Prin introducerea clasei java. rmi. server. SocketType se oferă posibilitatea construirii
unui RMISocketFactory care poate genera cel mai potrivit tip de socket pentru un anumit obiect.
Practic, se oferă utilizatorului RMI posibilitatea de a redefini fabrica ce produce soclurile
utilizate de RMI, redefinire introdusă încă din JDK 1. 1, însă o serie de restricţii destul de severe
au făcut ca această facilitate să nu poată fi exploatată corespunzător în JDK 1. 1, astfel:
 aceeaşi fabrică de socluri era necesar a fi folosită pentru toate obiectele
invocabile de la distanţă,
 era necesar să existe un registru RMI (rmiregistry) pentru fiecare tip de
socluri, iar
 clasele fabricii de socluri nu puteau fi aduse de la distanţă ci era obligatoriu să
fie încărcate local.

Limitările prezentate au dispărut în JDK 1. 2 astfel mecanismul în sine este analog cu


fabricile de socluri "clasice" din pachetul java. net, astfel concret, trebuie dată o implementare
următoarelor două interfeţe:
public interface RMIClientSocketFactory { public Socket createSocket(String host, int
port) throws IOException; }
public interface RMIServerSocketFactory { public ServerSocket createServerSocket(int
port) throws IOException; }

Tipul soclurilor (tip client pentru cel care iniţiază o conexiune, tip server ascultă în
aşteptarea unei conexiuni) utilizate de un obiect invocabil la distanţă se stabileşte la momentul
exportării obiectului. Presupunând că obiectul este derivat din UnicastRemoteObject, va fi
suficient să-l construim prin intermediul unui constructor care primeşte ca argumente fabricile de
socluri: protected UnicastRemoteObject(int port, RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
Ambele tipuri de socluri se transmit ca parametri. Fabrica de socluri server va fi folosită
de către obiect pentru a instanţia socluri pe care se vor primi conexiuni de la clienţi, iar fabrica
de socluri client nu e folosită ca atare de obiectul server, ci se va transmite clienţilor pentru ca
aceştia să se poată conecta la server.

56
Putem imagina un client care contactează un server prin RMI "obişnuit", stabileşte de
comun acord cu acesta ca sesiunea să se desfăşoare criptat, după care utilizează o fabrică de
socluri cu criptare pentru restul comunicaţiei, iar fabrica ce generează soclurile cu criptare poate
fi transmisă de la server la client pe parcursul execuţiei acestuia.

Apeluri inverse (tip callback)

În programarea concurentă, noţiunea de invocare la distanţa integrează un aspect


suplimentar: posibilitatea ca maşina server să "întoarcă un răspuns", adică să determine
executarea unei metode pe maşina client, facilitate suplimentară ce poartă numele de apel invers-
callback.
Pentru a putea realiza apelurile inverse este necesar să se definească o nouă interfaţă la
distanţă şi să se implementeze aceasta interfaţă de către client, iar interfaţa la distanţă
implementată de server va trebui să prevadă o metodă prin care clienţii îşi pot înregistra la server
interesul pentru a fi anunţaţi de apariţia anumitor modificări în starea serverului.
Principial, lucrurile decurg analog ca la invocarea la distanţă a unei metode. Fie metC
metoda care trebuie invocată pe maşina client din cadrul metodei metS. Este evident necesar ca
pe maşina client să fie creat un obiect ObC de tipul clasei care include metoda metC, iar maşina
server sa primească o referinţă la acest obiect, pentru ca (pe baza acestei referinţe) să poată
invoca metoda metC, ce va fi executată pe maşina client. Implementarea apelurilor inverse va fi
mai simpla, deoarece legătura între maşini este deja stabilită.
Într-adevăr, pentru realizarea apelurilor inverse, trebuie întreprinse doar următoarele două
acţiuni: 1) crearea obiectului şi pregătirea lui pentru a fi exportat; 2) transmiterea obiectului
maşinii server.
Prima acţiune presupune ca ObC este o instanţă a unei clase ce extinde interfaţa Remote.
Pregătirea sa pentru export este realizata prin invocarea următoarei metode publice şi statice a
clasei UnicastRemoteObject: RemoteStub exportObject(Remote ObC) throws RemoteException.
A doua acţiune poate fi realizată simplu, comunicând serverului obiectul ObC prin includerea lui
ca argument la invocarea unei metode prin intermediul referinţei la obiectul ObS. Se presupune
că obiectul ObC este de tipul unei clase serializabile

Obiecte activabile

57
În JDK 1. 2, mecanismul RMI se îmbogăţeşte cu obiecte activabile la distanţă. Acestea
reflecta un mecanism prin intermediul căruia se pot activa obiecte server doar atunci când este
nevoie de ele şi se folosesc identificatori persistenţi pentru a putea referi obiectele şi atunci când
acestea sunt inactive, aceasta conduce evident la o folosire mai eficientă a memoriei pe maşina
server
De lansarea în execuţie a acestor obiecte activabile este responsabil un demon (rmid) ce
lansează maşini virtuale Java în care rulează efectiv obiectele. Pentru a nu crea un număr excesiv
de maşini virtuale şi pentru a permite cooperarea între obiectele server, acestea pot fi adunate în
grupuri de activare; toate obiectele din acelaşi grup fiind executate în aceeaşi maşină virtuală
Prin introducerea clasei java. RMI. activation. Activatable şi a demonului RMI, rmid,
obiectele remote pot fi create şi executate atunci când este nevoie de ele, programele trebuie doar
să înregistreze informaţiile de implementare despre obiectele remote şi demonul rmid va furniza
instanţa obiectului atunci când va fi nevoie de ea.

58
Elemente de securitate

RMI pune la dispoziţie pentru securizarea canalelor de comunicatei între client şi server
un mecanism de izolare a implementărilor aduse intr-un ‘sand box’ securizat pentru a proteja
sistemul de posibile atacuri efectuate de clienţi nesiguri. Este important a se defini nevoile de
securitate pentru a stabili reguli stricte ce se vor aplica pentru toţi clienţii. S-ar putea să fie
nevoie a se securiza un canal de comunicaţie între client şi server.

RMI permite furnizarea unui constructor de socket-uri care permite crearea unor socket-
uri de diferite tipuri, inclusiv socket-uri criptate, care vor fi folosite la comunicaţie între client şi
server. Începând cu JDK 1. 2 se vor putea specifica cerinţele pentru serviciile oferite pentru
socket-urile server-ului. Aceasta nouă tehnică este utilă în applet-uri, unde majoritatea browser-
elor refuză permisiunea de setare a unui constructor de tipuri de socket-uri. Clasele aduse
remote prezintă alte probleme de securitate, securizarea acestora este realizată via un obiect de
tip SecurityManager, care va superviza orice acţiune ce implică un nivel de securitate mai
deosebit, cum ar fi deschiderea de fişiere, stabilirea conexiunilor pentru reţea etc. RMI
furnizează un tip RMISecurityManager, care e la fel de restrictiv ca acele tipuri folosite pentru
securizarea applet-urilor, astfel se previne ca implementările aduse remote să poată citi date
sau scrie date locale, sau să creeze conexiuni spre alte sisteme din spatele firewall-urilor. Se
poate de asemenea scrie şi instala un obiect propriu de securitate pentru a forţa diferite politici
de securitate specifice.
Dacă se încearcă execuţia pe Java 2 a unei aplicaţii RMI scrise pentru JDK 1. 1., se va
constata că aceasta nu rulează conform aşteptărilor. Politica implicită de securitate este prea
restrictivă şi împiedică execuţia aplicaţiilor RMI. Nu este însă necesar (şi nici recomandabil) să
se altereze politica implicită a JDK, ci este preferabil să se definească o politică particulară
aplicaţiei ce ridică probleme. Pentru a lansa în execuţie o aplicaţie Java cu altă politică decât cea
implicită se poate folosi un fişier de configurare care să definească noua politică. Apoi, maşina
virtuală trebuie instruită să folosească noua politică plasând numele fişierului respectiv în
proprietatea globală java. security. policy.
O soluţie care sa ofere o politică optimă de securitate care să permită execuţia aplicaţiei,
dar să nu ofere drepturi superflue presupune să se pornească cu politica implicită de securitate şi
să se monitorizeze execuţia aplicaţiei, observând ce încălcări ale politicii de securitate împiedică
buna funcţionare. Pentru monitorizarea verificărilor efectuate de managerul de securitate trebuie
ca proprietatea globală java. security. debug să conţină o listă ce precizează tipurile
evenimentelor monitorizate: access sau failure. Vom porni iniţial cu un fişier MYpolicy. sec care
nu conţine nici o permisiune suplimentară. Trebuie precizat că acest fişier va extinde (nu înlocui)

59
politica implicită. Procedăm apoi incremental: executăm aplicaţia, observăm permisiunile pe
care le solicită dar nu le primeşte, le adăugăm în fişierul MYpolicy. sec, după care de reia ciclul.
Un asemenea fişier ar putea avea următorul conţinut:

grant {
permission java. io. filePermission “/tmp/*”, “read”, “write”;
permission java. net. SocketPermission “somehost. somedomain. com:999”, ”connect”;
permission java. net. SocketPermission “*:1024-65535”, ”connect, request”;
permission java. net. SocketPermission “*:80”, ”connect”;
};

RMI furnizează o platformă solidă pentru aplicaţii orientate obiect distribuite. Se poate
utiliza RMI atât pentru a conecta obiecte Java între ele, cât şi obiecte Java cu obiecte
implementate în alte limbaje. Se va observa că folosind Java în mediul de programare se obţin
toate beneficiile acesteia: portabilitate largă, costuri mici de întreţinere, siguranţa şi securitatea
mediului. RMI oferă posibilitatea extinderii Java în orice parte a sistemului într-un mod
incremental, adăugând noi clienţi şi servere Java atunci când este necesar.

3.3.2.5. Aplicaţii client –server bazate pe mecanismul RMI

Etapele proiectării/implementării unei aplicaţii distribuite RMI sunt:


 definirea interfeţei remote
 implementarea interfeţei
 dezvoltarea serverului
 dezvoltarea clientului
 generare stuburi/skeletoane, pornire RMI registry
 stabilire/definire/implementare politici de securizare

Capitolul IV

AFACERI ÎN COMERŢUL ELECTRONIC. APLICAŢIA E-Shop

60
De-a lungul timpului au apărut mai multe modele de afaceri în sfera comerţului electronic cum ar
fi: magazinul electronic (e-shop), magazinul electronic universal (e-mall), licitaţiile electronice
(e-auctions), achiziţiile electronice (e-procurements), brokerajul informaţional (price
investigation agencies), portaluri pentru călătorii (travel portals).

4.1 Magazinul electronic (E-shop)

Magazinul electronic este în esenţă un website cu catalogul produselor oferite. Firmele mici şi
medii oferă de multe ori produsele lor în această formă. Se prezintă cataloage cu descrieri,
fotografii, preţuri şi condiţii de livrare. De cele mai multe ori există posibilităţi de comandă on-
line a produselor dorite. E-shop este folosit mai ales în domeniul B2C şi oferă produse ca CD-
uri, DVD-uri, cărţi, echipamente electronice etc. Site-ul care implementează un e-shop poate fi
plasat în diferite locuri:

• Pe un server consacrat (un computer deţinut de o firmă E-shop);


• Pe un sever virtual (spaţiul de pe hard deţinut de o companie e-shop pe un computer
furnizor de spaţii web);
• În interiorul unui mall.

Exemple de magazine electronice: http://www.amazon.com, http://www.fleurop.com.

Principalele avantaje ale magazinului electronic sunt:


• Efectuarea cumpărăturilor de acasă, fără a pierde timpul cu deplasări la magazine
fizice,
• Posibilitatea de a face rapid comparaţii de produse şi preţuri,
• Posibilitatea de a alege din oferte mult mai variate decât în cazul comerţului fizic.

Printre dezavantaje pot fi enumerate:


• Produsul real achiziţionat să difere de cel sugerat prin imaginea din catalog;
• Nu pot fi încercate hainele, nu pot fi mirosite sau gustate produsele;
• Nu există interacţiune personală şi contact social.

61
ETAPELE DE PARCURS ÎN LANSAREA UNUI MAGAZIN VIRTUAL (E-SHOP)

Comerţul electronic este una dintre soluţiile complexe, "integrate", pe care le oferă tehnologia
Internet. Asta înseamnă ca o multitudine de aplicaţii şi de furnizori de servicii Internet trebuie să
conlucreze intr-o sincronizare perfecta pentru ca un site de comerţ electronic să poată funcţiona. Se poate
rezuma lansarea unui magazin virtual în următorii paşi:

4.1.1 Definirea produsului


Este absolut necesar să studiaţi în detaliu caracteristicile produsului pe care urmează să-l puneţi în
vânzare. La fel ca şi în comerţul tradiţional, natura produsului vândut va determina alegerea mijloacelor.
În spaţiul virtual, furnizorul de servicii şi aplicaţiile sunt primele alegeri pe care trebuie să le faceţi.
Tehnologia "shopping cart" (cărucior de cumpărături) stă la baza oricărui proces de comerţ
electronic. Cum funcţionează aceasta tehnologie şi cum influenţează natura produsului alegerea aplicaţiei
şi a opţiunilor incluse? Sistemul de shopping cart este cel care permite să fie expuse imagini ale
produselor, descrieri şi preţuri. Furnizează, de asemenea, mecanismele prin care consumatorul să alege
cantitatea de produse pe care doreşte să o cumpere, face verificarea şi înregistrarea datelor, calculează şi
afişează valoarea totală a cumpărăturilor, incluzând şi taxele de transport daca este cazul.

4.1.2. Chestiuni de securitate


In ce-l priveşte pe consumator, el va fi foarte interesat de garanţiile de securitate pe care le oferiţi.
Cum vor fi transmise prin Internet informaţiile asupra plăţii (de cele mai multe ori este vorba de datele
cărţii sale de credit)? Există riscul ca acestea să fie interceptate? Unde sunt stocate aceste informaţii? Ar
putea fi la îndemâna hackerilor?
Soluţia utilizată pe scară largă la această oră este SSL (Secure Socket Layer) - server securizat de
date - în combinaţie cu Certificatul Digital (Digital Certificate). Certificatul Digital este cel care
recunoaşte standardul şi confirmă că serverul pe care se află web site-ul utilizează într-adevăr criptarea
SSL atunci când primeşte şi transmite datele. În momentul în care sunt accesate pagini în care se cer
informaţii de plată de la consumator, acestea trebuie să se afle pe un astfel de server securizat. Paginile
de acest fel au în URL "https:" (Hyper Text Transfer Protocol Secure). Fără SSL şi un Certificat Digital,
nici un consumator avizat nu-şi va transmite datele cărţii de credit prin Internet.

4.1.3. Contul de comerciant (Merchant Account)


Contul de comerciant este cu totul diferit de conturile bancare obişnuite, utilizate în afacerile
tradiţionale pentru că vă permite să acceptaţi plăţi prin cărţi de credit sau de debit ca forma de plată
electronică de la clienţi. Din momentul în care aţi primit un cont de comerciant, veţi avea un număr de
identitate (Merchant ID) şi POS, adică un terminal la punctul de vânzare (point of sale terminal). Un

62
terminal de acest fel (POS) poate comunica prin intermediul liniilor telefonice, cam la fel ca un fax. Prin
POS se citesc şi se înregistrează informaţiile despre consumator de pe banda magnetică a unei cărţi de
credit sau de debit. După aceea, tot POS trimite informaţiile şi detaliile tranzacţiei către instituţiile
autorizate să proceseze plata (VISA, AMEX, MASTERCARD etc. sau la banca emitentă, dacă este vorba
de o carte de debit). Acestea răspund cu informaţia dacă fondurile/creditul existent sunt suficiente
efectuării plăţii şi autorizează sau declină tranzacţia. În situaţia în care comunicarea la terminalul POS nu
este posibilă din diverse motive (ex. întrerupere temporară), tranzacţia poate fi totuşi procesată manual la
un număr de telefon gratuit (1-800).

4.1.4. Cum se face comanda electronică?


Exista mai multe opţiuni pentru expunerea produselor şi trimiterea comenzilor online. Cea mai
obişnuita este pagina simpla HTML (pentru expunerea produselor) şi un formular electronic de
comanda. Dacă aveţi un număr mic de produse aceasta este varianta de care aveţi nevoie. Dacă numărul
de produse pe care intenţionaţi să le vindeţi este mai mare şi clienţii cumpăra în mod frecvent un număr
mai mare de produse aveţi nevoie de un sistem de scripturi mai complex.

4.1.5. Modalităţi de plata electronică


Alegerea metodei de plata depinde în primul rând de ce fel de site de comerţ electronic
administraţi: de tip B2C (adresat consumatorului) sau B2B (dedicat tranzacţiilor de afaceri). Câteva dintre
modalităţile de plata obişnuite sunt: ordinul de plată, viramentul, plata prin carte de credit sau debit,
cecurile. În timp ce în site-urile de tip B2C cea mai frecventa metodă de plată este cartea de credit, la cele
de tip B2B sunt mai degrabă utilizate ordinele de plată şi viramentele bancare. În comerţul electronic de
tip B2B, clienţii implicaţi în tranzacţii deţin de obicei cont de firmă şi solicita eliberarea unei facturi. Este
necesară verificarea solvabilităţii clientului înainte de trimiterea mărfii.

4.1.6. Opţiuni de publicitate pentru magazinul virtual


Strategiile de marketing şi publicitate sunt absolut necesare pentru a obţine succesul pe Internet.
Mai întâi, publicaţi adresa web pe toate materialele tipărite - cărţi de vizita, foi cu antet - cadouri
promoţionale (pixuri, agende), reclame în presă, la radio sau TV. După aceea, stabiliţi ce mijloace de
promovare prin Internet v-ar avantaja?

Programe Afiliate: Este un tip de program care stimulează vânzările oferind site-urilor care se înscriu
intr-o astfel de reţea (afiliate) comisioane pentru fiecare vânzare realizată prin intermediul lor. Pentru
promovarea produselor şi a serviciilor puse în vânzare, se folosesc atât link-uri grafice (casete publicitare
şi bannere) cât şi link-uri text. Sistemul de afiliere asigură urmărirea clienţilor şi contorizarea vizitelor şi a
vânzărilor fiecărui site afiliat în parte, printr-un cod unic de identitate. Pentru detalii vizitaţi
AffiliateWorld.com

Directoare cu plată: Sunt directoare specializate de obicei pe un segment de piata care percep taxe
pentru listarea site-urilor.

63
Campanie de bannere: Bannerele sunt link-uri grafice plasate de obicei la începutul paginilor care
înregistrează traficul cel mai mare dintr-un site. Taxele pentru plasarea unui banner se calculează de
obicei în raport cu numărul de impresii (expuneri) sau de clickuri.

4.2 Aplicaţia E-Shop


4.2.1 Introducere
Aplicaţia este creată pe baza limbajului Java, folosind cod Java pentru lucrul cu bazele de date
şi gestionarea mai eficientă a paginilor web. Pentru lucrul cu baze le de date este folosit serverul
MySQL. Codul este scris folosind Eclipse WTP, configurat cu serverul Tomcat 6.0. La realizarea
lucrului paginilor web a fost folosită tehnologia JSP. Designul paginilor este creat cu JSF şi
HTML.

Pagina de start a aplicaţiei.

Mai jos sunt date toate fişierele care sunt folosite pentru lucrul aplicaţiei, denumirile lor precum
şi a directoarelor în care se conţin date în formă arborescentă :

css
eshop.css
images
1.gif, 2.gif, 3.gif, 4.gif, 5.gif, 6.gif
bg_header.gif
bg_menu.gif

64
cart.gif
jsp
BookDetails.jsp
Checkout.jsp
LeftMenu.jsp
OrderConfirmation.jsp
SearchOutcome.jsp
SelectCatalog.jsp
ShoppingCart.jsp
TopMenu.jsp
META-INF
MANIFEST.MF
WEB-INF
web.xml
classes
eshop
ShopServlet.class
ShopServlet.java
beans
Book.class, Book.java
CartItem.class, CartItem.java
Category.class, Category.java
Customer.class, Customer.java
model
BookPeer.class, BookPeer.java
CategoryPeer.class, CategoryPeer.java
DataManager.class, DataManager.java
OrderDetailsPeer.class, OrderDetailsPeer.java
OrderPeer.class, OrderPeer.java
shop.sql

4.2.2 Ce se întâmplă când porneşte aplicaţia


Utilizatorul porneşte aplicaţia tapând în browserul său următoarea adresă:
//localhost:8080/eshop/shop/ . După ce aplicaţia a fost pornită se execută metoda doGet:

65
După cum se vede metoda doGet execută doPost, care la randul său execută o cerere către
index.jsp.
Pagina index.jsp, ca toate celelalte pagini ale aplicaţiei expune un header cu un linc către coşul
cu cumparături şi un meniu în partea stângă pentru controlul selectării şi căutărilor.
Pentru a reliza acest lucru au fost incluse două module separate după cum urmează:

<jsp:include page="TopMenu.jsp" flush="true"/>


<jsp:include page="LeftMenu.jsp" flush="true"/>

TopMenu.jsp este foarte simplu, conţine următoarele elemente după cum urmeză:

<a class="link2" href="<%=base%>?action=showCart">Show Cart


<img src="<%=imageURL%>/cart.gif" border="0"/></a>

unde ambele variabile sunt obţinute din sfera aplicaţiei:

String base = (String)application.getAttribute("base");


String imageURL = (String)application.getAttribute(“imageURL”);

Parametrul action setat către showCart indică metodei doPost din ShopServlet să urmeze o cere
către /jsp/ShoppingCart.jsp.
Modulul LeftMenu.jsp deasemenea este simplu, el expune un câmp de căutare şi o listă pentru
selectarea categoriilor de cărţi. Codul care relizeză cererea pentru căutare este următorul:

66
<p>Book Title/Author:</p>
<form style="border: 0px solid; padding: 0; margin: 0;">
<input type="hidden" name="action" value="search"/>
<input id="text" type="text" name="keyword" size="15"/>
<input id="submit" type="submit" value="Search"/>
</form>
Aici este codul care realizeză descrierea listei cu categoriile de cărţi:

<%
Hashtable categories = dataManager.getCategories();
Enumeration categoryIds = categories.keys();
while (categoryIds.hasMoreElements()) {
Object categoryId = categoryIds.nextElement();
out.println("<p><a href=" + base + "?action=selectCatalog&id="
+ categoryId.toString() + ">" + categories.get(categoryId) + "</a></p>"
);
}
%>

Metoda getCategories din DataManager execută o altă metodă, getAllCategories:

public Hashtable getCategories() {


return CategoryPeer.getAllCategories(this);
}

care interoghează baza de date pentru a obţine identificatorul şi numele disponibil.


Mai departe este redat listingul metodei getAllCategories, care se află în fişierul
CategoryPeer.java.
public static Hashtable getAllCategories(DataManager dataManager) {
Hashtable<String, String> categories = new Hashtable<String, String>();
Connection connection = dataManager.getConnection();
if (connection != null) {
try {
Statement s = connection.createStatement();
String sql = "select category_id, category_name from categories";

67
try {
ResultSet rs = s.executeQuery(sql);
try {
while (rs.next()) {
categories.put(rs.getString(1), rs.getString(2));
}
}
finally { rs.close(); }
}
finally {s.close(); }
}
catch (SQLException e) {
System.out.println("Could not get categories: " + e.getMessage());
}
finally {
dataManager.putConnection(connection);
}
}
return categories;
}

Liniile evidenţiate sunt cele care execută tot lucrul: în primul rând este realizată o interogare
SQL şi apoi rezultatul este salvat într-un tabel, în care cheia este ID-ul categoriei iar valoarea
este numele categoriei.
LeftMenu.jsp utilizează conţinutul tabelului pentru a genera câte un link pentru fiecare categorie,
după cum este arătat în următorul exemplu:

<a href=/eshop/shop?action=selectCatalog&id=3>Action Novels</a>

Parametrul action este setat către selectCatalog. Acesta este alcatuit din toate categoriile şi indică
fişierului ShopServlet să urmeze cererea către /jsp/SelectCatalog.jsp, când utilizatorul execută
click pe o anumită categorie.

4.2.3 Manipularea cererilor pentru căutarea şi selectarea cărţilor

68
După cum sa menţionat, când utilizatorul selectează o categorie de cărţi sau execută o căutare,
paginile prezentate sunt SelectCatalog.jsp şi SearchOutcome.jsp, respectiv. Ambele pagini expun
o listă de cărţi şi sunt asemănătoare una cu alta.
În SelectCatalog.jsp, cererea categoriei este specificată după parametrul id. Pentru a obţine un
nume de categorie, se execută DataManager şi anume metoda getCategoryName:

public String getCategoryName(String categoryID) {

Category category = CategoryPeer.getCategoryById(this, categoryID);

return (category == null) ? null : category.getName();


}

care încarcă înregistrarea categoriei din baza de date. În SearchOutcome.jsp, cuvântul cheie ca
parametru este stringul de căutare.
Pentru a obţine lista de cărţi, SelectCatalog.jsp execută următorul cod de script:

ArrayList books = dataManager.getBooksInCategory(categoryId);

while SearchOutcome.jsp executes this statement:

ArrayList books = dataManager.getSearchResults(keyword);

Pentru fiecare carte din listă, ambele pagini generează un link după cum urmează în următorul
rand:

<a class="link1" href="/eshop/shop?action=bookDetails&bookId=3">Details</a>

Cu parametrul action setat către bookDetails, ShopServlet urmează cererea către


BookDetails.jsp.

4.2.4 Expunerea detaliilor despre carţi


Până acum mecanismul ar trebui să fie foarte clar: fiecare pagină JSP trimite cererea cu
parametrul chieie la metoda DataManager, care prelucreză logic informaţiile. Acesta este modul
în care partea „view” şi partea „model” a arhitecturii MVC sunt ţinute separate, făcănd posibil ca
partea de design şi partea software sa lucreze independent una de alta.
BookDetails.jsp trimite cererea cu parametrul bookId către metoda getBookDetails din
DataManager:

69
public Book getBookDetails(String bookID) {

return BookPeer.getBookById(this, bookID);


}

şi metoda getBookById din fişierul BookPeer, obţine înregistrarea corespunzătoare din baza de
date.
Pentru a cumpăra o carte utilizatorul face un click pe următorul link:

<a class="link1" href="/eshop/shop?action=addItem&bookId=4">Add To Cart</a>

Cu parametrul action setat la addItem, ShopServlet urmeză cererea la ShoppingCart.jsp.

4.2.5 Administrarea coşului cu cumăraturi


Aplicaţia prezintă coşul cu cumpărături nu numai când utilizatorul execută click pe Add to Cart,
în timp ce priveşte detaliile despre cărţi, dar deasemenea când utilizatorul execută click pe lincul
coşului cu cumpărături din oricare altă pagină. În primul caz, diferenţa este ca parametrul action
trimis către ShoppingCart.jsp are valoarea addItem, în timp ce pentru al doilea caz valoarea este
showCart.
Coşul de cumpărături este un obiect de tip Hashtable care se păstrează în atributul sesiunii.
Cheia tabelului este ID-ul carţii, cât timp valoarea este de tip CartItem. Clasa CartItem conţine
doar metodele getters şi setters pentru author, title, price, bookID, şi
quantity.
Este convenabil de salvat preţul cărţii în coşul cu cumpărături, pentru că utilizatorul trebuie să
plătescă preţul pe care îl vede în detaliile pentru cărţi când execută click pe Add to Cart,
deasemenea dacă preţul păstrat în baza de date este schimbat înainte, atunci el poate să işi
completeze ordinea.
Pentru fiecare item al coşului cu cumpărături, ShoppingCart.jsp afişează cantitatea de cărţi
şi adaugă opţiunile Update şi Delete. Aceasta dă posibilitate utilizatorului să modifice numărul
de copii care doreşte să le ordoneze sau să le şteargă complet. Mai jos este un exemplu cu forma
update:
<form>

<input type="hidden" name="action" value="updateItem"/>

<input type="hidden" name="bookId" value="4"/>

<input type="text" size="2" name="quantity" value="1"/>

70
<input type="submit" value="Update"/>

</form>

şi aici este un exemplu cu forma delete:


<form>

<input type="hidden" name="action" value="deleteItem"/>

<input type="hidden" name="bookId" value="4"/>

<input type="submit" value="Delete"/>

</form>

Atunci când utilizatorul execută click pe unul din butoane, ShopServlet transmite cererea înapoi

către ShoppingCart.jsp.
Înainte de a prezenta conţinutul coşului de cumpărături, ShoppingCart.jsp trebuie să execute un
cod, care depinde de valoarea parametrului action.

Pentru a manipula cu addItem, ShoppingCart.jsp obţine detaliile despre carte de la data manager
prin intermediul metodei getBookDetails şi creaza un obiect nou de tip CartItem, pe care îl
adaugă în coş.
Pentru lucrul cu updateItem, ShoppingCart.jsp utilizează metoda setQuantity pentru a modifica
cantitatea itemului din coş identificat prin bookId. Pentru deleteItem, ShoppingCart.jsp pur şi
simplu sterge identificatorul coşului identificat de către bookId.
După ce a înscris conţinutul coşului de cumpărături, ShoppingCart.jsp prezintă următorul link:

<a class="link1" href="<%=base%>?action=checkOut">Check Out</a>

Dacă parametrul action este setat la valoarea checkOut, ShopServlet execută cerere către
Checkout.jsp.

71
4.2.6 Acceptarea unei succesiuni
Checkout.jsp interoghează utilizatorul pentru a furniza date personale şi financiare. Când
utilizatorul execută click pe butonul Check Out, parametrul ascuns action este setat la
orderConfirmation, care cauzeză ca ShopServlet să execute o cerere către
OrderConfirmation.jsp.

Conţinutul paginii Checkout.jsp.


4.2.7 Furnizarea detaliilor despre plată
În scheletul implementării, OrderConfirmation.jsp doar slvează succesiunea în baza de date.
Într-o situaţie reală, ar fi trebuit să execute o serie de verificări, privitor la cartea de credit astfel
încât acesta să fie validă şi să nu fie blocată.

72
CONCLUZII

Incontestabil, prezentul ştiinţei calculatoarelor este dominat de tehnologiile Internet, în


general, şi de cele Web, în special. Scopurile principale ale spaţiului WWW au fost acelea de a
oferi o modalitate de comunicare inter-umană prin partajarea cunoştinţelor şi posibilitatea
exploatării în manieră distribuită a puterii de calcul a computerelor conectate la Internet.
Pe măsură ce aceste tehnologii devin mai accesibile, ele încep a fi necesare în domenii tot
mai diverse, încercându-se exploatarea la maxim a posibilităţilor oferite de acestea.
În lucrare au fost sistematizate principalele tehnologii de dezvoltare a aplicaţiilor de reţea
în Java. Deasemenea au fost analizate noile perspective oferite de tehnologiile de ultimă
generaţie bazate pe programarea pe componente introdusă de JSF şi .NET ASP.
A fost făcut un studiu al arhitecturilor pentru crearea aplicaţiilor de Intranet şi Internet,
clasificarea şi specificul lor.
La elaborarea E-shop-ului am obţinut abilităţi de lucru cu tehnologiile de ultimă generaţie
aduse de Java. Paralel cu aceasta am obţinut o porţie de experienţă profesională în elaborarea
aplicaţiilor Web.

73
BIBLIOGRAFIE

1. Sabin Corneliu Buraga, Aplicaţii Web la cheie, Polirom, Iaşi, 2003


2. Sabin Corneliu Buraga, Tehnologii Web, vol. I , II, Matrix, Bucureşti, 2001.
3. Năstase Fl., Năstase P., Tehnologia aplicaţiilor web, Ed Economică, 2002
4. Java 2 SDK /docs/, Sun Microsystems.

5. J2EE Tutorial, Sun Microsystems.

6. BURAGA S. (ed), 2007, Programarea în Web 2.0., Ed. Polirom, Iasi.

7. Hall, Marty, Brown,Larry – CoreServlets and JavaServer Pages:


Volume 1: CoreTechnologies, 2nd Edition, Prentice Hall, 2003

8. BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru


aplicatii Web. Ed. Albastră, Cluj-Napoca.

9. ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iasi.

10. http://en.wikipedia.org

11. http://java.sun.com/

12. http://java2s.com/

13. http://preferatele.com/

14. http://apache.org/

15. http://blog.search3w.com/dynamic-to-static/hello-world/
16. http://www.afaceri-online.net;
17. http://en.wikipedia.org/wiki/Web_page

74
18. http://en.wikipedia.org/wiki/Web_application
19. http://ro.wikipedia.org/wiki/Website
20. http://ro.wikipedia.org/wiki/HyperText_Markup_Language
21. http://ro.wikipedia.org/wiki/Sistem_de_management_al_continutului

75