Sunteți pe pagina 1din 8

Curs 6 Dezvoltarea componentelor custom JSF

Ciclul de viata al cererilor JSF


In acceptiunea JSF o componenta este o interfata utilizator (UI) refolosibila, precum camp
text de intrare, buton, tabel de date, lista, etc. Componentele fac mai usor designul unei
pagini. Ierarhia de componente dintro pagina JSF este foarte asemanatoare celei din S!ing,
spre exemplu.
"rhitectura unei componente JSF este bazata pe notiunea de separare a continutului de
prezentare. Ierarhia unui #ie! JSF este o ierarhie de componente ce nu neaparat #or fi redate
in format $%&'. ( componenta din arborescenta poate fi redata intro prezentare intrun alt
format decat $%&', spre exemplu )&' (!ireless mar*up language).
Un exemplu generic de arborescenta este redat mai +os,
%impul de #iata al unei pagini JSF este scurt. -l se intinde pe perioada unui ciclu cerere
raspuns. .e indata ce raspunsul este trimis arborescenta #ie!ului si toate obiectele
componenta sunt distruse. /ac*ing beanurile pastreaza #alorile lor pentru un timp mai
indelungat, de obicei pe parcursul unei sesiuni.
Componentele pot sasi persiste atributele si proprietatile folosind un mecanismul de stocare
al atributelor al ser#letului.
Cand se receptioneaza o cerere de catre Faces Ser#let, reprezentarea arborescentei de
componente a paginii este construita pe ser#er (faza 0estore 1ie!) din fisierele JS2 create de
dez#oltatorul aplicatiei !eb JSF. .upa ce reprezentarea paginii a fost refacuta parametrii de
intrare ai cererii sunt transferati fiecarui obiect componenta din arborescenta (faza "ppl3
0e4uest 1alues). In ultima faza a ciclului de #iata #alorile si logica fiecarei componente sunt
utilizate pentru a reda componenta, adica a o 5desena6 intrun flux de iesire.
Ciclul de #iata al unei cereri JSF este ilustrat mai +os,
2asii concreti care se produc sunt urmatorii,
7. cand aplicatia este incarcata se instantiaza structura FacesContext, clasele #ie! sunt
incarcate precum si clasele pentru manipularea e#enimentelor, con#ertorilor si
#alidatorilor componetelor
8. daca aceasta este prima #izualizare a paginii in sesiunea utilizator, se #a instantia un
obiect gol ViewRoot, o noua arborescenta de componentelor #ie! #a fi construita
reprezentand prima pagina si ciclul de #iata trece direct la ultima faza 0ender
0esponse
9. in momentul in care utilizatorul se intoarce la aceeasi pagina pe timpul aceleiasi
sesiuni ViewRoot si arborescenta de componente sunt reconstruite din atributele
ser#letului iar ciclul de #iata se muta in faza "ppl3 0e4uest 1alues.
In faza "ppl3 0e4uest 1alues parametrii din proprietatile cererii sunt mutati intro instanta a
componentei. 1alorile parametrilor cererii sunt stringuri, asa ca parte a mutarii componenta
apeleaza metode de decodare care pot con#erti #alorile catre tipurile obiectului. .aca
con#ersia esueaza este generata o eroare care este trecuta in FacesContext. .aca cererea
include atributul immediate setat la #aloarea true se trece direct in faza 0ender 0esponse.
In faza 2rocess 1alidation se aplica regulile de #alidare definite in aplicatie, pentru fiecare
componenta din #ie! tree. -rorile generate, daca exista, #or fi trecute in FacesContext. .aca
a#em componente in#alide trecem direct in faza 0ender 0esponse, altfel intram in faza
Update &odel 1alues.
In faza Update &odel 1alues pentru fiecare componenta de pe pagina si pentru fiecare
proprietate a componentei apelam metodele setter din bean.
In faza In#o*e "pplication se executa business logicul si se in#oca urmatorul #ie! in acord
cu regulile de na#igare.
In faza 0ender 0esponse se creaza etichetele ce #or fi #izualizate de catre client pe baza
#alorile trimise de la bean.
In faza 2rocess -#ents, existenta oricand pe perioada ciclului de #iata, obiectele e#eniment
pot fi instantiate si inregistrate cu managerul ciclului de #iata. Intre ma+oritatea fazelor, orice
metoda de manipulare a e#enimentelor este apelata sec#ential. ( utilizare tipica a
e#enimentelor este sa incheie unele procese ale ciclului de #iata prin returnarea #alorii
complete a raspunsului.
Motivarea crearii componentelor custom
JSF permite extinderea componentelor standard pentru a le imbunatati functionalitatea sau
pentru a crea componente noi. In ultimul caz #om extinde clasa UIComponent, care este baza
tuturor componentelor UI standard.
( clasa component defineste starea si comportamentul unei componente UI. Comportamentul
include con#ertirea #alorii componentei la un marca+, asezarea in coada a e#enimentelor
componentelor, #alidari si alte functionalitati.
%rebuie sa cream o componenta custom in urmatoarele situatii,
atunci cand trebuie sa adaugam un comportament nou unei componente standard, spre
exemplu generarea unui nou tip de e#eniment
atunci cand a#em ne#oie de o componenta suportata de $%&', dar care nu este
implementata in JSF, spre exemplu frameurile
atunci cand a#em ne#oie sa redam unui client non$%&' componente ce nu sunt
suportate de $%&', spre exemplu progress barurile pentru telefonia mobila. "ceasta
situatie poate fi simplificata prin crearea doar a unui customer render
:u trebuie sa cream o componenta custom in urmatoarele situatii,
atunci cand agregam componente pentru a crea o noua componeta cu un
comportament unitar. 2entru acest caz #om folosi composite component (#ezi
cursurile #iitoare)
atunci cand trebuie sa manipulam date pe componenta sau sa adaugam functionalitati
specifice aplicatiei. In acest caz #om crea un bac*ing bean pe care il #om lega de
componenta standard
atunci cand a#em ne#oie de un con#ertor specific
atunci cand a#em ne#oie de #alidatori specifici
atunci cand dorim sa inregistram e#ent listenerI pe componente
Descrierea unei componente custom
( componenta JSF are doua parti,
tag handler, care are rolul de a transfera #alorile atributelor din cerere catre
componenta. In aceasta parte implementam, in mod obisnuit, o extensie a clasei %ag
$andler si un fisier %ag 'ibrar3 .escriptor. %ag handlerul nu este renderizat chiar
daca implementeaza o interfata ce suporta renderizarea. %'. defineste interfata prin
cod Ja#a. -l mapeaza un tag JSF lui %ag $andler. Si atributele tagului sunt descrise in
fisier. %oate numele de atribute din tld trebuie sa fie reprezentate de getteri si setteri
in clasa %ag$andler.
Component, care are rolul de a reprezenta componenta. Spre exemplu, un camp de text
readonl3 (UIOutput), un camp de text editabil (UIInput), un tablou bidimensional de
text (UIData), o lista de elemente de selectie (UISelectOne, UISelectMany) sau o
actiune (UICommand) . 2artea aceasta nu necesita un %ag $andler specific. (
Component poate fi pusa in legatura cu diferite %ag $andlere ce transfera #alori de la
di#ersi clienti. "poi, #om implementa un descendent al clasei UIComponent, o
extensie a clasei Renderer si un fisier ;&' cu partea de inregiastrare a informatiilor
componentei
%recerea datelor de la cerere la componenta se numeste decoding. %recerea datelor de la
componenta la raspuns se numeste encoding. Specificatiile JSF suporta doua modele de
programare pentru aceste doua operatii,
Implementarea directa (direct implementation), adica clasa componenta le
implementeaza
Implementarea delegata (delegated implementation), adica implementarea este
delegata unui render separat. 2rin delegarea operatiilor a#em optiunea asocierii
componentei custom diferitilor renderi astfel incat sa reprezentam componenta in
diferite moduri. .aca aceasta reprezentarea diferita nu este necesara se prefera
alegerea primului tip de implementare. Uneori, insa, se practica ambele tipuri de
implementari
.esignul lui UIComponent acorda flexibilitatea fiecarei componente de a fi asociata unui
obiect render la rulare. In acest fel o singura componenta poate fi redata catre multiple
dispoziti#e client sau multiple stiluri de interfata.
Situatia cea mai generala este aceea in care o custom component foloseste un custom render.
2entru a asocia componeta renderului si pentru a referi componeta din pagina #om a#ea
ne#oie si de un custom tag.
Situatii rare sunt acelea in care folosim o componenta standard cu un render custom sau un
custom tag fara un render sau componenta. Folosirea unui render custom fara o componenta
custom sar putea face atunci cand dorim sa adaugam #alidari la client ale unei componente
standard. 1alidarile sar implementa printrun limba+ de scripting.
Pasii pentru creerea unei componente custom
7. cream o clasa component cu urmatoarele functionalitati
suprascrie metoda getFamily() ce returneaza familia componentei, utilizata
pentru a cauta renderii ce pot renderiza componenta. Implementarea acestei
metode este,
public String getFamily()
return (!cst!)"
#
unde, cst este identificatorul familiei componentei si trebuie sa se potri#easca cu
#aloarea elementelor component$%amily incluse in configuratiile componentei si
renderului din fisierul de configuratie al aplicatiei.
include codul de renderizare sau il delega catre un render
permite atributelor componentei sa accepte expresii
inregistreaza in coada un e#eniment pe componenta daca componenta genereaza
e#enimente
sal#eaza si restaureaza starea componentei
8. delegam renderizarea unui render daca nu o implementeaza componenta. 2entru
aceasta,
creem o clasa render custom prin extinderea &a'ax(%aces(render(Renderer
inregistram renderul unui render *it
identificam tipul renderului in tag handlerul componentei
9. inregistram componenta
<. cream un e#ent handler daca componenta genereaza e#enimente
=. scriem o clasa tag handler ce extinde &a'ax(%aces(we)app(UIComponent*+,ag. In
aceasta clasa a#em ne#oie de o metoda getRender,ype() ce returneaza tipul
renderului custom, daca folosim #reunul, o metoda getComponent,ype() ce
returneaza tipul componentei custom si o metoda set-roperties() cu a+utorul careia
setam toate atributele noi ale componentei
>. cream un tag librar3 descriptor (tld) ce defineste custom tagul
Crearea clasei componentei custom
Starea acestei clase include tipul componentei, identificatorul si #aloarea locala.
Comportamentul definit de clasa include, decodarea, codarea, sal#area starii componentei,
updatarea #alorii beanului cu #aloarea locala a componentei, #alidari pe #aloarea locala,
inregistrarea in asteptare a e#enimentelor.
Ierarhia clasei componenta este urmatoarea,

Clasa de baza a ierarhiei este UIComponent, clasa abstracta. -a contine un numar de metode
abstracte. UIComponent.ase este o implementare a lui UIComponent. %oate clasele ce
reprezinta componente standard sunt extinse din aceasta. "ceste clase adauga propriile
definitii de functionalitate, la fel precum #a face si clasa component custom.
Clasa componenta custom fie extinde direct UIComponent.ase, fie extinde o clasa
componenta standard. "ceste clase sunt localizate in pachetul &a'ax(%aces(component si
numele lor au prefixul UI.
2e langa extinderea unei clase, clasa custom component implementeaza si di#erse interfete,
/ctionSource, indica faptul ca o componenta poate declansa un /ction*'ent
/ctionSource0, extinde /ctionSource si permite proprietatilor componentelor sa
refere metode ce manipuleaza action e#ents, referinta facanduse prin -'
Value1older, indica faptul ca componenta mentine o #aloare locala precum si
obtiunea de a accesa datele in model tier
*dita)leValue1older, extinde Value1older si specifica functionalitati aditionala
pentru componentele editabile, precum #alidarea sau emiterea e#enimentelor #alue
change
2amingContainer, mandateaza faptul ca fiecare componenta are un unic I.
State1older, e#identiaza faptul ca o componenta are o stare ce trebuie sal#ata intre
cereri
(bser#atie, daca componenta custom extinde UICommand automat implementeaza
/ctionSource0, ceea ce nu este e#ident din diagrama e#identiata anterior.
Clasa UIComponent.ase defineste o serie de metode pentru marcarea renderizarii,
encode.egin(), encodeC3ildren() si encode*nd(). .aca componenta are componente
descendente trebuie sa utilizam mai multe astfel de metode pentru renderizare, altfel toata
renderizarea se poate face in encode*nd(). "lternati#, putem folosi metoda encode/++(), ce
le cuprinde pe toate.
1om da in continuare un exemplu de metode de codificare,
public void encode.egin(FacesContext context4 UIComponent component) throws
IO*xception
if ((context 55 null) 66 (component 55 null))
throw new 2ull-ointer*xception()"
#
#
public void encode*nd(FacesContext context4 UIComponent component) throws
IO*xception
if ((context 55 null) 66 (component 55 null))
throw new 2ull-ointer*xception()"
#

UICst cst 5 (UICst) component"
Response7riter writer 5 context(getResponse7riter()"

writer(start*lement(!di'!4 cst)"
writer(write/ttri)ute(!id!4 cst(getClientId(context)4 null)"
String style5(String)cst(get/ttri)utes()(get(!style!)"

if(style85null)
writer(write/ttri)ute(!style!4 style4 null)"
String title 5 (String)cst(get/ttri)utes()(get(!title!)"

if (title85null)
writer(write/ttri)ute(!title!4 title4 null)"

writer(end*lement(!di'!)"
#
&etodele au doua argumente, FacesContext creaza o instanta ce contine toate informatiile
asociate cererii curente, UIComponent creaza o instanta a componentei ce urmeaza a fi
renderizata.
2utem implementa nebanal si alte metode in afara de encode*nd(). Spre exemplu, in cazul in
care dorim sa recuperam #alorile componentei din parametri cererii trebuie sa implementam si
metoda decode(). In faza "ppl3 0e4uest 1alues se proceseaza metodele decode() ale
tuturor componentelor din arborescenta. &etoda decode() extrage #aloarea locala a
componentei din parametrii de intrare ai cererii si utilizeaza con#ertori pentru ai con#erti in
tipuri acceptate de clasa component.
"proape toate atributele tagurilor accepta expresiile, indiferent ca sunt #alue sau method. -ste
recomandat sa acordam atributelor componentei sa accepte expresii.
Un tag handler seteaza #alorile componentei atunci cand proceseaza tagul, prin doua actiuni,
( metoda pentru fiecare atribut ce este instanta a Value*xpression sau
Met3od*xpression pentru a accesa #aloarea obiectului expresie potri#it si de a o
returna
( metoda set-roperties() ce stocheaza obiectele Value*xpression sau
Met3od*xpression pentru fiecare proprietate a componentei, astfel incat clasa
componenta sa returneze apoi obiecte expresie
protected void set-roperties(UIComponent component)
super(set-roperties(component)"
UICst componentCst 5 (UICst) component"
if(style85null)
componentCst(get/ttri)utes()(put(!style!4 style)"
if (title 85 null)
if (8title(is+iteral,ext())
componentCst(setValue*xpression(!title!4 title)"
# else
componentCst(get/ttri)utes()(put(!title!4title(get*xpressionString())"
#
#
#
.aca componenta extinde UICommand, atunci nu trebuie sa mai implementam metoda de
obtinere a instantelor lui Value*xpression sau Met3od*xpression pentru a accesa
obiecteloe expresiei.
.aca componenta custom extinde UIComponent.ase trebuie sa implementam aceasta
metoda. Spre exemplu, putem include o metoda pentru obtinerea unei instante
Value*xpression ce contine attributul immediate,
pu)lic )oolean isImmediate()
i% (t3is(immediateSet)
return (t3is(immediate)"
#
Value*xpression 'e 5 getValue*xpression(!immediate!)"
i% ('e 85 null)
.oolean 'alue 5 (.oolean) 'e(getValue(
getFacesContext()(get*+Context())"
return ('alue()ooleanValue())"
# else
return (t3is(immediate)"
#
#
.eoarece clasa componenta implementeaza State1older trebuie sa implementeze metodele
sa'eContext() si restoreContext() pentru a a+uta JSF sa sal#eze si restabili starea
componentelor dea lungul multiplelor cereri.
&etoda sa'eContext() este apelata in timpul fazei 0ender 0esponse unde starea raspunsului
este sal#ata pentru cereri ulterioare. Spre exemplu,
public O)&ect sa'eState(FacesContext context)
O)&ect 'alues9: 5 new O)&ect9;:"
'alues9<: 5 super(sa'eState(context)"
return ('alues)"
#
"ceasta metoda initializeaza un arra3, ce #a retine starea sal#ata.
&etoda restoreState() este apelata pe timpul fazei 0estore 1ie! in care JSF #erifica daca
exista #reo stare ce a fost sal#ata pe timpul renderizarii ultimului raspuns si care trebuie
restaurata in pregatirea urmatoarei cereri. Spre exemplu,
public void restoreState(FacesContext context4 O)&ect state)
O)&ect 'alues9: 5 (O)&ect9:) state"
super(restoreState(context4 'alues9<:)"
#
"l doilea parametru reprezinta un arra3 ce retine starea componentei. "ceasta metoda seteaza
proprietatile componentei fata de #alorile sal#ate in al doilea parametru.
'a implementarea acestor metode trebuie sa a#em gri+a sa a#em specificat in we)(xml unde
dorim sa sal#am starea, la client sau la ser#er. .aca o sal#am la client atunci starea intregului
#ie! este renderizata ca un camp hidden in pagina. Sectiunea din we)(xml de setare a locului
in care este apoi setata starea arata,
=context$param>
=description>State sa'ing met3od? @client@ or @ser'er@ (5de%ault)( See
ASF Speci%ication 0(B(0=Cdescription>
=param$name>&a'ax(%aces(S,/,*DS/VI2EDM*,1OD=Cparam$name>
=param$'alue>client=Cparam$'alue>
=Ccontext$param>
Delegarea renderizarii catre un render
2entru a delega renderizarea trebuie,
Sa cream o clasa ce extinde clasa Renderer
Sa identificam tipul renderului prin anotatia FFacesRenderer sau prin tag handlerul
componentei
.elegare inseamna toata codarea si decodarea sau doar o parte a ei. 0enderul trebuie sa
implementeze metoda encode*nd(). 0enderul trebuie, de asemenea, sa contina un
constructor #id, necesar pentru a instantia renderului si prin aceasta sa fie adaugat render *it
ului.
In timpul procesului de renderizare a raspunsului JSF apeleaza metoda getRenderer,ype()
din tag handlerul componentei pentru a determina ce render sa in#oce, daca exista #reunul.
public String getRenderer,ype()
return (!Cst,ag!)"
#
Crearea tag handler-ului componentei
Clasa tag handler conduce faza 0ender 0esponse. 2rimul lucru pe care il face este sa
returneze tipul componentei ce este asociata tagului. "poi, seteaza atributele componentei la
#alorile date in pagina. In pasul urmator returneaza tipul renderului, daca exista #reunul, astfel
incat sa poata incepe codarea componentei. 'a final elibereaza resursele utilizate pe timpul
procesarii tagului.
Clasa extinde UIComponent*+,ag ce suporta atat fuctionalitatea
&a'ax(ser'let(&sp(tagext(,ag cat si JSF. Clasa UIComponent*+,ag este clasa de baza a
tagurilor JSF ce corespund unei componente. %agurile care trebuie sasi proceseze bod3urile
#or trebui sa extinda UIComponent.ody*+,ag.

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