Web framework in ambito Java: Java Server...
Transcript of Web framework in ambito Java: Java Server...
POLITECNICO DI TORINO
III Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica
Monografia di Laurea
Web framework in ambito Java:
Java Server Faces
Terzulli Pierangelo
matr. 113149
A.A. 2006/ 2007
2 2
CAPITOLO 1 ............................................................................................................................. 4
INTRODUZIONE ......................................................................................................................... 4
METODOLOGIA DI RICERCA....................................................................................................... 4
CAPITOLO 2 ............................................................................................................................. 5
LA PIATTAFORMA JAVA ENTERPRISE EDITION .......................................................................... 5
IL FRAMEWORK SPRING ............................................................................................................ 6
Spring IoC............................................................................................................................ 7
Spring AOP .......................................................................................................................... 8
Spring DAO e Spring ORM.................................................................................................. 9
SPRING MVC............................................................................................................................ 9
Controller........................................................................................................................... 11
URL Mapping..................................................................................................................... 12
View Resolver..................................................................................................................... 13
View.................................................................................................................................... 13
CAPITOLO 3 ........................................................................................................................... 14
L’ APPLICAZIONE BANCARIA COB........................................................................................... 14
STRATEGIA IMPLEMENTATIVA ................................................................................................ 16
IL PROBLEMA DEL MANTENIENTO DELLO STATO..................................................................... 25
CAPITOLO 4 ........................................................................................................................... 28
ARCHITETTURA DEL FRAMEWORK JSF.................................................................................... 28
Execution Model ................................................................................................................ 32
User Interface Component Model...................................................................................... 34
Component Rendering Model ............................................................................................ 36
Conversion Model.............................................................................................................. 37
Event e Listener Model ...................................................................................................... 38
Validation Model ............................................................................................................... 39
Navigation Model............................................................................................................... 40
Backing Bean Management Model .................................................................................... 41
3 3
IL CICLO DI VITA DELLE RICHIESTE JSF................................................................................... 43
Restore View ...................................................................................................................... 43
Apply Requests ................................................................................................................... 44
Process Validation ............................................................................................................. 44
Update Model Values......................................................................................................... 44
Invoke Application ............................................................................................................. 45
Render Response................................................................................................................ 45
VANTAGGI DERIVANTI DALL ’USO DI JSF ................................................................................ 45
CAPITOLO 5 ........................................................................................................................... 47
INTEGRAZIONE CON SPRING.................................................................................................... 47
Configurazione della Web Application.............................................................................. 47
Il Backing Bean CriteriController ..................................................................................... 48
La view crtieri.jsp .............................................................................................................. 50
SOLUZIONI ALTERNATIVE D ’ INTEGRAZIONE TRA SPRING E JSF .............................................. 51
CONCLUSIONI....................................................................................................................... 53
4 4
Capitolo 1
Introduzione
Il tirocinio si è svolto presso l’azienda Trim Srl, il cui core business è lo sviluppo di applicazioni di
classe enterprise in ambiente Java/.Net. Il mio compito consisteva nell’analisi dell’architettura
software adottata internamente al fine di individuare se e come il web framework JSF (Java Server
Faces) dimostrasse una maggiore scalabilità e flessibilità rispetto a quello usato internamente e se
fosse facilmente integrabile nei progetti preesistenti.
Al fine di capire le reali necessità dell’azienda sono stato affiancato ad un team di sviluppatori per
seguire lo sviluppo di un progetto reale, nella fattispecie un’applicazione bancaria, COB
(COllateralizzazione dei prestiti Bancari).
In tal modo ho potuto osservare da vicino le problematiche da loro riscontrate nell’uso del web
framework adottato correntemente, per poter così determinare se e come l’uso di JSF potesse
risultare vantaggioso.
Metodologia di ricerca
Ho suddiviso quindi la mia attività in cinque fasi fondamentali:
• capire il funzionamento dell’architettura Java EE e Spring;
• analizzare la strategia implementativa dell’applicazione COB, in particolar modo lo sviluppo dell’interfaccia web;
• indivudure i problemi riscontrati nell’uso del web framework corrente;
• analizzare le opportunità offerte da JSF in termini sviluppo e integrazione;
• dimostrare come JSF semplifica la codifica del WebLayer.
5 5
Capitolo 2
L’architettura interna adottata dall’azienda per il progetto da me seguito è basata sulla piattaforma
Java Enterprise Edition (Java EE) e fa uso del framework Spring. Tale architettura è stata utilizzata
anche per altri progetti realizzati precedentemente. Il progetto da me seguito consisteva nella
realizzazione di una applicazione multi-layer bancaria di livello enterprise, accessibile tramite
interfaccia web e supportata da un database Oracle preesistente. Oltre alle funzionalità di business,
l’applicazione doveva quindi gestire le transazioni e l’interfacciamento con l’utente.
Prima di analizzare il design dell’applicazione ritengo opportuno descrivere in linea generale
l’architettura software su cui si basa il progetto.
La piattaforma Java Enterprise Edition
La piattaforma Java Enterprise Edition, secondo la definizione della stessa Sun (l’azienda che l’ha
realizzata) è uno standard industriale per lo sviluppo di applicazioni Java-based portabili, robuse,
scalabili e sicure. Si tratta di una piattaforma multi-livello che fornisce un gran numero di servizi,
tra i quali transazionalità, web services, un component model, un sistema di accesso ai dati,
sicurezza, tutti requisiti fondamentali per un’applicazione di classe enterprise.
La piattaforma è definita attraverso una specifica alla quale tutti i produttori di software Java EE
compatibile devono aderire. È proprio grazie a questo meccanismo che è considerata di fatto uno
standard industriale. Anche i servizi da essa forniti sono definiti attraverso specifiche, denominate
API specification: Enterprise Java Beans, Servlets, JDBC sono solo alcune di esse e servono
rispettivamente a definire un ambiente entro cui eseguire gli oggetti di una applicazione Java EE,
un ambiente entro cui eseguire una applicazione web, un sistema standard di accesso ai dati.
Tutte le applicazioni Java EE devono essere eseguite all’interno di un Application Server, cioè
un’applicazione che implementi la specifica Java EE. Considerata la complessità e la vastità della
specifica, non stupisce che soluzioni basate su questa piattaforma costino non poco. In genere i
produttori di software Java EE compatibile vendono licenze annuali dei loro applicativi, in quanto
si rivolgono a clienti che hanno particolari esigenze sia in termini di performance, sia in termini di
sicurezza e fault-tolerance.
Purtroppo, proprio la complessità della specifica ha reso negli anni lo sviluppo di applicazioni Java
EE piuttosto difficile, lungo e tedioso. Man mano che l’ingegneria del software sviluppava nuove
metodologie di sviluppo (Test Driven Development, Model Driven development, Extreme
Programming solo per citarne alcuni), ci si rendeva conto di come il modello di programmazione
6 6
adottato da Java EE fosse poco flessibile: le applicazioni sviluppate per questa piattaforma erano
intimamente legate ad essa e col tempo divenivano difficilmente manutenibili e scalabili. Nel 2002
alcuni di questi problemi furono esposti in un libro, Expert One-on-One J2EE Design and
Development, in cui l’autore Rod Johnson proponeva alcune linee guida e best practice da
adottare; il codice che accompagnava il libro sarebbe diventato quello che oggi è conosciuto come
il framework Spring.
Figura 1 – Panoramica della piattaforma Java EE
Il framework Spring
Spring è un framework open-source sviluppato per semplificare la realizzazione di applicazioni
basate su Java EE. Nel corso degli anni però si è arricchito di una moltitudine di servizi le cui
funzionalità spaziano dalla gestione delle transazioni, alla sicurezza, all’ORM, al sistem
management,ai web services. Ad oggi è considerato una valida e leggera (lightweight) alternativa al
più pesante Java EE, soprattutto in quei casi dove è richiesto solo una piccola parte (tipicamente
gestione delle transazioni e interfacciamento web) delle funzionalità offerte da un Application
Server.
7 7
SSSSPRING PRING PRING PRING IIIIOOOOCCCC
Il framework Spring è, nella sua più intima essenza, un container che implementa l’ Inversion of
Control pattern (IoC). Con IoC ci si riferisce ad un metodo per risolvere le dipendenze tra oggetti
a run-time senza che esse siano specificate nel codice degli oggetti dipendenti. Generalmente in
una qualsiasi applicazione non banale, un oggetto che voglia fornire una determinata funzionalità
ha bisogno delle funzionalità fornite da uno o più oggetti esterni, siano essi locali o remoti; per
ottenerle può utilizzare diversi modi: può istanziare direttamente l’oggetto/gli oggetti nel corpo di
uno dei suoi metodi, può ottenerlo/i attraverso un oggetto factory oppure può ottenere un
riferimento ad esso/i effettuando un lookup JNDI.
Qualunque approccio si preferisca, gli oggetti dell’applicazione risultano fortemente legati tra di
loro: nel primo caso a nulla servirebbe nascondere l’oggetto desiderato dietro una interfaccia, in
quanto l’oggetto chiamante deve fornire comunque una implementazione specifica; nel caso in cui
si usi JNDI invece, l’oggetto sarà fortemente legato ad un servizio esterno, offerto generalmente
dall’ application server in cui opera.
In qualunque modo si operi dunque si “sporcano” gli oggetti di business logic, cioè si interrompe il
flusso logico per risolvere un problema che logicamente è indipendente dalle funzionalità che gli
oggetti devono fornire.
Un IoC container come quello alla base di Spring, al contrario, si fa carico di risolvere queste
dipendenze per loro, “iniettando” gli oggetti desiderati quando essi saranno richiesti e rendendoli
disponibili nello Spring Context: allo sviluppatore è richiesto soltanto di dichiarare queste
dipendenze nel file applicationContext.xml. Esternalizzare le dipendenze in un file XML separato
permette quindi di minimizzare quanto più possibile le dipenze tra gli oggetti stessi, favorendone
un più efficace riutilizzo e rendendo l’applicazione nel suo insieme più facilmente manutenibile,
rendendola inoltre completamente disaccoppiata dal container entro la quale gira.
8 8
Figura 2 – Spring Overview
SSSSPRING PRING PRING PRING AOPAOPAOPAOP
Altro modulo importante del framework Spring è quello che fornisce il supporto all’Aspect
Oriented Programming (AOP). Tale paradigma è una evoluzione del più famoso Object Oriented
Programming (OOP) che sta alla base della tecnologia Java stessa e di una moltitudine di altri
linguaggi moderni (C++, .Net, Delphi, Python tanto per fare alcuni esempi). L’uso di AOP è
indicato per tutta quella classe di problemi che non sono facilmente modellabili con un approccio
object oriented, semplicemente perché interessano l’applicazione nel suo insieme (sono cioè dei
cross-cutting concern): esempi tipici sono la sicurezza, il logging, la transazionalità o la persistenza:
sono caratteristiche che il sistema deve avere, ma sono logicamente indipendenti dalla business
logic dell’applicazione. Implementare questi “aspetti” con logica object oriented significherebbe
ancora una volta sporcare gli oggetti, interrompere il flusso logico per risolvere problematiche che
esulano dalla logica applicativa. L’uso di AOP invece fa sì che la loro gestione sia trasparente
all’applicazione.
9 9
SSSSPRING PRING PRING PRING DAODAODAODAO E E E E SSSSPRING PRING PRING PRING ORMORMORMORM
Il supporto per l’accesso ai dati in Spring è garantito dai moduli DAO (Data Access Object) e
ORM (Object-Relational Mapping): il primo semplifica notevolemente il codice JDBC per
l’accesso alle basi di dati, evitando di aprire e chiudere le connessioni e, attraverso l’uso di AOP,
offre un supporto alle transazioni addirittura più esteso rispetto a quello fornito da JTA (la
specifica Java EE relativa alle transazioni), che tra l’altro richiede il supporto di un Application
Server. Il secondo permette di fare uso nella propria applicazione delle più svariate tecnologie di
ORM (Object-Relational Mapping) oggi esistenti: Hibernate, iBatis, JPA, JDO, Oracle TopLink
per citare i più diffusi. A tal proposito, nonostante la scelta sia molto variegata, negli ultimi anni
l’elevato grado di integrazione tra l’IoC container e Hibernate (altro progetto open-source) sta
dimostrando un notevole successo in ambito enterprise, ponendosi in diretta concorrenza con
software commerciali similari.
Spring MVC
Per quanto riguarda il supporto web, Spring dispone del modulo Spring MVC che fa uso delle
Servlet API. Essendo questo il modulo usato per l’implementazione dell’interfaccia web di COB,
ritengo opportuno descriverlo in maniera più approfondita.
Spring MVC, come si evince dal nome, implementa il pattern Model View Controller, in cui il
Model rappresenta il dato da presentare all’utente, la View rappresenta ciò che l’utente vede e con
cui interagisce, mentre il Controller interpreta le richieste dell’utente, le elabora e ne fornisce i
risultati. È costruito attorno alla servlet DispatcherServlet, la quale agisce come Front
Controller delegando la gestione delle richieste in arrivo alle classi Controller. Il diagramma seguente
illustra il flusso del framework per rispondere ad una richiesta proveninete da un client. Il
Controller quindi processa la richiesta, esegue la logica di back-end necessaria e alla fine genera un
oggetto ModelAndView che la DispatcherServlet utilizzerà per effettuare il rendering
della response con la collaborazione di un ViewTemplate.
10 10
Figura 3 – Gestione di una request
Come tutte le servlet, anche la DispatcherServlet va configurata nel file web.xml, il file
descriptor della web application. Nel caso di COB, esso appare così:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/classes/applicationContext.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>cob</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cob</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
Da notare le definizioni del parametro contextConfigLocation e del listener
ContextLoaderListener, necessari rispettivamente per localizzare il file
applicationContext.xml contenente le dipendenze del progetto e caricare all’avvio l’ Application
Context.
11 11
La servlet DispatcherServlet così configurata, denominata cob, verrà richiamata per tutte le
richieste alle pagine il cui nome corrisponde all’espressione *.htm. Durante la sua
inizializzazione, essa carica un particolare file xml, cob-servlet.xml, all’interno del quale sono
configurati i vari controller, handler mapping e resolver coinvolti nell’elaborazione delle richieste
ad essa associate. Il file cob-servlet.xml, come l’applicationContext.xml per L’IoC di Spring, definisce ciò
che viene chiamato WebApplicationContext associato alla servlet cob.
Figura 4 – il file cob-servlet
CCCCONTROLLERONTROLLERONTROLLERONTROLLER
I controller, come anticipato precedentemente, permettono di accedere al comportamento della
web application. In Spring MVC una classe che voglia agire da controller deve implementare
l’interfaccia Controller:
public interface Controller { ModelAndView handleRequest( HttpServletRequest request, HttpServletResponse response) throws Exception; }
Essendo molto generica, il framework mette a disposizione dello sviluppatore una serie di
Controller specificatamente pensati per risolvere alcune situazioni comuni. In COB ad esempio
tutte i controller estendono la classe BaseMultiActionFormController, la quale estende
12 12
a sua volta il controller fornito da Spring MultiActionFormController. Esso permette ad
un unico controller di gestire più richieste, siano esse di tipo GET o POST, centralizzando
funzionalità comuni su un'unica classe.
I controllers, così come le servlet, sono mappati ad una o più URL e hanno accesso agli oggetti
HttpServletRequest e HttpServletResponse necessari per poter estrarre i dati
inviati dall’utente, elaborarli (attraverso i servizi messi a disposizione dallo strato di business-logic
sottostante) ed infine indirizzare i risultati alla view dedicata alla loro rappresentazione.
URLURLURLURL MMMMAPPINGAPPINGAPPINGAPPING
Per determinare quale controller deve eleborare una particolare richiesta, effettuando quindi ciò
che viene definito come URL Mapping, bisogna configurare un HandlerResolver. Spring, a
seconda della strategia utilizzata per il mapping, mette a disposizione alcune implementazioni di
HandlerResolver: nel caso di COB si è scelto di usare il
PropertiesMethodNameResolver, attraverso il quale è stato possibile associare gli URL
direttamente ai metodi dei Controller che si occupano della loro gestione. Tali metodi devono
restituire un oggetto ModelAndView affinchè il framework sia poi in grado di determinare quale
pagina restituire all’utente.
Figura 5 – Mapping attraverso PropertiesMethodNameResolver
13 13
VVVVIEW IEW IEW IEW RRRRESOLVERESOLVERESOLVERESOLVER
L’oggetto ModelAndView contiene al suo interno un riferimento alla view da visualizzare e i
risultati dell’oprazione richiesta. Tale riferimento non è altro che un nome logico, che verrà poi
risolto da un oggetto, il ViewResolver appunto, fornito direttamente da Spring MVC e che il
programmatore deve configurare appositamente. Questa separazione permette un completo
disaccoppiamento tra il Controller e la particolare tecnologia di rendering utilizzata per la view.
VVVVIEWIEWIEWIEW
La tecnologia di rendering predefinita per Spring MVC è JSP, la stessa adottata per l’applicazione
COB in quanto ben conosciuta dal team di sviluppo. È possibile però utilizzare altre tecnologie,
come XML, XUL, JSF o addirittura formati binari come PDF, XSL o DOC (queste necessitano
però di un ViewResolver specifico e appositamente configurato).
14 14
Capitolo 3
L’applicazione bancaria COB
Dall’analisi si è dedotto che l’applicazione da realizzare deve gestire la collateralizzazione dei
prestiti bancari per conto dell’azienda committente, la banca San Paolo. Nella fattispecie si tratta di
gestire il rapporto che sussiste tra il cliente e la Banca d’Italia duante l’erogazione dei prestiti.
Quando alla banca San Paolo arriva una richiesta di prestito, questa deve soddisfare una serie di
condizioni (definite mediate criteri di idoneità) per poter essere autorizzata. Se queste condizioni
sono soddisfatte, la richiesta viene assegnata al comitato crediti, il quale può decidere se assegnarla
a sua volta alla propria tesoreria, SPIMI, o scartarla. A questo punto la tesoreria può comunicare a
Banca d’Italia la richiesta del prestito attraverso un sistema di messaggistica sicuro e adottato a
livello internazionale, denominato SWIFT. Qualora Banca d’Italia autorizzi il prestito, esso viene
considerato “costituito in pegno” e San Paolo può richiederne lo svincolo, altrimenti viene
scartato.
In generale quindi il ciclo di vita di un prestito prevede quattro fasi:
• verifica della congruità tecnica e accettazione del comitato crediti � (assegnazione a tesoreria);
• segnalazione a Banca d’Italia;
• costituzione in pegno;
• svincolo.
15 15
tecnicamente congruo
scartato
da approvare comitato
assegnato a tesoreria
Figura 6 – diagramma di stato del prestito per la congruità tecnica richiesta da San Paolo
segnalato a B anki t
costituito in pegno
svincolato
rifiutato da Bankit
n/a (stato di part enza)
da segnalare a Bankit
stato n/a applicabile quando lo stato 1 non vale "assegnato a tesoreria"
stato "da segnalare a Bankit" applicabile quando lo stato congruità (campo di stato 1) diventa "assegnato a tesoreria"
richiesta di svinc olo
s cadutonon
ripresentabile
Figura 7 – Diagramma di stato del prestito per l’autorizzazione da parte di Banca d’Italia
16 16
In fase di analisi sono stati individuati due diversi livelli di criterio di idoneità: un criterio di
idoneità "forte" (MASTER) per rispondere alle regole imposte dalla Banca d'Italia e un criterio di
idoneità "debole" (di PRESELEZIONE) interno a San Paolo.
I criteri MASTER sono i criteri che vengono applicati dal sistema ai soli prestiti assegnati a
tesoreria al fine di verificarne giornalmente la congruità tecnica richiesta da Banca d'Italia per
l’accettazione. Sono creati da un utente amministratore e vengono applicati con scadenza
giornaliera dal sistema in maniera automatica. Per ciascun criterio l’amministratore può indicare se
la sua mancata verifica debba portare necessariamente allo svincolo del prestito e se la cosa debba
essere trascritta in un file di log: può cioè creare criteri che svincolano il prestito e criteri che
tracciano soltanto l’incongruità del prestito riferita al singolo criterio.
I criteri di PRESELEZIONE sono legati alle opportunità definite dalla tesoreria SPIMI e possono
mutare nel tempo con maggiore frequenza rispetto ai criteri MASTER. Sono creati e applicati nella
fase di preselezione dei prestiti, volta a individuare quali prestiti possono essere assegnati al
comitato crediti per l’approvazione. Sono di competenza per l’appunto dell’operatore addetto alla
preselezione dei crediti.
Se il prestito soddisfa i criteri di idoneità imposti da Banca d’Italia (criteri MASTER) esso entra
nello stato “da segnalare a Bankit” e la tesoreria può inoltrare la richiesta a Banca d’Italia: inviando
un messaggio SWIFT di segnalazione a Banca d’Italia. Banca d’Italia, allorquando riceve la
segnalazione, invia un altro messaggio SWIFT, detto di ack su segnalazione. Se la Banca d’Italia
conferma la validità del prestito inviando un messaggio di SWIFT di accettazione, il prestito entra
nello stato “costituito in pegno”, altrimenti al ricevimento di un messaggio SWIFT di invalidità
entra nello stato “scartato”.
Strategia implementativa
Trattandosi di una applicazione di livello enterprise piuttosto complessa, si è deciso di strutturare
COB concettualmente su tre livelli o layer: Il DataLayer, che rappresenta la base dati Oracle locale
ove risiedono le informazioni relative ai prestiti (ricevute giornalmente tramite un servizio remoto
denominato “host”), il Business Layer ove risiede la logica di business dell’applicazione stessa, ed
infine il Web Layer che rappresenta l’interfaccia utente dell’applicazione. La separazione tra
business logic e interfaccia utente è fondamentale ed è considerata una best practice nello sviluppo
software. Nel caso di COB in particolare semplifica una eventuale sostituzione del web framework
utilizzato.
17 17
Grazie all’utilizzo estensivo del framework Spring durante l’ingegnerizzazione dell’applicazione,
l’applicazione non necessita di un completo Application Server per poter funzionare, giacchè gran
parte delle funzionalità di classe enterprise sono fornite dal framework stesso. In particolare Le
funzionalità di accesso ai dati e la transazionalità sono ottimamente gestite dal modulo Spring
DAO, mentre per quelle di ORM si è fatto uso di Hibernate.
Per lo sviluppo del Web Layer ci si è affidati, come anticipiato precedentemente, al modulo Spring
MVC e al servlet container Apache Tomcat: è stato quindi possibile modellare COB
semplicemente come una web-application e deployare il file war corrispondente sul server Tomcat.
L’ambiente di sviluppo adottato quindi è costituito dall’ IDE Eclipse nella sua versione 3.2,
affiancato da Spring versione 1.2, Hibernate versione 3.0 e dal servlet container Apache Tomcat
nella versione 5.0.
Figura 8 – Struttura del progetto eclipse relativo all’applicazione COB
Il codice dell’applicazione è fondamentalmente strutturato in due progetti eclipse:
COBBusinessLayer, e COBWebApplication. Per quanto riguarda il primo, dalla figura sottostante
si notano:
18 18
Figura 9 – Struttura del progetto COBBusinessLayer
• Il package com.sanpaolo.cob.beans: qui risiedono i beans che rappresentano il modello dell’applicazione e ne mantengono lo stato. In particolare essi sono stati automaticamente generati tramite Hibernate mappando le tabelle presenti nella base dati Oracle e la cui locazione è specificata all’interno del file applicationContext.xml;
Figura 10 – contenuto del package com.sanapolo.cob.beans
19 19
• Il package com.sanpaolo.cob.business: come si evince dal nome, qui invece trovano spazio gli oggetti che implementano la logica di business, ovvero le funzionalità di COB. Il codice che definisce l’interfaccia web si appoggia direttamente a queste classi per fornire le funzionalità di business agli utenti, perciò tali classi saranno esposte come service nel file applicaitionContext.xm;
Figura 11 – contenuto del package com.sanapolo.cob.business
• Il package com.sanpaolo.cob.dao: contiene al suo interno l’oggetto HibernateDAO che è esposto nel file applicationContext.xml per fornire il servizio DataAccess necessario per l’accesso ai dati;
Figura 12 – contenuto del package com.sanapolo.cob.dao
20 20
• Il file applicationContext.xml: rappresenta il file xml necessario all’IoC container di Spring per capire le dipendenze tra le varie classi dell’applicazione. In particolare, come si evince dalla figura, le classi che implementano la logica applicativa e quelle che realizzano la comunicazione con il database sono esposte attraverso il tag <bean>; Spring si occuperà quindi di renderle disponibili nelle classi che definiscono l’interfaccia utente.
Figura 13 – contenuto del file applicationContext.xml
La struttura del progetto COBWebApplication è invece costituita dai sorgenti che definiscono la
parte Controller e dalle pagine JSP che definiscono la parte View:
21 21
Figura 14 – Struttura di COBWebApplication con espanso il package relativo ai controller
Figura 15 – Vista delle pagine JSP
22 22
Per quanto riguarda lo sviluppo della View, si è deciso di adottare una struttura a quattro pagine,
ognuna dedicata ai casi d’uso individuati in fase d’analisi e cioè:
• definizione dei criteri MASTER;
• preselezione dei prestiti da presentare al comitato;
• gestione dei prestiti assegnati a tesoreria;
• gestione degli SWIFT.
Figura 16 – schermata iniziale di COB in modalità Amministratore
La figura mostra la pagina iniziale dell’applicazione attraverso cui l’operatore può accedere alle
varie funzionalità: ogni pagina quindi presenta una serie di TAB o sottsezioni ognuna delle quali
relativa alle varie operazioni necessarie al completamento del task.
23 23
Figura 17 – Definizione dei criteri MASTER
Tramite il primo link l’amministratore può definire le condizioni di eligibilità previste dai criteri
MASTER imposti da Banca d’Italia per l’autorizzazione del prestito.
Figura 18 – Definizione dei criteri di preselezione dei crediti
Il secondo link permette di gestire le operazioni relative alla preselezione dei prestiti da inviare al
comitato crediti. L’operatore di preselezione crediti può quindi definire i criteri di
24 24
PRESELEZIONE, avviare la procedura di preselezione dei prestiti provenienti da HOST
(applicando i criteri precedentemente definiti), assegnare i prestiti preselezionati al comitato crediti
e, in base alle decisioni prese da quest’ultimo, assegnarli alla tesoreria o scartarli.
Figura 19
Il terzo link è accessibile dagli operatori della tesoreria, e permette di gestire il ciclo di vita del
prestito rispetto a Banca d’Italia (segnalazione, costituzione in pegno, scarto). La generazione degli
SWIFT necessari alla comunicazione è fatta automaticamente da COB (ma non l’invio degli stessi
la cui operazione è demandata all’utente). Inoltre il sistema permette all’utente di trascrivere i
dettagli delle operazioni compiute in un documento MS Word (funzione richiesta da San Paolo per
espletare alcuni obblighi legali e burocratici).
25 25
Figura 20 – Gestione Swift e Alert
Il quarto link è dedicato interamente alla gestione dei messaggi SWIFT e ALERT (messaggi
informativi generati dal sistema al verificarsi di certe condizioni) generati al link precedente. Qui
l’utente può controllare che i messaggi SWIFT generati dal sistema siano validi e quindi
autorizzarne l’invio.
Il problema del manteniento dello stato
Durante lo sviluppo di COBWebApplication mi sono reso conto delle difficoltà incontrate dagli
sviluppatori nella realizzazione nel WebLayer, in particolar modo quando era necessario gestire lo
stato dell’interfaccia web tra una request e l’altra, ma anche nell’aggiunta di funzionalità che
esulavano dalla business logic e che riguardavano esclusivamente l’aspetto e il comportamento
della GUI. Inizialmente ho pensato fosse un problema dovuto alla mancanza, nel team di sviluppo,
di un web designer, una figura esperta nella realizzazione di pagine html. In realtà col procedere
dello sviluppo diventava sempre più chiaro che il problema risiedeva in alcune limitazioni del
modello di programmazione proposto da Spring MVC.
Il problema deriva essenzialmente dal fatto che il protocollo HTTP su cui si basa il web è
essenzialmente un protocollo stateless. Ciò comporta che il passaggio dei dati da una pagina
all’altra e in generale il mantenimento dello stato della GUI è totalmente a carico dello
sviluppatore; Spring MVC d’altro canto non offre alcun supporto a questo genere di problema,
concentrandosi esclusivamente sulla coordinazione tra Model, View e Controller: tale problema
26 26
dunque si riflette sia nello sviluppo delle pagine JSP che nello sviluppo dei controller ad esse
associati.
Un esempio particolarmente evidente di questo problema riguarda la selezione dei criteri di
PRESELEZIONE e il loro successivo processamento per l’assegnamento al comitato. La
soluzione adottata all'interno di COB prevede che l'utente possa creare criteri su qualunque dei
campi presenti all'interno del flusso prestiti proveniente da host: per uno specifico campo possono
esistere soltanto un criterio di tipo "applica o non applica" o un criterio di tipo "valuta e scrivi nel
log"; per ciascun criterio inoltre, l'utente può indicare se, qualora non fosse verificato, esso deve
portare all'esclusione del prestito oppure se deve soltanto causare una scrittura nel log applicativo
relativo all'operato dei criteri.
L’implementazione di questa funzionalità è affidata al controller criteriController e alla
pagina JSP criteri.jsp (forniti in allegato alla presente relazione). Il primo, attraverso l’uso degli
oggetti di business logic, preleva i campi SQL relativi ai prestiti provenienti da host e li inserisce
all’interno dell’oggetto ModelAndView. Uno sguardo più approfondito al codice rivela però che
buona parte di esso è dedicato all’invio di variabili di controllo per la presentazione, ad esempio
_selectedRow, _azione, visualizzaDettagli. Tale codice, secondo chi scrive, non
dovrebbe interessare il controller ma esclusivamente la view. Il controller dovrebbe solo
intercettare gli input dell’utente (provenienti dalla view) e provvedere di conseguenza a richiamare
le funzionalità di business richieste, restituendone i risultati. D’altro canto il reperimento dei
parametri inviati dall’utente avviene attraverso l’oggetto HttpServletRequest, un oggetto
messo a disposizione dalle Servlet API ma che opera a basso livello, quello HTTP, e che non ha
alcuna cognizione del contesto applicativo in cui opera.
Per quanto riguard criteri.jsp, si nota subito l’abbondanza di codice JavaScript personalizzato,
utilizzato prevalentemente per l’invio dei dati al server (manipolando opportunamente gli elementi
form della pagina web), mentre invece il codice JSP è usato per lo più per visualizzare i dati
richiesti e controllare l’aspetto della view attraverso le variabili rese disponibili da
CriteriController. Nell’insieme Il codice della pagina si presenta abbastanza caotico e di
difficile manutenzione, a causa anche della stretta interdipendenza tra view e controller. Questo
aspetto limita moltissimo il riutilizzo dei componenti; si pensi ad esempio all’uso delle variabili
_selectedRow, _azione e visualizzaDettagli, che si riferiscono esclusivamente
allo stato della view ma sono definite nel controller: se un altro controller volesse far uso della
stessa view saremmo costretti a reimplementare le stesse variabili nel nuovo controller,
duplicando inutilmente il codice.
27 27
La gestione lato server dello stato di un’applicazione web quindi comporta numerosi problemi di
scalabilità e manutenzione, e nonostante il problema sia stato discusso e affrontato in vari modi
nessuna delle soluzioni proposte dal mercato è risultata soddisfacente. La piattaforma Java EE
d’altro canto, si è limitata finora a fornire solamente un supporto basilare alle applicazioni web
(attraverso le Servlet API), senza mai affrontare direttamente il problema del mantenimento dello
stato in maniera sufficiente. Da ciò è nata la necessità da parte di Trim di orientarsi verso altri
framework, in particolare verso JSF.
28 28
Capitolo 4
Architettura del framework JSF
JavaServer Faces (JSF) è una nuova specifica definita all’interno della piattaforma Java Enterprise
Edition versione 5, per la realizzazione di web application. Si tratta di un framework basato sulle
Servlet API che implementa il pattern MVC ma che adotta un approccio completamente diverso e
per certi versi innovativo rispetto alle soluzioni precedenti. Esso infatti fornisce un modello di
sviluppo component-based, event-driven, molto simile a quello proposto da Swing per
applicazioni desktop. In JSF l’interfaccia utente è rappresentata lato server da un albero di oggetti
(i componenti appunto) che ne rappresentano lo stato in ogni momento del suo ciclo di vita. Ogni
azione che l’utente effettua su un dato componente dell’interfaccia genera un evento che può
essere intercettato e processato lato server: il collegamento (binding) tra elementi dell’interfaccia e
oggetti lato server è effettuato in maniera automatica dal framework stesso, liberando lo
sviluppatore dai problemi derivanti dalla natura stateless del protocollo HTTP.
Figura 21 – Il Modello di comunicazione a eventi di JSF
JSF fa uso di servizi già presenti nella piattaforma Java EE (sulla quale del resto si basa) ma su
questi costruisce un nuovo impianto architetturale entro cui fornisce alcune tipologie di servizi
completamente nuove. Se si pensa l'infrastruttura di una applicazione web come uno stack di
servizi che partono da un livello di astrazione minimo fino a un livello più alto infatti, si vede come
i servizi di JSF forniscono uno strato di astrazione più elevato rispetto a quelli forniti da Spring
MVC, che già a loro volta sono più in alto nella pila rispetto a quelli dell'implementazione standard
di Servlet e JSP.
29 29
Figura 22 – Visione Stack dell’infrastruttura di una applicazione web
I concetti chiave introdotti dunque da questo nuovo livello di astrazione sono:
• UI component: Un JavaBean residente sul server che incapsula le funzionalità specifiche per l’interazione con l’utente. Più UI Component fornano una View, cioè un albero di componenti che può essere poi renderizzato come pagina web.
• Renderer: Un oggetto responsabile della visualizzazione o rendering di un UI Component e che si occupa della conversione dei dati inseriti dall’utente nel tipo di dato accettato dal componente. Il Renderer può operare su più UI Component e ogni UI Component può avere più Renderer.
• Validator: È usato allorquando è necessario assicurarsi che i dati inseriti dall’utente in un UI Component siano validi. Ad ogni UI Component possono esssere assegnati più oggetti Validator.
• Backing Bean: Rappresenta il Controller della View. E’ un semplice JavaBean a cui si possono associare gli UI Component di una view e i metodi che implementano la logica di gestione del Web Layer.
• Converter: Converte il valore di un UI Component in una stringa (e viceversa) per la visualizzazione. Ogni UI Component può essere associato ad un solo Converter.
• Event e Listener: Costituiscono gli elementi base del modello di programmazione a eventi, tipico dello sviluppo Swing. L’utente esegue un’azione su di un UI Component, quest’ultimo scatena un evento e i listener registrati per quell’evento lo processerano.
30 30
• Message: Rappresenta un’informazione che viene inviata all’utente. Infatti, qualsiasi elemento dell’applicazione (backing bean, validator, converter eccetera) può generare un messaggio informativo o di errore che verrò quindi visualizzato all’utente.
• Navigation System: Rappresenta il sistema di navigazione utilizzato in JSF.
Figura 23 – Modello concettuale della comunicazione tra i vai elementi di JSF
La figura mostra le relazioni che intercorrono tra questi elementi: gli UI Component contenuti
nella View aggiornano i Backing Bean e generano eventi (Event) in base alle azioni degli utenti. I
Validator verificano che i valori degli UI Component siano validi. I Converter traducono e
formattano i valori contenuti negli UI Component e li rendono disponibili per la renderizzazione.
I Backing Bean contengono Event Listener e Action Method attraverso cui gestiscono gli eventi
generati dagli utenti. In particolare gli Action Method sono degli Event Listener il cui valore di
ritorno è usato dal Navigation Sytem per determinare quale View visualizzare all’utente. Infine i
Renderer effettuano il rendering degli UI Component della View selezionata.
In aggiunta a questi JSF offre una serie di servizi necessari per lo sviluppo di applicazioni web:
• Conversioni di tipo: Come è noto, un client web può inviare via HTTP al server solo delle stringhe, per cui è necessario convertire queste stringhe in valori corrispondenti ai tipi necessari per il livello Model. JSF fornisce perciò gli strumenti per automatizzare questa conversione.
31 31
• Validazione: La validazione dei dati ricevuti dal client è uno dei compiti più comuni e ripetitivi nello sviluppo dell'interfaccia web. JSF fornisce una serie di validatori standard per le esigenze tipiche, che sollevano lo sviluppatore dal realizzare questa attività e mette a disposizione un modello di sviluppo che consente di realizzare molto semplicemente validatori custom.
• Binding tra campi di interfaccia e attributi di JavaBean: I dati immessi lato client nell'interfaccia web di una applicazione devono poi essere contenuti in oggetti lato server che modellano le entità sulle quali devono andare ad agire le elaborazioni del livello di Model. I dati di interfaccia, dopo essere stati convertiti in valori di tipo opportuno ed essere stati sottoposti a validazione, devono andare a popolare opportuni attributi di JavaBean. JSF fornisce gli strumenti per effettuare questa operazione di "binding" in modo automatico e dichiarativo.
• Gestione del Flusso di Navigazione: Una parte molto importante di una applicazione web è la gestione del flusso di navigazione tra le pagine web che la costituiscono. JSF, analogamente a quanto fatto ad esempio in Spring MVC, consente di definire in maniera semplice ed esternamente al codice la logica di navigazione della propria applicazione.
• Rendering dei componenti: Un aspetto molto importante in JSF è la separazione tra il comportamento di un elemento di interfaccia e la sua rappresentazione grafica. L'elemento di interfaccia viene modellato da una classe che ne definisce il comportamento. L'aspetto grafico, ovvero la sua "renderizzazione", è a carico di una classe completamente distinta, un Renderer appunto. Ciò significa che una stessa interfaccia può essere "renderizzata" in formati diversi senza modificarne il comportamento funzionale.
• Gestione degli errori: JSF ha i meccanismi necessari per la gestione degli errori e per la segnalazione degli stessi al livello di interfaccia.
• Internazionalizzazione: JSF supporta la gestione dell'internazionalizzazione di una applicazione web con strumenti molto simili a quelli già in uso in altri framework.
In termini di sviluppo JavaServer Faces mette a disposizione dello sviluppatore un ampio insieme
di classi e API che permettono di definire i componenti dell’interfaccia utente e gestirne il
mantenimento dello stato, gestire gli eventi che vengono generati lato client con oggetti e codice
lato server, specificare la navigazione fra le pagine all’interno della web application e realizzare
componenti personalizzati che estendono e potenziano le funzionalità delle classi basi del
framework. Queste classi sono raggruppate in modelli, in relazione a specifici aspetti realizzativi di
una applicazione Web.
• Execution Model;
• UI Component Model;
• Component Rendering Model;
• Event and Listner Model;
• Validation Model;
• Navigation Model;
• Backing Bean Management Model
32 32
EEEEXECUTION XECUTION XECUTION XECUTION MMMMODELODELODELODEL
Questo modello fa riferimento a tutto ciò che riguarda l’esecuzione dell’applicazione, quindi in
particolar modo definisce le classi che costituiscono il Controller del pattern MVC. Trattandosi di
un framework per lo sviluppo di applicazioni Web, la classe principale è costituita dalla servlet
FacesServlet, la quale allo stesso modo della DispatcherServlet per Spring MVC, agisce da Front
Controller per tutte le richieste entranti di tipo JSF. Ovviamente va configurata nel file web.xml
dell’applicazione:
<servlet> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping>
La classe Application è di tipo “singleton” ed il suo scopo è quello di descrivere interamente la Web
application ed in particolare i parametri di quest’ultima che sono specificati nel file di
configurazione faces-config.xml.
In pratica, all’avvio dell’applicazione, viene eseguita la lettura del file di configurazione faces-
config.xml e tutte le informazioni in esso contenute vengono caricate all’interno delle proprietà
corrispondenti della classe Application, una classe che implementa il singleton pattern. In questo
modo, durante l’esecuzione dell’applicazione è possibile accedere a queste informazioni ed
eventualmente modificarle.
Le classi principali che sono legate ad essa e che vengono specificate nel file faces-config.xml sono le
seguenti:
• ActionListener: permette la gestione degli action events;
• NavigationHandler: gestisce la navigazione fra le pagine sulla base delle navigation-rules e degli outcome;
• ViewHandler: ha il compito di gestire le fasi di ricostruzione della vista di una pagina da uno stato precedente e di visualizzare una risposta, anche sulla base di dispositivi client di accesso differenti;
• StateManager: efettua il salvataggio ed il ripristino dello stato dell’applicazione fra una richiesta ed un’altra;
• MessageBundle: identifica il file .properties nel quale ci sono tutti i messaggi da visualizzare nell’applicazione, sulla base di un certo Locale, permettendo l’internazionalizzazione;
• Lifecycle, PhaseListener: permette la gestione del ciclo di vita di ciascuna richiesta;
33 33
• VariableResolver: individua gli oggetti referenziati nelle pagine JSF attraverso l’Expression Language.
Se tali classi non vengono specificate nel file faces-config.xml, verranno utilizzate quelle di default. In
caso contrario, lo sviluppatore ha la possibilità di personalizzare il framework, estendendo queste
classi e specificandole nel file di configurazione. Ad esempio Spring dispone della classe
org.springframework.web.jsf.DelegatingVariableResolver attraverso cui
rende disponibili in JSF gli oggetti definiti all’interno del suo ApplicationContext, rendendo
l’integrazione tra i due framework estremamente semplice. Ovviamente lo stesso tipo di
operazione può essere eseguita anche per le altre classi.
Altre informazioni associate alla classe Application e quindi contenute nel file faces-config.xml,
specificano il Renderer Kit di default per la visualizzazione delle pagine e l’internazionalizzazione,
definendo il Locale di default e tutti quelli supportati.
Infine, essa è legata a tutte quelle classi che definiscono gli elementi costitutivi dell’applicazione, in
particolare:
• UIComponent: definisce ciascun componente dell’interfaccia utente insieme a tutte le sue classi derivate;
• Validator: che implementa un validatore per i dati di input dell’utente;
• Converter: che permette di eseguire la conversione dei dati;
• MethodBinding, ValueBinding: associano i componenti ed i loro valori, ai metodi o alle proprietà dei backing beans;
La classe FacesContext definisce il contesto dell’applicazione, cioè mantiene tutte le
informazioni che caratterizzano una richiesta e ciò che riguarda la relativa risposta da generare.
Essa può essere modificata in ciascuna fase del ciclo di vita di una richiesta, per garantire che il
contesto sia sempre aggiornato. È ovviamente legata alla classe Application, facendo uso del
metodo getApplication().
Oltre alle informazioni che riguardano l’applicazione, essa è legata anche a tutte quelle classi che si
occupano in particolare della fase di rendering e quindi della produzione della risposta per una
specifica richiesta. Nella fattispecie tali classi sono:
34 34
• UIViewRoot: rappresenta il nodo radice della view che definisce l’albero dei componenti (il component-tree) di una certa pagina;
• RenderKit: è una collezione di istanze della classe Renderer che si occupano di visualizzare i componenti dell’interfaccia utente, secondo una certa grafica, in relazione al dispositivo client che viene utilizzato per accedere all’applicazione, il linguaggio di markup ed il Locale corrente;
• ResponseWriter: definisce uno stream attraverso il quale è possibile produrre, direttamente nella pagina di risposta, il codice specifico per la tecnologia di rendering utilizzata (markup HTML, XML eccetera);
• FacesMessage: è la classe che contiene un singolo messaggio associato ad un componente specifico e che va visualizzato in ogni pagina. Il messaggio in questione può essere ad esempio un messaggio di errore dovuto ad una validazione o conversione errata.
Infine, attraverso il metodo getExternalContext(), è possibile ricavare l’istanza della
classe ExternalContext, la quale definisce il contesto esterno, ossia tutto ciò che riguarda
l’ambiente in cui viene eseguita l’applicazione. Da questa classe è possibile accedere direttamente a
tutte le variabili il cui scope (ambito di visibilità) sia quello di tipo session, request o application e
quindi ai parametri ed agli attributi di una richiesta. In pratica permette l’accesso ai servizi di basso
livello offerti dalle Servlet API.
UUUUSER SER SER SER IIIINTERFACE NTERFACE NTERFACE NTERFACE CCCCOMPONENT OMPONENT OMPONENT OMPONENT MMMMODELODELODELODEL
Il framework JSF mette a disposizione una serie di classi relative ai componenti della UI e le
corrispondenti interfacce che ne descrivono il comportamento e le funzionalità, oltre al
mantenimento dello stato, i riferimenti agli oggetti (backing beans) e la gestione degli eventi. Tali
classi possono essere estese, permettendo allo sviluppatore di potenziare i componenti standard,
aggiungendovi nuove funzionalità.
La classe di base da cui derivano tutte le classi per i componenti standard è
UIComponentBase, la quale definisce lo stato ed il comportamento di default di un generico
componente ed a sua volta estende la classe UIComponent.
Di seguito sono riportate tutte le classi che descrivono i componenti previsti in JSF :
• UIColumn: generica colonna del componente UIData;
• UICommand: controllo che può intercettare un action event (es. click del mouse) quando viene attivato;
• UIData: permette di gestire il binding con una collection di dati per la loro visualizzazione. Tale collection può essere eventualmente definita con un DataModel;
• UIForm: permette di raggruppare più controlli di una pagina e definire, appunto, un form di invio delle informazioni contenute. E’ paragonabile al tag <form> dell’ HTML;
35 35
• UIGraphic: immagine da visualizzare in una pagina;
• UIInput: permette di acquisire un’informazione di input dall’utente;
• UIMessage: permette la visualizzazione di un messaggio anche sulla base della localizzazione geografica dell’utente (internazionalizzazione);
• UIMessages: come il precedente, ma permette di visualizzare un gruppo di più messaggi;
• UIOutput: visualizza un’informazione di output in una pagina;
• UIPanel: permette di raggruppare più componenti secondo un certo layout;
• UIParameter: usato insieme ad altri componenti per specificare una serie di parametri da passare ad essi;
• UISelectBoolean: controllo che permette all’utente di selezionare un valore booleano;
• UISelectItem: definisce una singola item di una collection di items;
• UISelectItems: definisce un insieme di items;
• UISelectMany: permette all’utente di selezionare una o più items da una collection di items;
• UISelectOne: permette all’utente di selezionare una sola item nell’ambito di una collection di items a disposizione;
• UIViewRoot: rappresenta il nodo radice dell’albero dei componenti che, secondo una gerarchia, costituiscono una pagina;
Le classi suddette, oltre ad estendere la classe base UIComponentBase, implementano anche
una serie di interfacce che ne definiscono il comportamento :
• ActionSource: indica che un componente può intercettare un evento ActionEvent;
• ValueHolder: indica che un componente può immagazzinare un valore (local value) così come ha la possibilità di accedere al dato corrispondente all’interno del Model;
• EditableValueHolder: estende ValueHolder aggiungendo ulteriori funzionalità ai componenti editabili, tra cui la validazione e l’intercettazione di eventi del tipo ValueChange
• NamingContainer: fa in modo che ciascun componente abbia un identificativo univoco;
• StateHolder: segnala che un componente ha uno stato che va salvato ad ogni richiesta;
In generale, la classe UICommand implementa ActionSource e StateHolder. La classe
UIOutput e tutte le classi che la estendono, implementano StateHolder e ValueHolder.
La classe UIInput e tutte le classi che la estendono, implementano StateHolder,
ValueHolder ed EditableValueHolder.
36 36
Per la realizzazione di un componente personalizzato (Custom Component) , è necessario estendere la
classe UIComponentBase oppure una delle sue classi derivate in modo da sfruttare le
potenzialità di queste ultime ed aggiungerne delle altre.
Infine, per poter introdurre un componente all’interno di una pagina, è necessario associare ad
esso un tag realizzato mediante una classe nota come Tag Handler. Tale classe è , in generale,
un’estensione della classe UIComponentTag e definisce gli attributi del tag stesso.
CCCCOMPONENT OMPONENT OMPONENT OMPONENT RRRRENDERING ENDERING ENDERING ENDERING MMMMODELODELODELODEL
L’architettura dei componenti, messi a disposizione dalla tecnologia JSF prevede che le
funzionalità degli stessi, così come lo stato ed il comportamento, vengano definite con le classi e le
interfacce precedentemente viste, mentre la visualizzazione (rendering), venga realizzata mediante
altre classi specifiche note come renderer.
Questa separazione comporta i seguenti vantaggi :
• coloro che scrivono i componenti (Component writers) possono definire una sola volta il comportamento di un componente, mediate un’unica classe, ma possono permetterne diverse visualizzazioni, mediante molteplici renderers, in relazione ai tanti dispositivi client che possono accedere alla Web application;
• coloro che realizzano le pagine (Page authors) e coloro che sviluppano l’applicazione (Application developers) possono scegliere la grafica di un certo componente, utilizzando un tag che individui la giusta combinazione fra la classe del componente stesso ed il renderer appropriato;
Un Renderer Kit definisce una mappatura fra le classi dei componenti ed i tag che permettono di
inserire questi ultimi nella UI, anche in base al dispositivo client di accesso alla Web application. Le
varie implementazioni di JSF, forniscono un Renderer Kit standard per i client HTML, il quale
permette di inserire i componenti della UI all’interno di una pagina JSP attraverso opportuni tag.
La classe Renderer permette di definire un renderer associato ad un componente. Essa
converte la rappresentazione interna di un componente in una rappresentazione grafica, attraverso
uno stream di output sulla pagina.
Mediante la realizzazione di una o più classi che estendono la classe Renderer, si possono
realizzare diversi renderers che cambiano la modalità di visualizzazione dello stesso componente in
base alle necessità o al dispositivo client di accesso. Ad esempio, un componente della classe
UISelectOne ha tre renderers associati: il primo che visualizza il componete come un insieme
di radio buttons, il secondo come una combo box e l’ultimo come una list box. Il comportamento
37 37
del componente è sempre il medesimo, ossia la definizione di una lista di items e la possibilità
all’utente di selezionarne una di esse, ma le modalità di visualizzazione sono molteplici.
In definitiva, ogni tag della libreria HTML che JSF mette a disposizione, è associato ad una classe
che definisce le funzionalità del componente (UIComponent) e ad una classe che ne permette la
visualizzazione (Renderer).
Un esempio tipico è la classe UICommand la cui funzionalità principale è quella di intercettare un
action event (es. click del mouse) e permettere un invio di informazioni, così come il passaggio da
una pagina all’altra. Questo scopo può essere raggiunto attraverso un “link” oppure un “bottone”.
Questi ultimi hanno due tag associati per la loro visualizzazione e quindi due classi Renderer
diverse, che ne permettono una grafica differente, pur basandosi sulla medesima classe
componente (appunto UICommand).
Figura 7 - Rendering UICommand
Inoltre, come già anticipato, un insieme di classi Renderer costituiscono un Renderer Kit associato
ad uno specifico dispositivo di accesso alla Web application, il quale si basa su un determinato
linguaggio di markup.
Infine, per quanto concerne la produzione degli elementi da visualizzare nella pagina, viene
utilizzata la classe ResponseWriter che rappresenta uno stream di scrittura verso la pagina
stessa.
CCCCONVERSION ONVERSION ONVERSION ONVERSION MMMMODELODELODELODEL
In una Web application realizzata con JSF, generalmente ogni componente è associato ad un
oggetto server side, tipicamente realizzato mediante un JavaBean, che in particolare viene definito
backing bean o managed bean. Nell’ambito dell’applicazione, si accede ai valori memorizzati dai
componenti, utilizzando i metodi getter e setter delle proprietà corrispondenti dei backing beans
associati. Ciò vuol dire che , nel momento in cui un componente è legato ad un backing bean,
esistono due viste del dato relativo :
38 38
• model view (model value): il valore è rappresentato secondo un certo tipo di dato all’interno della proprietà del backing bean (es. tipo int, long, ..) ;
• presentation view (local value): il valore è rappresentato secondo una modalità per cui può essere letto e modificato dall’utente.
Ad esempio, un componente potrebbe prevedere l’immissione di una data da parte dell’utente. Il
valore del componente è associato alla proprietà del backing bean legato al componente stesso. La
data sarebbe rappresentata come un oggetto java.util.Date all’interno del backing bean
(model view) ma attraverso una stringa del tipo “yyyy-mm-dd” nel componente (presentation
view). L’implementazione JSF effettua automaticamente la conversione tra una vista e l’altra,
ovviamente quando la proprietà del backing bean associato al componente è di un tipo di dato tra
quelli ammessi dal componente stesso.
In alcuni casi, è possibile però che una proprietà di un backing bean, non sia di un tipo di dato
standard tra quelli previsti dal linguaggio Java, ma sia un di un tipo di dato, magari una classe,
definito dallo sviluppatore. In queste situazioni, associando il backing bean ad un componente, si
rende necessaria la realizzazione di un opportuno convertitore, che ovviamente non è fornito
nell’implementazione di JSF. A tal scopo è possibile definire un custom converter estendendo
l’interfaccia Converter. Essa è caratterizzata fondamentalmente da due soli metodi
getAsObject() e getAsString() che eseguono le conversioni in un verso e nell’altro e
che lo sviluppatore deve implementare.
Infine, per poter associare un converter ad un componente dell’interfaccia utente, è necessario
definire un tag mediante la classe ConverterTag.
EEEEVENT E VENT E VENT E VENT E LLLLISTENER ISTENER ISTENER ISTENER MMMMODELODELODELODEL
Il modello che definisce gli eventi ed i relativi gestori (listeners o handlers) di JSF è molto simile al
modello degli eventi dei JavaBeans, in quanto fortemente tipizzato e basato su una serie di classi e
di interfacce che permettono di intercettare e gestire gli eventi dei componenti della UI.
Un oggetto Event identifica il componente su cui si è scatenato l’evento e memorizza le
informazioni dell’evento stesso. Per notificare il verificarsi di un evento, una Web application deve
prevedere un oggetto della classe Listener che va registrata sul componente in questione. Nel
momento in cui l’utente, interagendo con la UI, fa scatenare l’evento sul componente, entra in
gioco il listener che si occupa di gestire l’evento.
La tecnologia JSF supporta tre tipi di eventi :
39 39
• action event: si scatena quanto l’utente attiva un componente che implementa l’interfaccia ActionSource, come nel caso di bottoni o collegamenti ipertestuali (link);
• value-change event: si verifica quando l’utente cambia il valore di un componente implementato dalla classe UIInput o da una delle sue sottoclassi, come il caso dei semplici campi di testo, checkbox, radio buttons, list box, combo box e drop-down list;
• data-model event: si scatena quando c’è uno spostamento ad una nuova riga in un componente della classe UIData;
Ci sono due modi per poter gestire un evento: implementare una classe listener e registrarla sul
componente di interesse, utilizzando gli attributi actionListener oppure
valueChangeListener del tag del componente stesso, oppure implementare all’interno del
backing bean associato al componente, un metodo che debba gestire l’evento.
Il modello a eventi è implementato attraverso la classe FacesEvent e l’interfaccia
FacesListener. La prima è la classe base che definisce il generico evento che si può verificare
su un componente dell’interfaccia utente e memorizza lo stato del componente che lo ha generato.
Da essa derivano le due sottoclassi ActionEvent che definisce un evento dovuto all’interazione
con l’utente) e ValueChangeEvent, la quale notifica il verificarsi di un cambiamento di valore
in un componente.
La seconda è l’interfaccia mediante la quale è possibile realizzare una classe che abbia la capacità di
gestire un generico evento FacesEvent. Da essa derivano le interfacce ActionListener e
ValueChangeListener, specializzate rispettivamente nella gestione di un ActionEvent e
di un ValueChangeEvent. Esse rappresentano un altro punto di estensione del framework in
quanto se lo sviluppatore ha la necessità di gestire dei particolari eventi, può realizzare delle classi
che implementano le interfacce suddette.
VVVVALIDATION ALIDATION ALIDATION ALIDATION MMMMODELODELODELODEL
JSF fornisce un particolare meccanismo per la validazione del local value di un componente
“editabile” (ad esempio un campo di testo). Tale validazione viene eseguita prima che il model
value corrispondente venga aggiornato ed assuma come valore proprio il local value. Come nel
caso del Conversion Model, anche il Validation Model fornisce una serie di classi standard per
effettuare le operazioni di validazione. Inoltre, all’interno sono previsti dei tag che permettono di
utilizzare tali validatori in una pagina JSP, associandoli ai componenti.
E’ comunque possibile realizzare dei validatori personalizzati (Custom Validators) in due modi
differenti: se si vuole rendere la validazione riusabile, bisogna realizzare una classe che implementa
l’interfaccia Validator, registrarla all’interno dell’applicazione e definire un tag che permetta di
40 40
utilizzare il validatore in una pagina JSP, associandolo ad un componente; altrimenti un modo più
semplice consiste nell’implementare all’interno del backing bean associato al componente su cui
fare la validazione del valore un metodo che la esegua.
Il framework fornisce una serie di classi standard che possono eseguire delle semplici validazioni,
in particolare:
• LengthValidator: verifica se il valore di un componente ha una lunghezza che rientra nei limiti specificati;
• LongRangevalidator, DoubleRangeValidator: verifica se il valore di tipo long o double di un componente, rientra in un range prefissato;
A ciascun validator è associato un tag in modo da poterlo utilizzare in una pagina JSP in relazione
ad uno specifico componente. La classe che permette di realizzare il Tag Handler corrispondente è
la classe ValidatorTag.
NNNNAVIGATION AVIGATION AVIGATION AVIGATION MMMMODELODELODELODEL
Nell’ambito di JSF, la navigazione tra le pagine è definita da una serie di regole, denominate
navigation-rules, che individuano la pagina successiva dopo aver cliccato su un bottone oppure su un
link. Tali regole sono definite all’interno del file faces-config.xml, mediante una serie di elementi
XML. Per definire la navigazione è necessario quindi:
• specificare le regole di navigazione, ciascuna delle quali indica a partire da una certa pagina, quale sia la pagina successiva verso la quale proseguire;
• definire in corrispondenza dei bottoni e dei link, il cosiddetto outcome ossia una stringa che permette di selezionare una tra le regole ammesse e quindi permettere la navigazione;
Ad esempio, quando si clicca su un bottone oppure su di un link, viene generato un action event
gestito dall’istanza ActionListener di default, che invoca un action-method, implementato
all’interno di un backing bean. Tale metodo esegue eventualmente un’elaborazione e ritorna una
stringa, l’outcome, che viene passato al NavigationHandler di default, il quale analizza le regole di
navigazione, cerca l’outcome che gli è stato fornito ed individua la pagina successiva.
Ciascuna navigation-rule specifica come eseguire la navigazione da una certa pagina verso tutta
un’altra serie di pagine, attraverso delle casistiche di navigazione (navigation-cases). Ciascun
navigation-case, all’interno di una navigation-rule, specifica una pagina di destinazione e l’outcome
che permette di referenziarla per proseguire la navigazione.
41 41
BBBBACKING ACKING ACKING ACKING BBBBEAN EAN EAN EAN MMMMANAGEMENT ANAGEMENT ANAGEMENT ANAGEMENT MMMMODELODELODELODEL
Un’applicazione JSF prevede una serie di backing beans, che sono associati ai componenti
dell’interfaccia utente in una pagina JSP. Un backing bean è associato ad uno o più componenti
della UI, in quanto ciascuna delle sue proprietà è legata al valore del componente stesso oppure ad
una sua istanza. Inoltre, il bean può avere dei metodi che permettono di eseguire ulteriori
elaborazioni sui componenti, come la validazione, la gestione degli eventi e il processo di
navigazione.
Il binding tra il valore di un componente della UI oppure di una sua istanza e le proprietà di un
backing bean, viene realizzato con la sintassi dell’Expression Language (EL), così come è possibile
esprimere il riferimento ad un metodo del backing bean dal componente stesso. Nel primo caso si
parla di value-binding, mentre nel secondo di method-binding.
Se si considera un componente dell’interfaccia utente, immesso in una pagina JSP mediante l’uso
di un particolare tag, il suo valore sarà legato ad una proprietà di un backing bean mediante
l’attributo value, referenziando tale proprietà mediante l’EL. In questo modo, il componente avrà
un suo local value ed il corrispondente model value sarà memorizzato nella proprietà del bean.
Nel caso in cui si voglia associare l’istanza del componente e non il suo valore, ad una proprietà di
un backing bean, si può utilizzare l’attributo binding.
Inoltre, è possibile utilizzare gli attributi validator, actionListener e
valueChangeListener per fare riferimento ad alcuni metodi dei backing bean, per poter
eseguire delle operazioni di validazione e per poter gestire gli eventi del tipo action e value-change. Ad
esempio, considerando un campo di testo il cui valore deve essere trasferito nella proprietà di un
backing bean, dopo essere stato validato attraverso un metodo di quest’ultimo, la sintassi del tag
<h:inputText> è la seguente:
Sulla base di questa definizione, se il valore del componente subisce un cambiamento ed il form
che lo contiene viene trasmesso, si scatena un value-change event che verrà gestito dal metodo del
backing bean specificato.
42 42
Infine, nel momento in cui si ha a che fare con un componente che implementa l’interfaccia
ActionSource (es. bottone o link) si può utilizzare l’attributo action per specificare il
metodo di un backing bean che esegue una certa elaborazione e fornisce come risultato un
outcome per proseguire la navigazione in una certa direzione.
Eseguire il binding fra l’istanza di un componente e la proprietà di un bean, ha come vantaggio il
fatto che il bean può istanziare un compomente e modificarne gli attributi durante l’esecuzione.
Invece l’uso del binding fra il valore del componente e la proprietà del bean fa sì che i backing
beans non siano legati alle classi dei componenti, determinando di fatto una più netta separazione
fra Model e View; in più l’implementazione JSF può realizzare la conversione tra il valore del
componente e la relativa proprietà del backing bean in maniera automatica, senza che lo
sviluppatore debba realizzare un convertitore, se non in casi particolari.
I backing beans devono essere configurati nel file faces-config.xml, in modo tale che JSF possa
istanziarli quando sono referenziati all’interno dei tag. In particolare è necessario specificare un
nome da poter usare attraverso l’EL, la classe e lo scope. Quest’ultimo può essere di tre tipi:
• request: un nuovo backing bean viene istanziato ad ogni richiesta HTTP;
• session: un nuovo backing bean viene istanziato all’avvio di una sessione utente ed è accessibile per tutta la sua durata;
• application: il backing bean viene creato all’avvio dell’applicazione ed è accessibile da tutti gli utenti per tutta la durata dell’applicazione.
43 43
Il ciclo di vita delle richieste JSF
Analizzate le componenti che costituiscono il framework JSF, è necessario capire il modo in cui
viene elaborata una richiesta HTTP, cioè quello che prende il nome di ciclo di vita di una richiesta
(lifecycle). Esso è molto simile a quello di una normale pagina JSP: il client invia una richiesta HTTP
per ricevere una certa pagina ed il serer invia tale pagina trasformata in HTML. In realtà,
considerando le potenzialità offerte da JSF, sono previste alcune elaborazioni aggiuntive. Quando
il client richiede una pagina, ha inizio il lifecycle e il framework JSF costruisce la view, tenendo
conto dello stati degli relativo ad una richiesta precedente della pagina stessa (viene ricostruito
l’utimo stato della pagina). Il client interagisce con la pagina ed invia i dati; il framework allora
esegue la validazione di quest’ultimi e la conversione dei valori in tipi validi per il lato server. Infine
esegue le funzionalià della web application e produce i risultati per il client. JavaServer Faces
dunque prevede sei fasi di elaborazione, raffigurate nella figura sottostante.
Figura 24 – lifecycle di una richiesta JSF
RRRRESTORE ESTORE ESTORE ESTORE VVVVIEWIEWIEWIEW
In questa fase il framework acquisisce il component-tree della pagina richiesta se non è la prima
richiesta alla stessa oppure ne crea uno nuovo nel caso di prima richiesta. Come già detto ogni
44 44
pagina di una applicazione JSF viene rappresentata da un albero di componenti che corrispondono
ai vari elementi dell'interfaccia grafica; esso è memorizzato di default nel server, ma opzionalmente
è possibile demandarne la memorizzazione lato client (nel caso di HTML attraverso l’uso di un
hidden field). Se la richiesta non ha dati associati (generalmente quando la pagina è richiesta per la
prima volta) il framework redirige il flusso direttamente alla fase di RenderResponse, altrimenti
prosegue con la fase successiva.
AAAAPPLY PPLY PPLY PPLY RRRREQUESTSEQUESTSEQUESTSEQUESTS
Nella fase apply requests il framework si occupa di convertire i parametri associati alla richiesta in
tipi validi per il Model, quindi li memorizza nei relativi elementi del component tree. Ad esempio
se l’utente deve inserire un valore numerico all’interno di un campo di tipo input, il valore di quel
campo viene prima convertito in tipo Integer, quindi, se la conversione avviene correttamente,
viene associato all’elemento del component tree relativo a quel campo, altrimenti il framework
genera un messaggio di errore che verrà poi inviato al client nella fase di render response. Il
component tree in definitiva contiene al suo interno lo stato dei vari componenti della pagina
richiesta ed è aggiornato automaticamente ad ogni richiesta senza che lo sviluppatore se ne debba
preoccupare. Rispetto a Spring MVC si tratta di un notevole passo avanti, in quanto questa
operazione non è più a carico dello sviluppatore ma viene effettuata direttamente dal framework.
PPPPROCESS ROCESS ROCESS ROCESS VVVVALIDATIONALIDATIONALIDATIONALIDATION
Una volta aggiornato il component tree con i valori immessi dal client, il framework richiede a tutti
gli elementi del component tree di verificare che i dati acquisiti durante la fase di apply request
siano validi e quindi accettabili. JSF mette a disposizione alcuni validatori di default ma lo
sviluppatore può definirne di propri. Se i dati superano con successo questa fase, il framework
passa alla fase successiva, altrimenti marca il componte come errato e salta alla fase di rendering
response accodando degli opportuni messaggi di errore.
UUUUPDATE PDATE PDATE PDATE MMMMODEL ODEL ODEL ODEL VVVVALUESALUESALUESALUES
Terminata la fase di validazione, è possibile trasferire i dati ricevuti dal client allo strato Model
dell’applicazione. Tale operazione è effettuata per mezzo dei cosidetti backing-beans, oggetti che
implementano l’aspetto Controller del pattern MVC e i cui attributi possono essere associati
direttamente ai componenti del component tree. Rispetto ai Controller di Spring MVC essi non
devono estendere alcuna interfaccia particolare, e il loro codice non contiene alcun riferimento ai
dettagli della view: in particolare essi non devono preoccuparsi dell’acquisizione, conversione e
validazione dei dati inviati dall’utente, in quanto queste operazioni vengono effettuate direttamente
dal framework o comunque gestite esternamente.
45 45
IIIINVOKE NVOKE NVOKE NVOKE AAAAPPLICATIONPPLICATIONPPLICATIONPPLICATION
Aggiornato il Model con i nuovi dati immessi dal client (che sono stati già convertiti e validati nelle
fasi precedenti), nella fase Invoke Application JSF processa gli eventi generati dai componenti
della view in seguito all’interazione con l’utente, ad esempio come il submit di una form o il click
su di un link. Questi eventi, detti Action Event, sono gestiti dagli Action Listener i quali possono
influenzare la navigazione dell’applicazione. A questo scopo gli Action Listener, similmente a
quanto avviene nella programmazione Swing, delegano il loro compito agli Action Method definiti
nel backing-bean della view che di fatto eseguono la logica applicativa corrispondente all’azione
effettuata dall’utente sull’interfaccia. Gli Action Method inoltre possono determinare quale view
visualizzare all’utente in seguito alla loro esecuzione.
RRRRENDER ENDER ENDER ENDER RRRRESPONSEESPONSEESPONSEESPONSE
Determinata quindi la view da visualizzare all’utente, JSF procede a popolarne i componenti e a
renderizzarla all’utente. Questa operazione è effettuata attraverso il Renderer Kit, un modulo del
framework che trasforma il component tree nella tecnologia di view desiderata (XML, HTML,
XFORM eccetera).
Vantaggi derivanti dall’uso di JSF
JSF non è il primo framework a componenti esistente sul mercato (Tapestry e WebObject esistono
da più tempo ad esempio), ma presenta alcuni aspetti peculiari che ne hanno motivato l’interesse
da parte di Trim:
• Standardizzazione: a differenza di tutti gli altri framework JSF è una specifica definita all’interno Java EE platform, e rappresenta quindi il framework standard per lo sviluppo di applicazioni web. L’azienda che lo adotta può contare sull’esperienza decennale e il supporto di numerosi vendors (tra i quali Sun, Bea, Oracle, Ibm, Jboss).
• Supporto negli ambienti di sviluppo: facendo parte di una piattaforma di sviluppo diffusa e collaudata, il supporto a JSF negli ambienti di sviluppo è garantito dagli stessi vendor che promuovono la piattaforma Java EE. Gli IDE più diffusi (Jdeveloper, Eclipse, Netbeans) offrono già oggi pieno supporto a JSF. Inoltre la sua logica a componenti permette di fornire un ambiente di tipo RAD per lo sviluppo della GUI applicativa, semplificando notevolmente la produttività.
• Struttura a componenti: grazie all’uso di componenti riutilizzabili è possibile realizzare applicazioni veramente modulari. Inoltre essa alimenta il mercato dei vendor di componenti aggiuntivi: al momento esistono già component-suite molto interessanti come IceFaces, Oracle ADF Faces, WebGalileo Faces, RichFaces che dimostrano come sia possibile estendere le funzionalità di JSF in maniera produttiva.
46 46
Lo sviluppo di COB potrebbe trarre un grande vantaggio dall’uso di questo framework, sia in
termini di flessibilità che di manutenibilità. Sarebbe possibile rendere riutilizzabili molti
componenti dell’interfaccia web (soprattutto per quanto riguarda i controllers e le view) e il loro
codice sarebbe decisamente più chiaro e lineare. Sfruttando l’elevata espandibilità di JSF e gli
strumenti di integrazione messi a disposizione da Spring, è possibile convertire il codice Spring
MVC in codice JSF senza dover riscrivere tutta l’applicazione web e riutilizzando i servizi di
business già sviluppati nel BusinessLayer. Nel prossimo capitolo quindi mostrerò una possibile
integrazione di JSF con l’infrastruttura esistente basata su Sping. In particolare mostrerò come
questa non solo è possibile, ma è anche molto semplice.
47 47
Capitolo 5
Integrazione con Spring
Grazie all’elevata modularità di Spring, è possibile integrare facilmente il framework JSF all’interno
dell’applicazione COB. È possibile infatti rendere disponibili direttamente in JSF i servizi realizzati
nello strato Business, riducendo l’integrazione a tre semplici passi:
• configurazione dell’applicazione web;
• adattamento dei controller Spring MVC in backing beans;
• sviluppo delle pagine JSF.
CCCCONFIGURAZIONE DELLA ONFIGURAZIONE DELLA ONFIGURAZIONE DELLA ONFIGURAZIONE DELLA WWWWEB EB EB EB AAAAPPLICATIONPPLICATIONPPLICATIONPPLICATION
Per una corretta integrazione, è necessario ovviamente configurare la FacesServlet nel file web.xml
dell’applicazione, aggiungendo le seguenti righe:
<servlet> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping>
A questo punto è necessario creare il file di configurazione faces-config.xml. In questo file sarà
necessario dichiarare i backing-bean che compongono l’applicazione web assieme alle regole di
navigazione (navigation-rules). Inoltre bisognerà configurare la classe
org.springframework.web.jsf.DelegatingVariableResolver per far si che i
servizi definiti nello strato business siano disponibili per i backing bean di JSF.
Qui di seguito è mostrato come esempio la configurazione del backing-bean relativo alla
definizione dei criteri MASTER e le navigation-rules necessarie per gestire la home page. Si noti
come la proprietà service del backing-bean faccia riferimento al bean PresentationService definito
nel contesto di Spring.
48 48
<application> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> </application> <managed-bean> <managed-bean-name>criteriController</ managed-bean-name> <managed-bean-scope>Application</managed-bean-scope> <managed-bean-class> com.sanpaolo.cob.web.controllers.CriteriController </managed-bean-class> <managed-property> <property-name>service</property-name> <value>#{presentationService}</value> </managed-bean> <navigation-rule> <from-view-id>/home.jsp</from-view-id> <navigation-case> <from-outcome>config</from-outcome> </to-view-id>/config.jsp</from-outcome> </navigation-case> <navigation-case> <from-outcome>comitato</from-outcome> </to-view-id>/comitato.jsp</from-outcome> </navigation-case> <navigation-case> <from-outcome>tesoreria</from-outcome> </to-view-id>/config.jsp</from-outcome> </navigation-case> <navigation-case> <from-outcome>alert</from-outcome> </to-view-id>/config.jsp</from-outcome> </navigation-case> </navigation-rule>
IIIIL L L L BBBBACKING ACKING ACKING ACKING BBBBEAN EAN EAN EAN CCCCRITERIRITERIRITERIRITERICCCCONTROLLERONTROLLERONTROLLERONTROLLER
Per quanto riguardo il backing-bean CriteriController, è possibile utilizzare con minime
modifiche la stessa classe sviluppata precedentemente con Spring MVC. In realtà sarebbe possibile
utilizzarla senza alcuna modifica, ma ciò comporterebbe l’implementazione di un ELResolver
che traduca l’oggetto ModelAndView restituito dai metodi del controller in un outcome
interpretabile da JSF. Del resto le modifiche da apportare sono davvero minime e aiutano a
rendere il codice già sviluppato più pulito. Uno dei problemi individuati in fase di analisi è
costituito infatti dalla non pulizia del codice dovuta alla presenza di alcuni workaround per la
gestione dello stato delle pagine web. Inoltre è comunque necessario riprogettare la pagina web
relativa alla selezione dei criteri MASTER per cui ritengo preferibile mostrare come adattare il
codice esistente al modello di programmazione proposto da JSF, piuttosto che mantenere
inalterato un codice che si è già rivelato difficile da gestire.
Le modifiche necessarie da apportare sono semplicemente la modifica della signature dei metodi,
più l’aggiunta di alcune proprietà. Ad esempio per qunto riguarda il metodo loadCriterio():
49 49
public ModelAndView loadCriterio( HttpServletRequest request, HttpServletResponse response) throws ServletException { ModelAndView mv = createModelAndView(getFormView()); try { String codCampo = request.getParameter("id.codCampo"); String codTipo = request.getParameter("id.codTipo"); String codMfiCostituente = Request.getParameter("id.codMfiCostituente"); CriterioIdoneitaId id = new CriterioIdoneitaId( codCampo, codTipo, codMfiCostituente ); CriterioIdoneita criterioCaricato=getService().loadCriterio(id); //MyBeanUtils.valueCopy(criterioCaricato, criterio); //mv.addObject(this.gnetCommandName(),criterio); mv.addObject(this.getCommandName(),criterioCaricato); CampiCriteri cc = getService() .getCampiCriteriByCampo( criterioCaricato.getId().getCodCampo() ); mv.addObject( "listaClausole", this.getClausoleByTipo(cc.getCodTipoCampo()) ); mv.addObject("currentCodCampo", codCampo); mv.addObject("_selectedRow",request.getParameter("selectedRow")); mv.addObject("_azione", "modificaCriterio"); mv.addObject("visualizzaDettagli", "true"); } catch(Exception e) { e.printStackTrace(); throw new ServletException(e); } return mv; }
Diventa:
public void loadCriterio() { String codCampo = getCurrentCriterio().getCodCampo(); String codTipo = getCurrentCriterio().getCodTipo(); String codMfiCostituente = getCurrentCriterio().getCodMfiCostituente();
50 50
try { CriterioIdoneitaId id = new CriterioIdoneitaId( codCampo, codTipo, codMfiCostituente ); setcurrentCriterio(getService().loadCriterio(id)); CampiCriteri cc = getService() .getCampiCriteriByCampo( getCurrentCriterio().getId().getCodCampo() ); setListaClausole(this.getClausoleByTipo(cc.getCodTipoCampo()); } catch(Exception e) { e.printStackTrace(); throw new ServletException(e); } }
È evidente quanto il codice rimodellato sia molto più snello e lineare rispetto a quello originale: in
particolare si notano l’uso dei metodi di tipo getter per ottenere i parametri codCampo, codTipo e
codMfiCostituente e i metodi di tipo setter per impostare la lista dei criteri caricati e la lista delle
clausole. Questi, che nella versione originale erano impostati manualmente nella view, in JSF
diventano proprietà del backing-bean e possono dunque essere associati direttamente ai
componenti della pagina in modo tale che il trasferimento tra client e server avvenga in maniera
trasparente e automatica. Ciò non solo si traduce in un codice più conciso e meno caotico per il
backing-bean, ma anche in una più pulita realizzazione della view.
LLLLA VIEW A VIEW A VIEW A VIEW CRTIERICRTIERICRTIERICRTIERI....JSPJSPJSPJSP
Mentre l’originale criteri.jsp necessitava di una complessa interazione tra codice javascript, tag
HTML e JSP, la versione JSF risulta più snella e lineare: gran parte del codice originale necessario a
gestire gli elementi della pagina infatti è inglobato all’interno dei component tag di JSF. Il risultato
è quindi una pagina composta per lo più dai tag JSF che costiuscono gli elementi della GUI
(bottoni, caselle di testo, link) e codice HTML che definisce la struttura della pagina. Ecco quindi
quale sarebbe il codice (semplificato) della pagina criteri.jsp in versione JSF :
51 51
Figura 25 – Codice JSF per la pagina Criteri
In particolare si nota la totale assenza di codice Javascript e l’uso dei tag JSF
<commandButton> e <inputText> al posto di quelli HTML per la definizione degli
elementi attivi della view. I primi sono legati ad un metodo del backing bean CriteriController
attraverso l’attributo actionListener: Quando il commandButton viene premuto, l’evento
viene intercettato dall’action listener registrato su di esso e tutte le operazioni relative vengono
effettuate. Gli elementi inputText invece sono legati alle proprietà dell’oggetto currentCriterio
esposto da CriteriController di modo che riflettano i valori contenuti nel criterio selezionato. Se
l’utente li modifica, inoltre, l’oggetto currentCriterio viene aggiornato automaticamente.
La pagina in versione JSF esegue dunque le stesse funzionalità della pagina in versione Spring
MVC, ma richiede molto meno codice.
Soluzioni alternative d’integrazione tra Spring e JSF
La soluzione d’integrazione adottata usando la classe VariableResolver fornita da Spring, sebbene
sia molto semplice è pulita, permette solo una integrazione unilaterale tra le due tecnologie: è
possibile rendere visibili a JSF i bean definiti nel contesto Spring, ma non il contrario. D’altronde
si tratta di una situazione molto comune, in quanto spesso si usa Spring per la realizzazione del
business layer e poi ci si affida a tecnologie diverse (JSF, Spring MVC, Struts) per la realizzazione
del web layer.
52 52
Qualora sia necessaria una comunicazione bilaterale tra Spring e JSF è possibile far ricorso alla
libreria JSF-Spring, una libreria sviluppata esternamente ai due progetti ma che risulta più potente
di quella adottata da Spring. In pratica essa fornisce a Spring un WebapplicationContext
contenente i managed beans di JSF, permettendo quindi allo sviluppatore di sfruttare le potenti
capacità di Spring anche nella loro gestione.
Un’altra libreria, o per meglio dire framework viste le notevoli capacità, molto utile durante lo
sviluppo JSF è costituita da Jboss Seam. Sfruttando i molti punti di estensione forniti da JSF, esso
ne estende le funzionalità ad un livello tale da permettere uno sviluppo JSF-centrico di tutta quanta
l’applicazione, permettendo l’uso dei managed bean di JSF direttamente nel business layer. Ciò
perché fornisce alcuni meccanismi d’integrazione con la specifica EJB (e quindi anche con Spring).
Inoltre facilita ulteriormente lo sviluppo delle pagine JSF e la loro navigazione introducendo il
concetto di conversation, uno scope a metà tra request e session.
53 53
Conclusioni
L’esperienza maturata in Trim è stata molto stimolante e formativa. Ho avuto modo di partecipare
attivamente ad un progetto di sviluppo reale, affiancato da professionisti del settore attraverso cui
ho potuto sperimentare di persona cosa significa lavorare in una squadra per realizzare un progetto
partendo da zero e le problematiche che si possono incontrare durante lo sviluppo. È
un’esperienza che ha accresciuto in me la passione, già elevata, che nutro per la programmazione
Durante l’attività di ricerca ho potuto valutare personalmente le deficienze del framework di
sviluppo web utilizzato presso Trim, e sono giunto alla conclusione che, per il tipo di applicazioni
sviluppate, la tecnologia JSF potesse rivelarsi ideale. Dopo averne studiato le fondamenta, mi sono
concentrato sulle possibilità di integrazione tra JSF con l’applicazione esistente. Ovviamente ve ne
sono diverse, ma quella che ho reputato più efficace (considerando la strategia implementativa
adottata da Trim) è quella fornita da Spring: semplicissima e trasparante.
L’esempio di integrazione che ho mostrato è limitato ad una parte del codice, ma mostra bene le
potenzialità di questo approccio: non è stata necessaria alcuna riscrittura delle funzionalità
business, mentre gran parte del codice originale Spring MVC può essere adattato senza troppa
fatica. Dunque, alla luce di questi risultati, ritengo che l’integrazione di JSF nell’applicazione
originale sia realmente possibile.
54 54
Bibliografia
K. D. Mann - “JavaServer Faces in Action” - Ed. Manning
Doris Chen Ph.D. - “JavaServer Faces and Sun Java Studio Creator : Experience the Next Generation Web-
Application Framework”, Sun Tech Days 2005 - Sun Microsystems
D. Goyal, V. Varma - “Introduction to JavaServer Faces (JSF)” - Sun Microsystems
E. Burns - “About Faces : The JavaServer Faces API and how it relates to Struts” - Sun Microsystems
M. Hall - Tutorial “JavaServer Faces 1.1” (www.coreservlets.com)
A. Winder, C. Straub - “Extreme Reuse in JavaServer Faces Technology” , JavaOne - Sun’s 2005
Worldwide Java Developer Conference - Oracle
J. Pardi – “JavaServer Faces”, 25 Maggio 2005