Sunteți pe pagina 1din 67

Capitolul I I

Mediul Java pentru Internet

2.2. Java 2 Enterprise Edition

Chiar dacă HTML este independent de platformă, apar probleme când se introduce o
cerere incompletă sau impropriu formulată în cadrul unui formular. Java oferă posibilitatea de a
crea “forme inteligente” (smart form) care verifică legitimitatea cererilor de intrare ale clientului,
eliminând consumurile inadecvate de lăţime de bandă din scenariul anterior.
Interactivitatea pe partea clientului este realizată diferit faţă de paginile Web
tradiţionale, unde procesul este preluat pe partea serverului. Utilizând un browser disponibil java,
pagina Web conţine URL-ul appletului Java. Accesând această pagină, appletul este trimis pe
calculatorul propriu, care îl execută. Marea majoritate a prelucrărilor este transferată pe partea
clientului, de la serverul la distanţă. Aceasta permite interactivitate, fără întârzierile datorate
timpului de răspuns ce apar când informaţia este trimisă înapoi pe Internet. Intrările utilizatorului
sunt trimise direct programului responsabil pentru procesarea lor, ceea ce aduce interactivitatea
paginilor Web.
Dezvoltarea API (Application Programming Interface) oferă programatorului acces la
clase, furnizând structuri comune de date, rutine I/O, tabele, fişiere, dispozitive reţea, grafică şi
audoi, funcţii matematice, etc. Java API furnizează elemente predefinite (butoane, bare de
defilare, casete de dialog, etc.) necesare construcţiei GUI (Graphic User Interface) şi referite în
AWT (Abstract Window Toolkit).[java_4]
Din punct de vedere teoretic nu sunt restricţii cu privire la aplicaţiile de sine stătătoare,
respectiv tot ce realizează acestea poate realiza un applet rezident pe pagina Web. Se preferă
appleturile deoarece oferă securitate a structurilor construite pe un browser.Java poate utiliza
structuri de date gestionate de Security Manager şi indiferent de localizarea calculatorului
poate activa sau inhiba programe Java pentru a prelucra operaţii certe: încărcarea automată a
unui program sau formă dintr-o locaţie Internet, închiderea/deschiderea unui fişier,etc.Acest
lucru este utilizat pentru a preveni încărcarea unui applet infectat (ca şi virulsul Troian Horse),
care poate crea prejudicii acestui applet (sau sistemului local de fişiere) ori să faciliteze
curiozităţi neautorizate din exterior.
Unele caracteristici de securitate sunt accesibile din caseta de dialog a meniului Security
Preferences dar nu pot fi modificate de utilizator şi nici nu pot fi alterate de codul încărcat de un
host la distanţă. Netscape ca şi alte browsere impune doar limitări extinse la appleturile ce
beneficiază de înteaga gama de facilităţi Java, dar este necesară dezvoltarea browserelor pentru a
limita extensiile de către acei utilizatori care pot relaxa restricţiile de securitate locală ale
appleturilor. Interacţiunea utilizator-utilizator prin reţea poate fi necesară pentru a avea aplicaţii
Java de sine stătătoare, care sunt implementate cu politici diferite de securitate pe Netscape,
luând măsuri specifice pentru drepturi, pentru a se asigura că nu pot apare breşe de securitate.
[An_96]
Protocol handler este un progam care aparţine JDK şi permite unui browser disponibil
Java interpretarea unui nou tip de protocol. Acest lucru elimină inconvenientul browserelelor
tradiţionale, unde apariţia unui nou protocol implica dezvoltarea browserului, astfel încât să
conţină tot codul ce permite manipularea solicitărilor făcute de protocol, ceea ce implică
realizarea unui program monilitic, care consumă multă memorie RAM. Dezvoltarea browserelor
disponibile Java este modulară şi extensibilă iar browserul în sine este un program cu flux
liniar, care utilizează un set de protocoale ce reprezintă repertoriul curent ce poate fi interpretat.
Manipulatorul poate fi încărcat "transparent" astfel încât utilizatorul nu trebuie să fie preocupat

1
de detalii, singura sarcină fiind accea de a naviga în URL-ul propice. Protocul handler încarcă în
background tot ce trimite browserul iar browserul îşi încarcă doar handler-ele necesare realizând
o optimizare a memoriei RAM ocupate.
Content handlers are rolul de a furniza o alternativă a ideii de aplicaţii standallone, permiţând
programatorului Java să scrie codul ce extinde browserul, dându-I abiliatea de a interpreta
conţinutul inline fără a solicita apelul unor aplicaţii externe. In dezvoltarea browserelor
programatorii şi-au dat seama că nu se poate determina tipul conţinutului trimis prin MIME şi
apoi să se lege browserul de "helper-e" prezente pe calculatorul local al utilizatorului. Content
handler este încărcat automat la fel ca şi protocul handler, atunci când se accesează pagina Web,
ce conţine un nou tip (video, audio, conţinut special de pe Web, etc) deşi Netscape nu suportă
modelul Java pentru content handler.

Platforma Java conţine JVM şi JAVA API


1) Java Basic API conţine applet, AWT, I/0 (sau fluxuri inclusiv serializarea obiectelor),
language (inclusiv reflection) şi utility incluzând data structures and events).
2) Java Enterprise API – asigură suport pentru database entreprise şi aplicaţiile legacy şi
conţine :
- JDBC – standard SQL
- Java RMI – invocarea la distanţă client-server;
- Java IDL – furnizează interoperabilitatea şi conectivitatea cu CORBA ;
- JNDI – interfaţa standard cu nume multiple şi servicii de directoare în entreprise.
3) Java Bean API
4) Java Security API – include criptografia serverului digital, criptare, autentificare.
5) Java Foundation Clases (JFC) API este GUI pentru programe şi faţă de AWT include :
 SWING SET – reflectă un grup de componente legate în AWT, extinzându-le prin
butoane simple şi completându-le cu arii text şi arii vizuale şi folder
 Accesibility API – furnizează interfaţa clar în cititoare de ecou, sisteme de
recunoaştere a vocii, extinzând JFC şi AWT
6) Java Server API – permite crearea de Servleţi Java şi încorporarea în aplicaţii Web,
furnizează acces consistent şi uniform la server Web şi resursele administrative ale
sistemului ;
7) Java Commerce API – API pentru comerţ şi management financiar. Java Wallet –
specifică un cadrul client-side pentru cărţi de credit, debit şi tranzacţia cu bani electronici.
8) Java Media and Communication API – integrarea clipuri audio-video, prezentări animate,
grafice, imagini 3D, modele 3D.
- Java 2D API - set de clase pentru grafică şi imagini BD incluzând linii text şi
imagini în model unic.
- Java 3D API – pentru aplicaţii 3D şi applets
- Java Media FrameWork API - dă arhitectură unificată, protocolul mesajelor,
programarea interfeţelor pentru media players, capturi media şi conferinţe.
- Java SOUND API dezvoltă 32 chanel audio cu calitate bună şi asigură control MIDI
al sintezei sunetului.
- Java Telephony API – interfaţă portabilă în aplicaţii computer –telephony.
- Java Speech API – cross-platform interface, ce permite controlul recunoaşterii,
sistemului de dictare şi sinteza vorbirii.
9) Java Management API – set de obiecte extensibile şi metode destinate reţelelor,
serviciilor de management în reţele eterogene.
10) Personal Java API – destinată conectării la distanţă a dispozitivelor personale: mobile,
calculatoare, hand-held, boxe Set-top, console de jocuri, smart phone.
11) Embeded Java API pentru dispozitive complexe ca: mobil, pagere, instrumentare de
control al proceselor, periferice de control, rutere reţea şi switchuri reţea.

2
CORE API – conţine 2 categorii:
- CORE – adică JDR plus Personal Java şi Embeded;
- Standard Extension – din exteriorul lui CORE.
Java CORE conţine: Java Basic API, Entreprise API (fără JNDI), Java Beans API, Java Security
API, Swing Set, Java 2D.

Java Reflection API


Dacă politica de securitate permite, API poate fi folosit la:
- descoperirea informaţiilor despre câmpuri, metode şi constructori din clasele
încărcate;
- construcţia de noi clase şi noi tablouri;
- accesul şi modificarea câmpurilor, obiectelor şi claselor ;
- accesul şi modificarea elementelor de tablou ;
- invocarea metodelor obiectelor şi claselor.
Spre exemplu Java Beans şi Entreprise Java Beans, solicită acces la public members pe un obiect

ţintă iar Java ObjectSerialization are nevoie de acces la toţi membri declaraţi pentru o clasă dată.

Java Reflection API conţine :


 Class – furnizând instanţe pentru Field, Method şi Constructor;
 Field Method, Constructor – furnizează informaţii reflexive despre membri
asociaţi, implementează intefaţa Member. Numai JVM poate crea instanţe ale
acestei clase.
 Field - poate fi o clasă statică sau o instanţă variabilă;
 Method – metodă abstractă, metodă (statică), a clasei sau instanţă a metodei;
 Array- furnizează metode de construcţie dinamică şi acces la tablouri. Sunt clase
finale şi de aceea neinstanţiabile.
 Modifier – permite modificarea informaţiilor (static şi public) despre clase şi
membri. Sunt clase neinstanţabile.
Security Model
Java Security manager are 2 nivele de verificare :
- metodele din clasa Class ce dau acces reflexiv sau set de membri. Surse pentru
instanţele Field Method, Constructor. Aceste metode leagă verificările de securitate
către system security manager:
- o dacă ce system security manager dă acces la membru, orice membru, reflectat poate
apela pe obiecte Java (protected, default la package şi clase private pentru membri);
Thread
Crearea firelor – ca subclasă Thread ce implementează Runnable sau direct din interfaţa
Runnable prin metoda run(). Implicit firul este membru în Theread Group. Aceste grupuri de
fire formează tree iar un daemon thread reprezintă furnizor de servicii sau entităţi background
ce nu se termină niciodată.
Ciclul de viaţă
Prioritate
Sincronizare
Wait() şi notification()

3
Tipuri de aplicaţii J2EE
Arhitectura Model-View-Controller

Indiferent de varianta arhitectonică abordată, aplicaţiile J2EE pot fi realizate cu ajutorul


Model-View-Controller (MVC) care le conferă scalabilitate şi uşurinţă în dezvoltare, prin
independenţa componentelor. In esenţă MVC este un design pattern (model de proiectare),
conceput pentru a prezenta date în interfeţe grafice standard, care oferă posibilitatea de a diviza
funcţionalitatea obiectelor ce sunt implicate în prezentarea datelor cu grad de dependenţă mai
mic. Modelul este reprezentat de datele aplicaţiei şi regulile de acces şi modificare a acestora, în
fapt o aproximare a proceselor din business. Orice schimbare a modelului (Change Notification)
este notificată de View care dispune de modele de interogare asupra stării modelului (State
Query) . Controller-ul nu are acces direct la datele încapsulate de Model ci doar la API-ul pus la
dispoziţie. View afişează datele încapsulate de model şi pune la dispozţia Controller-ului
metode de acces la funcţionalităţile aplicaţiei. View accesează datele din model şi secifică modul
de prezentare chiar şi atunci când datele din model sunt modificate. Cu alte cuvinte modelul
răspunde de consistenţa prezentării gesturile utilizatorului fiind transmise Controllerul-ui (figura
2.5.).

Model
State Query
State Change

Change
Notification
View Selection
View Controller

User Gestures

Figura 2.6. Interacţiunea Model-View-Controller

Controller-ul defineşte comportamentul aplicaţiei prin interpretarea gesturilor (User Gestures)


utilizatorului şi transpunerea în acţiuni executate de model (State Change). User Gestures la
aplicaţii stand alone sunt selecţii de meniu, deplasări, click de mouse iar la aplicaţii Web sunt
cereri GET sau POST destinate Web tier-ului.

Web Conteiner
EJB Conteiner
Web Browser Resurse
EIS

Web Conteiner EJB Conteiner

Client
stand- alone

Figura 2.1. Arhitectura J2EE de complexitate maximă

4
Acţiunile sunt reprezentate de activarea proceselor de business sau schimbarea stării
modelului. Controllerul va selecta un view care îl trimite ca răspuns la cererea primită (View
Selection). La fiecare set de funcţionalităţi există de obicei câte un controller.

Arhitectura n-tier anterior prezentată reprezintă baza modelului de programare J2EE care
oferă posibilitatea realizării unor aplicaţii scalabile, a căror componente să poată fi reutilizate.
Complexitatea maximă a unei aplicaţii presupune utilizarea mai multor Web conteinere şi EJB
conteinere, ceea ce creşte scalabilitatea aplicaţiilor (figura 2.1.) .

Aplicaţiile multi-tier (figura 2.2.) folosesc conterinerul Web pentru a găzdui componente
dedicate logicii de prezentare, conţinutul dinamic furnizat clientului fiind realizat de pagini JSP
sau servet-uri. Componentele aplicaţie sunt găzduie de conteinerul EJB care răspund cererilor
din Web Tier şi în acelaşi timp accesează resurse din Enterprise Information Systems (EIS). In
aceste condiţii accesarea atelor este decuplată de interacţiunea cu clientul, ceea ce permite o
modifcare facilă şi o dezvoltare rapidă.

Web Browser Resurse


EIS

Web Conteiner EJB Conteiner

Figura 2.2. Arhitectura multi-tier a aplicaţiei J2EE

Conteinerul Web comunică cu browserul prin protocol HTTP, producând şi consumând


mesaje XML.Mesajele primite de la diversele platforme pot fi XML enable browser sau
renderings engines (motoare de afişare) . Web conteinerul este gazda paginilor JSP, servlets,
JavaMail şi XML fiind orientat spre JSP generate în mod dinamic. Conteinerul EJB găzduieşte
Enterprise Beans, JMS,JTA<JDBC sau conectori ce permit acces la resurse şi comunicaţie cu
componentele de prezentare.

Aplicaţiile standalone au în vedere trei tipuri de clienţi : EJB, aplicaţii stand alone şi clienţi
Visual Basic.

Entity Bean
Data Access
Client Object JDBC

Session
Bean Data Access
Object JDBC

EJB tier

Figura 2.3. Interacţiunea client- componente EJB

5
Clienţii EJB interacţionează direct cu serverul EJB prin conteinerul EJB (figura 2.3) prin
intermediul RMI-IIOP care accesează EJB. Resursele întreprinderii sunt accesate prin JDBC şi
conectori.

Clienţii aplicaţii stand alone accesează resursele întreprinderii prin JDBC, unde logica de
business şi logica de prezentare se află în aceeaşi aplicaţie pe partea clientului, fără a avea midle
tier. Aceasta este în fapt aplicaţie client-server care atrage probleme legate de scalabilitate,
distribuţie şî mai ales întreţinere.
Clienţii Visual Basic consumă mesaje XML ce reprezintă conţinutul dinamic Web.Conteinerul
Web converteşte date în format şi le trimite cienţilor iar logica de prezentare este rezidentăîn
client-tier. Web tier accesează direct bazele de date dar conţine şi logica de business, deşi este
de dorit ca aceasta şa se plaseze pe serverul EJB.

Aplicaţia centrată Web tier

Java Mail
Firewall

Servlet
Data Access
Browser Object JDBC
HTTP

Pagina
JSP Data Access
HTMl,/XML Object JDBC

Midle tier
Java Mail

Figura 2.4. Interacţiunea client- componente EJB

In această abordare, Web conteinerul găzduieşte logica de prezentare şî logica de


business. Unele implementări J2EE ca şi cea furnizată de Sun implementează serverul J2EE
integrând atât Web conteinerul cât şi conteinerul EJB ceea ce le oferă o comunicare eficientă. Si
în acestă situaţie se consideră o implementare multi tier (figura 2.4.).

Aplicaţii business to business

Web Conteiner EJB Conteiner


Resurse
HTTP RMI-IIOP EIS
XML JMS

Web Conteiner EJB Conteiner

6
Figura 2.5. Arhitectura J2EE de complexitate maximă

Aplicaţiile sunt centrate pe interacţiunea dintre conteinere folosind HTTP şi XML pentru
comunicarea între conteinerele Web şi RMI-IIOP pentru comunicarea între conteinerele EJB.
Scenaiul este clasic în cazul aplicaţiilor de comerţ electronic,deoarece comunicarea între
conteinere este mai puţin restrictivă.

Obiectele de business

Pentru a putea utiliza Enterprise JavaBeans în dezvoltarea unei aplicaţii de business este
necesară cunoaşterea logicii de business (Busines Logic), definită într-un sens foarte larg, ca "un
set de reguli utilizate pentru a realiza o anume funcţie de business (funcţie necesară pentru
întreprindere"[Blueprints_2000].
In acest sens, utilizatorul foloseşte un set de componente, obiecte de business (business
objects) care sunt caracterizate de stare şi comportament.. Aceste obiecte de business au o
funcţionalitate bine precizată, un mod de comportament şi interacţionează între ele pentru a
obţine funcţionalitatea dorită. Regulile de business sau logica de business au ca scop
identificarea structurii şi comportamentului obiectelor de business, a pre condiţilor şi post
condiţiilor impuse atunci când unul sau mai mult obiecte îşi expun comportamentul în cadrul
sistemului.
Orice obiect de business trebuie să respecte anumite reguli impuse de specificul aplicaţiilor de
business.
Cerinţa primordială este de a-şi menţine starea (conversaţională sau persistentă)
reprezentată de variabilele instanţiate între apelurile metodelor.
Starea conversaţională este caracteristică obiectelor care operează asupra datelor legate de
sesiunea cu clientul şi poate fi exemplificată prin "coşul virtual", care iniţial este gol, când
cumpărătorul virtual nu a selectat încă produsele şi îşi modifică mereu conţinutul pe măsura
adăugării şi/sau ştergerii de produse cumpărate. In acest exemplu, "coşul virtual" păstrează starea
anterioară selecţiei dar indică mereu noua stare, în raport cu schimbările impuse de cumpărătorul
virtual prin apelul metodelor de adăugare de produse noi, renunţarea la un produs).
Starea persistentă este caracteristică obiectelor care operează asupra datelor independente de
sesiunea cu clientul şi poate fi exemplificată de contul de email, pentru care se stochează
informaţia la creare şi este menţinută într-un mediu persistent astfel încăt la momentul la care
utilizatorul reintră în aplicaţie regăseşte toate informaţiile legate de contul său.
Posibilitatea de a opera asupra datelor partajate este o altă cerinţă impusă obiectelor
de business , caz în care este necesară stabilirea unor nivele de izolare a datalor partajate paralel
cu controlul concurent. Spre exemplu, orice cumpărător virtual are acees la toate produsele,
conţinutul coşului virtual modificând stocurile existente.
Participarea la tranzacţii este una din cele mai importante cerinţe impuse obiectelor de
business. Tranzacţiile definite ca set de taskuri ce sunt executate împreună posedă la rândul lor
două stări: roolled back (derulată) atunci când un tack din set nu s-a executat şi toate celelate
sunt derulate şi commited caz în care tranzacţia s-a execuat cu succes şi se salvează noua stare.
Spre exemplu, comanda de produse presupune un set de taskuri (modificarea stocurilor, salvarea
detaliilor despre comandă, confirmarea primirii comenzii, şi/sauconfirmarea plăţii) ce
interacţionează cu obiectele de business. Dacă acestea nu sunt realizare cu succes, tranzacţia este
derulată şi obiectele de busienss revin la starea anterioară. In cazul tranzacţiilor distribuite se

7
impun condiţii suplimentare ce asigură integritatea datelor datorită faptului că tranzacţiile pot
avea mai multe surse de date aflate la distanţă (clientul, depozitul de mărfuri, banca la care are
cont,etc).
Specificul aplicaţiilor de business impune obiectelor să deservească mai mulţi clienţi
simultan, ceea ce conduce la crearea unor obiecte dedicate care să permită deservirea cererii
fiecărui client. Spre exeplu fiecare client va avea propriul "coş virtual" caracterizat de starea
conversaţională proprie. Dacă accesul este realizat la distanţă obiectul este integrat într-un
mediu distribuit iar clienţii îl utilizează la distanţă prin mecanisme ferme de localizare în reţea.
Problemele legate de controlul accesului se impun acelor obiecte supuse unor mecanisme de
autentificare şi autorizare, prin care anumiţi clienţi beneficiază de serviciile protejate, altora le
este inhibat accesul. Spre exemplu, modificarea de sold în contul clientului este precedată de
mecanismul de autentificare pentru că accesul la operaţiile de plată/încasare nu este permisă
oricărui client. In aplicaţiile de business apar mai multe nivele de control a accesului în raport cu
funcţionalitatea acestor aplicaţii şi cu obiectele ce iau parte la tranzacţii.
Posibilitatea reutilizării obiectelor este o cerinţă impusă atât la nivel de inter-aplicaţii cât şi la
nivelul intra-aplicaţiilor. Din acest motiv se impune o standardizare a proiectării şi dezvoltării
acestora şi rularea lor în medii care dispun de facilităţi standard, definite şi acceptate pe piaţă. In
acest mod se pot cumpăra componente de la mai mulţi providers iar acestea sunt asamblate în
aplicaţiile proprii alocând un efort minim de proiectare şi dezvoltare, ceea ce conduce la costuri
scăzute şi timp redus de realizare a aplicaţiilor.Spre exemplu obiectul angajat va fi gestionat şi de
aplicaţia specifică compartimentului financiar-contabil, pentru a determina drepturile salariale
lunare, şi în aplicaţia ce gestionează situaţia concediilor sau a declaraţiilor de venituri precum şi
de aplicaţia comercială care analizează situaţia vânzărilor în raport cu agenţii comerciali.

Obiectele de business şi Enterprise JavaBeans

Respectând cerinţele anterior expuse, obiectele de business oferă servicii generice clienţilor lor,
deoarece participă la tranzacţii, posedă securitate şi sunt accesibile la distanţă. Aceste servicii
comune sunt implementate la nivel de platformă iar utilizatorul beneficiază de ele fără a
implementa nimic, deoarece complexitatea implementării este dependentă de infrastructura
standard pe partea server, care le furnizează aceste servicii.
EJB tier conţinut în platforma J2EE oferă un model comportamental distribuit pe partea
serverului, care simplifică sarcina elaborării logicii de business. Astfel experţii sistem oferă
cadrul de implementare la nivel de sistem iar experţii de business furnizează informaţii legate
problemele firmei.
Obiectele de business sunt implementate ca şi enterprise beans sau componente EJB, de două
tipuri:entity beans şi session beans. Abordate din prisma clientului, session beans sunt fie resurse
private fie destinate clienţilor care le-au creat, fiind privite ca şi anonime.Entity beans au în
schimb o identitate unică prezentată sub forma unei chei primare.Inaara acestor obiecte,
enterprise bean defineşte în plus trei entităţi: servere, conteinere şi clienţi. EJB există în
interiorul unor conteinere care gestionează ciclul lor de viaţă şi furnizează o serie de alte servicii.
Conteinerele sunt o parte a serverului EJB, care furnizează servicii de naming and directory,
email, tranzacţii,securitate,etc.La momentul când clientul invocă o anume operaţie asupra unui
enterprise bean, apelul este preluat de conteiner, care se întrepune între client şi componentele de
la nivelul apelului. Conteinerul realizează servicii ce se propagă dincolo de apelurile metodelor
componentelor şi dincolo de conteinere aflate pe servere diferite sau chiar pe maşini diferite.
Portabilitatea şi reutilizarea obiectelor este realizată prin intermediul trăsăturilor unice cere le
posedă enterprise beans şi conteinerele EJB, ceea ce conduce la simplificarea dezvoltării
aplicaţiilor sau clienţilor.
In timpul execuţiei enterprise beans sunt create şi gestionate de conteinerele EJB, care pot
furniza şi servicii adiţionale faţă de standardele EJB specificate. Dacă enterprise bean foloseşte
doar servicii definite în specificaţii EJB atunci el poate fi folosit în orice conteiner care respectă

8
standardul EJB.Un enterprise beans care depinde de servicii specializate poate fi folosit în orice
conteiner care furnizează aceste servicii.
Serviciul de tranzacţii şi serviciul de securitate sunt separate de implementarea enterprise bean,
deoarece comportarea enterprise beans nu este conţinută integral în implementarea sa. Serviciile
sunt configurate la deployment, fază în care aplicaţia este adaptată la platformă, configurând
anumiţi descriptori la platformă şi în acest mod se pot include enterprise beans în aplicaţii
asamblate fără a modifica sursele sau fără a recompila aplicaţia.
Vederea clientului asupra enterprise beans este realizată de provider şi nu poate fi afectată de
conteiner sau serverul ce găzduieşte aplicaţia. Prin aceasta atât enterprise beans cât şi clienţii pot
fi regăsiţi în mai multe medii de execuţie, fără a solicita recompilarea. Clienţii au vederea
enterprise beans prin implementarea a două interfeţe: Home şi Remote, construite la
deployment de conteiner, prin clase bazate pe informaţiile furnizate de clasa enterprise beans.

Construcţia Enterprise JavaBeans

Clasa EnterpriseBean furnizează detaliile de implementare a componentei bean, implementând


metodele de business prin interfeţele ce extind interfaţa javax.ejb.EnterpriseBean respectiv
javax.ejb.EntityBean la componentele de tip entity bean sau interfaţa javax.ejb.SessionnBean
la componentele de tip session bean. Interfaţa javax.ejb.EnterpriseBean precizează că
respectiva clasă este enterprise bean şi extinde java.io.Serializable, prin care orice enterprise
bean poate fi serializat, adică stocat şi/sau refăcut ca şir de biţi.

public interface javax.ejb.EnterpriseBean extends java.io.Serializable


{
}

Orice instanţă a unei clase EnterpriseBean folosită de un client nu invcă direct instanţa clasei ci
lanseză apel la conteinerul EJB care este delegat instanţei EnterpriseBean.
Clasa EnterpriseBean nu poate fi invocată dicect prin reţea deoarece nu este prevăzută cu
mecanisme de acces la reţea. Conteinerul EJB înfăşoară clasa bean cu un obiect (network
enabled) ce dispune de mecanisme de acces a reţea, cere primeşte apelurile de la clienţi şi le
deleagă instanţei EnterpriseBean. Programatorul care elaborează cod RMI sau RMI-IIOP
utilizează serviciul de networking pus la dispoziţie de conteinerul EJB (figura 2.7.).
Client
1 4
Interfaţa Remote Interfaţa Home
EJB Object Home Object
3
2

Enterprise Bean
EJB Conteiner

Figura 2.7. Obiectul EJB şi apelul metodei Enterprise Bean

Clientul apelează metoda (1) iar prin interfaţa Remote, obiectul EJB obţine un bean şi deleagă
metoda către Enterprise Bean (2). Acesta returnează metoda (3) preluată de obiectul EJB, care
trimite apoi rezultatul la client (4).

9
Interceptând cererile de către conteinerul EJB, se automatizează operaţiile de management ce
privesc securitatea, tranzacţiile, mecanismul de pooling, etc. Conteinerul EJB reprezintă un nivel
de redirectare sau strat indirect (indirection layer) între bean şi codul clientului, constituit ca un
obiect cu mecanisme de acces la reţea, numit EJB object.Obiectul EJB este inteligent şi poate
realiza tranzacţii, securitate şi logică intermediară solicitată de conteinerul EJB înainte de apelul
metodelor din Enterprise Bean.Practic obiectul EJB reprezintă o punte între client şi bean, şi
expune fiecare metodă pe care o pune la dispoziţie obiectul enterprise bean.
Interfaţa Remote
Cum clienţii nu invocă metode asupra obiectelor enterprise beans, este necesar ca obiectele EJB
să cloneze fiecare metodă pe care o expune bean-ul , specificate în interfaţa Remote. Interfeţele
Remote extind interfaţa javax.ejb.EJBObject pusă la dispoziţie de Sun Microsystem, cu
metodele aferente acesteia şi în plus trebuie să conţină metode de business ale bean-ului.
Principalele metode pe care trebuie să le expună obiectele Ejb pot fi succint prezentate:
getEJBHome() -prin care se obţine o referinţă la obiectul Home;

getPrimaryKey() -returnează cheia primară a obiectului EJB, mai precis entity beans;
remove() - distruge obiectul EJB iar pentru entity beans îl şterge din mediul persistent;
getHandle() -returnează o referinţă persistentă a obiectului EJB (handle), pentru o reutilizare
viitoare în vederea obţinerii obiectului EJB;
isIdentical() - testează dacă două obiecte EJB sunt identice.
Codul clientului ce apelează la enterprise bean, utilizează un obiect ce implementează interfaţa
javax.ejb.EJBObject astfel:

public interface javax.ejb.EJBObject extends java.rmi.Remote {


public abstract javax.ejb.EJBHome getEJBHome()
throws java.rmi.RemoteException;

public abstract java.lang.Object getPrimaryKey()


throws java.rmi.RemoteException;

public abstract void remove()


throws java.rmi.RemoteException,
java.ejb.RemoveException;

public abstract javax.ejb.Handle getHandle()


throws java.rmi.RemoteException;

public abstract boolean isIdentical(javax.ejb.EJBObject)


throws java.rmi.RemoteException;
}

Home Object şi Home Interface

Clientul nu poate să instanţieze direct un obiect EJB deoarece tehnologia EJB propune o
transparenţă totală faţă de localizarea obiectelor EJB astfel încât clienţii să nu fie preocupaţi de
locul unde rezidă obiectele EJB. Un object factory este responsabil de instanţierea şi
distrugerea obiectelor EJB, fiind denumit şi home object, care are rol de creare a obiectelor EJB,
permite regăsirea obiectelor EJB existente (entity beans) şi de ştergere a obiectelelor EJB.
Obiectele Home sunt specifice fiecărui conteriner, aparţin acetor conteinere şi sunt generate
folosind unelte specifice fiecărui conteiner.

10
Client
1 3

Interfaţa Remote Interfaţa Home


EJB Object Home Object
2

Enterprise Bean
EJB Conteiner

Figura 2.8. Obiectul Home

Deoarece conteinerul EJB solicită informaţii necesare creării obiectelor Home, iniţializarea
acesora este realizată prin intermediul interfeţelor Home. Clientul cere rearea unui obiect EJB
(1) iar interfaţa Home defineşte metode de creare, distrugere şi găsire a obiectelor EJB (2).
Obiectul Home al conteinetului implementează interfaţa home specificată de programator.
Metodele definite de interfaţa home extind metodele definite de interfaţa javax.ejb.EJBHome
astfel:

public interface javax.ejb.EJBHome extends java.rmi.Remote {


public abstract EJBMetaData getEJBMetaData()
throws java.rmi.RemoteException;

public abstract void remove(Handle handle)


throws java.rmi.RemoteException,
java.ejb.RemoveException;

public abstract void remove(Object primaryKey)


throws java.rmi.RemoteException,
java.ejb.RemoveException;
}

Secvenţa de cod arată că javax.ejb.EJBHome derivă din java.rmi.Remote care ce conduce la


ideea că obiectele home sunt prevăzute cu posibilitatea accesului la reţea prin Java RMI care
realizează comunicaţia dintre maşini virtuale diferite. Din acest motiv metodele specificate în
home interface trebuie să fie valide pentru Java RMI, obiectiv realizat prin implementarea
java.io.Serialiazable.
In acest mod un obiect EJB poate fi iniţializat printr-un parametru şir în vreme ce alt obiect EJB
poate fi iniţializat printr-un parametru întreg.

Pentru ca un conteiner să fie informat despre serviciile solicitate de componentă, se cer


specificate midleware services în deployment descriptors. Un deployment descriptor este un
fişier care poate specifica modul în care conteinerul gestionează ciclul de viaţă a unui obiect,
servicii de securitate, control al tranzacţiilor sau persistenţa obiectelor. Midleware service
reprezintă un serviciu de care bean-rile beneficiază în mod automat, fără ca programatorul să

11
scrie cod. Pentru a beneficia de servicii midleware puse la dispoziţie de platforma J2EE, este
necesară configurarea corespunzătoare a platformei, folosind uneltele serverului, conterinerului
sau IDE. Deployment descriptor este un obiect serializabil a cărui creare este automatizată de
EJB conteiner tools sau Java Development Environment Tools.

Tipuri Enterprise JavaBeans

Se poate defini o conversaţie ca interacţiunea dintre client şi bean, fiind compusă dintr-un apel
succesiv de metode dintre client şi bean. Orice tip de beans menţin conversaţii cu clienţii într-un
anume mod, conversaţia fiind desfăşurată pe parcursul unui proces de business pentru client.
In specificaţiile EJB 1.0 şi EJB 1.1 sunt definite două tipuri diferite de enterprise beans
corespunzător celor două obiective de business: session beans pentru logica de business şi entity
beans, pentru modelarea datelor.

Session beans nu sunt partajate de mai mulţi clienţi, fiind dedicate utilizării unui singur client la
un moment dat şi au durata de viaţă egală cu sesiunea clientului. Dacă un client utilizează session
beans pentru a realiza cumpărături electronice (coşul de cumpărături) serverul EJB este
responsabil de crearea unei instanţe a componentei session bean şi la deconectare tot serverul va
distruge respectiva instanţă.
La rândul lor, pot fi divizate în două categorii în funcţie de procesele de business pe care le
deservesc.

Statefull session beans deservesc procesele de business care cuprind mai multe apeluri de
metode sau chiar tranzacţii şi menţin starea de partea clientului. Dacă starea este modificaţă în
timpul apelului unei metode, ea va fi disponibilă clientului la momentul apelului altei metode.
Coşul de cumpărături este exemplul elocvent pentru acest tip de bean deoarece solicită
modificarea stării la fiecare adăugare/ştergere de produse din coş.

Stateless session beans deservesc procesele modelate pentru o singură cerere şi sunt denumiţi ca
furnizori anonimi de metode deoarece nu cunosc istoria clientului. Un exemplu în poate constitui
componenta care realizează un portofoliu virtual de acţiuni sau care furnizează operaţii
matematice complexe asupra datelor de intrare. Componenta primeşte într-un buffer datele
despre valoarea investiţiei şi gradul de risc asumat. In urma procesării datelor, furnizează un
portofoliu de acţiuni care răspund cerinţelor clientului, după care componenta poate fi reutilizată
pentru că nu trebuie să reţină informaţii despre starea clientului pe care l-a deservit.

Entity beans sunt acele componente care reprezintă date persistente, stocate de obicei în baze
de date. Acestea sunt utilizate în modelarea datelor şi nu conţin logică de business, pentru că
furnizează o vedere obiectuală asupra datelor dintr-un mediu de stocare. Faţă de metodele
tradiţionale de manipulare (citire/scriere) a datelor aflate spre exemplu în tabele relaţionale,
entity beans sunt de fapt reprezentarea obiectuală a acestor date.Durata de viaţă a acestor obiecte
este mai mare deoarece modelează date permanente şi au sarcina de a rezista căderilor majore
(căderea serverului sau defectarea unei maşini), deoarece depind de durata de viaţă a datelor
stocate (a bazei de date).

Dacă session beans au durată de viaţă egală cu sesiunea clientului, entity beans supravieţuiesc
atât cât supravieţuieşte baza de date. Mai mult, entity beans pot fi accesate simultan de către mai
mulţi clienţi prin intermediul tranzacţiilor, ceea ce înseamnă ca aceşti clienţi pot manipula
simultan date din baza de date, spre deosebire de session beans care sunt dedicate unui singur
client.

12
Session beans

Session beans au rolul de a reprezenta procesele de business: logică, algoritmi de prelucrare,etc.


Session beans au ciclul de viaţă egală cu a sesiunii clienţilor, sesiunea fiind egală cu timpul în
care este deschisă fereastra browserului sau ciclul de viaţă al appletului în care rulează session
beans. O altă caracteristică este dată de faptul că aceste obiecte pot fi distruse de conteinerul EJB
cănd timpul de lucru cu clientul expiră. Dacă se estimează că un client foloseşte bean-ul timp de
15 minute, timpul de viaţă setat pe server poate fi setat la 30-35 minute ceea ce implică faptul că
session bean nu pot supravieţui căderilor serverului. In plus session beans sunt nonpersistente
nefiind salvate într-un mediu persistent.

Client
1
Interfaţa Remote
EJB Object
Bazin de
2 Bean componente
Bean
EJB Conteiner

Figura 2.9. Session beans

Orice clasă care reprezintă un session bean, implementează interfaţa javax.ejb.SessionBean.


Clienţii bean-ului nu vor apela niciodată metodele descrise în interfaţă deoarece acestea sunt
utilizate doar de conteinerul EJB, care va anunţa bean-ul de evenimentele importante.
Interfaţa javax.ejb.SessionBean extinde javax.ejb.EnterpriseBean astfel:

public interface javax.ejb.EJBHome extends javax.ejb.EnterpriseBean {

public abstract void setSessionContext(SessionContext ctx)


throws java.rmi.RemoteException;

public abstract void ejbPassivate( )


throws java.rmi.RemoteException;

public abstract void ejbActivate( )


throws java.rmi.RemoteException;

public abstract void ejbPassivate( )


throws java.rmi.RemoveException;
}

Conteinerul EJB utilizează metoda setSessionContext(SessionContext ctx) pentru a asocia


bean-ului un context sesiune (SessionContext), care reprezintă poarta de interacţiune bean-
conteiner. In implementarea tipică, bean-ul va păstra contextul într-o variabilă membru, care va

13
fi utilizată ulterior. Starea în care se află bean-ul la un moment dat este dată de runtime, care
include câteva informaţii de bază cum sunt:
 informaţiile legate de obiectul Home sau EJB al bean-ului;
 informaţii referitoare la tranzacţiile ca care participă bean-ul şi care pot fi folosite pentru a
sări anumiţi paşi dacă tranzacţia este eşuată;
 informaţii de securitate necesare autentificării clientului, dat fiind faptul că benu-ul poate
interoga mediul în care se află pentru a determina nivelul drepturilor necesare respectivei
operaţii în care este implicat.
Iniţializarea bean-ului poate fi realizată în mai multe moduri de către clienţii acestuia, în funcţie
de parametri pe care îi furnizează. Din acest motiv metoda ejb.Create() nu este prezentă în
această interfaţă, dar este necesară implementarea ei pentru a putea realiza iniţializarea bean-ului.
Metoda ejb.Create() are rol de a iniţializa toate variabile necesare bean-ului şi de a seta
variabilele membru cu valorile primite ca parametru la apelul metodei. Un exemplu de metodă
poate fi:
import javax.ejb.*;
public class Firstbean implements SessionBean {
private int memberVariable;
public void ejbCreate(int initialValue){
this.memberVariable= initialValue;
}

Conteinerul invocă metode ejbCreate() în nici un caz clienţii, aceştia în schimb pot implementa
mai multe metode de acest tip pentru un bean.Clienţii dispun de metode care trimit parametri la
metode ejbCreate(), care furnizează valorile de iniţializare. Cum interfaţa home este apelată de
clienţi la iniţializarea bean-ului, este necesar ca fiecare metodă ejbCreate() să aibă corespondent
în interfaţa Home. Astfel, dacă în cadul bean-ului am declarat metoda:
public void ejbCreate(int initialValue){ }
în vom plasa metoda corespunzătoare:
public void Create(int initialValue){ }

După cum se observă din exemplu, interfaţa Home nu are prefix ejb, iar clienţii care apelează
metoda Create(int initialValue) asupra interfeţei Home, parametri sunt pasaţi metodei
ejbCreate(int initialValue) din bean.
Metoda ejbPassivate() este apelată de conteiner la momentul când sunt instanţiate prea multe
bean-uri şi acestea nu dispun de resurse necesare. In această situaţie conteinerul pasivizează o
parte din bean-uri, salvâdu-le într-o bază de date sau un sistem de fişiere. Conteinerul apelează
metoda ejbPassivate() este apelată şi înainte de pasivizare, pentru a anunţa bean-ul să elibereze
orice resurse utilizate, ca şi în exemplul următor:

import javax.ejb.*;
public class FirstBean implements SessionBean {

public void ejbPassivate(){


<close socket connections, database connections, etc…>
}
Activarea reprezintă procesul prin care conteinerul aduce bean-ul din mediul de stocare şî îl pune
la dispoziţia clientului, activându-l (reversul pasivizării). Odată ce a fost activat, apelează metoda
ejbActivate() prin care I s epun la dispoziţie toate resursele necesare:

import javax.ejb.*;
public class FirstBean implements SessionBean {
14
public void ejbActivate(){
<open socket connections, database connections, etc…>
}

Pasivizarea sau activarea nu este aplicată bean-urilor de tip stateless session bean, datorită
faptului că acestea nu păstrează starea de la o sesiune la alta şi pot fi create sau distruse fără a
folosi mecanismul de activare/pasivizare.
Un conteiner ce doreşte să distrugă o instanţă a unui bean, apelează la metoda ejbRemove()
pentru a-l anunţa să se pregătească pentru distrugere, respectiv să elibereze resursele utilizate.
Conteinerul apelează această metodă în orice moment chiar în cazul în care timpul de viaţă a
expirat, şi spre deosebire de metodele ejbCreate() care furnizează parametri, acestă metodă nu
primeşte parametri şi este una per bean.
Faţă de metodele descrise anterior, apelate doar de conteiner, business methods sunt metodele
care soluţionează problemele de business şi sunt implementate în manieră specifică. Un exemplu
simplu poate fi descris:

import javax.ejb.*;
public class FirstBean implements SessionBean {

public int add(int i, int j){


return (i+j);
{……..
}
}

Clientul care invocă o metodă de business o declară în interfaţa Remote .

Utilizarea unui session bean

Soluţionarea unei probleme de business poate implica unul sau mai multe beanuri. Pentru fiecare
bean, clientul trebuie să obţină obiectul Home, să creeze un obiect EJB, să apeleze metodele
necesare, definite în interfaţa Remote şi apoi să distrugă bean-ul.

Obţinerea obiectului Home presupune că serviciul Java Naming and Directory Interface
(JNDI) intermediază regăsirea resursei de către client.
Cum proiectarea J2EE are în vedere transparenţa locaţiei, codul scris de client nu depinde de
modul de distribuţie al bean-urilor pe tiers sau pe maşinile unde sunt localizate.Serviciul de
naming and directory are rolul de a stoca şi regăsi resursele în reţea.Astfel de servicii sunt
Active Directory al firmei Microsoft sau Lotus Notes al firmei IBM iar firmele folosesc aceste
servicii pentru a stoca numele utilizatorilor şî parolele acestora, locaţia fiecărei maşini în parte
sau a dispozitivelor periferice (imprimante,scannere,etc).
J2EE exploatează aceste servicii de directory pentru a stoca resursele folosite de aplicaţie,
resurse care pot fi atât obiecte Home, proprietăţi ale mediului EnterpriseBean, drivere de baze de
date, cât şi orice alte resurse utilizate de bean. In momentul în care se mută una din resurse, este
suficientă consemnarea modificării în directory service, iar J2EE va realiza regăsirea resursei
parcurgând două etape: una în care resursei i se asociază un identificator, pentru care conteinerul
va realiza asocierea identificator-resursă şi a doua, în care clienţii folosesc JNDI şi identificatorul
asociat pentru a regăsi resursa respectivă.
Conteinerele EJB maschează locaţia obiectelor Home pentru a asigura transparenţa locaţiei.
Clienţii utilizează serviciile JNDI pentru a regăsi obiectele deoarece nu utilizează nici măcar

15
numele maşinii pe care rezidă aceste obiecte. Programatorul sau utilizatorul bean-ului nu este
preocupat de locaţia acestui bean şi obiectele Home sunt localizate în reţea, astfel încât prin
identificatorul asociat de conteiner fiecărui obiect Home, orice client de pe orice maşină va putea
regăsi acel obiect Home, fără a localiza fizic bean-ul. JNDI caută în mai multe directory services
obiectul Home care are asociat respectivul identificator iar dacă obiectul este găsit, se întoarce
clientului o referinţă la el.
De pilda în bean-ul FirstBean se specifică identificatorul firstBeanIdentif, care va fi asociat
automat de conteiner pentru obiectul Home al bean-ului respectiv. Orice client va putea folosi
firstBeanIdentif pentru a găsi obiectul Home, fără a localiza bean-ul.
Pentru aplicaţii, obiectul de tip context iniţial dispune de configurările necesare pentru a
beneficia de serviciul naming and directory. Când se apelează metoda bean-ului
setInitialContext, conteinerul furnizează obiectul InitialContext iar pentru a regăsi interfaţa
Home a bean-ului este suficient apelul metodei lookup.
Prezentăm continuare modul de utilizare a unui Bean în altul, prin care se obţine o referinţă la
obiectul Home al bean-ului de tip FirstBean, cu identificatorul firstBeanIdentif, din interiorul
bean-ului SecondBean.

import javax.ejb.*;
public class SecondBean implements SessionBean {
InitialContext secondCtx

// se seteaza context pentru SecondBean

public void setInitialContext(InitialContext ctx){


this.secondCtx=ctx;

//metoda ce utilizează alt bean numit firstBeanIdentif


public void businessmethod1(){

//cauta obiectul Home pentru MyBean


FirsHome home=(FirstHome)secondCtx.lookup("firstBeanIdentif");

//creaza obiect EJB


FirstRemote ejbObject=home.create();

//utilizează metoda din FirstBean


int result ejbObject.add(2,3);
//distruge instanţa
ejbObject.remove();
}

}

Obiectul Home odată obţinut, poate fi folosit la crearea de obiecte EJB, prin intermediul
metodei create expusă de obiectul Home şi implementată în codul bean-ului prin metoda
corespondentă ejbCreate().
In exemplul anterior, FirstBean este stateless session bean şi se va specifica la deployment,
pentru că acestea nu conţin stare şi nu primesc parametri de iniţializare.

După crearea obiectului EJB, el se poate utiliza pentru apelul oricărei metode pe care o expune
bean-ul prin intermediul acestui obiect. Când clientul apelează o metodă asupra obiectului EJB,

16
trebuie să aleagă o instanţă de tipul bean-ului, care să îi îndeplinească cererea. Obiectul EJB
poate să instanţieze un alt bean sau să reutilizeze o instanţă existentă deja, în funcţie de modul în
care este implementat mecanismul de pooling, aflat la atitudinea conteinerului.

Distrugerea obiectului EJB se realizează prin apelul metodei remove() din interfaţa acestuia.
Conteinerul poate să distrugă obicetul din memorie, să îl golească de informaţia conţinută şi să îl
depoziteze în pool (bazin) în vederea reutilizării. In acest mod se poate implementa mecanismul
de pooling, dependent de constructorul conteinerului.

In exemplul anterior, se utilizează bean-ul FirstBean care adună două numere prin metoda de
busness implementată. Bean-ul este utilizat de SecondBean în cadrul metodei
businessmethod1(). La crearea lui SecondBean, conteinerul furnizează contextul acestuia prin
apelul metodei setInitialContext, şi contextul este salvat în variabila secondCtx. In cadrul
metodei businessmethod1() se obţine o referinţă la obiectul Home al bean-ului de tip FirstBean,
cu ajutorul identificatorului firstBeanIdentif, care foloseşte contextul iniţial din SecondBean.
Când se apelează metoda create aspura obiectului Home, se obţine obiectul EJB pentru bean-ul
FirstBean. Din acel moment se poate apela medoda add expusă de FirstBean.Când FirstBean nu
mai este necesar, se apelează metoda remove(), iar conteinerul este încunoştinţat că bean-ul nu
mai este necesar şi poate implementa mecanismul de pooling.
In figura 2.10 se schematizează mecanismul expus, cu precizarea că în acest caz nu se apelează
bean-ul din interiorul unui alt bean, ci din alt context.

Client

6 3
5
1
2 Interfaţa Remote Interfaţa Home
EJB Object Home Object
JNDI 4
7

Enterprise
Bean
Naming
Services EJB Conteiner

Figura 2.10. Apelul unui bean din codul clientului

Când clientul apelează la un bean, JNDI obţine o referinţă la obiectul home (1), prin care
returnează apoi referinţă la obiectul Home (2). Aceasta permite utilizarea interfeţei Home (3)
pentru cererea de creare a obiectului EJB. Home va crea obiectul EJB (4) şi va returna o referinţă
clientului (5) la obiectul EJB. Clientul poate să invoce o metodă de business prin interfaţa
Remote a obiectului EJB (6), care va delega apoi apelul la bean-ul solicitat de client (7).

Stateless Session Bean

Spre deosebire de Statefull Session Bean care menţin conversaţia cu clientul, Stateless Session
Bean reprezintă logica de business, şi sunt utilizate pe parcursul unui singur apel de metodă,

17
nefiind particularizate pentru un anume client. Clientul care utilizează un stateless session beans
trebuie să furnizeze toţi parametri necesari logicii de business, chiar dacă bean-ul încarcă date
dintr-o sursă externă (bază de date, fişier, etc). Cum aceste bean-uri nu menţin starea de la un
apel la altul, nu este necesară decât o singură metodă ejbCreate() fără parametru. Interfaţa
Home expune metoda create(), fără nici un parametru.
Mecanismul de pooling din interiorul conteinerului este implementat relativ uşor pentru că bean-
urile menţin informaţiile legate de client doar pe durata ciclului de viaţă iar după execuţia
metodei solicitată nici măcar nu păstrează informaţii legate de clienţi. Din acest motiv, bazinul
pentru aceste bean-uri este mult mai mic faţă de numărul de clienţi conectaţi, conteinerul putând
alege dinamic bean-ul ce îl foloseşte pentru apelul unei metode cerute de client. Consumul de
resurse este redus pentru că nu toţi clienţii solicită servicii de le aceste beans în permanenţă.
Constructorul conteinerului va decide mecanismul de pooling pe care îl implementează pentru că
în timp ce un client se gândeşte, conteinerul poate reutiliza acel bean pentru a deservi un alt
client.

Exemplu de utilizare

Interfaţa remote pentru bean-ul HelloWorld


import javax.ejb.*;
import javax.rmi.RemoteException;
import javax.rmi.Remote;
public interface Hello extends EJBObject{
public String hello() throws java.rmi.RemoveException;
}

bean-ul HelloBean
import javax.ejb.*;
public class HelloBean implements SessionBean (

public void ejbCreate() {


System.out.printl("ejbCreate()");
}

public void ejbRemove( ) {


System.out.printl("ejbRemove()");
}

public void ejbActivate( ) {


System.out.printl("ejbActivate()");
}

public void ejbPassivate( ) {


System.out.printl("ejbPassivate()");
}

public void setSessionContext(SessionContext ctx) {


System.out.printl("setSessionContext()");
}
public String hello(){
System.out.printl("hello()");
return"Hello, World!";

18
}

Exemplu de mai sus are rol de a exemplifica folosirea tehnologiei EJB în realizarea componentei
stateless sesssion bean, care dispune de o metodă -hello() , la al cărui apel se returnează String-ul
"Hello World!".
Interfaţa Remote construită pentru acest bean, trebuie să posede metodele de business
implementate de obiectul EJB iar obiectul EJB deleagă toate cererile clientului la bean. Această
interfaţă extinde javax.ejb.EJBObject, de fapt obiectul EJB, generat automat de conteiner şi care
va implementa acestă interfaţă. In interfaţă apare şi metoda ce este apelată asupra bean-ului adică
hello().
Bean-ul construit implementează metoda hello() şi metode ale interfeţei javax.ejb.SessionBean
prin care bean-ul descris devine session bean.Bean-ul nu implementează interfaţa Remote
deoarece aceasta extinde javax.ejb.EJBObject.Dacă se doreşte transferul unei referinţe la un
bean, programatorul poate confunda obiectl EJB cu bean-ul deoarece ambele implelemntează
aceeaşi interfaţă. Deşi compilatorul nu detectează eroarea, un bean nu poate fi accesat decât prin
obiectul EJB corespunzător. In acest caz se recomandă utilizarea unei interfeţe care conţine doar
metode de business iar această interfaţă va fi implementată de bean şi extinsă prin interfaţa
Remote.
Metoda ejbCreate() nu primeşte nici un parametru, deoarece bean-ul este stateless şi nu are o
stare legată de client, deci şi metoda ejbRemove() este goală pentru că nu există nimic de
distrus. In plus setSessionContext() nu a fost stocat în nici un membru al clasei deoarece nu este
necesară interogarea contextului în care se află bean-ul.
Stateless session beans nu foloseşte activarea şi pasivizarea, motiv pentru care metodele
ejbActivate() şi ejbPassivate() nu au implementare.

Interfaţa home pentru bean-ul Hello bean


import javax.ejb.*;
import javax.rmi.RemoteException;

public interface Hello extends EJBHome{


Hello create() throws RemoteException, CreateException;
}

Aşa cum se poate observa din interfaţa home, metoda create() lansează două tipuri de excepţii,
RemoteException dat fiind faptul că pot apărea erori în comunicare atunci când se foloseşte
RMI (căderea maşinii, erori legate de obiectele din mediul distribuit,etc) şi CreateException,
excepţie la nivel de aplicaţie. In aplicaţiile de business există o distincţie clară între excepţiile la
nivel de aplicaţie şi cele la nivel de sistem. Spre exemplu, dacă se lansează aceeaşi cerere de aple
de metodă de pe servere diferite, excepţiile la nivel de sistem nu privesc clientul, în schimb dacă
un client doreşte să facă o plată şi suma este insufucientă, aplicaţia va trebui să gestioneze
această excepţie prin CreteException.
Pentru un client care utilizează bean-ul descris, codul poate fi sintetizat astfel:

Clientul care utilizează bean-ul HelloBean


import javax.ejb.*;
import javax.naming;
import javax.rmi.;
import java.util.Properties;

public class HelloClient {

19
try{
//se obţin proprietatile System pentru iniţializarea JNDI
Properties props=System.getProperties();

//formam contextul initial


Context ctx=new InitialContext(props);

//cream referinta la obiectul home


HelloHome home=(HelloHome)ctx.lookup("HelloHome");

//utilizam factory pentru a crea obiect EJB


Hello hello=home.create();

//apelam metoda hello si tiparim sirul


System.out.println(hello.hello());

//distrugem obiectul nefiind necesar


hello.remove();
}
catch(Exception ex){
ex.printStackTrace()
}
}
Explicaţia codului: Conteinerul asociază bean-ul unui session context, apoi apelează metoda
create() , iar apelul metodei hello() asupra obiectului EJB se deleagă asupra bean-ului.Prin
distrugerea obiectului EJB se distruge şi bean-ul. Mecanismul de pooling este propriu
constructorului conteinerului şi din acest motiv pe consola serverului apar mesaje diferite.
In vederea rulării acestui exemplu, se realizează deployment-ul HelloBean , în condiţiile în care
identificatorul ataşat bean-ului este exact "HelloHome", ca şi în exemplul j2sdkee1, regăsit pe
site-ul firmei Sun. Pentru alte exemple de aplicaţii de poate consulta adresa:
http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/DevGuideTOC.html
sau în format PDF
http://java.sun.com/j2ee/j2sdkee/devguide1_2_1.pdf
Pe consola serverului apar mesajele:
setSessionContext()
ejbCreate()
hello()
ejbRemove() iar la nivel de client: "Hello,World!" .

Statefull Session Beans

Pornind de la specificul acestor beans, acela de a realiza logica de business este necesară
păstrarea informaţiei legată de conversaţia cu clientul pe parcursul mai multor apeluri de metode.
In plus, ele sunt particularizate pentru un anume client, din care motiv sunt nevoite să
implementeze metodele ejbActivate() şi ejbPassivate() iar atributele care menţin starea trebuie
serializate.
Deoarece viteza de reacţie a clienţilor este mult mai mică decât a sistemului, bean-urile sunt
utilizate aleator şi nu sunt atât de numeroase comparativ cu numărul clienţilor, ceea ce înseamnă
1
adresa http://java.sun.com/j2ee/j2sdkee
adresa pentru instrucţiuni de instalare este
http://java.sun.com/j2ee/j2sdkee/install.html

20
că în cadrul unui conteiner se pot utiliza diferite statefull session beans pornind de la premisa că
resursele conteinerului sunt limitate. In cazul în care starea păstrată de statefull session bean
reprezintă un volum mare de date, serverul riscă să rămână fără resurse. Din acest motiv sunt
limitate instanţele statefull session bean şi conteinerul va realiza operaţii de asivizare/activizare
asupra anumitor bean-uri.
Client

Interfaţa Remote EJB Object

5
3 4

2
Enterprise Alte Enterprise
Bean Bean
Mediu de
stocare EJB Conteiner

Figura 2.11. Activarea unui statefull session bean

Atunci când clientul apelează o metodă de business (1) obiectul EJB obţine starea bean-ului prin
intermediul informaţiilor conţinute în mediul de stocare (2). Apoi are loc operaţia de reconstruire
a bean-ului (3), după care se apelează (4) metoda ejbActivate() şi apoi se invocă metodele de
business solicitate de client (5), conform figurii 2.11.

Procesul de pasivizare impune bean-ului elibearea tuturor resurselor pe care le are, deoarece nu
se pot serializa conexiunile la bazele de date sau socketuri deschise. Conteinerul face apelul
metodei ejbPassivate() asupra bean-ului, care va elibera resursele utilizate, după care conteinerul
serializează şi stochează bean-ul sub formă de blob, într-un mediu persistent reprezentat uzual de
o bază de date.
In acest caz, dacă un client apelează o metodă de business (1), conteinerul va lua bean-ul cel mai
recent utilizat (2) şi face apelul metodei ejbPassivate() asupra bean-ului (3) care conduce apoi la
serializarea bean-ului (4) şi îl stochează în mediul de stocare (5). Comparând cele două metode
constatăm că se inversează paşi 2-5 faţă de procesul de activizare.
Pasivizarea poate fi invocată oricând asupra unui bean, decizia de pasivizare aparţine
constructorului conteinerului dar bean-ul trebuie să fie pregătit pentru acest proces. Menţionăm
că orice bean poate fi pasivizat numai după ce tranzacţia în care este implicat a fost încheiată.

Exemplu de utilizare:CountBean

Rolul acestui bean este de a menţine starea de la un apel de metodă la altul, prin intermediul
metodei count() care va incrementa la fiecare apel atributul de stare al bean-ului.

Interfaţa remote pentru bean-ul CountBean


import javax.ejb.*;

21
import javax.rmi.RemoteException;
import javax.rmi.Remote;

public interface Count extends EJBObject{


public int count() throws java.rmi.RemoveException;
}

Interfaţa Remote expune doar metoda count() care implementează în bean incrementarea
variabilei val, care va reprezenta starea conversaţională cu clientul.
Implementarea bean-ului are o singură metodă de business count() care va incrementa atributul
de stare val. Bean-ul implementează interfaţă ejb.SessionBean iar la crearea bean-ului, metoda
ejbCreate() primeşte un parametru de iniţializare a bean-ului. Pentru a serializa bean-ul se
foloseşte tipul primitiv int pentru variabila val şi astfel este permisă activare şi pasivizarea bean-
ului.

bean-ul CountBean
import javax.ejb.*;

public class CountBean implements SessionBean (

private SessionContext ctx;


public int val;
public void ejbCreate(int val) throws CreateException{
this.val=val;
System.out.printl("ejbCreate()");
}

public void ejbRemove( ) {


System.out.printl("ejbRemove()");
}

public void ejbActivate( ) {


System.out.printl("ejbActivate()");
}

public void ejbPassivate( ) {


System.out.printl("ejbPassivate()");
}

public void setSessionContext(SessionContext ctx) {


this.ctx=ctx;
System.out.printl("setSessionContext()");
}
public int count(){
System.out.printl("count()");
Return ++val;
}

Interfaţa home pentru bean-ul CountBean

22
import javax.ejb.*;
import javax.rmi.RemoteException;

public interface CountHome extends EJBHome{


Count create(int val) throws RemoteException, CreateException;
}

In interfaţa home pentru obiectul Home se va detalia crearea şi distrugerea bean-urilor, dat fiind
faptul că se extinde interfaţa javax.ejb.EJBHome iar metoda remove() este disponibliă.

Pentru un client care utilizează bean-ul descris, codul poate fi descris:

Clientul care utilizează bean-ul HelloBean


import javax.ejb.*;
import javax.naming;
import java.util.Properties;

public class CountClient {


public static void main(String[] args){
try{
//se obţin proprietatile System pentru iniţializarea JNDI
Properties props=System.getProperties();

//formam contextul initial


Context ctx=new InitialContext(props);

//cream referinta la obiectul home


CountHome home=(CountHome)ctx.lookup("CountHome");

//utilizam factory pentru a crea obiect EJB


int countVal=0
Count count=home.create(countVal);

//apelam metoda count si tiparim valoarea


countVal=count.count();
System.out.println("noul count"+countVal);

//distrugem obiectul nefiind necesar


count.remove();
}
catch(Exception ex){
ex.printStackTrace()
}
}
}

Explicaţia codului este similară cu cea HelloBean cu pariticularităţile de activare/pasivizare.

23
Pentru a rula acestui exemplu, se realizează deployment-ul HelloBean , în condiţiile în care
identificatorul ataşat bean-ului este exact "CountHome", ca şi în exemplul j2sdkee 2, regăsit pe
site-ul firmei Sun. Pentru alte exemple de aplicaţii de poate consulta adresa:
http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/DevGuideTOC.html
sau în format PDF
http://java.sun.com/j2ee/j2sdkee/devguide1_2_1.pdf

Avantajele şi dezavantajele acestor două tipuri de bean-uri (Tabelul 2.1.) determină strategia de
proiectare şi dezvoltare a aplicaţiilor.

Stateless session bean Statefull session bean


Pot fi refolosite fără a consuma resurse în plus Reutilizarea presupune consumul mare de
de către mai mulţi clienţi prin conteinerul EJB resurse la activare/pasivizare şi chiar gâtuirea
sistemului (bottlenecks)

Nu menţin starea conversaţională. Pastrează starea conversaţională cu clientul,


Datele sunt furnizate bean-ului prin parametri eroarea conduce la pierderea stării
utilizaţi in apelul metodelor, ceea ce reduce conversaţionale.
performanţa şi aduce congestii în reţea. Se recomanda un conteiner de refacere a stării
O soluţie ar fi stocarea datelor în structuri de bean-urilor.
directoare folosind JNDI

Tabelul 2.1. Comparaţie stateless-statefull session bean.

Menţionăm că în interiorul instanţei unui session bean rulează doar un thread.

Entity Beans

Entity beans reprezintă aceea categorie de enterprise beans care se autosalvează într-un mediu de
stocare dar pot fi folosite şi la integrarea aplicaţiilor mai vechi (legacy systems) în aplicaţiile de
business. Spre deosebire de session beans, care sunt legate de interacţiunea cu clienţii şi
modelează procesele, entity beans conţin date legate de aplicaţie şi nu realizează taskuri
complexe.
Entity beans pot fi privite ca şi o reprezentare a datelor sub formă de obiect Java sau obiecte
capabile să citească date din mediul de stocare şi să populeze câmpurile cu aceste date respectiv
ca obiect ce poate fi modificat în memorie şi care va modifica datele în mediul de stocare.

Caracteristicile entity beans sunt legate de durata de viaţă egală cu durata datelor care le
reprezintă şi supravieţuiesc căderilor accidentale. Orice cădere a JVM (Java Virtual Machine)
sau a bazei de date nu afectează entity beans, deoarece după ce eroarea a fost soluţionată,
instanţele entity beans pot fi create citind doar datele din baza de date.

Intre instanţa bean asociată datelor din baza de date există o strânsă legătură. Orice modificare a
datelor în memorie, determină modificări în baza de date iar entity beans pot fi abordate ca un
zoom asupra datelor din baza de date.Transferul datelor în/din memorie în baza de date este
relizat prin implementarea a două metode: ejbStore(), care salvează datele din bean în baza de
date şi ejbLoad() care citeşte date din mediul de stocare şi le transferă în câmpurile bean-
2
adresa http://java.sun.com/j2ee/j2sdkee
adresa pentru instrucţiuni de instalare este
http://java.sun.com/j2ee/j2sdkee/install.html

24
ului.Cele două metode sunt coordonate de conteinerul EJB care decide asupra momenteleor când
transferă datele în/din mediul persistent dar bean-ul trebuie să accepte în orice moment cele două
metode.Practic sincronizarea datelor din bean-ul din memorie cu cele din baza de date este
sarcina conteinerului.

Dacă aplicaţia presupune accesul simultan la aceleaşi date, este necesară implementarea unui
mecanism de acces la entity bean. Dacă se permite clienţilor să partajeze acceaşi instanţă a unui
entity bean, codul din interiorul bean-ului trebuie să fie thread-safe şi ar putea apare o gâtuire a
accesului la date. Un cod thread-safe permite execuţia mai multor thread folosind aceleaşi date.
Pe de altă parte mai multe fire de execuţie pentru acelaşi entity bean face imposibilă efectuarea
tranzacţiei deoarece şi în interiorul unei instanţe entity beans nu suportă mai multe fire. Gâtuirea
apare dacă mai mulţi clienţi acceaseză aceleaşi date deoarece se formează o coadă de aşteptare.
Acest lucru este evitat deoarece conteinerul crează mai multe instanţe pentru acelaşi bean, ceea
ce conduce la soluţionarea accesului concurent.
Spre exemplu, este necesar ca mai mulţi clienţi să acceseze simultan un catalog de produse dar
orice modificare a stocului trebuie reflectată în baza de date şi ceilalţi clienţi trebuie să o
sesizeze. Conteinerul crează instanţe ale bean-ului dar se pune problema cum se pot sincroniza
modificările realizate într-o instanţă astfel încât să se reflecte şi în celelalte (modificarea stocului
un produs). Conteinerul soluţionează acest lucru sincronizând clientul cu mediul permanent de
stocare prin metodele ejbStore() şi ejbLoad(). La modificarea unei instanţe bean, conteinerul
va apela metoda ejbStore() a respectivului bean, după care va apela metoda ejbLoad() pentru
fiecare instanţă a bean-ului care reprezintă aceleaşi date.
Mecanismul de pooling este implementat la nivelul entity beans deoarece soluţia de a distruge
bean-ul pe măsură ce clienţii se conectează şi apoi de a-l crea la o nouă conectare este extrem de
costisitoare şi solicită resursele, datorită faptului că numărul de conexiuni ale clienţilor şi mai
ales frecvenţa acestora este mare.
Pe de altă parte, o clasă care defineşte entity bean, descrie doar câmpurile şi regulile de
manipulare ale acestora nu şi valorile specifice. Dacă o clasă entity bean descrie stocul de
produse, va preciza stocul iniţial, intrările şi ieşirile iar instanţa poate reprezenta stocul oricărui
produs din catalog.
Client Client

Interfaţa Remote Interfaţa Remote


EJB Object (1) EJB Object (2)
3
2
EJB Conteiner
Bean
Pool

Figura 2.12. Mecanismul pooling pentru entity beans

Folosind mecanismul de pooling, entity bean sunt tratate ca obiecte reciclabile, prin care se evită
timpul pierdut în instanţieri şi/sau distrugeri (figura 2.12). In exemplul anterior o instanţă entity
bean care descrie stocul de produs va putea fi reutilizată de îndată ce respectivul produs nu mai
este implicat în cumpărare, reprezentând stocul altui produs solicitat de client. La nivelul unui
cont bancar, instanţa reprezintă datele altui client odată ce primul client a terminat de utilizat
respectivul cont, reprezentat de instanţa bean-ului.

25
Identificarea bean-ului este realizată printr-o cheie primară asignată şî care poate fi orice tip de
obiect.
Conteinerul asigură asignarea dinamică a instanţelor entity bean la diverse obiecte EJB, specifice
unui client deşi acest mecanism implică o serie de complicaţii datorate faptului că un entity bean
asinat unui obiect EJB particular poate deţine o serie de conexiuni la baza de date sau la alte
aplicaţii prin intermediul socket-urilor.Când bean-ul se află în pool, nu mai este legat de un
client. Eliberarea şi recâştigarea resurselor asignate se realizează prin metodele ejbPassivate() şi
ejbActivate() cu funcţionalitate similară cu statefull session beans.

Conteiner Bean

ejbStore()

ejbPassivate()

ejbActivate()

ejbLoad()

Figura 2.13. Succesiunea metodelor la entity bean.

Metoda ejbPassivate() este invocată de conteiner la momentul când dezasociază bean-ul unui
obiect specific şi dezasociază cheia primară avută de respectivul bean. In acest moment bean-ul
va elibera toate resursele pe care le deţine şi îşi salvează starea pe care o are. Metoda
ejbActivate() este invocată de conteiner la momentul când asociază bean-ul unui obiect EJB
specific şi asociază o cheie primară respectivului bean. Acum bean-ul va redobâdi resursele
avute anterior şi eliberate prin ejbPassivate() (figura 2.13) precum şi ultimele date din baza de
date.
Mediul de stocare va conţine câmpurile bean-ului după ce a fost invocată metoda ejbStore(),
înainte de pasivizare iar încărcarea datelor în câmpurile instanţei bean-ului se va realiza prin
invocarea metodei ejbLoad(), după activarea bean-ului.

Se defineşte persistenţa ca fiind protocolul de transfer a stării unei instanţe a unui entity bean
către mediul de stocare. Implementarea protocolului poate fi realizată:
 în mod direct, în clasa ce defineşte enterprise bean-ul sau în alte clase ajutătoare -
persistenţă gestionată de entity bean denumită bean managed persistance;
 prin delegare de responsabilitate către conteiner - conteiner managed persistance.
In prima situaţie elaborarea codului de acces la baza de date este sarcina programatorului, care
va realiza apel la baza de date fie prin cod direct, încapsulat în entity bean, sau cod încapsulat
într-o componentă Data Access. Dacă persistenţa se va încapsula în entity bean, este dificil de
adaptat la o nouă arhitectură a bazei de date. Incapsularea în Data Access Object (design pattern)
conferă o adaptabilitate mai mare a aplicaţiei la o nouă arhitectură a bazei de date.
Pentru gestionarea persistenţei de către conteiner, programatorul identifică toate câmpurile ce se
stochează în baza de date şi generează codul de acces la baza de date prin uneltele puse la
26
dispoziţie de conteiner la deployment. Programatorul cunoaşte tipulogia şi structura bazei de date
iar uneltele conteinerului pot folosi JDBC (Java Database Connectivity) sau SQL/J pentru acces
la starea entity bean din tabelele bazei de date relaţionale sau din alte clase ce implementează
accesul la aplicaţii enterprise existente (legacy). Starea bean-ului este independentă de modul şi
locul de stocare ceea ce îi oferă flexibilitate dar apare dezavantajul că datele specifice din bazele
de date solicită unelte complexe pentru a le putea accesa (legate de specificul fiecărei baze de
date. In această situaţie este sarcina conteinerului de a elabora cod de acces la baza de date dar,
în cazul obiectelor complexe, care reprezintă rezultatul unui join şi/sau select imbricate,
conteinerul poate să deţină insuficiente resurse pentru a le gestiona starea. Practic, deşi
programatorul deleagă sarcina asupra conteinerului, acesta nu o poate realiza în orice situaţie.

Crearea şi distrugerea entity beans sunt diferite faţă de session beans datorită mecanismului de
persistenţă implementat în două moduri distincte precum şi a semnificaţie pe care o au entity
bean- oglindă a datelor din baza de date.
Iniţializarea unui entity bean înseamnă şi crearea datelor în baza de date astfel încât când datele
sunt iniţializate în memorie la apelul metodei ejbCreate(), trebuie inserate şi în baza de date. La
ştergerea datelor din memorie prin apelul metodei ejbRemove(), trebuie şterse şi în baza de date.
Cele două metode nu sunt completate în cazul conteiner managed persistence doar în cazul bean
managed persistence.
Cum datele dintr-o bază de date au identificator unic, entity beans trebuie să aibă identificator
unic. Frazele SELECT ce permit căutări în baza de date au ca şi corespondent finder methods în
entity beans, adică metode de căutare în mediul persistent după reprezentarea obiectuală a
datelor. Rezultatul unei metode de căutare find este o colecţie de referinţe la obiecte EJB,
asociate dinamic de către conteiner cu instanţe ale bean-urilor. In interfaţa Home se expun toate
metodele find deoarece obiectul home are ca scop furnizarea unei instanţe la obiectul EJB.
Dacă există alte aplicaţii care modifică datele dintr-o bază de date relaţională se poate considera
că s-a modificat în acelaşi timp şi entity beans iar dacă aplicaţiile şterg sau introduc date, se
consideră că s-a apelat metoda ejbRemove() respectiv ejbCreate() asupra interfeţei Remote
expusă de obiectul EJB.

O clasă entity bean implementează interfaţa javax.ejb.EntityBean cu toate metodele expuse şi


necesare conteinerului pentru gestiunea ciclului de viaţă. Interfaţă extinde
javax.ejb.EnterpriseBean şi implementează interfaţa Serializable, motiv pentu care entity
beans sunt serializabile.

Interfaţa javax.ejb.EntityBean

public interface javax.ejb.EntityBean implements javax.ejb.EnterpriseBean {


public abstract void setEntityContext(javax.ejb.EntityContext);
public abstract void unsetEntityContext();
public abstract void ejbRemove();
public abstract void ejbActivate();
public abstract void ejbPassivate();
public abstract void ejbLoad();
public abstract void ejbStore();
}

In plus interfaţa defineşte metode de tip ejbCreate() pentru a crea un entity bean şi pentru a
introduce date în mediul persistent, şi ejbFind() pentru a găsi anumite date.
Orice metodă ejbCreate() permite clientului crearea unui entity bean, respectând anumite reguli
de utilizare:

27
 Dacă datele se inserează în baza de date prin alte modalităţi, nu este necesară extinderea
metodelor ejbCreate() ca şi la session bean.
 Parametri primiţi de metodele ejbCreate() pot fi diferiţi deci pot exista mai multe metode de
iniţializare a bean-urilor, respectiv de introducere a datelor;
 Metodele ejbCreate() sunt expuse şi în interfaţa Home care crează obiectul EJB şi îl
asociază bean-ului propriu-zis la fel ca şi la session bean.
Dacă există un entity bean denumit AccountBean, reprezentând un cont bancar, va avea
interfaţă Home AccountHome şi cheia primară AccountPK. Metoda ejbCreate() din interfaţa
bean-ului este:

public AccountPK ejbCreate(String accounID, String Owner)

iar în interfaţa Home:

public Account Create(String accounID, String Owner)

Clientul face apel (1) la Bean iar prin interfaţa Home se apelează (2) metoda ejbCreate() asupra
Entyty Bean, care apoi va realiza crearea în baza de date (3). Instanţa bean-ului returnează o
cheie primară de clasă AccountPK , obiectul Home returnează un obiect EJB de clasă Account.
Bean-ul returnează o cheie primară conteinerului adică obiectului Home (4), care poate identifica
bean-ul. Cu acestă cheie primară conteinerul va genera obiectul EJB (5) care îl returnează apoi
clientului (6).

Client
1 6

Interfaţa Remote Interfaţa Home


EJB Object 5 Home Object
2
4
Enterprise Bean
EJB Conteiner

Database

Figura 2.14. Crearea entity bean

Găsirea entity beans se realizează cu finder methods care nu crează ci doar încarcă date în baza
de date. Pentru aceasta trebuie să existe cel puţin o metodă ejbFindByPrimaryKey() care
permite găsirea unei instanţe a unui entity bean folosind cheia primară asociată lui. Orice entity
bean are o cheie primară asociată, unică, în relaţie cu datele pe care le reprezintă din baza de
date. Parametri primiţi de metodele ejbFindByPrimaryKey() pot fi diferiţi deci pot exista mai
multe metode de căutare a bean-urilor, în funcţie de semantica datelor. O metodă de tip ejbFind
returnează o cheie primară sau o colecţie de chei primare, dacă există mai multe. Clienţii nu
invocă niciodată finder methods deoarece ele se invocă asupra obiectului Home implementat de
conteinerul EJB, care le deleagă apoi bean-ului propriu-zis.
28
Dacă există o metodă find denumită ejbFind, va avea corespondent în interfaţa Home:

public AccountPK ejbFindBigAccounts(int minimum) throws …

iar în interfaţa Home:

public Account findBigAccount(int minimum) throws…

In interfaţă nu are prefix ejb şi returnează un tip obiect diferit deoarece în instanţa entity bean
returnează o cheie primară sau o colecţie de chei primare iar obiectul Home returnează clientului
un obiect EJB sau o colecţie de obiecte ejb.

Distrugerea datelor reprezentate de entity bean este realizată prin metoda remove() asupra
obiectului Home sau obiectului EJB, care determină conteinerul să apeleze metoda ejbRemove()
a bean-ului. Acestă metodă nu va şterge obiectul ci doar datele din baza de date, bean-ul putând
fi reutilizat. Sper deosebire de ejbFind care pot fi numeroase, această metodă este unică şi trebuie
definită de orice bean.
Spre deosebire de session bean pentru care contextul este un obiect ce implementează interfaţa
javax.ejb.SessionContext entity bean are contextul un obiect ce implementează interfaţa
javax.ejb.EntityContext, ambele fiind descendenţi ai interfeţei javax.ejb.EJBContext.

public interface javax.ejb.EntityContext implements javax.ejb.EJBContext {


public abstract javax.ejb.EJBObject getEJBObject();
public abstract javax.lang.Object getPrimaryKey();
}

Metoda getEJBObject() permite obţinerea obiectului EJB asociat bean-ului. Fiecare client are
asociat obiectul EJB deoarece nu accesează bean-urile direct iar obiectului EJB returnat prin
această metodă se poate utiliza ca referinţă (this din Java).
Metoda getPrimaryKey() returnează cheia primară asociată cu instanţa bean-ului. Cheia primară
identifică unic entity bean iar datele din baza de date sunt identificate unic prin cheile primare
ale tabelelor componente. In acest mod se pot identifica exact acele date care sunt asociate unui
entity bean la un moment dat. Datorită mecanismului de pooling, entity beans sunt asociate fie
unui obiect EJB fie altuia motiv pentru care cheia primară este utilă şi la activizarea/pasivizarea
bean-ului.

De vreme ce bean-ul are legătură atât cu datele din baza de date cât şi cu obiectul EJB, este
importantă sincronizarea ocazională a acestui bean mai ales atunci când există mai multe bean-
uri ce reprezintă aceleaşi date. Conteinerul apelează la metodele ejbLoad() şi ejbStore() pentru
ca instanţa bean-ului să reprezinte ultimele date din bază.
Mai mult la expirarea timpului acordat fiecărui entity bean, sau dacă clientul apelează metoda
remove() asupra obiectului Home, conteinerul trimite bean-ul în pool, nu înainte de a apela
metoda ejbStore() astfel încât baza de date să conţină ultime versiune a datelor din memorie.
Ulterior apelează metoda ejbPassivate() care conduce la eliberarea resurselor bean-ului în
vederea reutilizării acestora.

Dacă bean-ul este asignat altui obiect EJB, va apela metoda ejbActivate() pentru ca bean-ul să
obţină resursele necesare precum şi metoda ejbLoad() care va încărca datele din baza de date în
bean.

29
Figura 2.15. Instanţă inexistentă
Ciclul de
viaţă al
entity bean newInstance()
setEntityContext() unsetEntityContext()
distrugerea bean-ului

Pool ejbFind()

ejbCreate() ejbActivate() ejbStore() ejbRemove()


ejbLoad() ejbPassivate()

ejbLoad() Ready ejbStore()

Business methods
setEntityContext()

Orice entity bean implementează interfaţa javax.ejb.EntityBean cu metodele care permit


soluţionarea problemei de business pentru care este realizat. Conform celor prezentate în figura
2.15, aceste metode sunt:
setEntityContext() apelată de conteiner, pentru instanţierea unui nou obiect din tipul clasei
bean, sau când doreşte să creasă numărul de bean-uri din bazin. Asupra instanţei se
apelează metoda setEntityContext() pentru a asocia bean-ului un context, după care
bean-ul poate apela metode pentru a afla date despre mediul în care rulează.
Intr-o variabilă membru se salvează EntityContext returnat, obţinând acele resurse de
care are nevoie indiferent de datele ce le va reprezenta. Bean-ul se află în bazin şi nu este
asociat nici unui obiect. Ulterior, EntityContext poate fi utlizat pentru a obţine informaţii
de la conteiner ( legate de securitate, mediu,etc).
ejbFind<…>(<…>) este folosită pentru a regăsi date din mediul persisitent cu metode find .
Chiar dacă instanţa bean-ului se află în bazin, poate fi utilizată pentru deservirea
metodelor find. Este obligatorie implementarea metodei ejbFindByPrimaryKey().
Metoda permite căutarea în baza de date după cheia precizată, utilizând JDBC, prin
interogări de tip SELECT… FROM … . Conteinerul primeşte cheile primare găsite şi va
crea obiecte EJB pe care le poate invoca clientul, asociind obiecte EJB instanţelor de
bean-uri. Instanţele asociate nu se află în bazin şi au asociate date specifice din baza de
date.
ejbCreate(<…>) o apelează conteinerul asupra bean-ului, dacă clientul apelează metoda
create() asupra obiectului Home. Metoda răspunde de crearea noilor date în baza de date
şi de iniţializarea beanului cu acele date.

30
Prin aceasta se verifică validitatea parametrilor de iniţializare şi utilizând JDBC se
stochează date în baza de date. Bean-ul nu se află în bazin şi are asociate date pe care le
reprezintă. Conteinerul asociază bean-ul cu un obiect EJB.
ejbPostCreate(<…>) o apelează conteinerul asupra bean-ului, cu aceeaşi parametri, după ce
apelează metoda ejbCreate().
După ce conteinerul asociază bean-ul cu un obiect EJB, apelează metoda şi termină
iniţializarea bean-ului, după care se poate realiza orice operaţie cu obiecul EJB, chiar
pasarea unei referinţe spre obiectul EJB la alte bean-uri.
ejbActivate( ) o apelează conteinerul dacă clientul apelează o metodă de business asupra unui
obiect EJB care nu are bean-ul asociat. Din bazin conteinerul ia un bean şi îl trece în
starea Ready() realizând activarea bean-ului însă nu este apelată niciodată în timpul unei
tranzacţii.
ejbLoad( ) este apelată de conteiner pentru a încărca în bean date din baza de date, pe baza stării
tranzacţionale curente.
Prin apelul metodei ejbFindByPrimaryKey() află cheia primară a EntityContext asociat
bean-ului iar din cheia primară determină datele ce trebuie încărcate din baza de date,
folosind JDBC.
ejbStore( ) are rol de actualizare a date din baza de date cu cele din bean şi este apelată de
conteiner pentru a sincroniza datele. Pe baza stării tranzacţionale curente conteinerul
decide momentul când apelează această metodă.
Prin apelul metodei, se actualizează datele din baza de date, folosind JDBC, şi comenzi
de tip UPDATE.. în care se salvează anumite atribute ale bean-ului în tabela bazei de
datele.
ejbPassivate( ) o apelează conteinerul înainte de a trimite bean-ul în bazin însă nu este apelată
niciodată în timpul unei tranzacţii.
Metoda permite eliberarea de orice resurse utilizate prin apelul metodei ejbActivate( )
sau care depind de clientul care a fost deservit. Starea este deja salvată prin apelul
anterior al ejbStore(), de către conteiner.
ejbRemove( ) distruge date din baza de date, însă nu şi instanţa bean-ului care poate fi
reutilizată. Prin apelul metodei ejbFindByPrimaryKey() se află cheia primară a
EntityContext asociat bean-ului iar din cheia primară determină datele ce trebuie şterse
din baza de date, folosind JDBC.
unsetEntityContext() apelată de conteiner, pentru dezasocierea bean-ului de mediul asociat la
instanţiere, înainte de a distruge efectiv bean-ul. Resursele obţinute cu metoda
setEntityContext() sunt eliberate şi bean-ul este pregătit pentru distrugerea de către
Garbage Collector.
Exemplu de entity bean managed persistance

Acest exemplu prezintă un cont bancar.Contul este stocat într-o bază de date, în tabelul account,
care este accesată cu JDBC. Tabelul din bază poate fi generat cu scriptul SQL păstrând numele şi
prenumele deponentului, soldul contului şi un identificator al contului. In cazul de faţă
identificatorul este seria si numărul buletinului, ca şir de caractere concatenate.

Scriptul SQL pentu tabelul account

CREATE TABLE tbl_account


(id VARCHAR(30)
firstname VARCHAR(24)
lastname VARCHAR(24)
balance DECIMAL(10,2)
);

31
ALTER tbl_account ADD CONSTRAINT pk_account PRIMARY KEY

Clasa entity bean

package exemple.entityBeanBMP;

import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;

public class AccountEJB implements EntityBean {

private String id;


private String firstName;
private String lastName;
private double balance;
private EntityContext context;
private Connection con;
private String dbName= "java:comp/env/jdbc/AccountDB;

//business methods

public void credit(double amount){


balance=+amount
}

public void debit(double amount){


throws Insufficient BalanceException {
if (balance-amount< 0) {
throw new Insufficient BalanceException ();
}
balance=-amount;
}

public String getFirstName(){


return firstName;
}

public String getLastName(){


return lastName;
}

public double getBalance(){


return balance;
}

//EntityBean interface methods

32
public void setEntityContext(EntityContext context){
this,context=context;
try {
makeConnection();
} catch (Exception ex) (
throw new EJBException("Unable to connect DB"+ex.getMessage());
}
}

public void ejbActivate(){


id=(String)context.getPrimaryKey();
}

public String ejbCreate(String id, String firstName, String lastName, double balance)
throws CreateException{
if (balance<0.00) {
throw new Create Exception( "A negative initial balance is not allowed");
}
try {
insertRow(id, firstName, lastName, balance);
} catch (Exception ex) {
throw new EJBException("ejbCreate:"+ex.getMessage());
}
this.id=id;
this.firstName= firstName;
this.lastName= lastName;
this.balance= balance;

return id;
}

public String ejbPostCreate(String id, String firstName, String lastName, double balance) {
}
public void ejbStore(){
try {
storeRow();
} catch (Exception ex) {
throw new EJBException("ejbStore:"+ex.getMessage());
}
}

public void ejbStore(){


try {
storeRow();
} catch (Exception ex) {
throw new EJBException("ejbStore:"+ex.getMessage());
}

public void ejbLoad(){


try {
loadRow();

33
} catch (Exception ex) {
throw new EJBException("ejbLoad:"+ex.getMessage());
}
}

public void ejbRemove(){


try {
deleteRow();
} catch (Exception ex) {
throw new EJBException("ejbRemove:"+ex.getMessage());
}
}

public void ejbPassivate(){


id-null;
}

public void unsetEntityContext(){


try {
con.close();
} catch (SQLException ex) (
throw new EJBException("UnsetEntityConext"+ex.getMessage());
}
}

public String ejbFindByPrimaryKey(String primaryKey)


throws FinderException {
boolean result;
try {
result=selectByPrimaryKey(primaryKey);
} catch (Exception ex) (
throw new EJBException("EJBFindByPrimaryKey "+ex.getMessage());
}
if (result) {
return primaryKey;
} else {
throw new ObjectNotFoundException (Row for id:+primaryKey+"not found");
}
}

public Collection ejbFindInRange(double low, double high)


throws FinderException {
Collection result;
try {
result=selectInRange(low, high);
} catch (Exception ex) (
throw new EJBException("EJBFind InRange"+ex.getMessage());
}
if (result.isEmpty()) {

34
return null;
} else {
return result;
}
}

// data base methods

private void makeConnection() throws NamingException, SQLException {

InitialContext ic=new InitialContext;


DataSource ds=(DataSource) ic.lookup(dbName);
Con=ds.getConnection();
}

private void insertRow(String id, String firstName, String lastName, double balance)
throws SQLException {
String insertStatement="insert into account values ( ?, ?, ?, ? )";
PreparedStatement prepStmt=con.prepareStatement(insertStatement);

prepStmt.setString(1,id);
prepStmt.setString(2,firstName);
prepStmt.setString(3,LastName);
prepStmt.setDouble(4,balance);

prepStmt.executeUpdate();
prepStmt.close();
}

private void deleteRow(String id) throws SQLException {


String deleteStatement="delete from account where id=?";
PreparedStatement prepStmt=con.prepareStatement(deleteStatement);

prepStmt.setString(1,id);
prepStmt.executeUpdate();
prepStmt.close();
}

private boolean selectByPrimaryKey(String primaryKey)


throws SQLException {
String selectStatement="select id from account where id = ?";
PreparedStatement prepStmt=con.prepareStatement(selectStatement);

prepStmt.setString(1,primaryKey);

ResultSet rs=prepStmt.executeQuery();
prepStmt.close();
return rs;
}

35
public Collection selectInRange(double low, double high)
throws SQLException {

String selectStatement="select id from account"+


"where balance between ? and ?";
PreparedStatement prepStmt=con.prepareStatement(selectStatement);

prepStmt.setDouble(1,low);
prepStmt.setDouble(1, high);
ResultSet rs=prepStmt.executeQuery();
ArrayList a=new ArrayList();

while(rs.next()) {
String id=rs.getString(1);
a.add(id);
}

prepStmt.close();
return a;
}

public void loadRow() throws SQLException {

String selectStatement="select fistname, lastname, balance"


+" from account where id = ?";
PreparedStatement prepStmt=con.prepareStatement(selectStatement);

prepStmt.setString(1,this.id);
ResultSet rs=prepStmt.executeQuery();

if (rs.next()) {
this.firstName=rs.getString(1);
this.lastName=rs.getString(2);
this.balance=rs.getDoube(1);
prepStmt.close();
} else {
prepStmt.close();
throw new NoSuchException("Row for id"+id+"not found in database");
}
}

private void storeRow() throws SQLException {


String insertStatement=" update account set fistname = ? ."
+" lastname,=?, balance =?"
+" where id = ?";
PreparedStatement prepStmt=con.prepareStatement(updateStatement);

prepStmt.setString(1,id);

36
prepStmt.setString(2,firstName);
prepStmt.setString(3,LastName);
prepStmt.setDouble(4,balance);

int rowCount = prepStmt.executeUpdate();


prepStmt.close();

if (rowCount==0) {
throw new EJBException("Storing Row for id"+id+"failed");
}
}

// end of AccountEJB
}

Conteinerul apelează constructorul bean-ului pentru a obţine o instanţă de bean, apoi metoda
setEntityContext() în care va stoca tot contextul bean-ului şi va obţine resursele necesare. Deşi
bean-ul nu este asociat încă unui obiect EJB, obţine legătura la baza de date, deoarece indiferent
cărui obiect EJB va fi asociat, are nevoie de conexiunea la baza de date. Bean-ul se află acum în
bazin.

Când conteinerul apelează metoda ejbActivate() bean-ul este scos din bazin şi este asociat cu o
cheie primară unui obiect EJB, cheie folosită pentru identificare datelor care le reprezintă.In
acest caz, se setează atributul cheie primară din bean cu cheia primară asociată de conteiner
bean-ului iar dacă bean-ul nu ar vi fost proiectat cu conexiunea la baza de date, ar fi putut obţine
acum această conexiune.

Metoda ejbCreate() din clasa bean-ul inserează o înregistrare în baza de date, verificănd dacă
suma depusă este pozitivă. In caz contrar lansează excepţia de tip javax.ejb.CreateException.
Această excepţie se lansează dacă unul din parametri de intrare este invalid, deoarece în cazul
cheilor duplicate apare excepţia de tip DuplicateKeyException extinsă din excepţia de tip
CreateException. Cu metoda InsertRow() se inserează în baza de date, folosind JDBC, după
care, dacă nu au apărut excepţii la inserare, de iniţializează variabilele membru ale clasei cu
datele inserate, pe care trebuie să le reprezinte bean-ul.Ulterior se returnează cheia primară a
înregistrării. Datele pot fi inserate şi printr-un script, utilizând entity beans pentru a le
reprezenta.

Metoda ejbPostCreate() poate invoca metode ca getPrimaryKey() sau getEJBObject() pentru


că după utilizarea metodei ejbCreate() conteinerul află deja cheia primară, In majoritatea
situaţilor metoda ejbPostCreate() dar trebuie să respecte anumite reguli: metoda primeşte
acceaşi parametrei ca şi în cazul metodei ejbCreate(), nu returnează paramatru şi este publică.
Dacă o metodă de business este asociată cu o tranzacţie, conteinerul invocă metoda ejbLoad()
înainte de a o executa pentru a împrospăta datele bean-ului iar după execuţia metodei de business
conteinerul invocă metoda ejbStore() pentru a salva datele din atributele bean-ului în baza de
date. Cele două metode sunt apelate de conteiner în mod automat şi de aceea în corpul metodelor
de business nu este necesară sincronizarea datele din atributele bean-ului în baza de date.
In cazul în care cele două metode eşuează, se lansează excepţia
javax.ejb.NoSuchEntityException care este subclasă a EJBException, descendentă la rândul
ei din RuntimeException. La lansarea NoSuchEntityException conteinerul EJB o înfăsoară
într-o excepţie RemoteException pentru a o trimite clientului. Metoda storeRow() are rol de a
salva datele în baza de date iar metoda loadRow() încarcă datele din baza de date.

37
Când conteinerul apelează metoda ejbPassivate() bean-ul este este dezasociat unui obiect EJB,
şi trimis în bazin şi nu reprezintă date, motiv pentru care se setează atributul cheie primară din
bean cu null, eliberând toate resursele obţinute pe parcurs.

Stergerea bean-ului se realizează cu metoda ejbRemove() care şterge şi datele din baza de date,
prin apelul metodei deleteRow(), folosind JDBC. In cazul în care ştergerea eşuează, se lansează
excepţia de tip RuntimeException dar datele pot fi şterse şi prin scripturi SQL.

Conteinerul apepează unSetEntityContext() înainte ca instanţa bean-ului să fie ştearsă,


dezasociind bean-ul de contextul lui şi eliberând resursele obţinute la apelul metodei
setEntityContext() respectiv conexiunea la baza de date.
Toate metodele de găsire a bean-ului au prefix find, doar metoda findByPrimaryKey() fiind
obligatorie, deoarece găseşte orice entity bean după cheia primară. Obiectul cheie primară primit
ca parametru este cheia primară din punct de vedere al clientului iar cel returnat de metodă ca
parametru este cheia primară din punct de vedere al conteinerului, fiind posibil ca cele două
obiecte să difere ca tip. Dacă nu există acel entity bean se lansează excepţia de tip
ObjectNoFoundException care descinde din FinderException şi este utilizată când finder
methods returnează o cheie primară.

Metoda ejbFindInRange() caută acele entity bean pentru care soldul este într-un anume interval
şi returnează un obiect de tip java.util.Collection în care stochează cheile primare ale tuturor
bean-urilor găsite. Fiecare cheie din colecţie permite conteinerului crearea unui obiect EJB.
Clientul apelează metoda findInRange() din interfaţa Remote() returnează o colecţie de obiecte
EJB. Metoda ejbFindInRange() foloseşte metoda findInRange() pentru a accesa baza de date şi
prin această metodă obţine cheile primare ale tuturor conturilor pentru care soldul este într-un
anume interval, adăugându-le într-un obiect ArrayList . Acest obiect implementează interfaţa
collection, şi poate fi returnat de metodă.

Separarea logicii de business de codul de acces la baza de date este realizat deoarece metodele de
business nu accesează la baza de date, astfel încât dacă se modifică aza de date componentele pot
fi reutilizate cu succes.Astfel cu metoda credit() se depun bani în cont şi cu metoda debit() se
extrag banii din cont.
Metodele de acces la baza de date sunt folosite doar din interiorul clasei, cu JBDC 2.0 care
permit adăugare, modificare, ştergere şi căutare în baza de date. Cu serviciul JNDI se obţine un
obiect de tip DataSource care permite conexiunea la baza de date.

Clasa InsufficientBalanceException

public class InsufficientBalanceException extends Exception {


public InsufficientBalanceException () {}

public InsufficientBalanceException (String msg) {


super(msg)
}
}

Interfaţa Home foloseşte metodele de creare - Create() şi găsire - findByPrimaryKey(),


findInRange() a bean-urilor. Fiecare metodă descrisă are corespondent în bean metoda cu acelaşi
nume şi prefixul ejb şi funcţionalitate similară. In mod obligatoriu se lansează excepţii de tip

38
javax.ejb.FinderException care descinde din FinderException respectiv
java.rmi.RemoteException.

Interfaţa Home pentru bean-ul Account

package exemple.entityMeabBMP;
import java.util.Collection;
import java.rmi.RemoteException;
import java.ejb.*;

public interface AccountHome extends EJBHome {

public Account create(String id, String firstName, String lastName, double balance)
throws RemoteException, CreateException;

public Account findByPrimaryKey(String id)


throws FinderException, RemoteException;

public Account findInRange(double low, double high)


throws FinderException, RemoteException
}

Interfaţa Remote extinde interfaţa javax.ejb.Object şi conţine toate metodele de business pe


care le poate invoca un client. Fiecare metodă din interfaţă are corespondent cu antet identic ca şi
cel din clasa bean-ului şi lansează în mod obliatoriu excepţia java.rmi.RemoteException.
Tipurile de date sunt serializabile, pentru a fi valide RMI; de obicei sunt folosite tipuri primitive.

Interfaţa Remote pentru bean-ul Account

package exemple.entityBeanBMP;

import java.rmi.RemoteException;
import java.ejb.EJBObject;
public interface Account extends EJBObject {

public void debit(double amount)


throws InsuficientBalanceException, RemoteException;

public void credit(double amount)


throws RemoteException;

public String getLastName()


throws RemoteException;

public double getBalance()


throws RemoteException
}
Un client pentru entity bean-ul Account foloseşte serviciul JNDI pentru găsirea interfeţei Home,
creează două conturi. Cheia primară a acestor conturi este seria şi numărul buletinului pentru
fiecare posesor de cont. In aceste conturi se depun şi se extrag sume.

39
Client pentru bean-ul Account

package exemple.entityBeanBMP;

package exemple.entityBeanBMP;

import java.rmi.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;

public class Client extends Object {

public static void main(String[] args) {


try {

// se obţine obiectul home


Context ctx= new InitialContext(System.getProperties());
AccountHome home=( AccountHome=ctx.lookup("AccountHome");

//utilizarea lui home factory pentru a crea două conturi


home.create("KX123456","Pop","Ion",10000);
Account accountM=home.create("PL123456","ADAM","PARASCHIVA",13000);

//depunere de suma in contul lui Adam


System.out.println("In contul lui Adam sunt:"+accountM.getBalance());
System.out.println(" depunere In contul lui Adam:"+accountM.credit(100));
System.out.println("In contul lui Adam sunt acum:"+accountM.getBalance());

//retragere de suma din contul lui Pop


Account accountG=home.findByPrimaryKey("KX123456");
System.out.println("In contul lui Pop sunt:"+accountG.getBalance());
System.out.println(" retragere din contul lui Pop:"+accountG.debit(50));
System.out.println("In contul lui Pop sunt acum:"+accountG.getBalance());

//depunere in toate conturile care au suma intre 50 si 100


Collection col=home.findAllInRange(50,100);
Iterator it=col.iterator();
Account account();
if(it.hasNext(){
account=it.next();
int creditWith=account.getBalance()*0.1;
account.credit(creditWith);
System.out.println(" depunere In contul lui :"+account.getFirstName()+'" "+
account.getLastName()+":"+creditWith);
}

//retragere de suma >soldul contului lui Pop


//cu exceptia InsufficientBalance
try{
System.out.println(" retragere din contul lui Pop:"+accountM.debit(350));
} catch {InsufficientBalanceException ibex) {

40
System.out.println("Imposibil! In contul lui Pop sunt doar:"+accountM.getBalance());
}
}catch (Exception ex) {
System.out.println(" O noua exceptie");
Ex.printStackTrace();
}
}//end of main
}//end of client Class

La deployment se specifică numele JNDI AccountHome pentru că altfel se va lansa o exceptie în


codul clientului la găsirea componentei folosind JNDI.
Serverul J2EE este free la adresa:http://java.sun.com/j2ee/j2sdkee şi poate fi instalat pe
Windows NT4, Windows 2000, Linux, Solaris. Kitul de Windows conţine 12MB iar
instructîunile de instalare sunt la adresa:
http://java.sun.com/j2ee/j2sdkee/install.html
Pentru alte aplicaţii:
http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/DevGuideTOC.html
sau în format PDF
http://java.sun.com/j2ee/j2sdkee/devguide1_2_1.pdf

Exemplu de entity bean conteiner managed persistance

Acest exemplu prezintă stocarea unor produse cu cod de identificare unic, descriere şi preţ.
Datele sunt stocate de conteiner iar baza de date poate fi obiectuală deşi codul aferent accesului
la baza de date este sarcina conteinerului. Programatorul specifică atributele bean-ului care se
vor stoca în bază de date, numite conteiner managed fields.

Clasa entity bean pentru product

package exemple.entityBeanCMP;

import java.util.*;
import javax.ejb.*;

public class productEJB implements EntityBean {

public String productid;


public String description;
public double price;

private EntityContext context;

public void setPrice(double price){


this.price=price;
}

public double getPrice(){


return price;
}

public String getDescription(){


return description;

41
}
//EntityBean interface methods

public String ejbCreate(String productId, String description, double price)


throws CreateException{
if (productId == null) {
throw new Create Exception( "The product id is required");
}

this.productId= productId;
this.description= description;
this.price= price;

return null;
}

public void setEntityContext(EntityContext context){


this,context=context;
}

public void ejbActivate(){


productId=(String)context.getPrimaryKey();
}

public void ejbPassivate(){


productId= null;
description= null;
}

public void unsetEntityContext(){}


public void ejbStore(){}
public void ejbLoad(){}
public void ejbRemove(){}
public String ejbPostCreate(String productId, String description, double price) {}
}
//product EJB

Metodele setEntityContext() şi unsetEntityContext() nu conţin cod pentru că nu solictă alocarea


de resurse ca şi în cazul bean managed persistance. Metoda ejbCreate() iniţializează câmpurile
gestionate de conteiner cu valoarea parametrilor de intrare şi întoarce null deoarece conteinerul
ignoră valoarea return, după care va insera date în baza de date. Metoda ejbPostCreate() se
apelează imediat după ejbCreate() şi nu conţine cod. La apelul metodei ejbActivate() se va activa
bean-ul, obţinând EntityContext, cheia primară fiind cea atribuită bean-ului la asocierea cu
obiectul EJB. Această cheie este păstrată într-un atribut al bean-ului.
Metoda ejbStore() sincronizează datele bean-ului cu cele din baza de date dar nu face şi stocarea
propriu-zisă. In această metodă se pot comprima datele de tip text spre exemplu.
Metoda ejbLoad() asigură sincronizarea datele bean-ului cu cele din baza de date dar face
pregatirea datelor pentru citire. In această metodă se pot decomprima datele de tip text, anterior
comprimate.
La apelul metodei ejbPassivate() se va dezasocia bean-ului de obiectul EJB, prin setarea cheii
primare pe null. Acum se şterg câmpurile de date pentru a nu păstra valori anterioare, însă nu şi
câmpul pret.

42
Metoda ejbRemove() este apelată de conteiner pentru a realiza operaţii premergătoare ştergerii
din baza de date.Datele sunt şterse de conteiner după apelul acestei metode, în caz de dificultăţî
lansându-se excepţia runtime, care nu se declară în throws.

Interfaţa Home foloseşte aceleaşi metodele de creare şi găsire a bean-urilor, codul acestor
metode fiind generat prin deployment tool. Metoda findByPrimaryKey() este implementată de
deployment tool , inclusiv fraza select ce aduce rândul din baza de date. Metodele
findByDescription() şi findInrange() sunt implementae de conteiner programatorul specificând
doar clauza where din fraza select iar aceste metode nu apar în clasa bean-ului, fiind gestionate
de conteiner.

Interfaţa Home pentru bean-ul product

package exemple.entityBeanCMP;
import java.util.Collection;
import java.rmi.RemoteException;
import java.ejb.*;

public interface ProductHome extends EJBHome {

public Product create(String productId, String description, double price)


throws RemoteException, CreateException;

public Product findByPrimaryKey(String productId)


throws FinderException, RemoteException;

public Product findInRange(double low, double high)


throws FinderException, RemoteException
}

Interfaţa Remote conţine toate metodele de business pe care le poate invoca un client.

Interfaţa Remote pentru bean-ul Product

package exemple.entityBeanCMP;

import java.rmi.RemoteException;
import java.ejb.EJBObject;
public interface Product extends EJBObject {

public void setPrice(double price) throws RemoteException;

public double getPrice() throws RemoteException;

public String getDescription() throws RemoteException;

Un client pentru entity bean-ul Account foloseşte serviciul JNDI pentru găsirea interfeţei Home,
creează două conturi. Cheia primară a acestor conturi este seria şi numărul buletinului pentru
fiecare posesor de cont. In aceste conturi se depun şi se extrag sume.

43
Client pentru bean-ul Product

package exemple.entityBeanCMP;

import javax.rmi.PortableRemoteObject;
import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;

public class Client {

public static void main(String[] args) {


try {

// se obţine obiectul home


Context ctx= new InitialContext(System.getProperties());
ProductHome home=( ProductHome=ctx.lookup("ProductHome");

//utilizarea lui home factory pentru a crea produse

Product st=home.create("001","stilou",130000);
System.out.println(st.getDescription()+":"+st.getPrice());
St.setPrice(70000);
System.out.println(st.getDescription()+":"+st.getPrice());
home.create("002","pix",40000);
home.create("003","liniar",10000);
home.create("003","pix",45000);

//afişare de produs cu cheia 002


Product cr=home.findByPrimaryKey("002");
System.out.println(cr.getDescription()+":"+cr.getPrice());

//afisare de o produse care au descrierea pix


Collection c=home.findByDescription("pix");
Iterator i=c.iterator();

while(i.hasNext(){
Product product = (Product)i.next();
String productId= (String)produc.getPrimaryKey();
String description=product.getDescription();
double price=product.getPrice();
System.out.println(productId+ description+price);
}

//afişarea produselor cu pret intre 10000 şi 100000


c=home.findInRange(10000.,100000.);
i=c.iterator();

while(i.hasNext(){
try{

44
Product product = (Product)i.next();
String productId= (String)produc.getPrimaryKey();
String description=product.getDescription();
double price=product.getPrice();
System.out.println(productId+ ":"+price);
}catch (Exception ex) {
System.out.println(" O noua exceptie");
Ex.printStackTrace();
}
}//end of main
}//end of client Class

La deployment se specifică numele JNDI ProductHome pentru că altfel se va lansa o exceptie în


codul clientului la găsirea componentei folosind JNDI.
Serverul J2EE este free la adresa:http://java.sun.com/j2ee/j2sdkee şi poate fi instalat pe
Windows NT4, Windows 2000, Linux, Solaris. Kitul de Windows conţine 12MB iar
instructîunile de instalare sunt la adresa:
http://java.sun.com/j2ee/j2sdkee/install.html
Pentru alte aplicaţii:
http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/DevGuideTOC.html
sau în format PDF
http://java.sun.com/j2ee/j2sdkee/devguide1_2_1.pdf

Tranzacţii în J2EE

2.1. Cerinţe privind securiatea tranzacţiilor electronice

Într-un sistem electronic, caracterizat de accesul la mare distanţă a informaţiilor, numeroase


rapoarte subliniază faptul că în dezvoltarea afacerilor apar o serie de probleme legate de:
 Securitatea internă, cunoscute fiind numărul mare al infracţiunilor de securitate produse de
către persoane din interior;
 Atacurile externe continue, cunoscute ca atacuri frecvente ale hacker-ilor care încearcă
diverse modalităţi de perturbare a securităţii şi integrităţii datelor şi acţionează asupra
conexiunii dintre client şi server;
 Codul maliţios creat cu scop distructiv, rău intenţionat, mai ales în limbajul Java;
 Atacurile la servicii care încearcă să ocolească mecanismele de confidenţialitate şi
integritate.
Atacurile pasive şi constau în monitorizarea traficului dintre client şi server iar cele active
determină modificarea traficului pe reţea şi acţionează asupra serverului vânzătorului.
In domeniul tranzacţiilor electronice apar o serie de cerinţe minime de securitate:
Confidenţialitatea presupune ca datele sunt păstrate în forma criptată inclusiv faţă de vânzătorul
care supraveghează tranzacţia pentru a preveni ascultarea şi înregistrarea neautorizată. Această
caracteristică presupune totodată şi criptarea canalelor de comunicaţie între cumpărător şi
vânzător.
Autentificarea originii tranzacţiilor implică suportul pentru semnătura digitală, care se referă la
posibilitatea de a identifica identitatea expeditorului, cunoscut fiind faptul că doar pentru
cumpărător autentificarea este opţională.
Integritatea datelor este o cerinţă menţinută permanent în cadrul plăţii electronice şi este
asigurată prin calculul unei chei de integritate a mesajului.

45
Nerepudierea este împiedicarea nerecunoaşterii tranzacţiei de către expeditor şi garantează
integritatea şi originea tranzacţiilor din punct de vedere al expeditorului şi nu al destinatarului.
Prin această cerinţă se ermite transmiterea tranzacţiilor către alţi destinatari, care pot verifica
identitatea originii mesajului precum şi a intermediarului. La recepţia acesteia se verifică
integritatea acesteia şi faptul că nu a fost alterată de către intermediari. O aplicaţie importantă a
acestui tip de serviciu o constituie ordinele de comandă transmise prin e-mail.
Aplicarea selectivă a unor servicii este necesară în special la acoperirea unei părţi a tranzacţiilor
(numărul cărţii de credit, pin-ul,etc.) ce sunt inaccesibile clar vânzătorului. Pentru aceasta se
folosesc sisteme criptografice cu chei publice.

Pentru asigurarea protecţiei împotriva acestor atacuri se realizează protocoale specifice:


- protocol de transport sigur end-to-end, necesar pentru prevenirea atacurilor de modificare şi
ascultare a reţelei;
- protocol de plată electronică sigura destinat prevenirii atacurilor de la serverul vânzătorului.

Faţă de situaţiile anterioare, când programatorii utilizau Transaction API pentru a realiza
tranzacţiile, în cazul tehnologie EJB sunt puse la dispoziţie de platforma J2EE într-o manieră
prietenoasă.
O caracteristică exenţială a tranzacţiilor o constituie atomicitatea acestora, dat fiind faptul că
orice tranzacţie ce presupune mai multe operaţii distincte este considerată reuşită abia dacă toate
operaţiile s-au efectuat cu succes la fel cum orice eşec al unei operaţii obligă aplicaţia să revină
la starea iniţială considerând tranzacţia eşuată.
O altă cerinţă presupune că starea sistemului rămâne consistentă după terminarea unei tranzacţii.
De exemplu, în urma unei tranzacţii, stocul d eproduse rămâne pozitiv sau nul, soldul unui cont
bancar este pozitiv,etc.
Izolarea tranzacţiilor are rol de protecţie pentru că fiecare tranzacţie nu poate vedea rezultatele
parţiale ale altor tranzacţii ce manipulează aceleaşi date. Izolarea permite tranzacţiilor citirea şi
scrierea simultană în aceeaşi bază de date, fără a depinde unele de altele şi astfel fiecare client
vede baza de date ca şi cum ar fi unicul utilizator. Sistemul de tranzacţii utilizează protocoale de
sincronizare care permit automat blocarea tranzacţiilor şi garantează faptul că nici o altă
tranzacţie nu poate opera asupra datelor blocate.
Orice cădere a sistemului indiferent de natura acestora nu afectează modificările asupra bazei de
date, datorită proprietăţii de durabilitate a tranzacţiilor.

2. Aspecte particulare ale tranzacţiilor în J2EE

In aplicaţiile de business sunt des utilizate două categorii de tranzacţii:flat transactions şi nested
transactions însă J2EE nu suportă decâţ primul tip de tranzacţii.
O flat transaction reprezintă o serie de operaţii efectuate ca tot unitar. Tranazacţia poate fi
realizată cu succes, caz în care este denumită commited şi operaţiile asupra datelor devin
permanente sau poate fi abandonată - aborted, ceea ce înseamnă că operaţiile asupra datelor nu
pot fi permanente, tranzacţia este derulată (rolled back).
In cazul tranzacţiilor abandonate, componentele de business nu conţin nici un fel de logică
pentru a realiza renunţarea la tranzacţie (undo) ci sistemul şi baza de date asupra căreia se fac
modificări vor conlucra la derularea tranzacţiei.
Spre exemplu, dacă o tranzacţie efectuează operaţii asupra bazei de date, una din componentele
de business va obţine o conexiune la baza de date, care va fi adăugată automat în tranzacţia la
care participă componenta, Când componenta efectuează operaţii care implică persistenţa
datelor, (update -actualizări), aceste operaţii nu sunt aplicate permanent de către resource
manager asupra datelor ci abia când primeşte comanda commit. Baza de date primeşte această
comandă doar dacă tranzacţia a reuşit, în caz contrar, modificărire făcute nu au efect asupra ei.

46
Componentele au sarcina de a controla tranzacţiile şi a le declara aborted sau commited, în rest
derularea tranzacţiilor este sarcina exclusivă a sistemului.
Tipuri de tranzacţii
In timpul derulării unei tanzacţii nu se utilizează sistemul de tranzacţii la nivelul inferior, ceea ce
înseamnă că nu se produc interacţiuni cu transaction manager sau resource manager. Sistemul
de tranzacţii este abstractizat de conteinerul EJB, componentele având doar sarcina a le declara
aborted sau commited.Aceasta înseamnă că tranzacţia se desfăşoară în spatele scenei dar se
specifică la frontiera ei.
Demarcarea frontierei unei tranzacţii poate fi realizată declarativ sau programatic. In cazul
demarcării programatice, în codul componentei EJB se specifică momentul când începe, cazul
când este declarată aborted (prin excepţiile proiectate) şi când devine commited.Dacă
demarcarea este declarativă aceste sarcini sunt realizate de conteinerul EJB.
Astfel, pentru un bean care reprezintă contul bancar, una din metodele acestuia va realiza
transfer de sume dintr-un cont în altul (1), pentru care conteinerul EJB va începe tranzacţia (4)
după apelarea metodei bean-ului (3) pentru care în prealabil obiectul EJB apelează begin()
asupra Transaction Service. In cadrul metodei de business (4) se pot executa operaţii logice,
scrierea în baza de date sau chiar apelul altor bean-uri. Dacă apare vreo excepţie, tranzacţia se
declară aborted iar conteinerul apelează sistemul de tranzacţii (5) ca şi în figura 2.177

Client

1
Interfaţa Remote
EJB Object
3 EJB Conteiner
2
5 Bean
Metode de
Transaction Service business
4

Figura 2.177. Bean cu tranzacţii declarative

In acest caz bean-urile şi clientul nu ştiu că participă efectiv la tranzacţii, deoarece bean-ul nu
apelează nici un API de tranzacţii ca şi în cazul celor programatice în care trebuie să se utilizeze
Java Transaction API.Conteinerul este cel care trebuie să cunoască tipul tranzacţiilor aplicate
asupra bean-urilor, prin intermediul transaction attribute specificat în deployment descriptor.
Orice bean posedă un deployment descriptor care precizează proprietăţi utilizate de conteinerul
EJB la interacţiunea cu bean-ul. Atributele deployment specificate la nivel de metodă a bean-ului
sunt prioritare faţă de cele specificate la nivelul întregului bean sau mai precis, atributele bean-
ului sunt aplicate doar metodelor care nu au atribute proprii.
Prin Application Deployment Tool sunt precizate atributele referitoare la trnazacţiile unui entity
bean, precizând tipul de management - conteiner managed transaction. Acestea pot fi: Not
Supported, Required, Requiers New, Supports, Mandatory, şi Never.
Atributul Not Supported este specific bean-urilor care nu realizează operaţii critice, în care să
beneficieze de atomicitate, consistenţă, izolare şi durabilitate, cu alte cuvinte este specific
metotodelor ce nu pot fi implicate tranzacţii. De exemplu, metoda care returnează numărul
vizitatorilor din magazinul virtual, nu este implicată în tranzacţii şi este de tip Not Supported.

47
Atributul Required al tranzacţiei indică faptul că metoda participă întotdeauna la tranzacţii. Dacă
tranzacţia există şi se derulează, atunci metoda bean-ului va fi adăugată la tranzacţie iar dacă nu
există încă, se va începe o tranzacţie nouă.
Atributul Requires new precizează începerea unei tranzacţii noi indiferent de starea altor
tranzacţii. Dacă o tranzacţie există şi se derulează, atunci se va suspenda până la derularea noii
tranzacţii şi se va relua după terminarea (commited sau aborted) a respectivei tranzacţii.
Atributul Supports diferă faţă de Required prin faptul că metoda nu va începe o tranzacţie nouă
iar dacă tranzacţia există şi se derulează, atunci metoda bean-ului va fi adăugată la tranzacţie.
Atributul Mandatory solicită obligatoriu ca tranzacţia să existe şi să se deruleze când metoda
este apelată. Dacă nu există nici o tranzacţie, atunci metoda bean-ului proiectează excepţia
javax.ejb.TransactionRequired şi conteinerul nu va începe o nouă tranzacţie.
Valoarea Never precizează metoda nu participă niciodată la nici o tranzacţie iar dacă la
momentul apelului există o tranzacţie şi se derulează, metoda bean-ului proiectează o excepţie.

Componentele WEB

1. Java Servlets

1.1. Aspecte definitorii

Pentru a extinde funcţionalitatea serverelor Web se folosesc Java Servlets care sunt programe
Java independente de platformă, care fac parte din componentele server-side şi care
interacţionează cu motorul servlet-ului, suportat de serverul Web, bazându-se pe protocolul de
comunicaţie tip cerere-răspuns, axat la rândul lui pe protocolul HTTP.
Spre deosebire de acestea, appleturile fac parte din componentele client-side care rulează într-un
browser Web, în interiorul unei pagini HTML sau a interfeţei grafice.
Aplicaţia client, web browser-ul de pildă, accesează serverul Web şi trimite o cerere care este
procesată de motorul servlet-ului instalat pe serverul Web. Acest motor întoarce un răspuns
servletului iar servetul returnează la rândul lui răspuns HTTP clientului.
Pachetul javax.servlet este pachetul principal utilizat precum şi extensia sa javax.servlet.http
care permit extensia claselor în cazul servleţilor HTTP.
Servleţii realizează prelucrarea şi/sau stocarea datelor trimise prin intermediul formularelor
HTTP, asigură conţinut dinamic prin manipularea unor date din baza de date şi permit
administrarea mai multor cereri HTTP.
Aceste caracteristici principale conduc la avantaje ale servleţilor faţă de CGI. Pentru modelul
CGI (Common Gateway Interface) fiecare cerere este administrată într-un proces de instanţă
separată a scriptului CGI iar la servlet-ul nu rulează în proces separat.
Programul CGI se încarcă în memorie la fiecare cerere CGI iar servlet-ul se încarcă în memorie
şi rămâne între cereri, existând o singură instanţă care răspunde la cereri simultane. Aceasta
conduce la administrarea facilă a datelor şi economie de timp şi memorie ocupaţă.
Deoarece servlet-ul este rulat de motorul servlet -Servlet Engine în zona restrictivă - SandBox se
folosesc potenţialele în siguranţă.

1.2. Arhitectura şi ciclul de viaţă al servlet-ului

Orice servlet implementează interfaţa Servlet, în care se declară metode de iniţializare a


servletului şi de comunicare cu clienţii, sau extinde clasa HTTPServlet care la rândul ei
implementează interfaţa Servlet.
Comunicarea client-server este încapsulată în două obiecte ServletRequest şi ServletResponse
care sunt primite la momentul când clientul trimite o cerere servlet-ului.

48
Interfaţa ServletRequest asigură accesul la informaţiile trimise de client (nume de parametri,
caracteristicile acestora) şi la protocolul utilizat (http,https,ftp,etc), precum şi numele
clientului.Clasa ServletInputStream permite servlet-ului să primească datele, prin metode
POST şi PUT, de la clienţii ce folosesc protocol HTTP.Subclasele ServletRequest asigură
recuperarea datelor de către server deoarece conţin metode ce accesează antetul HTTP, prin clasa
HTTPServletRequest .

ServletResponse asigură metode de răspuns către clienţi, deoarece clasa ServletOutputStream


asigură flux de ieşire prin metoda getWriter() iar servletul poate seta tipul, dimensiunea şi
conţinutul datelor trimise prin setarea Contentlenght şi MIME type. Subclasele
ServletResponse asigură funcţionalităti specifice protocolului iar HTTPServletResponse
conţine metode ce accesează câmpuri specifice protocolului HTTP.
Ciclul de viaţă al servletului este format din metode ce permit încărcarea şi instanţierea,
iniţializarea, tratarea cererilor precum şi modul de terminare al acestuia.

Incărcarea şi instanţierea este realizată de motorul servletului, fie la momentul în care trebuie
să răspundă cererilor clienţilor, fie la începutul activităţii. Deoarece foloseşte facilităţi Java de
încărcare, poate să facă încărcarea fie de pe un sistem local de fişiere, fie de pe un sistem la
distanţă sau de pe o sursă de reţea.

Iniţializarea are rolul de a asigura citirea datelor persistente care pot fi stocate şi presupune
iniţializarea conexiunilor la baza de date şi/sau stabilirea referinţelor la diferite resurse. Spre
deosebire de appleturi, metoda init() din interfaţa javax.servlet.Sevlet utilizează obiectul
ServletConfig transmis ca parametru de configurare.Acest obiect este implementat pe motorul
servletului
Tratarea cererilor
Cererile clienţilor sunt reprezentate de obiecte de tip ServletRequest iar servletul răspunde
cererii prin obiecte de tip ServletResponse. Motorul servletului trimite ambele obiecte atunci
când clientul execută o cerere iar Request şi Response sunt parametri ai metodei service()
definită de interfaţa Service, care este implementată de către servlet.
Distrugerea servletului este realizată de motorul servletului ori de câte ori acesta doreşte
eliberarea unei resurse sau oprirea servletului deoarece nu este obligat să menţină în viaţă un
servlet pe toată durata rulării serverului. Metoda destroy() implementată de servlet este apelată
de motorul servletului cu condiţia că se respectă un interval de timp de la apelul metodei
service().
Definirea ServletContext permite servletului să ruleze într-un singur context de servlet, deşi
servleţi diferiţi pot avea diverse vizualizări asupra motorului servletului. Prin utilizarea
obiectului ServletContext, servletul poate trata evenimente şi poate obţine diverse resurse de la
mototul servletului, ca şi obiectul RequestDispatcher de pildă.
Sesiunea HTTP permite identificarea unor serii de cereri unice care sunt trimise clientului aflat
la distanţă. Prin interfaţa simplă pusă la dispoziţie de Java Servlet API, motorul servletului poate
asigura utilizarea unui număr de tehnici de tratare a sesiunii dedicată unui utilizator.

1.3. Aspecte particulare de funcţionare a servleţilor

Deşi servleţii implementează direct interfaţa javax.servlet.Servlet în mod uzual aceştia nu sunt
dezvoltaţi în această manieră ci extinzând clasa specializată javax.servlet.http.HttpServlet
deoarece majoritatea folosesc protocolul HTTP. Această clasă suportă tehnica multithread şi
rulează simultan mai multe metode service().Dacă în schim se preferă ca un singur serviciu să
ruleze la un moment dat, se implelementează interfaţa SingleThreadModel care nu solicită
metode adiţionale.

49
Deservirea cererilor HTTP obligă la extinderea clasei abstracte HttpServlet prin metode ce
redefinesc diferite tipuri de cereri:
 doGet pentru cereri de tip GET şi HEAD;
 doPost pentru cereri de tip POST;
 doPut pentru cereri de tip PUT;
 doDelete pentru cereri de tip DELETE;

Toate aceste metode returnează implicit mesaj BAD_REQUEST(400) în cazul în care cererea nu
poate fi realizată. Dat fiind faptul că pe un server există mai mulţi servleţi, este necesară
comunicaţia inter-servleţi, având la dispoziţie o serie de metode în acest sens. Pentru aceasta
servleţii trebuie încărcaţi de ClassLoader iar prin apelul metodei getServletNames() se poate
obţine lista servleţilor. Comunicaţia este ceva mai complicată deoarece este necesară definirea
unei interfeţe ce se încarcă de către SystemLoader şi care facilitează co municaţia prin
intermediul obiectelor.
Comunicaţia servlet-server este realizată în scopul accesării unor resurse pasive ale serverului ,
prin metoda getResource() din clasa ServletContext sau pentru adresarea unor cereri în
manieră similară cu ale clienţilor obişnuiţi. In plus servletul poate trimite cookies asigură
internaţionalizarea aplicaţiilor din care face parte şi oferă posibilitatea autentificării unui user
după sesiune (Sessions).

In exemplul următor se descrie o posibilă extindere a metodei doPost pentru accesarea unei baze
de date prin intermediul unui servlet.

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import mypackage.myBean;

public class DBHandler extends HttpServlet {


public void doPost (HttpServletRequest req, HttpServlet.Response res){
try {
myBean bean=(myBean)req.getAttribute("formHandler");
boolean userExists=false;

//se obţine conexiunea la baza de date


// se execută o interogare
//daca exista un utilizator cu acelaşi id de setează flagul userExist

if(userExist) {
bean.setErrors("userName", "Duplicate User");
getServletConfig().get ServletContext().getRequestDispatcher
("/jsp/myforms/retry.jsp").forward(req,res);
}
else {
//citirea proprietătilor bean-ului si stocarea în baza de date
getServletConfig().get ServletContext().getRequestDispatcher
("/jsp/myforms/success.jsp").forward(req,res);
}
}
catch (Exception e) { e.printStackTrace();}
}
}

50
Afişarea conţinutului dinamic al unui formular HTML , într-o pagină HTML generată dinamic
de Servlet

package myPackage;

import java.io.PrintWriter;
import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServlet.ServletRequest;
import javax.servlet.http.HttpServlet.ServletResponse;
import javax.servlet.ServletException;

public class Form2 extends HttpServlet {

public void doGet (HttpServletRequest request, HttpServlet.Response response)


throws ServletException,IOException
{
response.setContextType("text/html");

File htmlFile = new File("e:/…/com/javapal/CellQuotes/CQForm.html");


PrintWriter responseWriter= response.getWriter();
BufferReader fileReader = new BufferReader(new fileReader(htmlFile));

String line;
while ((line= fileReader.readLine()) !=null)
{
responseWriter.println(line);
responseWriter.flush;
}
filereader.close();
responseWriter.close();
………
}

Citirea a 3 imagini d ela un URL, a 5 siruri dintr-o baza d edate şi afişarea lor într-o pagină
HTML generată dinamic, împreună cu 5 Checkbox-uri

package myPackage;

import java.io.PrintWriter;
import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServlet.ServletRequest;
import javax.servlet.http.HttpServlet.ServletResponse;
import javax.servlet.ServletException;

public class Form1 extends HttpServlet {

51
Conect con=new Conect();
int id=0;

public void service (HttpServletRequest request, HttpServlet.Response response)


throws ServletException,IOException
{
response.setContextType("text/html");
// fluxul de lucru out

PrintWriter out= response.getWriter();


//conţinut întrebare citit din DB;
String continutIntrebare=" " ;
String rasp=" " ;
//tablou pentru siruri citite din DB;
String [] strtab=new String[5] ;

try{
continutIntrebare=con.getStringDB("cont",1,"2");
for (int i=1; i<6; i++) {
strTab[I-1]=con.getStringDB("R"+i,1,"2");
}
}
catch (Exception e) {
}
out.println("<html>"+
"<head><title>First Form</head></title>" +
"<body bgcolor=\"#FFFFFF\">"+
"<center>"+
"<h1>"+<font size=\"+3\"color=\"blue\">Connected to </font>"+
+<font size=\"+3\"color=\"blue\">the Testing System </font>"+
"</h1>"+"<center>"+
"<br>&nbsp;<hr><br>&nbsp;");
for (int i=1; i<=strTab.length; i++) {
out.println("<FORM METHOD=POST>"+
continut intrebare+
"<P><INPUT TYPE=\"checkbox\"NAME=\"R1\">"+strTab[0]+
"<BR><INPUT TYPE=\"checkbox\"NAME=\"R2\">"+strTab[1]+
"<BR><INPUT TYPE=\"checkbox\"NAME=\"R3\">"+strTab[2]+
"<BR><INPUT TYPE=\"checkbox\"NAME=\"R4\">"+strTab[3]+
"<BR><INPUT TYPE=\"checkbox\"NAME=\"R5\">"+strTab[4]+
"</FORM>"+
"<IMG SRC=\"http://…//unu.jpg\" LOWSRC=\"http://…//unu.jpg\" HEIGHT=160
WIDTH=200
ALT=\"blue\">"+
"<IMG SRC=\"http://…//doi.jpg\" LOWSRC=\"http://…//doi.jpg\" HEIGHT=160
WIDTH=200
ALT=\"blue\">"+
"<IMG SRC=\"http://…//trei.jpg\" LOWSRC=\"http://…//trei.jpg\" HEIGHT=160
WIDTH=200
ALT=\"blue\">"+

52
"<br>&nbsp;<hr><br>&nbsp;");
}
out.println("<FORM METHOD=POST>"+
"<br>&nbsp;<hr><br>&nbsp;";
<INPUT TYPE=\"submit\" value=\"Submit\">"
"<br>&nbsp;<hr><br>&nbsp;");
out.close();
}
}

1.4. Tehnologia JSP

Orice aplicaţie Web realizată va solicita diferite componente de bază dintre care, precizăm:
 Java Runtime Environment, ce rulează obligatoriu pe serverul aplicaţiei;
 Java Beans, componente server-side care încapsulează comportamentele şi stările
aplicaţiei;
 Pagini JSP sau Java Servlets, ce preiau cererile clienţilor şi generează conţinut dinamic;
 Documente HTML, XML, DHTML etc.
 Java Applets şi alte fişiere Java de tip class şi/sau Java Beans, componente client-side care
încapsulează comportamentele şi stările aplicaţiei;
 Java Runtime Environment, ce rulează la client şi poate fi încărcat prin plug-in;

Java Server Pages (JSP) reprezintă tehnologia utilizată pe partea d eserver în scopul creării de
paginii HTML dinamice. In esenţă JSP este o extensie a Java Servlets şi oferă posibilitatea d
eseparare a părţii de prezentare de cea de procesare iar motorul JSP este un alt Servlet mapat la
extensia JSP.
Pagina JSP descrie modul de procesare a unei cereri (request) în vederea generării unui răspuns
(response) în care se includ date şablon (template data), acţiuni dinamice şi mecanisme proprii
platformei Java, suportând în special documente structurate HTML şi XML.
JSP-urile folosesc informaţii care le trimit la server într-o cerere HTTP şi care interacţionează cu
datele existente pe server, creând în mod dinamic un răspuns structurat în mod standard (ca
documente HTML, XML, DHTML etc) sau alte formate ce sunt suportate de client.
Java Server Pages moştenesc de la Servlets toate conceptele referitoare la Applications,
ServletContext, Sessions, Requests şi Response, având particularitatea că înglobează atât
componente JavaBeans, tag-uri personalizate şi scriptlets. Unicitatea lor este asigurată prin
înglobarea elementelor de conţinut cu cele de reprezentare.

1.4.1. Directivele JSP

Directivele JSP sunt elemente ce furnizează informaţii globale referitoare la pagina JSP, pe baza
unei sintaxe generale:

<%@ directive{attribute="value"}%>

O directivă poate conţine n perechi atribut/valoare şi sunt divizate în trei tipuri: page, include şi
taglib

Directiva page are rolul de a defini informaţiile care sunt disponibile global la nivelul JSP,
fiecare dintre acestea având rol în compilarea paginii JSP.
 language="scriptingLanguage" - specifică limbajul folosit la compilare;
 extends="className" - precizează clasa de bază a serverului generat;
 import="importList" - defineşte lista de pachete disponibile JSP-ului;

53
 session="true/false" defineşte disponibilitatea datelor de sesiune în cadrul paginii;
 buffer="none/size(KB)" precizează bufferul pentru outputStream;
 autoFlush="true/false" determină dacă fluxul de ieşire va fi golit automat (true) sau nu
(false);
 isThreadSafe="true/false" precizează dacă motorul JSP răspunde la mai multe cereri (true)
sau nu (false);
 info="text" specifică dacă pagina JSP va fi accesată de metoda getServlet a servletului
generat;
 erroPage="error_url" specifică URL-ul paginii JSP care va prinde toate excepţiile;
 isErrorPage="true/false" precizează dacă pagina JSP este o pagină de eroare(true) sau nu
(false);
 contentType="ctinfo" furnizează tipul MIME şi setul de caractere de răspuns;

Directiva include are rolul de a insera cod şi text folosind sintaxa:

<%@ include file="relative URL"}%>

Fişierul menţionat în directivă este de obicei un fişier text sau HTML dar poate fi chiar o pagină
JSP.

Directiva taglib se utilizează pentru a extinde setul curent de tag-uri JSP prin crearea unei
biblioeci de tag-uri. O pagină poate folosi aceste taguri particularizate, unice prin numele
acestora asociind prefixul tag pentru a le distinge la utilizare.

<%@ taglib="tagLibrary URI" prefix="tagPrefix"}%>

URI-ul referit în sintaxă numeşte în mod unic un set de tag-uri iar prefix este utilizat pentru a
distinge o instanţă de taguri.

Acţiunile reprezintă încapsularea diferitelor task-uri şi sunt utilizate pentru a crea obiecte
JavaBean sau pentru a acţiona asupra bean-urilor. In tehnologia JSP există câteva acţiuni
standard pe care le prezentăm în cele ce urmează.

<jsp:useBean> permite instanţierea unui JavaBean cu scop şi id bine precizat.


<jsp:setProperty> setează valoarea unei proprietăţi a Bean-ului.
<isp:getProperty> preia valoare proprietăţii unei instanţe a Bean-ului şi o converteşţe în String,
în vederea afişării acesteia.
<jsp:include page="URLSpec" flush="true"/> permite includerea resurselor statice.
<jsp:include page="URLSpec" flush="true"/>
{ jsp:param…/>}
</jsp:include> permite includerea resurselor dinamice.
<jsp:forward> permite ca un motor JSP să comunice în timpul execuţiei (runtime) cererea
curenţă către o resursă statică, Servlet sau alt JSP. Acţiunea se termină când se termină execuţia
paginii curente.Sintaxa este:
<jsp:forward page="relative URLspec"/> sau
<jsp:forward page="relative URLspec"/>
{ <jsp:param…/>}
</jsp:forward>
<jsp:plugin> permite generarea unei pagini HTML care conţine elemente dependente de
browser (OBJECT sau EMBEDED) rezultate din download-area plugin-ului Java şi execuţia
subsecvenţială a appletului respectiv sau a componentei JavaBean. In acest caz este posibil, în

54
funcţie de cerere, înlocuirea tag-ului <jsp:plugin> cu <object> sau <embeded> şi trimiterea
noului tag ca şi răspuns.Atributele prezente în <jsp:plugin> au rolul de a furniya date de
configurare pentru prezentarea elementului.
<jsp:plugin type="pluginType"
code="classFile"
codebase="relative URLpath">
{ <jsp:param>

</isp:param>}
</jsp:plugin>

Pentru a exemplifica modul de utilizare prezentăm mecanismul de funcţionare reprezentat de o


pagină JSP care utilizează un Script HTML şi un Bean şi care afişează login-ul clientului atunci
când acesta solicită o pagină prin intermediul unui formular HTML. In momentul în care se
întâlneşte primul element JSP, se crează un obiect server-side Bean, cu nume login şi tip
Profi.login, determinat de cerere. Obiectul poate fi folosit şi utilizat în pagină. La generarea
răspunsului, se foloseşte una din proprietăţile acestui obiect, inserând în pagină numele
utilzatorului ca şir de caractere (String), conform schemei din figura….
Pagina JSP
Figura…

Conteiner JSP <html>


Cerere request() <jsp:useBean id="login" class="Profi.Login"/>
<body>
<center>
Hello <%=login.getUsername()%>
</body>
Răspuns response() </center>
</html>

1.4.2. Semantica şi conţinutul paginilor JSP

Orice pagină JSP este executată într-un conteiner JSP care este instalat pe serverul Web. Acesta
preia cererile de la client şi le pune la dispoziţia paginii, livrând şi rezultatele. De aceea structura
semantică a paginilor JSP este similară cu a servleţilor descriind modul de creare a obiectului
răspuns pornind de la un obiect cerere creat pentru un anume protocul şi folosind alte obiecte
deja create.
Conteinerul JSP este o entitate la nivel de sistem care asigură managementul execuţiei
programului şi suport pentru componentele JSP şi Servlets. Un conteiner JSP suportă protocolul
HTTP ca şi protocol cerere/răspuns dar poate să suporte şi alte protocoale. Obiectele
cerere/răspuns sunt HttpServletRequest respectiv HttpServletResponse, putând indica şi
modul în care se tratează diverse evenimente sau poate iniţializa sau distruge un eveniment.
O pagină JSP este reprezentată de JSP page implementation class care implementează interfaţa
javax.servlet.Servlet dar de multe ori paginile sunt implementate folosind o singură dată JSP
translation phase, succedată de request processing phase utilizată o dată pentru o cerere.
Pagina conţine declaraţii, comenzi standard (fixed template), instanţele acţiunilor (action
instance) şi elemente de script folosite atunci când cererea se livrează paginii, pentru a crea un
obiect de tip răspuns ce va fi livrat clientului. Pagina JSP, ce descrie modul în care se crează
obiectul response pe baza obiectului request, folosind protocolul dat şi/sau alte obiecte este
executată de conteinerul JSP care trimite cererile către JSP page implementation class, subclasă
Servlet.

55
Aplicaţia Web reprezintă o colecţie de resurse (JSP, servlets, pagini statice sau dinamice, clase
bazate pe tehnologia Java) disponibile prin URL-uri. Inafara acestora există clase ce pot fi
folosite de client prin download (appleturi, componente Javabeans, etc). Descrierea aplicaţiei
este conţinută în web.xml, definit ca deployment descriptor care conţine informaţii referitoare la
JSP, servlets şi alte resurse utilizate de aplicaţie, care în cazul JSP 1.1. sunt asociate implicit cu
o instanţă unică ServletContext. Instanţa este disponibilă ca obiect implicit application iar JSP
moşteneşte noţiuni despre aplicaţiile Web de la Servlet 2.2. Aplicaţia căreia îi aparţine pagina
JSP este reflectată în obiectul application şi are o corespondenţă cu semantica elementelor. De
pildă instrucţiunea include are acţiunea jsp:include sau acţiunea jsp:forward.
Clasa JSP page implementation, ca subclasă Servlet defineşte metoda jspService() care
mapează cererea într-un obiect de tip response, tratând în mod specific detaliile de transformare
în funcţie de limbaj. Conţinutul majoritar al paginii JSP asigură descrierea datelor ce sunt puse la
dispoziţia clientului în stream-ul de scriere, returnat clientului. Descrierea este bazată pe un
obiect de tip JspWriter- out care poate avea la rândul lui mai multe valori. Iniţial el este un nou
obiect de tip out dar poate fi diferit de stream-ul obţinut prin apelul metodei
response.getWriter() imbricate.La nivelul unei acţiuni, out se poate realoca pentru o altă
instanţă aobiectului JspWriter deşi de obicei conţinutul sau rezultatul procesării acestor stream-
uri temporare este adăugat stream-ului out şi apoi reasignat. In anumite situaţii unele stram-uri
imbricate pot fi puse într-un buffer şi solicită crearea explicită pentru a returna conţinutul lor.
Dacă buffer are o dimensiune (KB) în instrucţiunile paginii, conţinutul bufferului va fi transferat
automat (dacă autoFlush="true") în stream-ul de scriere ServletResponse sau se lansează o
excepţie de tip buffer overflow în schimb dacă JspWriter nu se află într-un buffer conţinutul se
trece direct în fluxul de scriere.

Instrucţiuni JSP

Elemente JSP sunt divizate în două categorii: instrucţiuni şi acţiuni. In cazul instrucţiunilor sunt
furnizate informaţii globale, independente conceptual de orice cerere primită de JSP şi sunt
precizate prin sintaxa3 (JSP1.1.):

<%@ directive {atribute="valoare"} *%>

Această sintaxă nu este compatibilă XML , solicitând o mapare a comenzilor. Instrucţiunea


page defineşte un număr de atribute care sunt dependente de pagină şî le comunică conteinerului.
Intr-o unitate de interpretare, reprezentată de un fişier sursă şi orice alte fişiere precizate prin
instrucţiunea include, pot apărea mai multe instrucţiuni page, atributele incluse fiind aplicate
fiecărei unităţi de interpretare în parte. Se recomandă evitarea apariţiilor multiple de perechi
atribut/valoare deoarece perechile necunoscute sau repetate pot genera erori, excepţia făcând-o
atributul import. Cele mai cunoscute atribute vor fi prezentate în continuare.
 language - defineşte limbajul utilizat în scriptlets, expresii scriptlets şi declaraţii ce sunt
cuprinse în unităţile de interpretare. In JSP 1.1. sunt prezentate doar cele incluse în
semantica scripturilor pentru valoare "java" a acestui atribut, alte valori fiind
considerate erori de interpretare; versinile superioare JSP specifications vor defini alte
valori.
 extends - are valoarea un nume de clasă Java, dată de superclasa din care este derivată
pagina JSP. Dată fiind limitarea capacităţii conteinerului JSP este important să se
furnizeze clase specializate, care influenţează caliatea serviciilor.
 Import - are valoare o declaraţie de import din limbajul Java şi care poate include mai
mulţi parametri separaţi prin virgulă. Lista implicită este:
java.lang.*, javax.servlet.*, javax.servlet.jsp*, javax.servlet.http.*

3
Spaţiile ce apar între "<%@ " şi "*%>" sunt nesemnificative

56
caz în care language="java".
 Session precizează o sesiune http în cadrul paginii. Valoare implicită este true şi în mod
implicit varabila session este de tip javax.servlet.http.HttpSession, ceea ce înseamnă că
este o sesiune curentă sau nouă pentru pagina respectivă. Când session="false" pagina
nu participă la sesiunea respectivă şi orice referire la această pagină va proiecta o
eroare.
 Buffer - specifică mudelul bufferului pentru ieşirea iniţială out necesară la preluarea
conţinutului de ieşire din pagină. Când buffer="none" ieşirea este trimisă direct printr-
un obiect de tip PrintWriter din contextul lui ServletResponse. Dacă se specifică o
valoare în KB (implicit 8KB) ieşirea va fi trimisă într-un buffer de dimensiunea
precizată şi în funcţie de valoarea atributului autoFlush, la momentul umplerii
bufferului conţinutul va fi afişat sau se va lansa o excepţie.
 AutoFlush - are valoare implicită "true" caz în care, la momentul umplerii bufferului
conţinutul va fi golit automat iar pentru "false" se va lansa o excepţie. Dacă
buffer="none" outoFlush="true".
 IsThreadSafe - precizează nivelul de siguranţă al firului (thread) implementat în pagină şi
are valoare implicită "true" caz în care, procesarea cererilor este făcută simultan, cu
condiţia sincronizării accesului la pagină. Pentru valoarea "false" se vor procesa
cererile clienţilor în ordinea sosirii lor (first in first out).
 Info - şir de caractere ce se incorporează în pagină şi poate fi obţinut după implementarea
paginii prin apelul metodei Servlet.getServletInfo().
 IsErrorPage are valoare implicită "false" şi în acest caz variabila exception nu este
definită, ceea ce face ca orice referire la această variabilă să proiecteze o eroare. Pentru
valoarea "true" se indică faptul că respectiva pagină este ţinta (URL target) unei
errorPage proiectat de altă pagină. De această dată variabila exception este definită şi
are ca valoare o referinţă la Throwable din pagina care proiectează eroarea.
 ErrorPage defineşte ţinta (URL target) la o resursă care care orice obiect Throwable din
Java va fi trimis pe partea de tratare a erorilor. Acestea nu sunt erori lansate şi prinse de
page implelementation ci sunt trimise mai departe. Dacă URL-ul face referire la altă
pagină, variabila exception are ca valoare o referinţă la obiectul Throwable care nu a
fost prins. URL-ul este dependent de implelementare iar obiectul Throwable este
transferat de error page implelementation prin salvarea referinţei sale într-un obiect
comun ServletRequest cu ajutorul metodei setAttribute() din
javax.sevlet.jsp.jspException.
 ContentType defineşte tipul şi setul de caractere folosit la codificarea caracterelor atât în
pagina JSP cât şi a răspunsului returnat de aceasta. Valoarea implicită este
TYPE="text/html" şi charset="ISO-8859-1".

Paginile JSP sunt compilate în clase proprii - page implelementation class ceea ce conduce la
creşterea vitezei de răspuns prin eliminarea întârzierilor în recepţionarea cererilor şi reducerea
numărului de paşi la pornirea conteinerului JSP. Dacă page implelementation class solicită clase
adiţionale furnizate de pachetul JSP 1.1. şi/sau Servlet 2.2. aceste clase vor fi incluse în arhiva
Web pachetul WAR, ceea ce furnizează portabilitate în toate conteinerele JSP.

La fel ca şi clasele şi variabilele Java, paginile JSP pot crea şi/sau accesa obiecte şi clase Java
necesare procesării cererilor. Obiectele sunt create implicit ca rezultat al execuţiei unor
instrucţiuni, sau prin scrierea unui script respectiv explicit prin diverse acţiuni. Paginile JSP care
returnează un anumit obiect ca răspuns crează în cadul lor obiecte şi acestea au scope attribute,
prin care se precizează referinţa sa şi momentul în care aceasta este ştearsă. Obiectele ce sunt
accesibile scriptului au scripting-level. Utilizarea şi referinţele obiectelor depinde de domeniul
lor de vizibilitate şi de natura acestora, în funcţie de atributele scope definite de JSP:

57
 Page - obiectete sunt accesibile exclusiv în cadul paginii în care au fost create iar
referinţele la aceste obiecte sunt regăsite în obiectul pageContext. Referinţele la aceste
obiecte trebuie eliberate după ce răspunsul este formulat şi trimis.
 request - obiectete sunt accesibile în toate paginile care procesează aceeaşi cerere unde au
fost create iar referinţele la aceste obiecte sunt regăsite în obiectul request. Referinţele la
aceste obiecte trebuie eliberate după ce răspunsul este formulat şi trimis, cu excepţia cererilor
transmise în cadrul excepţiei curente.
 session - obiectete sunt accesibile în toate paginile care procesează cerere din aceeaşi
sesiune cu cea în care au fost create iar referinţele la aceste obiecte sunt regăsite în obiectul
session asociat cu activarea paginii. Referinţele la aceste obiecte trebuie eliberate după ce
sesiunea se termină.
 application - obiectete sunt accesibile în toate paginile care procesează cereri din aceeaşi
aplicaţie cu cea unde au fost create, iar referinţele la aceste obiecte sunt regăsite în obiectul
application.

Acţiunile JSP
Acţiunile JSP depind de natura şi particularităţile fiecărei cereri primite şi ele pot crea anumite
obiecte sau/şi le pot pune la dispoziţia elementelor de script prin intermediul unor variabile de tip
scripting-specific. Elementul JSP conţine element type ce descrie numele tag-ului, atributele
valide şi forma acestuia. Din acest motiv sintaxa acţiunilor este similară cu a elementelor XML,
cu taguri de start, body şi end:
<mytag attribute="attribute value"…>
…body…
</mytag>

Script-urile
Script-urileau rolul de manipulare a obiectelor fiind divizate în trei clase distincte declarations,
scriptlets şi expressions. Scripturile declarations au rolul de a declara constructorii limbajului,
valabili pentru toate celelalte elemente script, scriptlets reprezintă fragmente program necesare
pentru a descrie acţiunile care preced returnarea unui răspuns (execuţie condiţionată, cicluri
teste,etc) iar expressions sunt expresii complete evaluate la finalul scriptului, rezultatul evaluării
fiind convertit într-un şir ce se include în stream-ul de scriere. Conteinerele JSP posedă suport
pentru elementele script, pe baza limbajului Java ce asigură manipularea obiectelor, apelul
metodelor, tratarea excepţiilor,etc.
Obiectele sunt accesibile elementelor script din cod prin variabilele. Elementele pot fi definite
imediat după tag-ul de start sau după inchiderea tag-ului de sfârşit.Variabilele conţin o referinţă
la obiectul definit de element deşi există o altă referinţă dependentă de domeniul de vizibilitate a
obiectului. Numele şi tipul variabilei depind de scriptul folosit ceea ce conduce la influenţe
asupra modului de expunere a caracteristicilor obiectului.

Comportamentul dinamic al paginilor JSP este implementat prin scripturi, acţiuni şi elemente
beans care pot fi utilizate de programatori fără restricţii ale specificaţiilor JSP. Un bean extins,
care implementează interfaţa Tag devine tag handler şi poate fi folosit direct în pagină
respectând anumite acţiuni standard în interacţiunea cu acesta.

Paralelă JSP- ASP

Tehnologiile JSP şi ASP sunt foarte răspândite în dezvoltarea aplicaţiilor Web datorită
facilităţilor oferite în gestionarea obiectelor şi a modului în care soluţionează accesul la distanţă
asupra datelor.

58
ASP s-a răspândit cu uşurinţă odată cu includerea scripturilor în pagini HTML şi datorită
modului facil de asimilare. Insă pentru aplicaţii mari care solicită componente reutilizabile
soluţia scripturilor nu este eficientă.
Componentele JavaBeans au fost create pentru a asigura suport pentru componentele
reutilizabile.
Facilităţile comune pot fi concretizate în: funcţionaliatea avansată dată de utilizarea de către ASP
a obiectelor ActiveX şi a Javabeans de către JSP, avantajul limbajelor interpretative prin care
ASP este convertit în Pcod şi JSP în bytecode şi utilizarea elementelor externe deoarece ASP
permite crearea funcţiilor separate de cod iar JSP oferă posibilitatea utilizării claselor şi
variabilelor externe.
Deosebirile pornesc de la specificul celor două tehnologii: ASP este orientat spre Visual Basic
Script spre deosebire de JSP focalizat spre Java.
In plus, JSP beneficiază de forţa dată particularităţile de prelucrare în aplicaţii client-server,
recunoscut fiind ca un limbaj mai robust decât Visual Basic Script şi de faptul că Java este
independent de platformă spre deosebire de obiectele ActiveX, disponibile numai pe platforme
Windows.
JSP poate fi definită ca o platformă orientată spre componente:JavaBeans şi Enterprise
JavaBeans prin care aplicaţiile complexe ce manipulează valori, date şi informaţii returnate pot fi
încorporate în pagini HTML. Totuşi JSP este accesibil nu numai programatorilor avansaţi
datorită facilităţilor de reutilizare a componentelor create.

Structura şi modul de procesare a paginilor JSP

Paginile JSP conţin elemente JSP, ca exemple de anumite elemente cunoscute de conteiner şi se
supun standardelor impuse datelor.Când elementul (directive, scripting, actions) defineşte
obiecte, semantica include obiectele definite şi tipul acestora. Singurele date necunoscute de
conteinerul JSP sunt datele şablon (template). Sintaxa elementelor similară cu XML tagurile
fiind case sensitive la fel ca şi XML sau XHTML şi impune scrierea atributelor cu ghilimele,
impunând cu taguri de start, body şi end:
<mytag attribute="attribute value"…>
…body…
</mytag>
sau
<mytag attribute="attribute value"…>
Elementele care folosesc structura alternativă sunt de forma <%…%> şi toate tag-urile de start şi
end trebuie să înceapă şi să se termine în cadrul aceluiaşi fişier. Elementele goale (empty
elements) sunt cele care au taguri de start, body şi end goale iar elementele white spaces nu sunt
recomandate deşi nu se iau în considerare.
In procesarea fişierelor sursă a paginilor JSP se disting două etape:compilarea (translaţia) din
sursa JSP în fişier JSP page implementation class şi procesarea cererilor pentru fiecare client
către o instanţă din JSP page implementation class.

In etapele de procesare a paginilor JSP pot apărea două tipuri de erori: erori de translaţie şi erori
pe durata procesării cererilor. Deoarece translaţia fişierului sursă prin conteinerul JSP poate
avea loc în orice moment de la desfăşurarea iniţială a paginii în mediul de rulare al conteinerului,
recepţia şi procesarea cererii din partea unui client eroarea poate fi dependentă de implementare
sau nu. Când translaţia este realizată înainte de a sosi cererea din partea unui client, procesarea şi
notificarea erorii depinde de implementare iar la protocolul HTTP apare error status code 500
(server error).
In timpul procesării cererilor din partea unui client erorile depind de fiecare body JSP page
implementation class sau de alte coduri din Java sau din alte limbaje de programare apelate de
JSP. Erorile pot fi detectate prin soluţiile oferite de mecanismul de tratate a erorilor din Java şi

59
excepţiile pot fi soluţionate în fiecare body al clasei JSP. Orice excepţie netratată şi lansată de un
body este trimisă într-o adresă error page URL care este specificată în JSP.

Conteinerul JSP
Pe serverul Web se instalează conteinerul JSP care execută pagini JSP, livrând cererile clientului
către pagina JSP şi returnând apoi răspunsurile la clienţi. Semantica modelului JSP este similară
cu a servleţilor: pagina JSP realizează descrierea modului în care se crează obiectul response pe
baza obiectului request pentru protocolul Servlet şi are posibilitatea de a crea şi/sau utiliza alte
obiecte în cadrul procesului. De asemenea poate trata anumite evenimente, ca şi init sau destroy
în cazul JSP 1.1.

Protocolul este abordat din două punce de vedere: al serverului Web şi al autorului aginii JSP.
Entitatea care procesează cererile şi crează răspunsurile are acelaşi comportament ca şi orice
clasă Java care implementează protocolul descris de servlet. Conteinerul JSP localizează o
instanţă a unei clase de acest tip şi apoi procesează cererile cu protocolul descris (de exemplu:
HTTP).Intre conteinerul JSP şi JSP page implementation class este definit un contract care în
cazul protocolului HTTP este conţinut în clasa HTTPServlet, datorită faptului că uneori
conteinerul este nevoit să creeze anumite clase dinamice, înainte de a trimite răspunsul.
Contractul este definit între conteiner şi pagină şi este generat automat prin metoda
_jspService() care poate trata anumite evenimente, ca şi init sau destroy în cazul JSP 1.1.,
descriind acţiunile necesare în aceste situaţii. Constrângerile dintre conteinerul JSP şi pagina JSP
apar deoarece clasa Servlet asociată paginii trebuie să implementeze interfaţa HttpJsppage
pentru protocolul HTTP.

Conteinerul JSP crează o JSP page implementation class pentru fiecare pagină JSP şi numele
acesteia depinde de conteiner. Desi cearea acestei clase poate fi făcută şi de o superclasă pusă la
dispoziţie de programator prin atributul extends din comanda jsp nu este totuşi o soluţie
recomanată. Pentru soluţionarea cererilor se foloseşte protocolul Servlet şi o serie de clase
adiţionale, existente în acelaşi pachet cu clasa de implementare, ceea ce asigură portabilitate în
orice conteiner.

API contracts
Contractul dintre conteinerul JSP şi JSP page implementation class corespunde interfeţei Servlet
şi conţine:
 jspInit() metodă definită opţional în pagina JSP şi este invocată la iniţializarea paginii. La
apelul metodei, toate metodele din servlet inclusiv getSerrvletConfig() sunt diponibile.
 jspDestroy() este o metodă definită opţional în pagina JSP şi este invocată înainte de
distrugerea paginii.
 _jspService(<ServletRequestSubtype>,<ServletResponseSubtype>) metodă generată
automat de conteinerul JSP şi care nu poate fi definită în pagina JSP fiind invocată la fiecare
cerere a clientului.

Parametri cerere/răspuns
Contractul dintre conteinerul JSP şi paginile JSP implică parametri cerere/răspuns care sunt
concretizaţi de parametrul request regăsit în specificaţii ca ServletRequestSybtype, o interfaţă
care extinde javax.servlet.ServletRequest şi care defineşte un contract dependent de protocol
între conteiner şi clasa de implementare, respectiv parametrul response, o interfaţă care extinde
javax.servlet.ServletResponse. Contractul pentru protocolul HTTP este definit de interfeţele
javax.servlet.http.HttpServletResponse şi javax.servlet. http.HttpServletRequest.
Dacă în directiva language lipseşte atributul extends conteinerul JSP poate genera orice altă
clasă care să satisfacă contractul descris, în schimb prezenţa atributului extends obligă
conteinerul JSP să testeze dacă superclasa furnizată implementează HttpJspPage, dacă protocolul

60
este HTTP sau JspPage şi în caz contrar toate metodele din interfaţa Servlet sunt declarate final.
Autorul paginii JSP are grijă să includă în superclasa furnizată metodele:
 service() din Servlet API să invoce metoda jspService();
 metoda care păstrează configuraţiile - initServletConfig() trebuie să le pună la dispoziţie
prin metodele getServerConfig() şi apoi să invoce jspInit();
 destroy() va invoca jspDestroy().
In cazul în care aceste cerinţe nu sunt satisfăcute de superclasă, se lansează o eroare.
Dacă se specifică opţiune de stocare, conteinerul JSP va stoca datele ce se trimit la client iar
Header-ele vor fi trimise doar la apariţia metodei flush().Aceasta înseamnă că nu se execută nici
o operaţie care ar depinde de headere - metode ca şi setContentType(), redirect(), error(). Datele
sunt stocate într-o clasă numită javax.servlet.jsp.JspWriter care are şi roluld e a trimite datele
de ieşire, folosind metoda _jspPageService() conform exemplului:

import javax.servlet.jsp.JspWriter;
static JspFactory _jspFactory= JspFactory.getDefaultFactory();
_ jspService (<Srequest> request, <Sresponse> response) {
//initializare variabilelor implicite
PageContext pageContext=_jspFactory.createPageContext(this, request, response,
false, PageContext.DEFAULT_BUFFER, false);
JSPWriter out= PageContext.getOut();
// body va folosi in continuare out
out.flush();
}

Chiar şi în cazul unul buffer activat se poate folosi redirectarea metodelor dintr-un script prin
invocarea metodei response.redirect(URL).

Precompilarea
O pagină care foloseşte protocolul HTTP recepţionează cereri HTTP motiv pentru care
conteinerul JSP trebuie să suporte un protocol de precompilare simplu şi câţiva parametri
rezervaţi. Intre protocolul de precompilare şi compilarea propriu-zisă a paginii JSP într-un
Servlet există diferenţe majore. Precompilarea este iniţiată printr-o cerere jsp_precompile şi are
loc în propria clasă de implementare a conteinerului dacă valoarea parametrului transmis este
"true" sau fără valoare, în rest cererea nu se trimite paginii sau generează eroare.Cererile nu se
livrează paginilor JSP.

?jsp_precompile
?jsp_precompile="true"
?jsp_precompile="false"
?foobar="foobar" & jsp_precompile="true"
?foobar="foobar" & jsp_precompile="false"
?& jsp_precompile="foo"

In aceste exemple, cererea nu se transmite paginii (fără valoare sau valoarea "true") iar pentru
valoarea "false" cererea se transmite fără modificări, ultimul exemolu generând eroare.
Numele parametrilor care sunt prefixaţi de jsp trebuie să respecte specificaţiile iar paginile jsp
vor ignora orice parametru prefixat de _jsp.

Validarea paginilor JSP

61
Aşa cum precizeaza specificaţiile "o pagină JSP este valabilă pe o platformă Java dacă şi numai
dacă clasa de implementare JSP împreună cu orice altă clasă definită de conteinerul JSP este un
program valid pe platforma dată".
Specificaţiile JSP indică faptul că orice nume de tipul {_}jsp_* sau {_}jspx_* sunt rezervate,
secţiunea de declaraţii este rezultatul concatenării tuturor declaraţiilor din pagină, secţiunea de
iniţializare defineşte şi iniţializează obiectele implicite disponibile paginii JSP. Secţiunea main
asigură maparea între obiectele cerere-răspuns, conţinutul segmentului este format din scriplets,
expresii şi text din pagina JSP, elemente care sunt procesate secvenţial.
O translaţie între elemente este realizată după tipul elementului. Template data sunt transformate
într-un cod plasat în stream-ul de ieşire precizat de variabila out, păstrând spaţiile goale,
corespunzător unei comenzi de forma:
out.print(template);
Scriplets sunt transformate în fragmente de instrucţiuni Java iar o expresie devine comandă Java
ce inserează valoarea expresiei convertită în şir în stream-ul d eieşire desemnat de variabila out
prin:
out.print(expresie);
Acţiunea ce defineşte unul sau mai multe obiecte este transformată în una sau mai multe
declaraţii de variabile pentru aceste obiecte şi codul care le iniţializează, singura acţiune standard
în JSP 1.1. fiind jsp:useBean. Numele variabilei introduse este cel al atributului id şi tipul este
cel al atributului class, valoarea atributului scope afectează doar referinţele adiţionale la obiect
nu şi domeniul de vizibilitate al variabilei în programul respectiv.
O bibliotecă de tag-uri (Tag Library) asigură definirea unei secţiuni de limbaj ce separă anumite
funcţii, acţiunile definite în bibliotecă putâţnd fi utilizate explicit, prin scriere manuală sau prin
utilizarea unor unelte predefinite. Utilizarea comenzilor taglib permite imoprtarea acţiunilor
livrate în paginăşi pot fi utilizate printr-un prefix de comandă. Acţiunile pot crea obiecte noi ce
pot fi utilizate ulterior de alte acţiuni sau manipulare direct prin limbajul script.
Portabilitatea bibliotecilor de tag-uri asigură utilizarea în orice JSP indiferent de limbajul script
aferent paginii. In plus extinderea tag-urilor are ca obiective:
 Portabilitatea -datorită faptului că orice acţiune trebuie să poată fi utilizată d eorice
conteinet JSP;
 Simplitatea care să confere utilizare facilă şi pentru programatorii neexperimentaţi;
 Expresivitatea care să permită o diversitate de acţiuni (elemente de script în body-uri,
acţiuni imbricate, etc.);
 Reutilizarea codului scris în alte limbaje scripturale.
Semantica acţiunii este definită de tag handler (manipulator de tag-uri), o clasă Java ce
implementează interfaţa Tag sau BodyTag. Clasa de implementare a paginii instanţiază un obiect
tag handler pentru fiecare acţiune din pagină şi este instanţa clasei ce implementează interfaţa
javax.servlet.jsp.tagexl.Tag fiind responsabil pentru interacţiunea dintre JSP şi obiectele server-
side.
Interfaţa Tag defineşte metodele de bază necesare în toate tag handler asigurând în plus
metodele doStartTag() şi doEndTag() iar interfaţa BodyTag defineşte metodele doInitBody()
şi doAfterBody() destinate manipulării body-ului de către handler.
Inafara acestor interfeţe ce permit utilizarea obiectelor şi transformarea lor în tag handler sunt
puse la dispoziţie încă două clase: TagSupport şi BodyTagSupport.

Acţiunile

62
Majoritatea handler-elor folosesc metoda doStartTag() care este invocată la întâlnirea tag-ului
de start şi care accesează atributele tag-ului şi informaţiile despre starea paginii. Metoda
doEndTag() este invocată la întâlnirea tag-ului de sfârşit şi indică faptul că a rămas sau nu o
parte din pagină neevaluată. Acestea sunt acţiunile simple şi cazul particular al lor este folosirea
tag-ului gol.
Metodele doInitBody() şi doAfterBody() sunt invocate la acţiuni cu body când evaluarea este
realizată pe baza rezultatelor întoarse de metodele invocate. Metoda doStartTag() invocată la
început returnează o valoare int care indică dacă se poate evalua sau nu corpul tag-ului. Dacă
valoarea este EVAL_BODY_TAG se crează un stream imbricat în BodyContent şi se trimite
BodyTag prin setBodyContent. Apoi se invocă metoda doInitBody() şi se invocă corpul
acţiunii iar rezultatul este plasat în noul obiect BodyContent creat. Dacă valoarea este
SKIP_BODY nu se evaluează corpul tag-ului. Metoda doBody() foloseşte obiectul
bodyContext şi diferite funcţii cum sunt cele de conversie în şir şi utilizarea acestuia ca
argument sau filtrarea unor acţiuni înainte de a le pune în fluxul de ieşire.

Exemple de utilizare:

<x:foo attr1="…" attr2="…" attr3="…"/>


Tag-ul descris nu are body, colectează atributele şi invocă acţiuni (foo), caz în care se va defini
un tag handler FooTag ce extinde TagSupport redefind doar doStartTag. Acest handler va prelua
atributele şi va interacţiona cu PageContext.

<x:bar id="mybar" attr1="…" attr2="…" attr3="…"/>


Tag-ul descris nu are body,defineşte obiectul mybar care va deveni disponibil pentru limbajul
de script. Descriptorul bibliotecii de tag-uri va preciza o clasă TagExtraInfo care se utilizează
pentru a determina variabila ce se crează prin această acţiune.

<x:bar attr1="…" attr2="…" attr3="…"/>


BODY
</x:bar>
In acest exemplu se crează un obiect definit prin scop, body descriind funcţionalitatea acestuia.

Mecanismele template sunt puse la dispoziţie pe partea de server , cel mai banal exemplu fiind
acela prin care se ia o variabilă şi se înlocuieşte cu un text anterior specificat.
Tag Library este o colecţie de acţiuni ce încapsulează funcţii comune puse la dispoziţie în
pagină prin directiva taglib, care identifică biblioteca printr-un URI (Universal Resource
Indentifier), reprezentat de orice adresă ce identifică unic o bibliotecă. URI este asociat cu
fişierul TLD (Tag Libray Descriptor) şi cu clasele tag handler.

Packaged Tag Libraries sunt biblioteci împachetate în pachet JAR, pentru care sunt necesare
JSP Tools, deoarece orice fişier JAR are un descriptor META-INF/taglib.tld.
Clasele tag handler şi TagExtraInfo sunt clase Java care se vor afla în locaţia standard pentru
clasele Java sau întgr-un fişier JAR, în cazul utilzării serverului resin, care va rezida în WEB-
INF/lib sau în WEB-INF/classes.
Comanda taglib declară faptul că pagina foloseşte o bibliotecă de taguri şi o identifică în mod
unic printr-un URI asociind un tag prefix mai ales acţiunilor în cadrul bibliotecii. Dacă un
conteiner nu poate localiza biblioteca după un URI sau dacă taglib apare după o acţiune care
foloseşte prefixul, se consideră eroare.

Descriptorul bibliotecii (TLD) este un document XML ce descrie o bibliotecă de taguri şi


serveşte conteinerului pentru a interpreta paginile care include taglib şi descriu o bibliotecă. TLD
conţine informaţii despre conteinerul JSP, bibliotecă şi fiecare acţiune definită în bibliotecă.

63
Acţiunile sunt definite cu nume de clasă pentru tag handler-ul ei, informaţii opţionale referitoare
la clasa TagExtraInfo şi informaţii despre atributele ei. Fiecare atribut se menţionează explicit,
precizând dacă este împuternicit (mandatory) sau dacă poate accepta expresii de tip request-time.
TLD permite citirea informaţiilor despre unelte fără a solicita instanţierea respectivului obiect
sau încărcarea clasei deoarece URI-ul bibliotecii se poate mapa într-un fişier TLD fie implicit fie
prin web.xml folosind elementul taglib.

La maparea implicită:
<%@ taglib uri="tlds/Prlibrary_1_4.tld" prefix="x"%>
descriptorul va căuta locaţia indicată implicit de URI doar pentru adresele locale ale aplicaţiei
curente.
Maparea prin web.xml este realizată prin taglib cu cele două subelemente:
1. taglib ca subelement al aplicaţiei Web cu ale 2 sublelemente şi un atribut
<! element web-app …taglib…>

<!ELEMENT taglib(taglib-uri, taglib-location)>;


<!ELEMENT taglib id ID #IMPLIED>;
2. taglib-uri care descriu URI ce identifică biblioteca:
<!ELEMENT taglib-uri (#PCDATA)>;
PCDATA::=a URI , relativ la web.xml
3. locatia bibliotecii (calea relativă la aplicaţia Web unde se află fişierul TLD
<!ELEMENT taglib-location (#PCDATA)>;
PCDATA::=a localizarea resursei
TLD conţine informaţii de bază în care atributele se descriu folosind numele lor obligatoriu, sau
în lipsa acestuia prin expresii request-time; atributul bodyContent indică dacă o acţiune este
goală.

Asamblarea aplicaţiilor este realizată de Application Assembler care crează un director WEB-
INF cu subdirectoarele /lib şi /classes unde se vor afla paginile, servleţi, clasele auxiliare,
bibliotecile de tag-uri. In WEB-INF/web.xml va asambla toate aceste elemente. Acele biblioteci
livrate direct în format standard pentru JSP Tools vor fi puse în WEB-INF/lib, asamblorul
putând crea taglib-uri de intrare în web.xml pentru fiecare bibliotecă.

Radăcina documentului este taglib:


<!ATTLIST taglib
id
ID
#IMPLIED
xmlns
CDATA
#FIXED
*http://java.sun.com/j2ee/dtds/web-jsptaglibrary_!_!.dtd
>
Taglib are mai multe subelemente:
 tlibversion care descrie versiunea de bibliotecă:
<!ELEMENT tlibversion (#PCDATA)>;
unde #PCDATA::=[0-9]*{"."[0-9]}0…3.
 jspversion descrie versiunea JSP (implicit 1.1.)
 shortname permite utilizarea unui nume scurt în paginile JSP:
<!ELEMENT shortname (#PCDATA)>;
unde #PCDATA::=NMTOKEN.

64
 Uri defineşte URI public al versiunii curente pentru biblioteca de taguri ( URL la
descriptorul bibliotecii)
 Info text ce descrie biblioteca tag.
 Tag defineşte acţiunea din bibliotecă şi are un singur atribut:
<!ATTLIST tag id ID #IMPLIED>.

Tag-ul poate avea la rândul lui subelemente:


 Tag class element obligatoriu, care defineşte clasa tag handler, implementând interfaţa un
javax.servlet.jsp.tagext.Tag şi are sintaxa:
<!ELEMENT tagclass (#PCDATA)>;
unde #PCDATA::=clasa java complet calificată.
 Teilclass defineşte subclasa javax.servlet.jsp.tagext.TagExtraInfo
 Bodycontent precizează detalii de conţinut a acţiunii
 Attribute dă informaţii despre un atribut al acţiunii
<!ELEMENT attribute (name, required?, rtextvalue?)>;
unde:
- name defineşte numele tag-ului sau atributului;
- required - indică dacă atributul este obligatoriu sau optional şi are sintaxa:
<!ELEMENT required (#PCDATA)>;
unde #PCDATA::=treu/false/yes/no implicit false.
- rtextvalue indică dacă atributul poate avea un scriplet ca valoare.

Tag handler-ele

Pentru evaluarea facilă a acţiunilor în timpul execuţiei paginilor, s-a conceput tag handler, un
obiect de tip run-time server-side, în fapt o componentă invizibilă server-side JavaBeans.
Aceasta implementează o interfaţă adiţională pentru a indica protocolul run-time şi posedă două
interfeţe care o descriu: Tag ce se utilizează la handlere simple, care nu manipulează conţinut
din body şi BodyTag ca extensie a interfeţei Tag, destinată manipulării conţinut din body.
Pentru a crea un tag handler nou se pot folosi extensii ale claselor de bază TagSupport şi
BodyTagSupport. Un tag handler are proprietăti setate de conteinerul JSP prin JSP Page
Implelementation class fie prin obiectul pageControl la paginile unde este localizat tagul sau
prin tag handler-ul parent în cazul acţiunilor închise.
La fel ca orice componentă bean, tag handler-ul are anumite proprietăţi iar interfaţa Tag
defineşte contractul de bază pentru toate handlerele. Conteinerul are responsabilitatea de a
invoca metodele potrivite de iniţializare a proprietăţilor care odată setate rămân valabile pentru
instanţa dată. Ulterior iniţializării pot fi invocate prin metodele doStartTag() şi doEndTag() şi
dacă toate invocările handlerului sunt complete, se foloseşte metoda release() care resetează
proprietăţile la o valoare nespecificată.

Ciclul de viaţă al paginii presupune că în momentul execuţiei se foloseşte instanţa Tag


disponibilă care este iniţializată cu prefix şi nume, fără a fi folosită de alte instanţe. Iniţializarea
este corectă când snt setate proprietăţile pageContext, parent şi tagData. Când pagina eliberează
instanţa respectivă, ea devine disponibilă pentru o nouă reutilizare, ceea ce reduce numărul
instanţelor.

Variabilele script

Variabilele pot fi declarate într-un script şi folosite în alte scripturi iar acţiunile JSP pot defini
variabile, adică elemente script şi acţiuni. Spre exemplu la apelul acţiunii jsp:useBean de poate
defini un obiect ce va fi utilizat ulterior printr-o variabilă script. Metoda getVariableInfo()
permite obţinerea informaţiilor referitoare la fiecare variabilă creată la request time în momentul

65
execuţiei acţiunii. Metoda returnează o matrice care are ca valori obiecte de tip VariableInfo,
fiecare obiect descriind o variabilă script prin nume, tip, domeniu de vizibilitate şi dacă variabila
este nouă sau nu.
Valorile domeniului de vizibilitate sunt:
 NESTED dacă variabila script este disponibilă între tag-ul de start şi tag-ul de end a
acţiunii;
 AT_BEGIN dacă variabila script este disponibilă între tag-ul de start şi sfârşitul paginii;
 AT_END dacă variabila script este disponibilă între tag-ul de sfârşit al acţiunii şi până la
sfârşitul paginii;
Pentru variabilele cărora li s-a definit domeniul de vizibilitate metodele au sau nu efect asupra
valorii variabilelor şi este necesară sincronizarea.

Acţiunile cooperante sunt necesare deoarece apat situaţii în care o acţiune crează un obiect în
cadrul paginii şi alta doreşte să îl utilizeze.Cooperarea este posibilă prin două mecanisme de
bază id şi PageContent. Câd se identifică obiectul prin nume, prima acţiune crează obiectul şi
cealaltă îl foloseşte pentru a returna obiectul. Maparea între nume şi valoare este realizată de
JSP prin obiectul implicit pageContext.

Stiva run-time permite o alternativă la comunicarea explicită a informaţiei printr-un obiect,


coordonând explicit prin domenii de vizibilitate.
<action>
<bar/>
</action>
Dacă în fragmenul exemplu se crează un obiect server-side, acţiunea ce este descrisă în bar poate
accesa acest obiect. Paractic obiectul nu este denumit în pageContext ci este regăsit deoarece
elementul action este instanţa cea mai apropiată de tipul dorit. Metoda statică
findAncestorWithClass(Tag,Class) utilzează o referinţă la tag-ul părinte ţinut de fiecare
instanţă în parte şi care dă stiva run-time. Constrângerile impuse acţiunilor trebuie respectate
deoarece, în cazul nerespectării lor apar excepţii către utilizator.

Analiza comparată JSP-Servleţi

Majoritatea situaţiilor practice permit utilizarea JSP-urilor dar există situaţii când sunt preferaţi
servleţii. Un exemplu clasic este un servlet care generează cotaţii bursiere cu date preluate on-
line dintr-o bază de date, caz în care imaginea este stocată în memorie şi este regenerată în orice
minut. Prin utilizarea servleţilor creşte performanţa sistemului la nivelul ciclurilor de execuţie şi
scade timpul de acces la fişiere.
In general servleţii se recomandă la generarea datelor binare (imagini, date cu conţinut special),
caz în care cererile legate de respectivul conţinut sunt mapate la servleţii care sunt mandataţi să
genereze acel conţinut. Din punctul de vedere al clientului web solicitarea poate fi asimilată cu o
imagine normală cu condiţia că respectivul client suportă formatul generat.

Pentru a extinde funcţionalitatea unui server web care solicită suport pentru un nou format de
date, se preferă servleţii care oferă un mecanism portabil, fiind mapaţi pentru tipul respectiv de
date. La extensia unui web server pentru pagini JSP se foloseşte în mod frecvent un servlet care
parcurge toate fişierele cu extensia jsp şi le compilează în servleţi. Servleţii rezultaţi sunt
executaţi de conteinerul web iar răspunsul este furnizat clientului.

Se remarcă diferenţe între utilizarea servleţilor şi a paginilor JSP, deşi cele două tehnologii au
avantaje şi performanţe care trebuie cunoscute şi exploatate de echipa de dezvoltare. Servleţii
sunt recomandaţi în cazul funcţiilor la nivel inferior, ce nu implică modificări frecvente.

66
Paginile JSP oferă posibilitatea legării conţinutului dinamic de logică într-o manieră centrată pe
prezentare. Dat fiind faptul că paginile JSP fac diferenţa între partea de prezentare, axată spre
HTML şi partea logică a apliicaţiei, realizată cu componente JavaBeans şi taguri personalizate
se pot folosi modular ca şi componente reutilizabile.

67

S-ar putea să vă placă și