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()" #
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.