Tesi di Laurea - Framework MVC per lo sviluppo di Web Application

Transcript

Tesi di Laurea - Framework MVC per lo sviluppo di Web Application
Università degli studi di Napoli Federico II
Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica
TESI DI LAUREA
Framework MVC per lo sviluppo di Web Application :
JavaServer Faces e Struts
Relatore
Ch.mo Prof. Antonio d’Acierno
Candidato
Paolo Patierno
Matricola 041/2803
Anno Accademico 2004/2005
…a tutti coloro che hanno creduto in me
…alla mia pazientissima famiglia
…alla mia dolcissima Sara
…alle mie care nonne
Ringraziamenti
Quando nella vita si raggiungono grandi traguardi e si realizzano i propri
sogni, ci si rende conto che, senza l’appoggio delle persone che ci vivono accanto,
gli sforzi e l’impegno personali non avrebbero mai consentito da soli tali risultati.
Ho sempre considerato lo studio e la conoscenza tra gli elementi fondamentali
della vita di una persona e per questo, per raggiungere il mio obiettivo, non ho
mai lesinato nei miei confronti l’impegno, aggiungendovi costanza, instancabilità,
caparbietà e tenacia che comunque sarebbero state vane senza le persone che qui
ho il piacere ed il dovere di ringraziare.
I miei ringraziamenti vanno innanzitutto al Prof. Ing. Antonio d’Acierno,
il quale mi ha proposto questo lavoro che ho accettato con grande entusiasmo.
Grazie a lui, ho avuto la possibilità di affrontare ed approfondire nuovi temi legati
allo sviluppo del software per Internet, per me di estremo interesse.
Gli anni di studio, che mi hanno portato a questo grande traguardo, sono
stati caratterizzati da momenti di gioia così come da periodi di sacrifici ed
amarezze, che non avrei saputo superare senza coloro che mi hanno preso per
mano lungo questo cammino.
Un immenso grazie va innanzitutto alla mia famiglia, Mamma, Papà ed
ai miei fratelli Enzo e Daniela, che mi hanno dato la possibilità di realizzare
questo sogno, senza mai ostacolarmi nelle decisioni ma dandomi sempre il
massimo appoggio. In questi anni, hanno dovuto sopportare i miei comprensibili
momenti di tensione e di nervosismo,
senza mai rimproverarmi alcun
comportamento. A loro devo chiedere scusa, per non aver dedicato il giusto tempo
che merita una famiglia che ama il proprio figlio ed il proprio fratello.
Grazie a mio cugino Diego, che rappresenta per me il modello da
seguire, umanamente e professionalmente, il quale non ha mai risparmiato
consigli ed elogi nei miei confronti. Spero di poter crescere nel tempo ed acquisire
le notevoli capacità che gli riconosco.
Grazie a tutti i miei amici più sinceri, con i quali ho trascorso delle ore
spensierate, lontano dagli affanni dello studio, e che mi hanno fatto sentire una
persona importante per loro.
Un grazie particolare va a Sara, che ho avuto l’immensa fortuna di
conoscere circa un anno fa, diventando l’amore della mia vita. Si è ritrovata
“catapultata” nel mio mondo, fatto di moltissime ore si studio, di sacrifici e di
preoccupazioni, dandomi sempre la forza di rialzarmi nei momenti di rabbia e di
sconforto. Seppur soltanto in questo ultimo anno, il suo amore nei miei confronti è
stato una grande fonte di energia, dalla quale spero di attingere per tutto il resto
della mia vita.
Vorrei concludere con una dedica alle mie nonne, Edy ed Anna, che ne
sono certo mi hanno guidato da lassù e che in questo momento mi sono vicine, per
condividere con me l’enorme gioia che ho dentro. A voi …
Grazie di cuore a tutti
Indice
Introduzione
Obiettivo della tesi…………………………………………………… 1
Capitolo I – Il pattern MVC
1. Architettura software “a livelli” ………………………………….
3
2. L’importanza dei “design patterns” ……………………………....
6
3. Design Pattern MVC Model – View – Controller ………………...
8
4. Evoluzione dell’architettura delle Web Application ………………… 11
4.1 Model 1 (Page – Centric Architecture) ………………………… 12
4.2 Model 2 (Servlet – Centric Architecture) ………………………. 13
5. Le Servlet …………………………………………………….. 15
5.1 Struttura di base …………………………………………… 16
5.2 Ciclo di vita ………………………………………………... 17
5.3 Richiesta, Risposta, Sessione e Contesto ………………………... 19
6. Web Application Frameworks …………………………………… 21
7. Struttura di una Web application in Java …………………………. 22
7.1 Web Application Deployment Descriptor ………………………. 23
Capitolo II – Il framework JavaServer Faces
1 . Introduzione ………………………………………………….. 26
2. Teamworking …………………………………………………. 29
3. Modelli architetturali - Framework Models ………………………. 31
3.1 Execution Model …………………………………………… 32
I
3.1.1 FacesServlet ……………………………………………. 32
3.1.2 Lifecycle – PhaseListener ………………………………… 33
3.1.3 Application …………………………………………….. 34
3.1.4 FacesContext – ExternalContext …………………………. 35
3.2 User Interface Component Model ……………………………… 37
3.3 Component Rendering Model …………………………………. 40
3.3.1 Renderer ………………………………………………... 40
3.4 Conversion Model ……………………………………………. 42
3.4.1 Converter ……………………………………………….. 43
3.5 Event and Listener Model ……………………………………. 44
3.5.1 FacesEvent ……………………………………………… 45
3.5.2 FacesListener ……………………………………………. 45
3.6 Validation Model …………………………………………… 46
3.6.1 Validator ………………………………………………. 47
3.7 Navigation Model …………………………………………… 48
3.8 Backing Bean Management …………………………………... 49
4. Ciclo di vita di una pagina JavaServer Faces ……………………….. 52
4.1 Scenari di elaborazione di una richiesta ………………………… 53
4.2 Ciclo di vita Standard ……………………………………….. 55
4.2.1 Restore View …………………………………………… 56
4.2.2 Apply Request Values …………………………………… 56
4.2.3 Process Validation ………………………………………. 57
4.2.4 Update Model Values …………………………………… 57
4.2.5 Invoke Application ……………………………………… 58
4.2.6 Render Response ………………………………………… 58
II
5. JSF Expression Language ……………………………………… 59
6. Espandibilità del framework ……………………………………. 60
6.1 Custom Converter …………………………………………... 60
6.2 Event Listener ……………………………………………... 61
6.2.1 Implementazione di un ActionListener/ValueChangeListener ... 62
6.2.2 Backing Bean Method Listener …………………………… 63
6.3 Custom Validator …………………………………………... 63
6.3.1 Implementazione di un Validator …………………………. 64
6.3.1.1 Class Validator ……………………………………... 65
6.3.1.2 Tag Handler ………………………………………... 65
6.3.1.3 Tag Library Descriptor ………………………………. 66
6.3.2 Backing Bean Method Validator ………………………….. 66
6.4 Custom UI Components ……………………………………... 67
6.4.1. Class Component ……………………………………….. 69
6.4.2 Tag Handler ……………………………………………. 71
6.4.3 Tag Library Descriptor …………………………………… 72
6.4.4 Classe Renderer ………………………………………….. 73
7. Sicurezza ……………………………………………………… 73
8. Configurazione dell’applicazione ………………………………….. 74
8.1 Configurazione dei Backing Beans ……………………………... 75
8.2 Localizzazione, Internazionalizzazione e Messaggi ………………. 76
8.3 Registrare un Custom Validator ………………………………. 77
8.4 Registrare un Custom Converter ………………………………. 77
8.5 Configurare le Navigation Rules ………………………………. 78
8.6 Registrare un Custom Renderer in un Renderer Kit ………………. 79
III
8.7 Registrare un Custom Component ……………………………. 80
Capitolo III – Il framework Struts
1 . Introduzione ………………………………………………….... 81
2. Controller, Model and View Components ………………………….. 83
2.1 Controller Components ……………………………………….. 84
2.1.1 ActionServlet ……………………………………………. 85
2.1.2 RequestProcessor …………………………………………. 86
2.1.3 Action ………………………………………………….. 88
2.1.3.1 ForwardAction ………………………………………. 89
2.1.3.2 DispatchAction – LookupDispatchAction ………………. 90
2.1.3.3 SwitchAction ………………………………………… 91
2.1.4 ActionForward ………………………………………….. 91
2.2 Utility Classes ………………………………………………. 92
2.3 Model Components …………………………………………... 93
2.4 View Components …………………………………………… 94
2.4.1 ActionForm …………………………………………….. 95
2.4.2 ActionErrors …………………………………………… 97
2.4.2.1 ActionMessage – ActionError ………………………… 98
2.4.3 DynaActionForm ……………………………………….... 99
2.4.4 Tag Libraries …………………………………………….100
3. Ciclo di vita di una richiesta …………………………………….. 101
4. Exception Handling ………………………………………….... 102
4.1 Approccio Dichiarativo ………………………………………103
4.2 Approccio programmatico …………………………………......104
IV
4.3 ModuleException …………………………………………....104
5. Internazionalizzazione (I18N) …………………………………..105
6. JavaServer Pages Standard Tag Library (JSTL) …………………...107
7. Estensioni con i PlugIn ………………………………………….108
8. Validator framework……………………………………………109
9. Tiles framework ………………………………………………..111
9.1 Definitions …………………………………………………113
9.2 Costruzione di una pagina ……………………………………114
10. Sicurezza …………………………………………………….115
11. Configurazione dell’applicazione…………………………………116
11.1 DataSource ……………………………………………….117
11.2 FormBean ………………………………………………...118
11.3 Global Exceptions …………………………………………120
11.4 Global Forwards …………………………………………..121
11.5 Action Mapping …………………………………………...121
11.6 Controller ………………………………………………....123
11.7 Message resources …………………………………………..123
11.8 Plug-In …………………………………………………...124
Capitolo IV – I framework a confronto
1. Introduzione ……………………………………………………..125
2. Ciclo di vita di una richiesta ……………………………………….127
3. Controller Tier …………………………………………………...130
4. Interfaccia Utente (UI) ……………………………………………133
5. Events e Listeners …………………………………………….......136
V
6. Mappatura delle richieste sulla Business-Logic ………………………..140
7. Conversione ……………………………………………………...144
8. Validazione ……………………………………………………..145
9. Navigazione ……………………………………………………..148
10. Expression Language …………………………………………....150
11. Eccezioni ………………………………………………………152
12. Internazionalizzazione (I18N) …………………………………...154
13. Sicurezza ………………………………………………………155
14. Configurazione ………………………………………………….156
15. Web Application Layout ………………………………………...157
16. Migrazione da Struts a JavaServer Faces …………………………..159
16.1 Strategie di migrazione ……………………………………...159
16.1.1 Components Only ………………………………………159
16.1.2 Incremental migration …………………………………...161
16.1.3 Full migration ……………………………………….....164
Capitolo V – Case Study : Analisi e Progettazione
1. Introduzione ……………………………………………………..165
2. Requisiti ………………………………………………………...167
3. Progettazione …………………………………………………….168
3.1 Use Case Diagrams …………………………………………168
3.1.1 Generale ………………………………………………..169
3.1.2 Gestione Scheda Prepagata ………………………………..170
3.1.3 Registrazione ……………………………………………171
3.1.4 Azioni su Brani ……………………………………........171
VI
3.1.5 Gestione Playlist ………………………………………....172
3.1.6 Gestione Utenti ………………………………………….173
3.1.7 Gestione Archivio Brani …... ………………………...........174
3.1.8 Casi d’uso comuni : Login, Logout, Gestione Dati Personali ......176
3.2 Class Diagram ……………………………………………...177
3.3 Activity Diagrams – Sequence Diagrams …………………….....180
3.3.1 Login …………………………………………………..182
3.3.2 Logout …………………………………………………187
3.3.3 Registrazione ……………………………………………189
3.3.4 Richiesta Username / Password …………………………...192
3.3.5 Acquisto, Ricarica e Visualizzazione Info Scheda Prepagata ….193
3.3.6 Visualizzazione e Ricerca Brani ….... ……………………..199
3.3.7 Inserimento, Modifica ed Eliminazione Brano dall’Archivio .......202
3.3.8 Ascolto di un singolo Brano ……………………………….211
3.3.9 Gestione Playlist ………………………………………....214
3.3.10 Acquisto/Download Brano ……………………………...226
3.3.11 Modifica Dati Personali ………………………………....229
3.3.12 Gestione Utenti ………………………………………...234
3.4 Statechart Diagrams ………………………………………....237
3.5 Conceptual Data Model ……………………………………...244
3.6 Physical Data Model ………………………………………...247
Capitolo VI – Case Study : Implementazioni a confronto
1. Introduzione ……………………………………………………..252
2. Struttura dell’applicazione ………………………………………....254
VII
3. Controller …………………………………………………..........263
3.1 Gestione delle sessioni ………………………………………...264
3.2 Protezione pagine ……………………………………………266
4. View …………………………………………………………....268
4.1 Le librerie Standard …………………………………………269
4.1.1 I form : contenuto e layout ……………………......................270
4.1.2 Costruzione condizionale dei contenuti ……………………....272
4.1.3 DataTable JSF e Cicli JSTL ……………………………..273
4.2 Tiles ……………………………………………………….275
4.3 JavaServer Faces Custom Components ……………………….....278
4.3.1 DateSelectComponent …………………………………….279
4.3.2 DDListComponent ……………………………….............283
4.3.3 TimeSelectComponent ……………………………..............285
4.3.4 …e Struts ? …………………………………………….287
4.4 I formbean di Struts …………………………………………288
4.4.1 Login, Registrazione e Richiesta password …………………..289
4.4.2 Acquisto/Ricarica scheda prepagata ………………………..292
4.4.3 Modifica dati utente ed amministratore ………………….......294
4.4.5 Visualizzazione e ricerca dei brani ……………………........294
4.4.6 Inserimento/Modifica brani ……………………………….297
4.4.7 Gestione Playlist ………………………………………....298
4.4.8 Gestione Utenti ………………………………………….300
4.4.9 … e JavaServer Faces ? …………………………………..301
4.5 Player MP3 ………………………………………………...302
4.6 Internazionalizzazione (I18N) ……………………………......303
VIII
5. Validazione ……………………………………………………..306
5.1 JavaServer Faces Custom Validators …………………………..306
5.1.1 EmailValidator ………………………………………....308
5.1.2 SeqCifreValidator ……………………………………….310
5.1.3 TelefonoValidator ……………………………………......311
5.2 Plug-in Validator Struts ……………………………………..313
6. Model …………………………………………………………..316
6.1 Classi Exception ……………………………………………317
6.2 Classi di interfacciamento con il DataBase ……………………...318
6.3 Le Action di Struts ………………………………………….329
6.4 Business-Logic e funzionalità del sistema ……………………….344
6.4.1 Package accesso ………………………………………….346
6.4.2 Package ruolo …………………………………………...348
6.4.3 Package brani …………………………………………...357
6.4.4 Package playlist ……………………………………….....364
6.4.5 Package scheda ………………………………………......370
6.4.6 Package cartacredito ……………………………………...374
6.4.7 Package download ……………………………………….376
6.4.8 Package mail ……………………………………………376
6.5 I Backing Beans di JavaServer Faces …………………………..377
7. Plug-in di Struts …………………………………………………380
8. Navigazione ……………………………………………………..382
9. Eccezioni ………………………………………………………..384
10. Sicurezza ………………………………………………………385
IX
Appendice A – SRS Web Application MP3-Web……………………...390
Riferimenti Bibliografici ………………………………………………...426
X
Introduzione – Obiettivo della tesi
_________________________________________________________________
Introduzione
Obiettivo della tesi
Il lavoro di tesi svolto si pone come obiettivo il confronto tra due dei
principali framework MVC per lo sviluppo di Web application : JavaServer Faces e
Struts. Considerando il linguaggio comune su cui si basano, ossia il Java, tale
confronto è relativo soprattutto a ciò che riguarda gli strumenti, le funzionalità e le
potenzialità fornite dall’uno e dall’altro.
Si parte da una descrizione del pattern MVC (Model – View – Controller) e
di tutti gli aspetti relativi al suo meccanismo di funzionamento, nonché da una
spiegazione delle Servlet che sono alla base dei framework suddetti.
Successivamente, viene dato ampio spazio al framework JavaServer Faces
descrivendone tutte le classi che ne costituiscono l’architettura e tutte le funzionalità
messe a disposizione per realizzare un’applicazione Web. Allo stesso modo è stata
approfondita la struttura di Struts ed i relativi strumenti disponibili.
Raccolte le informazioni necessarie, è stato realizzato un confronto teorico
tra i due framework evidenziando vantaggi e svantaggi dell’uno e dell’altro in
relazione a ciascuna funzionalità offerta.
Per poter fornire una base solida al confronto teorico, è stato preso in
esame un caso di studio che ha previsto la realizzazione di una Web application
mediante i due framework. Tale applicazione mette a disposizione degli utenti la
possibilità di usufruire di contenuti audio, ossia brani MP3, registrandosi, creando
delle proprie playlist per poterle ascoltare in streaming e per poter eventualmente
acquistare i brani ed effettuarne il download. Per quanto riguarda l’amministratore,
egli ha a disposizione tutte le funzionalità di gestione dell’archivio dei brani e degli
utenti registrati. E’ stata eseguita una preventiva fase di analisi e progettazione che ha
previsto la realizzazione del documento di specifica dei requisiti (SRS) e di tutti i
1
Introduzione – Obiettivo della tesi
_________________________________________________________________
diagrammi UML (Use Case, Class, Activity, Sequence, Statechart) oltre al modello
concettuale e fisico della base di dati necessaria. A queste fasi ha fatto seguito una
doppia fase di implementazione che ha previsto la realizzazione della Web
application con entrambi i framework. Infine, sulla base di quanto sviluppato sono
state ripresi tutti gli aspetti che potessero rappresentare termini di confronto fra di
essi e sono state evidenziate le analogie e le differenze di implementazione dell’uno e
dell’altro.
Per quanto concerne gli strumenti adottati si è fatto ampio uso del software
Sybase Power Designer per lo sviluppo dei diagrammi UML, dell’ambiente IDE
Eclipse 3.1 ed i plug-in Exadel ed Omondo per l’implementazione ed infine del Web
Container Apache Tomcat 5.0.28 come ambiente di esecuzione delle due
implementazioni.
2
Capitolo I – Il Pattern MVC
_________________________________________________________________
Capitolo I – Il Patter n MVC
1. Architettura software “a livelli”
Nello sviluppo delle applicazioni software, è possibile descrivere
l’architettura del sistema utilizzando uno fra i molteplici paradigmi a disposizione, ma
in linea generale, trova una maggiore applicazione la nota architettura “a livelli”
(Layered Application Architecture). Quest’ ultima prevede che un sistema software
sia decomposto in tre livelli nettamente distinti, che comunque abbiano la possibilità
di comunicare fra loro secondo un’opportuna gerarchia. Ciascuno dei tre livelli ha un
proprio ruolo ed assolve ad uno specifico compito all’interno del sistema
complessivo, senza interferire con gli altri livelli ma scambiando con essi le
informazioni necessarie all’esecuzione di elaborazioni anche molto complesse.
I tre livelli in questione sono i seguenti :
-
Presentation layer : è il livello di presentazione, il cui compito è quello di
interagire direttamente con l’utente del sistema, acquisire i dati di input
immessi da quest’ultimo e visualizzare i risultati dell’elaborazione effettuata
dal sistema stesso. Esso, in pratica, definisce la GUI (Graphic User Interface)
ossia l’interfaccia grafica dell’applicazione;
-
Application processing layer : è il livello in corrispondenza del quale si trova la
“business-logic” dell’applicazione e quindi tutti i moduli software che
implementano le funzionalità che il sistema mette a disposizione. In sostanza,
è il centro dell’elaborazione dei dati in cui avvengono tutte le computazioni;
-
Data management layer : è il livello che si occupa della gestione della persistenza
e dell’accesso ai dati, per cui è tipicamente caratterizzato da un DBMS
(DataBase Management System);
3
Capitolo I – Il Pattern MVC
_________________________________________________________________
Figura 1 – Architettura Software “a livelli”
Sviluppando un’applicazione secondo questa architettura, ogni livello è indipendente
dagli altri, per cui la modifica di uno di essi non ha effetto sui restanti. Tuttavia è
prevista la comunicazione fra loro e lo scambio di informazioni.
Un tipico scenario di funzionamento del sistema può essere il seguente :
un utente utilizza l’applicazione, interagendo direttamente con la GUI e fornisce
quindi al Presentation layer, i dati su cui andrà eseguita l’elaborazione. Il Presentation
layer, acquisiti i dati di input, li trasferisce all’Application processing layer che esegue
su di essi una determinata computazione.
Durante l’elaborazione, la business-logic può prevedere la memorizzazione
persistente dei dati oppure la necessità di acquisire ulteriori dati già memorizzati. In
questo caso, c’è l’interazione con il Data managemente layer, il quale memorizza i
dati che gli vengono passati dal livello superiore, oppure recupera da un Data Source
(es. database)
i dati richiesti e li trasmette alla business-logic. Al termine
dell’elaborazione i risultati vengono passati al Presentation layer che li visualizza in
una certa forma all’utente finale.
Facendo riferimento al paradigma Client-Server, notevolmente utilizzato nelle Web
application ma di gran richiamo anche per applicazioni desktop, i tre livelli del
sistema devono essere correttamente ripartiti anche da un punto di vista hardware.
Le principali architetture per la ripartizione sono :
-
Two-Tier nelle due soluzioni Thin e Fat Client;
-
Three-Tier;
4
Capitolo I – Il Pattern MVC
_________________________________________________________________
L’architettura Two-Tier prevede un unico Client ed un unico Server ed i tre livelli
dell’applicazione software sono distribuiti fra di essi secondo due possibili modalità :
-
Thin Client : sul Client risiede il Presentation layer mentre sul Server gli altri
due livelli (Application processing layer e Data management layer). Un
vantaggio può risiedere nel fatto che una modifica alla business-logic va
eseguita una sola volta sul Server, mentre lo svantaggio principale può essere
caratterizzato dall’enorme carico di lavoro che deve supportare il Server
stesso dato il numero elevato di Client che possono accedere ad esso;
-
Fat Client : sul Client risiedono i primi due livelli (Presentation layer e
Application processing layer) mentre sul Server soltanto il Data management
layer. Il vantaggio è quello di ridurre il carico di lavoro sul Server che si
occupa solo dell’accesso ai dati, delegando l’elaborazione degli stessi al Client.
Lo svantaggio principale è la complessità maggiore dei Client e quindi la
necessità di aggiornare ciascuno di essi nel caso in cui vengano apportate
modifiche alla business-logic;
Figura 2 – Architetture Two Tier
L’architettura Three-Tier, maggiormente utilizzata, prevede la presenza di un unico
Client ed una coppia di Server. Sul Client risiede il Presentation layer e su ciascuno
dei due Server sono distribuiti i due restanti livelli (Application processing layer e
Data management layer). Nell’ambito di una Web application, il Client è
caratterizzato da un nodo della rete sul quale è in esecuzione il browser, mentre i due
Server, da un punto di vista software, sono tipicamente inglobati in un unico nodo
5
Capitolo I – Il Pattern MVC
_________________________________________________________________
della rete che funge da Server fisico. In particolare, sulla stessa macchina sono in
esecuzione il Web Server associato all’Application proccessing layer ed il Database
Server associato al Data management layer.
Figura 3 – Architettura Three Tier
In conclusione, è proprio su questa particolare architettura “a livelli” che si basa il
pattern MVC (Model – View – Controller) , che rappresenta il fondamento dei
framework Struts e JavaServer Faces (JSF) che saranno oggetto di studio e di un
approfondito confronto.
2. L’importanza dei “design patterns”
Alla metà del ventesimo secolo, l’architetto Christopher Alexander osservò
come i suoi colleghi tendevano a risolvere i medesimi problemi, più o meno allo
stesso modo. Da tale osservazione, introdusse il concetto di “design pattern”,
ovviamente riferito all’architettura. Secondo Christopher Alexander, un design
pattern “descrive un problema che si presenta frequentemente nel nostro ambiente, e
quindi descrive il nucleo della soluzione in modo tale che sia possibile impiegare tale
soluzione milioni di volte, senza peraltro produrre due volte la stessa realizzazione”.
Ovviamente, tale definizione era riferita all’ambito architetturale, ma nel 1994, con il
libro “Design Patterns : Elements of Reusable Object-Oriented Software”, Erich
Gamma, Richard Helm, Ralph Johnson e John Vlissides, applicarono questa
intuizione allo sviluppo del software. In questo caso, il principio è ugualmente valido
anche se riferito ad oggetti, classi ed interfacce piuttosto che ad elementi
architettonici come muri, archi e pilastri.
6
Capitolo I – Il Pattern MVC
_________________________________________________________________
Un pattern è un modello che permette di definire la “soluzione” di un “problema”
specifico che si ripresenta, di volta in volta, in un “contesto” diverso.
Presenta inoltre le seguenti caratteristiche :
-
il “nome” che individua il pattern e la cui importanza non è secondaria,
perché rientra a far parte del vocabolario dello sviluppo software;
-
la descrizione del “problema” in maniera dettagliata, con la sua struttura e le
condizioni al contorno;
-
la “soluzione” che descrive gli artefatti software per risolvere il problema
come gli elementi che rientrano nello sviluppo, quali le classi e le relazioni fra
esse, le associazioni ed i ruoli, le modalità di collaborazione tra le classi
coinvolte ed infine la distribuzione delle responsabilità nella soluzione del
particolare problema di design considerato;
-
le “conseguenze” che descrivono i risultati che si possono ottenere
dall’applicazione del pattern per spingere uno sviluppatore a farne uso;
Ad oggi i patterns sono di grande interesse, in virtù del fatto che rappresentano una
successiva evoluzione del paradigma OOP (Object – Oriented Programming), poiché
combinano classi ed oggetti atomici per fornire una base più ampia per la risoluzione
di un problema, nella fattispecie per lo sviluppo di un’applicazione software.
Sotto questo punto di vista, un design pattern fornisce allo sviluppatore :
-
una soluzione codificata e consolidata per un problema ricorrente;
-
un’astrazione di granularità e livello di astrazione più elevati di una classe;
-
un supporto alla comunicazione delle caratteristiche del progetto;
-
un modo per progettare software con caratteristiche predefinite;
-
un supporto alla progettazione di sistemi complessi;
-
un modo per gestire la complessità del software;
Può essere considerato un “buon” pattern un pattern che descrive una soluzione
“assodata” per un problema “ricorrente” in un contesto “specifico”.
7
Capitolo I – Il Pattern MVC
_________________________________________________________________
E’ ovvio che esistono numerose tipologie di design patterns, ma nell’ambito dello
sviluppo delle Web application, in riferimento all’obiettivo proposto, assume un
ruolo rilevante il pattern MVC (Model View Controller).
3. Design Pattern MVC Model – View – Controller
Il design pattern MVC ha le sue origini nell’ambiente Smalltalk, in cui
veniva utilizzato per la realizzazione della GUI (Graphic User Interface) di
applicazioni desktop e non orientate al Web. Tale pattern si basa sull’idea di separare
i dati dalla rappresentazione, poiché mantenere un forte accoppiamento tra essi
comporta che la modifica dell’uno, implica automaticamente un’ aggiornamento
dell’altro. Esso, quindi, prevede che un sistema software sia realizzato secondo
l’architettura “a livelli”, stabilendo un disaccoppiamento fra dati e rappresentazione,
mediante la definizione di tre elementi noti come : Model, View e Controller.
Figura 4 - Model, View e Controller
Il Model (Modello) è responsabile della gestione dei dati e del
comportamento dell’applicazione (data & behaviour). Esso coordina la “businesslogic” dell’applicazione, l’accesso alle basi di dati e tutte le parti critiche “nascoste”
del sistema. Incapsula lo stato dell’applicazione ed espone le funzionalità di
8
Capitolo I – Il Pattern MVC
_________________________________________________________________
quest’ultima. E’ indipendente dalle specifiche rappresentazioni dei dati sullo schermo
e dalle modalità di input dei dati stessi da parte dell’utente. Ad esso fanno riferimento
l’Application processing layer ed il Data managemente layer nel design del software
“a livelli”.
Il Model può essere scomposto in tre sottolivelli puramente concettuali :
-
External interface : caratterizzato dal codice che definisce un’interfaccia
mediante la quale il codice esterno comunica con il Model. Generalmente il
codice esterno è determinato dal framework adottato per sviluppare la Web
application, come ad esempio Struts e JavaServer Faces;
-
Business logic : rappresenta il cuore del Model contenente il codice che realizza
le funzionalità dell’applicazione;
-
Data access : costituito dal codice che permette di accedere ad un datasource,
come ad esempio una base di dati;
Figura 5 – Architettura del Model
I tre sottolivelli descritti non rappresentano necessariamente dei set di classi separate
ma, bensì, dei set di responsabilità differenti che ha il Model. Lo sviluppatore può
decidere di realizzare i tre sottolivelli mediante una o più classi e raggruppando due o
più sottolivelli. Tipicamente si preferisce realizzare il sottolivello Data access con una
9
Capitolo I – Il Pattern MVC
_________________________________________________________________
o più classi che hanno come unico scopo quello di permettere l’accesso ad un base di
dati. Gli altri due sottolivelli possono essere realizzati in due modi :
-
separazione : ci sono una serie di classi che realizzano la Business logic ed
ulteriori classi che definiscono l’External interface;
-
fusione : sono definite una serie di classi che definiscono la Business logic e
contengono all’interno anche le funzionalità di interfacciamento dell’External
interface;
La scelta può dipendere dalla complessità dell’applicazione ed , eventualmente, dalla
tecnologia che viene adottata sul Model per realizzare la Web application.
La View (Vista) ha il compito di visualizzare i dati e presentarli all’utente
anche in forme diverse, in relazione al dispositivo utilizzato per accedere al sistema
(es. personal computer, cellulare, ..) . Ciò vuol dire che, pur partendo dagli stessi dati,
è possibile effettuare “rendering” diversi ed ottenere viste multiple dello stesso
modello. Ad esso fa riferimento il Presentation layer.
Il Controller (Controllo) definisce il meccanismo mediante il quale il Model
e la View comunicano. Realizza la connessione logica tra l’interazione dell’utente con
l’interfaccia applicativa e i servizi della business-logic nel back-end del sistema. E’
responsabile della scelta di una tra molteplici viste dello stesso modello, in base al
tipo di dispositivo utilizzato dall’utente per accedere al sistema ma anche in relazione
alla localizzazione geografica dell’utente stesso. Una qualsiasi richiesta (request) fatta
al sistema viene acquisita dal Controller che individua all’interno del Model il gestore
della richiesta (request handler). Ottenuto il risultato dell’elaborazione (response), il
Controller stesso determina a quale View passare i dati per la presentazione degli
stessi all’utente.
Il vantaggio principale che scaturisce da questa architettura, è che la business-logic
definita all’interno del Model è separata dal Presentation layer che si trova all’interno
della View. Tutto ciò favorisce il riuso dei componenti e la possibilità di apportare
delle modifiche ad un livello senza avere degli effetti sull’altro.
10
Capitolo I – Il Pattern MVC
_________________________________________________________________
4. Evoluzione dell’architettura delle Web Application
Considerando il Java come uno dei migliori linguaggi per lo sviluppo delle
applicazioni Web, attraverso l’uso delle Servlets e delle pagine JSP (Java Server
Pages), l’architettura delle Web application ha subito una notevole evoluzione nel
corso degli anni, seguendo un iter di questo tipo :
1. Assenza del pattern MVC;
2. Utilizzo del pattern MVC secondo il Model 1 (Page – Centric);
3. Utilizzo del pattern MVC secondo il Model 2 (Servlet – Centric);
4. Web application Frameworks (es. Struts);
5. Web application Framework basato su uno standard ( JavaServer Faces – JSR
127);
Tale evoluzione ha previsto un aumento della complessità e della robustezza di
ciascuna applicazione e può essere schematizzata nel modo seguente, sino
all’introduzione del Model 1 :
Figura 6 - Evoluzione dello sviluppo di Web Application
11
Capitolo I – Il Pattern MVC
_________________________________________________________________
4.1 Model 1 (Page – Centric Architecture)
Il Model 1 del pattern MVC è detto anche Page – Centric, poiché
l’architettura della Web application è basata sulle pagine JSP. Il sistema complessivo è
composto da una serie di pagine JSP legate fra loro, ciascuna delle quali gestisce tutti
gli aspetti principali dell’applicazione tra cui la presentazione, il controllo ed i processi
di business. E’ evidente che la business-logic ed il controllo sono fortemente
accoppiati all’interno di ciascuna pagina JSP, attraverso l’utilizzo di JavaBeans,
Scriptlets ed Espressioni. I tre elementi del pattern, Model, View e Controller, pur
essendo distinti, sono inglobati all’interno di una stessa struttura che in questo caso è
rappresentata da una pagina JSP.
Figura 7 - MVC Model 1 (Page - Centric Architecture)
Il modello prevede uno scenario di interazione di questo tipo :
Il browser invia una richiesta (request) di una risorsa al Web Server, nella maggior
parte dei casi per la visualizzazione di una pagina JSP. Il Web Server, tipicamente,
funge da Web Container e quindi da Servlet Container in quanto va ricordato che
una pagina JSP, una volta richiesta, viene sempre trasformata in una corrispondente
Servlet. All’interno della pagina JSP, ci sono i tag che ne definiscono la presentazione
all’utente e quindi l’aspetto grafico (GUI) , ma anche gli elementi per l’esecuzione
12
Capitolo I – Il Pattern MVC
_________________________________________________________________
delle elaborazioni. Queste ultime possono essere eseguite all’interno della pagina
stessa, attraverso codice Java immerso nei tag (Scriptlets) oppure mediante dei
componenti esterni, ai quali si fa riferimento da tale pagina. I componenti in
questione sono tipicamente dei JavaBeans, i quali effettuano una qualsiasi
computazione, comunicando eventualmente con il back-end del sistema, ad esempio
per l’accesso a basi di dati. Il risultato di ciascuna elaborazione sarà così integrato
all’interno della pagina HTML prodotta, che sarà inviata nella risposta (response) al
browser.
Da quanto detto, si evince che Model, View e Controller sono praticamente integrati
all’interno di ciascuna pagina JSP e che non c’è una netta separazione fra essi.
I limiti principali di questo modello possono essere i seguenti :
-
viene incoraggiata una struttura a “spaghetti” delle pagine JSP, poiché la
business-logic si “perde” all’interno di ciascuna pagina e la navigazione nella
Web application complessiva viene fatta pagina per pagina;
-
è molto difficile eseguirne il debug, poiché tutti gli errori riportati dal Web
Container, fanno riferimenti al codice compilato della pagina JSP in una
Servlet e quindi sono difficili da individuare all’interno della pagina stessa;
Tutto ciò rappresenta un primo passo verso il modello definitivo del pattern MVC.
4.2 Model 2 (Servlet – Centric Architecture)
Il Model 2 del pattern MVC è detto anche Servlet – Centric, poiché
l’architettura della Web application si basa fortemente sull’utilizzo di una Servlet. Il
sistema complessivo è composto da una Servlet principale che svolge il ruolo di
Controller, da una serie di pagine JSP che rappresentano la View ed infine da un
insieme di JavaBeans che costituiscono il Model. I tre elementi del pattern MVC
sono quindi nettamente separati tra loro, pur mantenendo la possibilità di
comunicare per scambiarsi informazioni. In particolare, le pagine JSP si occupano
esclusivamente della presentazione dei dati all’utente, senza contenere un minimo di
business-logic. La Servlet “master” ha il compito di acquisire tutte le richieste
provenienti dalla rete e funge da “dispatcher”, inoltrando ciascuna di esse verso il
13
Capitolo I – Il Pattern MVC
_________________________________________________________________
corrispondente “handler” per permetterne la gestione. Al termine dell’elaborazione, è
la stessa Servlet che determina a quale pagina JSP restituire il controllo, eseguendo il
“redirecting”. Infine, i JavaBeans incapsulano le funzionalità dell’applicazione,
interagiscono con il back-end del sistema ed eseguono tutte le elaborazioni richieste.
Su tale modello, si basano i framework Struts e JavaServer Faces (JSF).
Figura 8 - MVC Model 2 (Servlet - Centric Architecture)
Il modello prevede uno scenario di interazione di questo tipo :
Il browser invia una richiesta (request) di una risorsa al Web Server, nella maggior
parte dei casi per la visualizzazione di una pagina JSP. Il Web Server, tipicamente
funge da Web Container e quindi da Servlet Container, in quanto è in esecuzione su
di esso, la “master” Servlet della Web application. Quest’ultima funge da Controller
ed acquisisce la richiesta, sulla base della quale individua l’handler che dovrà gestirla.
In particolare, vengono istanziati una serie di JavaBeans, costituenti il Model, che
eseguono le elaborazioni richieste ed eventualmente interagiscono con il back-end del
sistema, accedendo ad una base di dati. Al termine della computazione, il controllo
ritorna alla Servlet che sulla base del risultato, determina la View e quindi la pagina
JSP verso la quale eseguire il redirecting, la quale estrae dai JavaBeans i risultati e li
visualizza all’utente. Infine, la pagina HTML prodotta viene trasmessa al browser
come risposta (response) definitiva.
14
Capitolo I – Il Pattern MVC
_________________________________________________________________
Da quanto detto si evince che Model, View e Controller sono nettamente separati fra
loro e che il Controller funge da tramite per la comunicazione tra i primi due. Da ciò,
scaturisce anche che il debug può essere eseguito in maniera piuttosto semplice su
ciascun JavaBeans, estrapolandolo dal sistema complessivo.
Per quanto riguarda la struttura del Controller, è possibile pensare di utilizzare una
sola Servlet come detto sino ad ora, oppure più Servlets. La scelta dipende dal livello
di granularità della Web application ed è possibile pensare a tre diverse soluzioni :
-
una sola “master” Servlet;
-
una Servlet per ciascun caso d’uso dell’applicazione oppure per ogni
macrofunzionalità offerta;
-
combinazione delle due precedenti soluzioni : una “master” Servlet per
gestire le funzioni comuni a tutti gli ambiti dell’applicazione, che delega alle
Servlets “figlie” la gestione di particolari macrofunzionalità del sistema;
5. Le Servlet
L’elemento tecnologico che ha determinato un notevole miglioramento
nello sviluppo delle Web application e che si pone alla base dei framework MVC, è la
Servlet. Quest’ultima, per definizione, è sostanzialmente una classe Java orientata alla
comunicazione tra client e server. Essa riceve dei messaggi di richiesta da parte del
client e produce, in corrispondenza, dei messaggi di risposta. E’ in esecuzione
all’interno di un Web container secondo un particolare ciclo di vita per definito e può
essere di due tipi :
-
Servlet generica : non è orientata alla comunicazione con uno specifico
protocollo;
-
Servlet HTTP : orientata alla comunicazione Client-Server basata su protocollo
HTTP;
15
Capitolo I – Il Pattern MVC
_________________________________________________________________
Figura 9 - Classi Servlet
Essendo lo studio orientato ai framework MVC, assumono un ruolo fondamentale le
Servlet HTTP, delle quali vanno evidenziate gli elementi costitutivi ed i princìpi di
funzionamento.
5.1 Struttura di base
La parte fondamentale di una Servlet è caratterizzata dai suoi metodi di
servizio, che vengono invocati dal Web container, in cui è in esecuzione la Servlet
stessa, per gestire le richieste HTTP che le pervengono. Sono stati pensati in modo
tale che si abbia la possibilità di poter gestire in modo differenziato le richieste che
sono state inviate con metodi HTTP diversi, quali POST e GET.
Tali metodi di servizio sono sostanzialmente i seguenti :
-
doGet() : contiene le operazioni da eseguire per rispondere ad una richiesta
inviata con metodo GET;
-
doPost() : contiene le operazioni da eseguire per rispondere alle richieste
inviate con metodo POST;
Quando si realizza una propria Servlet, estendendo la classe HTTPServlet, è necessario
eseguire l’overriding di questi due metodi e , nel caso in cui una richiesta debba essere
gestita allo stesso modo indipendentemente che sia di tipo POST oppure GET, è
possibile scrivere il codice in uno dei due metodi e fare in modo che l’altro lo
invochi.
16
Capitolo I – Il Pattern MVC
_________________________________________________________________
Essi prevedono una signature particolare, in quanto i parametri caratteristici sono :
-
request : oggetto HTTPServletRequest che contiene le informazioni della
richiesta da gestire;
-
response : oggetto HTTPServletResponse che conterrà la risposta da inoltrare
verso il client;
5.2 Ciclo di vita
Una volta che la Servlet è stata realizzata dallo sviluppatore, non è
quest’ultimo che si occupa di istanziarla al momento opportuno ma è il Web
container, che ne gestirà il corrispondente ciclo di vita. Il programmatore non
dispone nemmeno di un riferimento alla Servlet ed ai suoi metodi, per cui non può
invocarli. Questi ultimi sono stati pensati per la gestione di particolari eventi che in
questo caso sono delle richieste HTTP. Ciò vuol dire che allo scatenarsi dell’evento
“richiesta HTTP” giunta al Web container ed indirizzata ad una certa Servlet, viene
avviato automaticamente uno dei due metodi doGet() e doPost() per la sua gestione.
Il ciclo di vita di un oggetto Servlet prevede le seguenti fasi :
-
inizializzazione : il contenitore crea un’istanza della Servlet;
-
servizio : l’istanza viene utilizzata per gestire le richieste;
-
distruzione : l’istanza viene deallocata e rimossa dal Web container;
Figura 10 - Ciclo di vita di una Servlet
17
Capitolo I – Il Pattern MVC
_________________________________________________________________
Nella fase di inizializzazione, il Web container invoca il metodo init() della Servlet, il
quale può essere soggetto ad overriding qualora si rendesse necessario effettuare
particolari operazioni di inizializzazione, come ad esempio l’azzeramento di
contatori. A questo punto, è stato creato un processo associato alla Servlet residente
in memoria e quest’ultima è pronta per ricevere e gestire le richieste. Nel momento in
cui giunge una richiesta, il Web container crea un thread associato alla Servlet e su di
esso invoca il metodo service(), il quale a sua volta non fa altro che invocare il metodo
doGet() oppure doPost() passandogli gli oggetti relativi alla request ed alla response.
La caratteristica peculiare delle Servlet è che non viene allocato un nuovo processo
per ogni richiesta ma bensì un thread, per cui c’è un notevole risparmio di risorse
rispetto alla gestione prevista dagli script CGI (Common Gateway Interface). Questi
ultimi prevedono, infatti, l’allocazione di un processo CGI per ciascuna richiesta
pervenuta al CGI Server. Ovviamente, i thread condividono le risorse del processo
associato alla Servlet e quindi si può verificare facilmente un’esecuzione concorrente
dei metodi di quest’ultima.
Figura 11 - Processi CGI
Figura 12 - Threads Servlet
18
Capitolo I – Il Pattern MVC
_________________________________________________________________
Figura 13 - Esempio di threads Servlet
La fase di distruzione viene eseguita quando c’è lo shutdown del Web Container
oppure è richiesta esplicitamente quando avviene il ricaricamento o la rimozione
dell’applicazione. Il contenitore non fa altro che invocare il metodo destroy(), il quale
può essere soggetto ad overriding qualora si rendesse necessario liberare delle risorse
che sono state occupate attraverso il metodo init(). L’esecuzione corretta della
procedura di distruzione non è sempre garantita, ad esempio nel caso in cui si
verifichi un crash dell’applicazione oppure del Web Container.
L’esecuzione delle Servlet in ambiente multithread comporta il notevole vantaggio
dell’ottimizzazione delle risorse, ma porta con se la necessità di fare molta attenzione
da parte dello sviluppatore, dovendo gestire la sincronizzazione e l’esecuzione
concorrente dei thread.
5.3 Richiesta, Risposta, Sessione e Contesto
Nel momento in cui una Servlet viene invocata, le vengono passati gli
oggetti che contengono le informazioni relative alla richiesta pervenuta ed alla
risposta che sarà generata. Tali oggetti sono accessibili all’interno dei metodi della
Servlet, così come gli oggetti che conterranno le informazioni relative alla sessione
utente ed all’applicazione.
19
Capitolo I – Il Pattern MVC
_________________________________________________________________
La classe HTTPServletRequest contiene tutte le informazioni che riguardano la request
che è giunta alla Servlet. Essa ha due funzione principali :
-
contiene una mappa dei parametri forniti attraverso la “query string”;
-
contiene le informazioni tipiche di una richiesta HTTP (es. metodo
GET/POST, URI, headers,…);
La classe HTTPServletResponse è necessaria per generare la risposta da inviare al client,
per cui ha le seguenti funzioni principali :
-
consente di specificare le intestazioni HTTP del messaggio di risposta;
-
consente di produrre il corpo del messaggio di risposta stampandone il
contenuto;
L’ordine delle operazioni da eseguire è fondamentale, in quanto deve rispecchiare la
struttura di una risposta HTTP che prevede in primo luogo le intestazioni (headers) e
successivamente il corpo (body).
La classe HTTPSession rappresenta una sessione di lavoro tra il client ed il server che
viene gestita in maniera trasparente dal contenitore. Quest’ultimo mantiene una
tabella contenente i dati delle sessioni instaurate con i client e consente di manipolarli
utilizzando appunto l’oggetto session. Tale oggetto viene restituito invocando il
metodo getSession() della classe HTTPServletRequest, in quanto le informazioni di
sessione sono strettamente legate alla richiesta. Ogni sessione prevede che il client
accetti i cookie, così come prevede un timeout fissato dal contenitore, allo scadere del
quale la sessione viene automaticamente chiusa. Un’istanza della classe HTTPSession è
notevolmente utile per poter mantenere in memoria una mappa di variabili, associate
ad un unico client, per tutta la durata della sessione. Tali variabili non sono
assolutamente visibili da parte di altri client.
La classe ServletContext rappresenta il “contesto” dell’applicazione Web in cui la
Servlet viene eseguita. Essa risulta utile per garantire la comunicazione tra più Servlet
facenti parte della stessa applicazione oppure per poter mantenere in memoria una
serie di variabili che saranno condivise tra più client.
20
Capitolo I – Il Pattern MVC
_________________________________________________________________
Per quanto riguarda la comunicazione tra più Servlet, capita frequentemente che una
Servlet debba inoltrare una richiesta ad un’altra Servlet. La problematica principale è
che la Servlet chiamante non dispone di un riferimento alla Servlet chiamata e quindi
non ne può invocare i suoi metodi. Le soluzioni possibili sono le seguenti :
-
redirezione della risposta;
-
inoltro all’interno del contenitore;
La prima soluzione corrisponde alla produzione di una risposta di tipo 3xx per
indicare al browser che è necessario richiedere un URI diverso con lo svantaggio di
innescare una nuova richiesta HTTP.
La seconda soluzione prevede che una Servlet richieda al contenitore l’inoltro delle
richiesta, in modo che tutto resti confinato nell’ambito di un’unica transazione
HTTP. Per eseguire questo compito la Servlet può fare uso di un’istanza della classe
RequestDispatcher che è possibile ricavare dal ServletContext.
6. Web Application Frameworks
Il Model 2 può essere considerato la base perfetta sulla quale fondare la
realizzazione delle Web application. Infatti, nello sviluppo di applicazione software
per il Web, molti sviluppatori hanno evidenziato come alcune parti di applicazioni
diverse basate sul Model 2, siano notevolmente simili. Un caso tipico è il Controller
realizzato attraverso una o più Servlet. Tali parti possono essere realizzate in modo
tale da poter essere riutilizzate più volte, concetto che è alla base di un “design
pattern”. Partendo, quindi, da un insieme di elementi precostituiti si ha a disposizione
un “framework”.
Per definizione, un framework è caratterizzato da un insieme di classi e di interfacce
che possono essere usate ed eventualmente estese dagli sviluppatori e che
rappresentano le infrastrutture sulla base della quale realizzare una Web application.
21
Capitolo I – Il Pattern MVC
_________________________________________________________________
Le motivazioni principali che spingono verso l’utilizzo di un framework sono le
seguenti :
-
è possibilie disaccoppiare il Presentation layer e la business-logic in
componenti distinti;
-
si dispone di un punto centrale di controllo;
-
è disponibile un set molto ricco di funzionalità;
-
è facilitato il testing delle singole unità del sistema e la sua manutenzione;
-
c’è il supporto da parte di numerosi ambienti di sviluppo;
-
c’è la garanzia di una buona stabilità;
-
è garantita l’nternazionalizzazione dei contenuti;
-
è semplificata la validazione dei dati di input;
7. Struttura di una Web application in Java
Per definizione, una Web application è una collezione di componenti
separati ma che possono comunicare fra loro, costituendo un software che possa
essere installato ed eseguito in un Web Container anche in maniera concorrente. Ciò
vuol dire che più istanze della stessa applicazione possono essere eseguite nel Web
Container, ma è ovviamente necessario poter distinguere un’istanza dall’altra
mediante URL e nomi differenti.
In generale, un’applicazione di questo tipo è costituita dai seguenti componenti :
-
Servlets;
-
Pagine JSP;
-
JavaBeans;
-
Pagine HTML;
-
File multimediali, quali (immagini, suoni, video, …);
-
Applets, fogli di stile (CSS) e file JavaScript;
Tipicamente, questi elementi sono disposti all’interno dell’applicazione secondo una
struttura gerarchica suddivisa in directory.
22
Capitolo I – Il Pattern MVC
_________________________________________________________________
Partendo dalla radice (root) dell’applicazione, una directory di fondamentale
importanza è la directory WEB-INF, nella quale vengono memorizzate le metainformazioni della Web application ed, in particolare, il deployment descriptor. Le
risorse in essa contenute non sono accessibili dal client, ma solo ed esclusivamente
dalle Servlet e dalle classi Java.
All’interno di questa directory, ci sono le seguenti due directory :
-
WEB-INF/classes : contiene i package e le relative classi Java che sono
utilizzate all’interno dell’applicazione;
-
WEB-INF/lib : contiene i file JAR (Java Archive), all’interno dei quali ci
sono ulteriori classi distribuite nell’applicazione;
Al di là di queste directory che costituiscono la base della Web application, lo
sviluppatore può poi organizzare tutte le risorse di quest’ultima in ulteriori
sottodirectory della root, sulla base delle funzionalità e del loro tipo.
Inoltre, la piattaforma Java permette di distribuire un’applicazione Web mediante la
realizzazione di un file WAR (Web Archive) , nel quale sono incluse tutte le risorse di
quest’ultima. Tale file può essere facilmente distribuito su un qualsiasi Web Container
che si occupa, in maniera automatica, della sua scompattazione restituendo la
struttura originaria delle directory .
7.1 Web Application Deployment Descriptor
Il Web Application Deployment Descriptor è un file XML, tipicamente
chiamato web.xml, all’interno del quale ci sono tutte le informazioni di configurazione
dell’applicazione, che vengono utilizzate dal Web Container in fase di start-up della
stessa.
Nell’ambito dell’utilizzo di un framework, le informazioni principali che
costituiscono tale file sono le seguenti :
-
definizione della Servlet che funge da Controller e mapping delle richieste su
di essa;
23
Capitolo I – Il Pattern MVC
_________________________________________________________________
-
dichiarazione dei parametri iniziali che sono passati alla Servlet in fase di
start-up;
-
configurazione delle librerie di tag (Tag Libraries) da adottare;
-
elenco dei file di benvenuto dell’applicazione (Welcome File List);
-
utilizzo di eventuali filtri per il filtraggio delle richieste prima che vengano
passate alla Servlet Controller;
Per la definizione della Servlet che funge da Controller dell’applicazione, viene
utilizzato il tag <servlet>, mediante il quale vengono specificate le seguenti
informazioni :
-
il nome da assegnare alla Servlet, mediante il quale fare riferimento ad essa
nel resto del file (<servlet-name>);
-
la classe che definisce la Servlet (<servlet-class>);
Il passo successivo è quello di fare in modo che, ciascuna richiesta di un certo tipo,
ad esempio verso risorse con una particolare estensione, vengano smistate dal Web
Container verso la Servlet specificata. Tale operazione è nota come “mapping”, in
quanto viene eseguita una vera e propria mappatura fra le tipologie di richieste e la
Servlet. Per questo scopo, viene utilizzato il tag <servlet-mapping> all’interno del quale
sono specificate le seguenti informazioni :
-
il nome della Servlet a cui inoltrare le richieste (<servlet-name>);
-
elenco delle estensioni che devono avere le richieste per essere inoltrate alla
Servlet suddetta (<url-pattern>);
Considerando l’utilizzo di un framework come Struts e JavaServer Faces, la Servlet
che funge da Controller ha un parametro iniziale che è rappresentato dal file di
configurazione XML dell’applicazione. In questo modo, nella fase di start-up di
quest’ultima, la Servlet del framework esegue l’operazione di parsing e caricamento
del contenuto del file, all’interno della memoria. Per questo scopo, viene adottato il
tag <init-param>, mediante il quale è possibile specificare un qualsiasi tipo di
24
Capitolo I – Il Pattern MVC
_________________________________________________________________
parametro iniziale della Servlet, oltre all’applicazione particolare suddetta. All’interno
del tag, possono essere definite le seguenti informazioni :
-
nome del parametro (<param-name>);
-
valore del parametro (<param-value>);
Generalmente, una Web application prevede l’utilizzo dei normali tag HTML
all’interno delle proprie pagine ma anche eventualmente ulteriori tag appartenenti a
librerie particolari, come quelle che vengono fornite con i framework Struts e
JavaServer Faces. Per poter rendere disponibili tali librerie, esse vanno specificate
all’interno del file web.xml mediante l’utilizzo del tag <taglib>, specificando le seguenti
informazioni :
-
la locazione fisica del file TLD (Tag Library Descriptor) che contiene la
descrizione dei tag della libreria (<taglib-location>);
-
un URI associato alla libreria, per includerla all’interno delle pagine ed evitare
di fare riferimento alla locazione fisica (<taglib-uri>);
Infine, è possibile specificare un elenco di risorse, tipicamente pagine, che il Web
Container invia per una certa richiesta, se quest’ultima non è completa, ossia prevede
soltanto una parte dell’URL. Ciascun file viene definito con il tag <welcome-file>,
all’interno del blocco <welcome-file-list>.
25
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Capitolo II – Il framework JavaSer ver Faces
1 . Introduzione
JavaServer Faces (JSF) è un framework per la realizzazione di Web
application secondo il pattern MVC (Model – View – Controller). In particolare, esso
mette a disposizione una serie di componenti server-side per la realizzazione della UI
(User Interface) dell’applicazione stessa.
L’elemento principale, che caratterizza la tecnologia JSF, è l’ampio insieme delle classi
e delle relative API (Application Program Interface) che permettono di :
-
definire i componenti dell’interfaccia utente (UI) e gestire il mantenimento
del relativo stato;
-
gestire gli eventi che si verificano sui suddetti componenti, eseguirne la
conversione dei valori e la validazione degli stessi;
-
specificare la navigazione fra le pagine all’interno della Web application;
-
supportare l’internazionalizzazione e l’accessibilità;
-
realizzare dei componenti personalizzati (Custom Components) che
estendono e potenziano le funzionalità delle classi base del framework;
Inoltre, JSF mette a disposizione due librerie di tag (Tag Libraries) :
-
libreria HTML : per l’inserimento dei componenti della UI all’interno di una
pagina JSP, secondo il linguaggio HTML;
-
libreria Core : per gestire il legame tra gli elementi dell’interfaccia utente e gli
oggetti di back-end dell’applicazione;
Inoltre, l’architettura complessiva si basa sull’utilizzo delle Servlet, nelle versioni 2.3 e
2.4, così come sulle JavaServer Pages nella versione 1.2.
26
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Figura 1 - Architettura JSF
Attraverso l’utilizzo di JSF, con il minimo sforzo, è possibile ottenere i seguenti
vantaggi :
-
gestire gli eventi che vengono generati dal lato client (client side), con oggetti
e codice lato server (server side);
-
legare i componenti della UI con dati lato server;
-
costruire un’interfaccia utente con componenti riutilizzabili ed estendibili;
-
salvare e recuperare lo stato di ciascun componente della UI, attraverso il
particolare ciclo di vita di una richiesta JSF (Faces request);
Figura 2 - HTTP Request/Response
Un’applicazione realizzata con JSF può essere ricondotta ad una qualsiasi Web
application realizzata con il linguaggio Java. Essa si basa fondamentalmente sulle
pagine JSP e sulle Servlets; basta considerare che l’applicazione stessa è gestita
complessivamente attraverso una Servlet che è in esecuzione in un Servlet Container.
27
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Come si può osservare dalla figura, l’interfaccia utente che viene realizzata con JSF è
in esecuzione sul server e viene visualizzata nella risposta al client.
Figura 3 - Comunicazione Client/Server
Per realizzare ciascuna pagina JSP e quindi la UI, è possibile sfruttare i tag che la
tecnologia JSF mette a disposizione attraverso le sue librerie. Mediante tali tag,
direttamente dall’interfaccia utente, si referenziano tutti gli oggetti che compongono
la Web application, in particolare :
-
gli oggetti che rappresentano i componenti della UI mappati attraverso una
serie di tag, direttamente sulle pagine JSP;
-
gli oggetti event listeners, validators e converters, rispettivamente per la
gestione degli eventi, la validazione e la conversione associati ai componenti
della UI;
-
gli oggetti che incapsulano le funzionalità specifiche dell’applicazione,
tipicamente realizzati attraverso dei JavaBeans;
Inoltre, l’applicazione può fare uso di una serie di classi di “helper”, realizzate dallo
sviluppatore per accedere al back-end del sistema ed eventualmente ad una base di
dati. Infine, viene definito un file di configurazione dell’applicazione nel linguaggio
XML, facilmente gestibile e modificabile, per parametrizzare tutti gli aspetti di
funzionamento principali dell’applicazione stessa e le relative risorse.
Uno dei vantaggi principali che offre la tecnologia JavaServer Faces è la separazione
fra il comportamento (Application processing layer – Model) e la presentazione
28
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
(Presentation layer - View) di una Web application, per favorire il team-working
(lavoro di gruppo) separando i compiti degli sviluppatori software e dei designers.
Un ulteriore vantaggio è caratterizzato dal fatto che la presentazione non prevede
l’utilizzo di una particolare tecnologia o di un particolare linguaggio di markup, anche
se in generale si può preferire far uso delle pagine JSP, considerando le librerie che
JSF mette a disposizione. E’ ovvio che, nel caso in cui si dovesse utilizzare un
particolare dispositivo client per accedere all’applicazione stessa, ad esempio un
cellulare in luogo di un personal computer, si può prevedere un’interfaccia utente
realizzata con una tecnologia ed un linguaggio di markup differenti (WML in luogo
dell’HTML).
Figura 4 - Accesso con dispositivi Client diversi
2. Teamworking
Grazie alla divisione strutturale che comporta JSF in una Web application,
lo sviluppo e la manutenzione di quest’ultima possono procedere rapidamente e nel
modo più semplice possibile.
In moltissimi team di sviluppo il singolo sviluppatore, talvolta, si occupa di numerosi
e differenti compiti che in alcuni casi non sono di sua stretta competenza. Mediante
la tecnologia JavaServer Faces è possibile evitare ciò, assegnando ad ogni
componente del team di sviluppo una sua responsabilità ben precisa.
29
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Tipicamente, i membri assumono i seguenti ruoli :
-
Page author : colui che usa un linguaggio di markup, come l’HTML, ed ha
esperienza di sviluppo grafico per la realizzazione delle pagine. Con l’utilizzo
di JSF, egli usa anche i tag delle librerie standard o delle librerie custom,
realizzate dagli sviluppatori del software;
-
Application developer : sviluppa gli oggetti, i gestori degli eventi (event handlers
o event listeners), i validatori (validators) ed i convertitori (converters) ed in
alcuni casi anche le “helper” class per l’accesso alle basi di dati;
-
Component writer : ha esperienza con la progettazione dell’interfaccia utente
delle applicazioni e preferisce realizzare dei Custom Components per la UI,
estendendo le funzionalità degli Standard Components messi a disposizione
da JSF;
-
Application architect : colui che definisce l’architettura dell’applicazione,
assicurandone la scalabilità, definendo la navigazione fra le pagine,
configurando i JavaBeans e registrando gli oggetti;
-
Tools vendors : le case produttrici che realizzano gli ambienti di sviluppo che
supportano la tecnologia JSF, per poter realizzare l’interfaccia utente in
maniera semplice, attraverso il “Drag & Drop” dei componenti;
Figura 5 - Teamworking
30
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Infine, sviluppare una Web application con JSF, generalmente prevede i seguenti
passi fondamentali :
-
Creare le pagine JSP utilizzando i componenti della UI ed i tags delle librerie
a disposizione;
-
Definire la navigazione fra le pagine dell’applicazione stessa, modificando
opportunamente il file di configurazione dell’applicazione (faces-config.xml);
-
Sviluppare i backing beans che implementano le funzionalità offerte;
-
Aggiungere le informazioni riguardanti i backing beans all’interno del file di
configurazione dell’applicazione;
Questi compiti possono essere eseguiti rigorosamente in ordine oppure in parallelo,
garantendo comunque la possibilità di comunicazione fra le persone del team di
sviluppo. Ad esempio, colui che sviluppa le pagine deve comunque conoscere i nomi
degli oggetti (backing beans) che realizzano le funzionalità della Web application, per
richiamarli
dalle
pagine
stesse,
comunque
disinteressandosi
della
loro
implementazione interna.
3. Modelli architetturali - Framework Models
Il framework JSF è costituito da un insieme di classi che sono raggruppate
in modelli (models), in relazione a specifici aspetti realizzativi di una Web application.
In particolare :
-
Execution Model;
-
User Interface Component Model;
-
Component Rendering Model;
-
Conversion Model;
-
Event and Listener Model;
-
Validation Model;
-
Navigation Model;
31
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Ad essi va aggiunto il Backing Bean Management, il quale permette la realizzazione dei
backing beans (menaged beans) che implementano la business-logic dell’applicazione.
Di seguito, verranno descritti tali modelli mettendo in risalto quelle che sono le
caratteristiche principali delle classi che entrano in gioco per ciascuno di essi ed ,
inoltre, esplicitando la loro interazione che determina il funzionamento del
framework.
3.1 Execution Model
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.
3.1.1 FacesServlet
La classe principale su cui si basa il funzionamento del framework è la
classe FacesServlet. Quest’ultima rappresenta la vera e propria Servlet in esecuzione nel
Web Container, che riceve le richieste da parte dei client occupandosi della loro
gestione ed assumendo quindi il ruolo di Controller secondo il modello MVC.
Come tutte le Servlet, secondo l’implementazione in Java, essa prevede i metodi di
inizializzazione (init()), servizio di una richiesta (service()) e di distruzione (destroy()),
mediante i quali viene avviata dal Web Container all’arrivo della prima richiesta, serve
quest’ultima e tutte le richieste successive e viene infine distrutta, tipicamente nei casi
in cui il Web Container venga interrotto o riavviato.
La FacesServlet va configurata nel Deployment Descriptor web.xml tipico di ogni Web
Application realizzata in Java :
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
32
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Viene specificata la classe e quindi un nome da assegnare alla Servlet, nonché un
ordine di sequenza di start-up, nel caso in cui la Web Application preveda l’utilizzo di
più Servlet per poter gestire richieste di tipo diverso.
Ovviamente la FacesServlet ha il compito di gestire le richieste per file del tipo .jsf
oppure .faces e per questo motivo è necessario specificarne il mapping su di esse :
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
Con questa configurazione, ogni qualvolta giunge una richiesta di una pagina .jsf al
Web Container, quest’ultimo passa tale richiesta alla FacesServlet che si occuperà di
gestirla.
3.1.2 Lifecycle - PhaseListener
Ogni richiesta di tipo JSF (Faces Request), che arriva alla Web application,
ha un proprio ciclo di vita (lifecycle) che prevede l’esecuzione di una serie di fasi, fino
alla determinazione della risposta. Di tali operazioni, si occupa la classe Lifecycle che
riceve ciascuna richiesta dalla FacesServlet ed esegue le varie fasi, mediante il proprio
metodo execute().
Inoltre, ad essa è associata l’interfaccia PhaseListener, la quale permette di notificare
l’inizio e la fine di ciascuna fase. Tale interfaccia rappresenta un punto di estensione
del framework, in quanto è possibile definire alcune elaborazioni specifiche da
eseguire prima o dopo una certa fase. Per fare ciò, è necessario realizzare una classe
che implementi l’interfaccia PhaseListener ed esegua l’overriding dei metodi
beforePhase() ed afterPhase(), all’interno dei quali sarà contenuto il codice da eseguire.
Tale classe va poi associata ad una specifica fase e legata all’istanza di Lifecycle, in
modo che, prima o dopo questa fase, saranno eseguite le elaborazione richieste.
33
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.1.3 Application
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 mediante un parsing
XML, del file di configurazione e tutte le informazioni in esso contenute vengono
caricate all’interno delle proprietà corrispondenti della classe Application. 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 facesconfig.xml sono le seguenti :
-
ActionListener : per la gestione degli action events;
-
NavigationHandler : il cui scopo è quello di gestire 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 : per il salvataggio ed il ripristino dello stato dell’applicazione fra
una richiesta ed un’altra;
-
MessageBundle : che 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 : per la gestione del ciclo di vita di ciascuna richiesta;
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 specificando le proprie classi così ottenute nel
file di configurazione. In questo modo, ad esempio, è possibile realizzare un proprio
NavigationHandler che esegua delle operazioni particolari prima di far proseguire la
navigazione. Lo stesso tipo di operazione può essere eseguita per le altre classi.
34
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Altre informazioni associate alla classe Application e quindi contenute nel file facesconfig.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 : che 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 : che associano i componenti ed i loro valori, ai
metodi o alle proprietà dei backing beans;
3.1.4 FacesContext - ExternalContext
La classe FacesContext definisce il “contesto” dell’applicazione, nel senso che
contiene tutte le informazioni che caratterizzano una richiesta e ciò che riguarda la
relativa risposta da generare. Essa viene potenzialmente modificata in ciascuna fase
del ciclo di vita di una richiesta, per garantire che il contesto sia sempre aggiornato.
E’ ovviamente legata alla classe Application, in quanto è possibile ricavare l’istanza di
quest’ultima direttamente dalla classe FacesContext, 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 di produzione della risposta per una specifica richiesta.
Nella fattispecie tali classi sono :
-
UIViewRoot : rappresenta il nodo radice della view che definisce l’albero dei
componenti 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’applcazione,
il linguaggio di markup ed il Locale corrente;
35
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
ResponseWriter : definisce uno stream attraverso il quale è possibile produrre,
direttamente in una pagina di risposta, degli elementi ed i corrispondenti
attributi come per i linguaggi HTML ed XML;
-
FacesMessage : classe che contiene un singolo messaggio associato ad un
componente specifico e che va visualizzato in una pagina. Il messaggio in
questione può essere tipicamente un messaggio di errore, ad esempio dovuto
ad una validazione o conversione errata, ma anche di un qualsiasi altro tipo;
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 ambito di visibilità (scope) sia quello di
tipo session, request ed application e quindi ai parametri ed agli attributi di una richiesta.
Figura 6 - Class Diagram Execution Model
36
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.2 User Interface Component Model
La tecnologia JSF mette a disposizione una serie di classi relative ai
componenti della UI e le corrispondenti interfacce che ne descrivono il
comportamento (behavioral interfaces) 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 un “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;
-
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;
37
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
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 action–event;
-
ValueHolder : indica che un componente può immagazzinare un 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 value-change;
-
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.
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.
38
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
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.
Figura 7 - Class Diagram UI Component Model / Rendering Model
39
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.3 Component Rendering Model
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, il cosiddetto “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.
3.3.1 Renderer
Questa classe permette di definire un renderer associato ad un
componente. Essa converte la rappresentazione interna di un oggetto UIComponent 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.
40
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
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 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).
h:commandLink
UICommand
h:commandButton
Figura 8 - 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.
41
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.4 Conversion Model
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 :
-
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 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.
Questa operazione è possibile sviluppando una classe che implementi l’interfaccia
Converter e specificando la modalità con cui questa debba realizzare la conversione da
una vista all’altro dei dati. In tal modo, si implementano dei convertitori
personalizzati (Custom Converters).
42
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.4.1 Converter
E’ l’interfaccia che deve essere implementata da una classe per poter
eseguire una conversione Object-to-String (da model view a presentation view) e
quella inversa String-to-Object (da presentation view a model view).
Le implementazioni JSF mettono a disposizione una serie di classi standard che
implementano tale interfaccia per l’esecuzione delle conversioni per i tipi di dato
semplici.
Ad essa è legata anche la classe ConverterException che definisce un’eccezione che può
essere sollevata nel momento in cui, per un qualsiasi motivo, la conversione eseguita
attraverso i metodi del converter non vada a buon fine. In tal caso, verrà creato
automaticamente un oggetto FacesMessage, contenente il messaggio che segnala
l’errore, che verrà memorizzato nel FacesContext e visualizzato all’utente.
Inoltre, essa è caratterizzata fondamentalmente da due soli metodi getAsObject() e
getAsString() che eseguono le conversioni in un verso e nell’altro.
Infine, per poter associare un converter ad un componente dell’interfaccia utente, è
necessario definire un tag mediante la classe ConverterTag.
Figura 9 - Class Diagram Conversion Model
43
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.5 Event and Listener Model
Il modello che definisce gli eventi (events) 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 :
-
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 modalità 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;
-
implementare all’interno del backing bean associato al componente, un
metodo che debba gestire l’evento;
44
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
3.5.1 FacesEvent
E’ la classe base che definisce il generico evento che si può verificare su un
componente dell’interfaccia utente e memorizza tutte le informazioni che riguardano
proprio quest’ultimo.
Da essa derivano due sottoclassi :
-
ActionEvent : che definisce un action event;
-
ValueChangeEvent : che notifica il verificarsi di un value-change event;
Ovviamente, tale classe è legata al generico UIComponent su cui l’evento è stato
intercettato.
3.5.2 FacesListener
E’ l’interfaccia mediante la quale è possibile realizzare una classe che abbia
la capacità di gestire un generico FacesEvent.
Da essa derivano due interfacce :
-
ActionListener : interfaccia capace di gestire un action event;
-
ValueChangeListener : interfaccia per la gestione di un value-change event;
Ovviamente, esse utilizzano rispettivamente le classi ActionEvent e ValueChangeEvent,
per avere informazioni sull’evento che ciascuna di esse deve gestire.
Inoltre, quando lo sviluppatore ha la necessità di realizzare dei propri listeners per
gestire dei particolari eventi, può realizzare delle classi che implementano le
interfacce suddette.
Infine, le interfacce e le classi listeners in questione sono legate alla classe
AbortProcessingException, che rappresenta l’eccezione che può essere sollevata nel
momento in cui si verifichi un errore durante la gestione di un evento.
45
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Figura 10 - Class Diagram Event and Listener Model
3.6 Validation Model
La tecnologia JSF fornisce un particolare meccanismo per la validazione del
local value di un componente “editabile” (es. 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 della
Core Library di JSF, ci sono dei tag che permettono di utilizzare tali validatori in una
pagina JSP, associandoli ai componenti.
46
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
E’ comunque possibile realizzare dei validatori personalizzati (Custom Validators),
nel seguenti modi :
-
realizzare una classe che implementa l’interfaccia Validator, registrarla
all’interno dell’applicazione e definire un tag che permetta di utilizzare il
validatore in una pagina JSP, associandolo ad un componente;
-
implementare all’interno del backing bean associato al componente, di cui
fare la validazione del valore, un metodo che la esegua;
3.6.1 Validator
E’ l’interfaccia che viene implementata da una qualsiasi classe che debba
eseguire delle operazioni di validazione, attraverso l’overriding dell’unico metodo
validate().
Le implementazioni JSF forniscono una serie di classi standard che possono eseguire
delle semplici validazioni, in particolare :
-
LengthValidator : per verificare se il valore di un componente ha una
lunghezza che rientra nei limiti specificati;
-
LongRangevalidator, DoubleRangeValidator : per verificare se il valore di tipo long
o double di un componente, rientra in un range prefissato;
E’ possibile, ovviamente, realizzare un validatore personalizzato (Custom Validator)
implementando questa interfaccia.
Inoltre, il metodo validate() che esegue la vera e propria validazione, può sollevare
un’eccezione del tipo ValidatorException nel momento in cui si è verificato un
problema nel processo di validazione.
Infine, è ovvio che 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.
47
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Figura 11 - Class Diagram Validation Model
3.7 Navigation Model
Tipicamente, una Web application è costituita da un insieme di pagine. Una
delle prime operazioni da eseguire nell’ambito dello sviluppo, è quella di definire la
navigazione fra di esse.
Nell’ambito della tecnologia JSF, la navigazione (navigation) tra le pagine è definita
da una serie di regole (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
di configurazione dell’applicazione, mediante una serie di elementi XML.
Per definire la navigazione bisogna :
-
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;
48
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
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 actionmethod, implementato all’interno di un backing bean. Tale metodo esegue
eventualmente un’elaborazione e determina 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.
3.8 Backing Bean Management
Una funzione particolarmente critica di una Web application è la gestione
delle risorse disponibili. Ciò prevede una separazione degli oggetti che definiscono i
componenti della UI e gli oggetti che implementano le funzionalità disponibili.
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.
49
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
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 “valuechange”. 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 :
<h:inputText id="idCampoTesto"
value="#{backingBean.proprieta}"
validator="#{backingBean.metodoValidazione}"
valueChangeListener="#{backingBean.metodoEvento}"/>
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.
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.
<h:commandButton id="idBottone" action="#{backingBean.metodo}"/>
Eseguire binding fra l’istanza di un componente e la proprietà di un bean, ha i
seguenti vantaggi :
-
il bean può modificare gli attributi del componente durante l’esecuzione;
-
il bean può istanziare un componente;
Invece, eseguire il binding fra il valore del componente e la proprietà del bean, ha i
seguenti vantaggi :
-
colui che ha realizzato la pagina ha più controllo sugli attributi dei
componente;
50
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
i backing beans non sono legati alle classi dei componenti e quindi si ha una
netta separazione fra Model e View;
-
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 sono configurati nel file faces-config.xml che viene valutato all’avvio
dell’applicazione, rendendo disponibili tali beans che vengono poi istanziati quando
sono referenziati all’interno dei tag.
<managed-bean>
<managed-bean-name>backingBean</managed-bean-name>
<managed-bean-class>
package.ClasseBackingBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Gli ambiti di visibilità (scope) in cui sono accessibili i backing beans, sono :
-
request : un bean è accessibile soltanto in corrispondenza di una richiesta
HTTP;
-
session : un bean è visibile durante un’intera sessione utente;
-
application : un bean è condiviso ed accessibile fra tutti gli utenti che accedono
all’applicazione;
Figura 12 - Dichiarazione Backing Beans
51
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Quando un backing bean viene referenziato all’interno di una pagina JSP, esso viene
cercato dall’implementazione JSF in tutti i possibili ambiti di visibilità.
La presenza dei backing beans introduce in JSF, l’uso dei pattern Inversion of Control
(IoC), noto anche come Dependency Injection. Tale pattern prevede che, nell’ambito
della realizzazione di un software, ci sia sempre una classe nota come “container” che
ha il compito di istanziare gli oggetti della business-logic e gestirne la dipendenza e lo
scambio di dati fra essi. Nel framework JSF, tutto ciò accade in maniera
assolutamente automatica, in virtù del fatto che i backing beans vengono istanziati
nell’ambito di visibilità corretto, nel momento in cui si fa riferimento ad essi
attraverso il value-binding o method-binding. Lo sviluppatore non ha più l’onere di gestire
l’allocazione degli oggetti nel momento in cui ne ha bisogno, perché il tutto viene
gestito dal framework in maniera completamente trasparente.
4. Ciclo di vita di una pagina JavaServer Faces
Il ciclo di vita (life-cycle) di una pagina JSF è molto simile a quello di una
normale pagina JSP. Il client invia una richiesta HTTP per ricevere una certa pagina
ed il server invia tale pagina trasformata in HTML. In realtà, considerando le
potenzialità in più offerte dalla tecnologia JSF, sono previste alcune elaborazione
aggiuntive.
Una pagina JSF è rappresentata da un albero dei componenti che costituiscono
l’interfaccia utente, chiamato view, caratterizzato da una gerarchia ben definito.
Ad esempio, nella figura che segue, la pagina contenente il form di Login avrà :
-
il nodo root dell’albero;
-
il nodo relativo al form, legato al nodo root;
-
all’interno del nodo del form, i nodi associati ai tre seguenti componenti : due
campi di testo ed un bottone;
Ovviamente, questa è soltanto una parte della pagina, che potrebbe contenere
ulteriori componenti.
52
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
:UIViewRoot
loginForm
:UIForm
userName
password
:UIInput
:UIInput
loginButton
:UICommand
Figura 13 - Esempio struttura della view
Quando il client richiede la pagina, inizia il life-cycle e l’implementazione JSF
costruisce la view, tenendo conto dello stato degli oggetti relativo ad una richiesta
precedente della pagina stessa (viene ricostruito l’ultimo stato della pagina). Il client
interagisce con la pagina ed invia i dati; l’implementazione JSF esegue la validazione
di questi ultimi e la conversione dei valori in tipi validi dal lato del server. Infine,
vengono eseguite le funzionalità della Web application e proposti i risultati al client,
nella forma della pagina HTML risultante.
4.1 Scenari di elaborazione di una richiesta
Un’applicazione JSF supporta due tipi di richieste (request) e due tipi di (response) :
-
Faces response : risposta generata durante la fase di Render Response del ciclo di
vita di una request;
53
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
Non-Faces response : risposta che non è creata durante la fase di Render Response
del ciclo di vita di una request; caso tipico è quello di una pagina JSP che non
contiene componenti JSF;
-
Faces request : una richiesta che viene inviata da una Faces response generata in
precedenza;
-
Non-Faces request : richiesta inviata ad un elemento come una Servlet o una
pagina JSP e non direttamente ad un componente dell’albero dei componenti
JSF di una pagina;
La differenziazione delle richieste e delle risposte suddetta, da luogo a tre possibili
scenari del ciclo di vita di una richiesta :
Scenario 1 : Non-Faces request genera una Faces response
Un esempio tipico si verifica nel momento in cui si clicca su semplice link
HTML per aprire una pagina JSF. In questo caso, entra in gioco il Controller della
tecnologia JSF, ossia una Servlet della classe FacesServlet che accetta la richiesta e la
passa alla classe che implementa il ciclo di vita della stessa per elaborarla. Quando
deve essere generata la Faces response, l’applicazione acquisisce i riferimenti agli oggetti
necessari alla view, memorizza quest’ultima nel FacesContext (contesto contenente tutte
le informazioni della richiesta) ed invoca il metodo renderResponse(), passando alla fase
Render Response.
Scenario 2 : Faces request genera una Non-Faces response
Talvolta, un’applicazione JSF può avere la necessità di generare una
response che non contiene componenti della tecnologia JavaServer Faces. In queste
situazioni, lo sviluppatore deve saltare la fase di Render Response invocando il metodo
responseComplete() della classe FacesContext. Tale chiamata può avvenire in una delle
seguenti fasi : Apply Request Value, Process Validations, Update Model Values.
54
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Scenario 3 : Faces request genera una Faces response
Questo è lo scenario tipico, che segue il ciclo di vita standard di una
richiesta, in cui un componente JSF invia una request ad un’applicazione JSF
utilizzando la FacesSarvlet. Tutti i listeners, validators e converters sono invocati nella
fase opportuna del ciclo di vita stesso.
4.2 Ciclo di vita Standard
Il ciclo di vita standard di una richiesta è quello dello terzo scenario, che è
stato introdotto in precedenza. La tecnologia JSF permette di gestire due tipologie di
richieste : richiesta iniziale (initial request) e postback. L’initial request è caratterizzata dal
fatto che il client richiede per la prima volta una certa pagina, mentre un postback
scaturisce dall’invio di un form che è stato generato da un’initial request precedente.
Quando deve essere gestita un’initial request, vengono eseguite solo le fasi di Restore
View e Render Response, perché non ci sono azioni da processare, mentre nel caso di
un postback vengono eseguite nell’ordine tutte le fasi.
Figura 14 - Ciclo di vita Standard
55
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
4.2.1 Restore View
Una richiesta per una pagina JSF viene generata nel momento in cui si
clicca su di un link oppure su di un bottone inviando le informazioni di un form; in
entrambe le situazioni viene avviata la prima fase del life-cycle, la Restore View.
Durante questa fase, viene costruita la view della pagina (albero degli oggetti associati
ai componenti della UI), vengono associati gli events handlers (listener), i validators
ed i converters ai componenti ed infine la view viene memorizzata nel FacesContext,
che avrà tutte le informazioni per gestire la richiesta.
Se si tratta di una initial request viene creata una view vuota e si passa direttamente alla
fase di Render Response. Tale view vuota sarà popolata quando, ad esempio, l’utente
immetterà dei dati in un form e verrà comandato un postback.
Se si tratta di un postback, la view precedente relativa alla pagina già esiste e viene
recuperata, utilizzando le informazioni di stato dei componenti della UI che sono
salvate sul client oppure sul server (per default).
4.2.2 Apply Request Values
Dopo aver recuperato l’albero dei componenti (view), ogni componente
estrae il suo nuovo valore dai parametri della richiesta, usando il metodo decode(). Tale
valore, noto come submittedValue, viene memorizzato localmente al componente
stesso. Se la conversione del valore fallisce, viene memorizzato nel FacesContext un
messaggio di errore che sarà visualizzato nella fase di Render Response, insieme ad
eventuali altri errori di validazione successivi.
Se un metodo decode() oppure un event listener invoca il metodo renderResponse() del
FacesContext, si salta direttamente alla fase di Render Response.
Se degli eventi vengono accodati in questa fase, ne verrà eseguito il broadcast
(smistamento) verso i corrispondenti listeners, ma la loro gestione avverrà nelle fasi
successive.
Se, invece, alcuni componenti della pagina hanno l’attributo immediate settato a true,
allora la validazione, conversione e gestione degli eventi associati vengono processati
subito e non posticipati alle fasi successive.
56
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
A questo punto, se bisogna redirezionare il flusso dell’applicazione verso una risorsa
che non ha componenti JSF, viene invocato il metodo responseComplete() del
FacesContext.
Al termine di questa fase, i componenti sono settati ai loro nuovi valori
(submittedValues) ed i messaggi eventuali di errore e gli eventi sono messi in coda,
pronti per essere processati nelle fasi successive.
4.2.3 Process Validation
Durante questa fase, vengono eseguiti tutti i validators registrati sui
componenti della view. In primo luogo, vengono valutati gli attributi fissati che
specificano le regole di validazione e viene confrontato il valore memorizzato in
ciascun componente (local-value) con le regole stesse.
Se il valore locale di un componente non è valido, viene memorizzato un messaggio
di errore nel FacesContext e si passa alla fase di Render Response, per visualizzare tutti i
messaggi di questo tipo, insieme ad altri eventuali messaggi dovuti ad errori di
conversione nella fase precedente.
Se un metodo validate() oppure un event-listener invoca il metodo renderResponse() del
FacesContext, si passa direttamente alla fase di Render Response.
A questo punto, se bisogna redirezionare il flusso dell’applicazione verso una risorsa
che non ha componenti JSF, viene invocato il metodo responseComplete() del
FacesContext.
Se degli eventi vengono accodati in questa fase, ne verrà eseguito il broadcast
(smistamento) verso i corrispondenti listeners, ma la loro gestione avverrà nelle fasi
successive.
4.2.4 Update Model Values
Una volta che i valori locali dei componenti sono considerati validi, è
possibile percorrere l’albero dei componenti stessi ed assegnare alle proprietà dei
backing beans, tali valori. Ciò vuol dire rendere i submittedValue, valori effettivi del
modello (model-value). Ovviamente i local-values devono essere convertiti
57
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
correttamente nei tipi di dati accettati dalle proprietà dei backing beans. Se si
verificano degli errori, si passa direttamente alla fase di Render Response per
visualizzarli, in maniera molto simile agli errori di validazione nelle fasi precedenti.
Se un metodo updateModels() oppure un event listener chiama il metodo
renderResponse() del FacesContext, si salta direttamente alla fase di Render Response.
A questo punto, se bisogna redirezionare il flusso dell’applicazione verso una risorsa
che non ha componenti JSF, viene invocato il metodo responseComplete() del
FacesContext.
Se degli eventi vengono accodati in questa fase, ne verrà eseguito il broadcast
(smistamento) verso i corrispondenti listeners, ma la loro gestione avverrà nelle fasi
successive.
4.2.5 Invoke Application
In questa fase viene gestito ogni evento sia di tipo action che di tipo valuechange, come nei casi di invio di un form di click su di un link.
Se bisogna redirezionare il flusso dell’applicazione verso una risorsa che non ha
componenti JSF, viene invocato il metodo responseComplete() del FacesContext.
Se la view è stata recuperata da una richiesta precedente ed su di un componente viene
sollevato un evento, questo viene smistato verso il suo listener.
4.2.6 Render Response
Durante questa fase, l’implementazione JSF delega il compito della
visualizzazione (rendering) della risposta al JSP container, ovviamente nel caso in cui
si utilizzino delle pagine JSP.
Se si tratta di una initial request, i componenti della pagina vengono aggiunti alla view,
mentre nel caso di un postback già sono presenti. In entrambi i casi, i componenti
eseguono il proprio rendering sulla base dei tag che li rappresentano nella pagina JSP.
Nel caso di un postback, se nelle fasi precedenti si è verificato qualche errore, viene
visualizzata comunque la pagina e se ci sono in essa dei tag <h:message> oppure
<h:messages>, vengono visualizzati i messaggi di errore.
58
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Una volta visualizzata la pagina, viene salvato lo stato della response, ossia lo stato
dei componenti,
sul client oppure sul server, in modo che per un’eventuale
successiva request potrà essere eseguita la fase di Restore View.
5. JSF Expression Language
Il framework JSF dispone di una particolare versione dell’Expression
Language (EL), rispetto a quello disponibile nella librerie di tag JSTL (JavaServer
Pages Standard Tag Library) ampiamente utilizzate con Struts.
Tale linguaggio permette di definire delle espressioni, mediante le quali può essere
realizzato il value-binding ed il method-bindig tra i componenti dell’interfaccia utente
e le proprietà oppure i metodi dei backing beans. Infatti, è attraverso l’EL che è
possibile associare la proprietà di un componente con la proprietà di un bean, così
come un evento oppure un azione su un componente con il metodo di un bean.
Nell’espressione viene specificato il nome del bean e la proprietà oppure il metodo a
cui fare riferimento, mediante la tipica “dot notation”.
#{backingBean.[proprieta | metodo]}
Inoltre, esso fornisce una serie di operatori aritmetici e logici per definire espressioni
molto più complesse, magari utilizzando come operandi le proprietà dei backing
beans a cui si fa riferimento.
Sono altresì disponibili i seguenti oggetti impliciti (implicit object) ai quali si può fare
riferimento da una qualsiasi pagina JSP :
-
applicationScope : oggetto Map con varibiabili e beans che si trovano
nell’ambito di visibilità di tipo application;
-
requestScope : oggetto Map con varibiabili e beans che si trovano nell’ambito di
visibilità di tipo request;
-
sessionScope : oggetto Map con varibiabili e beans che si trovano nell’ambito di
visibilità di tipo session;
-
cookie : oggetto Map contenente i cookie associati alla richiesta;
-
facesContext : istanza della classe FacesContext;
59
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
header : oggetto Map contenente gli header HTTP della richiesta corrente;
-
param : oggetto Map che ha al suo interno i parametri della richiesta;
-
view : oggetto che rappresenta il nodo root della view;
6. Espandibilità del framework
La tecnologia JavaServer Faces offre allo sviluppatore la possibilità di
estendere completamente le classi del framework. Nella maggior parte dei casi, per
quanto riguarda l’Execution Model, vengono utilizzate sempre le classi di default a
meno di particolari esigenze. La potenzialità di personalizzare il framework viene
sfruttata soprattutto per quanto riguarda la realizzazione di :
-
Custom Converter;
-
Event Listeners;
-
Custom Validator;
-
Custom UI Components;
6.1 Custom Converter
L’implementazione JSF esegue automaticamente
tutte le conversioni
necessarie dei valori dei componenti della UI nelle corrispondenti proprietà dei
backing beans.
In alcuni casi particolari, può esserci l’esigenza di realizzare un convertitore
personalizzato che sia capace di eseguire una conversione che non rientri tra quelle
standard di JSF. Per fare questo, è necessario realizzare una classe che implementa
l’interfaccia Converter.
Tale classe dovrà inoltre eseguire l’overriding dei due metodi seguenti :
-
getAsObject() : riceve il valore del componente e lo converte nel tipo di dato
della proprietà corrispondente del backing bean associato;
-
getAsString() : riceve il valore della proprietà del backing bean e lo converte in
stringa per la visualizzazione nella UI;
60
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
public Object getAsObject(FacesContext context,
UIComponent component,
String value) {
...
}
public String getAsString(FacesContext context,
UIComponent component,
Object value) {
...
}
Durante la fase di Apply Request Values, quando l’utente ha immesso dei valori nei
componenti (es. riempiendo un campo di testo), viene invocato il metodo decode() del
componente oppure del renderer corrispondente, che si occupa di acquisire tale
valore. Ovviamente, è in questo metodo che viene invocato getAsObject().
Viceversa, durante la fase di Render Response, quando bisogna visualizzare
nell’interfaccia utente il valore di un componente, vengono invocati i metodi di
encoding del componente stesso oppure del renderer associato, che a loro volta
invocano getAsString().
Infine, per rendere disponibile il converter nell’applicazione, bisogna registrarlo nel
file faces-config.xml. Inoltre, affinché lo si possa associare ad un componente, è
necessario usare l’attributo converter del componente stesso oppure il tag <f:converter>
della Core Library di JSF.
<f:converter converterId="idConverter"/>
6.2 Event Listener
Come visto in precedenza, l’implementazione JSF permette di gestire due
tipologie di eventi che si possono verificare sui componenti della UI :
-
action event;
-
value-change event;
61
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Tale gestione, può essere eseguita in due modi diversi :
-
realizzare una classe listener che implementi l’interfaccia ActionListener oppure
ValueChangeListener;
-
realizzare, all’interno di un certo backing bean, un metodo che sia capace di
gestire l’evento;
6.2.1 Implementazione di un ActionListener/ValueChangeListener
Per poter gestire un action event che può essere sollevato da un
componente, è possibile sviluppare una classe che implementa l’interfaccia
ActionListener. All’interno di essa, sarà eseguito l’overriding del metodo processAction(),
il quale prevede come parametro di ingresso un oggetto di tipo ActionEvent che
contiene tutte le informazioni sull’evento e sul componente che l’ha generato.
Ovviamente, all’interno di questo metodo, sarà necessario scrivere il codice per la
gestione dell’evento, in quanto il metodo sarà immediatamente invocato, nel
momento in cui l’evento sarà intercettato.
public void processAction(ActionEvent event)
throws AbortProcessingException {
...
}
Una volta realizzata la classe, essa sarà associata ad un componente utilizzando il tag
<f:actionListener>.
<f:actionListener type="classeActionListener"/>
Per poter gestire un value-change event per un certo componente, è possibile
realizzare una classe che implementa l’interfaccia ValueChangeListener. Tale classe deve
semplicemente eseguire l’overriding del metodo processValueChange(), il quale ha un
parametro di ingresso di tipo ValueChangeEvent che contiene le informazioni
sull’evento che si è verificato. Tale metodo viene invocato nel momento in cui
l’evento si verifica e quindi conterrà il codice per la sua gestione.
62
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
...
}
Infine, per poter registrare la classe listener sul componente, si può utilizzare il tag
<f:valueChangeListener> della Core Library di JSF.
<f:valueChangeListener type="classeValueChangeListener"/>
6.2.2 Backing Bean Method Listener
Una possibile strada alternativa alla realizzazione delle classi listener, è lo
sviluppo di alcuni metodi all’interno dei backing beans che abbiano la capacità di
gestire gli eventi.
Nel caso in cui bisogna gestire un action event, è possibile realizzare un metodo che
non ha parametri di uscite ed ha come unico parametro di ingresso, un oggetto di
tipo ActionEvent con le informazioni dell’evento intercettato. Tale metodo potrà
essere associato al componente, utilizzando l’attributo actionListener del tag che
rappresenta il componente stesso all’interno di una pagina.
<h:commandLink actionListener="#{backingBean.metodoListener}"/>
Se invece abbiamo a che fare con un value-change event, bisogna realizzare un
metodo che ha come parametro di ingresso, un oggetto del tipo ValueChangeEvent e
che sarà associato al componente, mediante l’attributo valueChangeListener del
medesimo tag.
<h:inputText
valueChangeListener="#{backingBean.metodoListener}"/>
6.3 Custom Validator
Per eseguire la validazione dei dati, JSF mette a disposizione una serie di
validatori standard, ma nel caso in cui questi ultimi non siano sufficienti, è possibile
realizzarne di propri.
63
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Le modalità possibili sono le seguenti :
-
realizzare una classe che implementa l’interfaccia Validator;
-
sviluppare un metodo all’interno di un backing bean, che si occupi della
validazione;
6.3.1 Implementazione di un Validator
Nel caso in cui la scelta sia quella di realizzare una classe che implementa
l’interfaccia Validator, si deve poi poter associare tale validatore ad un qualsiasi
componente che ne possa fare uso. Le possibili soluzioni sono le seguenti :
-
se il validator prevede degli attributi e si vuole dare la possibilità al Page author
di assegnare ad essi dei valori specifici, bisogna realizzare un custom tag
mediante il quale è possibile immettere il validatore all’interno della pagina.
Tale tag avrà quindi degli attributi accessibili al realizzatore della pagina,
secondo una modalità XML-like;
-
in alcuni casi si può preferire non realizzare un tag proprietario del validator.
In queste situazioni, per associare il validatore ad un componente, si deve
utilizzare il tag <f:validator> della Core Library , specificando la classe del
validatore, ed uno o più tag <f:attribute> per specificarne gli attributi;
-
un ultimo caso particolare è quello in cui si realizza un Custom Component e
gli si vuole associare un validatore integrato. Ciò vuol dire che quest’ultimo
verrà associato al componente durante l’esecuzione, mediante il metodo
addValidator(), e non ci sarà la possibilità per il Page author di farlo
manualmente all’interno di una pagina. Questa soluzione “integrata” fornisce
un componente potenziato di un validator integrato, ma non da flessibilità al
realizzatore della pagina di poter utlizzare il validatore al di fuori del
componente;
Durante la validazione, si potrebbe verificare un errore ed in questo caso, sarebbe
utile visualizzare un messaggio all’utente. E’ possibile creare i messaggi durante
l’esecuzione mediante la classe FacesMessage, memorizzandoli nel FacesContext. In
64
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
generale, si preferisce sollevare un’eccezione del tipo ValidatorException, nel metodo
validate() della classe , con il messaggio di errore da visualizzare.
Nel caso più generale possibile, i passi per poter realizzare un validatore sono i
seguenti :
-
realizzare la classe che implementa l’interfaccia Validator;
-
realizzare un Tag Handler;
-
definire un tag associato al validatore, all’interno di un file TLD (Tag Library
Descriptor);
6.3.1.1 Class Validator
La classe che implementa l’interfaccia Validator deve tipicamente avere una
serie di proprietà, che non sono altro che gli attributi del validatore stesso.
Ovviamente, deve essere anche dotata dei metodi di accesso a tali proprietà
(Accessor Method), nella forma getNomeProprieta() setNomeProprieta(). Inoltre,
bisogna eseguire l’overriding del metodo validate() che dovrà contenere il codice per
eseguire la validazione.
public void validate(FacesContext context,
UIComponent toValidate,
Object value)
throws ValidatorException {
...
}
6.3.1.2 Tag Handler
Per poter associare un tag al validatore, è necessario realizzare un Tag
Handler, che altro non è che una classe che estende la classe di base del framework
ValidatorTag. Tale classe deve avere le stesse proprietà della classe validator che
saranno gli attributi del tag.
65
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Le caratteristiche principali della classe sono le seguenti :
-
i metodi di accesso alle proprietà;
-
esegue l’overriding del metodo createValidator(), all’interno del quale viene
creata un’istanza del validatore e ne vengono inizializzate le proprietà sulla
base dei valori che il page author ha assegnato agli attributi del tag;
protected Validator createValidator() throws JspException {
...
}
6.3.1.3 Tag Library Descriptor
Per poter associare il validatore ad un componente all’interno di una
pagina, è necessario realizzare un tag che lo rappresenti. Fondamentalmente, il tag
non fa altro che rappresentare il Tag Handler, il quale avrà poi il compito di utilizzare
la classe validator. Per la descrizione dei tag, vengono utilizzati i file TLD (Tag
Library Descriptor) all’interno dei quali, i tag stessi, vengono elencati con i relativi
attributi, sfruttando una sintassi XML-like.
<tag>
<name>nomeValidator</name>
<tag-class>package.ClasseValidatorTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>attributo</name>
<required>true</required>
<type>package.ClasseTipoAttributo</type>
</attribute>
...
</tag>
6.3.2 Backing Bean Method Validator
La validazione del valore di un componente può essere eseguita anche
realizzando, all’interno di un backing bean, un metodo che riceve come parametri di
ingresso : l’oggetto FacesContext dell’applicazione, il componente del cui valore farne
la validazione ed infine il valore stesso. Tale metodo non ha parametri di uscita ed ha
66
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
la possibilità di generare dei messaggi di errore, nel caso in cui la validazione non
andasse a buon fine.
public void metodoValidate(FacesContext context,
UIComponent toValidate,
Object value) {
...
}
Per fare in modo che il metodo venga eseguito, è necessario utilizzare l’attributo
validator del componente il cui valore deve essere soggetto a validazione.
<h:inputText id="idCampoTesto" value="#{backingBean.proprieta}"
validator="#{backingBean.metodoValidate}"/>
6.4 Custom UI Components
La tecnologia JSF mette a disposizione una serie di componenti standard
per la realizzazione dell’interfaccia utente, ma è comunque possibile estendere le
funzionalità di questi ultimi o addirittura creare di nuovi, con delle funzionalità non
ancora esistenti. E’ inoltre possibile, creare uno o più renderer per poter visualizzare
ciascun componente in maniera diversa su client di tipo differente. Ciò vuol dire che
il comportamento del componente viene definito una sola volta, mentre la sua
visualizzazione viene delegata ai renderer che possono essere molteplici. Ciò non
toglie, che un componente può gestire la visualizzazione in maniera autonoma, non
facendo uso dei renderer.
In generale, la classe che realizza un componente, ne definisce lo stato ed il
comportamento, il quale include : convertire i valori del componente attraverso i
convertitori , accodare gli eventi, eseguire la validazione facendo uso dei validatori
ed altre funzionalità.
C’è bisogno di creare un Custom Component, in queste situazioni :
-
aggiungere un nuovo comportamento ad un componente standard, ad
esempio un nuovo tipo di evento;
-
aggregare più componenti per costituirne uno solo con un unico
comportamento;
67
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
se si ha bisogno di un componente supportato da un client HTML ma non
implementato da JSF;
-
realizzare un componente che possa essere utilizzato da un client non
HTML, quando magari il componente stesso esiste per un client HTML;
Non c’è la necessità di realizzare un Custom Component in queste situazioni :
-
se bisogna manipolare i dati di un componente o aggiungervi semplici
funzionalità. In questo caso, basta creare dei metodi nel backing bean,
associato ad esso;
-
bisogna convertire il valore di un componente in un dato non supportato dal
suo renderer. In tale situazione, conviene adottare un convertitore standard o
realizzarne uno personalizzato;
-
se bisogna eseguire la validazione sul valore del componente, conviene
utilizzare un validatore standard o realizzarne uno;
-
se c’è la necessità di registrare degli event listeners su un componente. In tal
caso, si adottano le tecniche per la realizzazione degli event listeners;
Quando si crea un Custom Component, bisogna essere sicuri che la classe sia capace
di eseguire le seguenti operazioni :
-
Deconding : prelevare, dai parametri della request, il valore del componente che
è stato immesso dall’utente ed associarlo al local value;
-
Encoding : eseguire il rendering del componente secondo un certo linguaggio
di markup, quale può essere HTML , XML , WML in relazione al tipo di
client;
JSF supporta due modelli di programmazione per il deconding e l’encoding :
-
Direct implementation : la stessa classe del componente implementa il decoding
e l’encoding;
-
Delegated implementation : la classe del componente delega l’implementazione
del decoding e dell’encoding ad un renderer;
68
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Con il secondo modello, si ha il vantaggio di poter definire il componente una sola
volta (stato e comportamento) ma di avere più renderer associati ad esso, che ne
permettano la visualizzazione in forme diverse a secondo del device client (browser
web , cellulare,…).
Nel caso di un Custom Component, si rende necessaria la realizzazione di un tag che
permetta di introdurre il componente in una pagina, operazione opzionale, invece,
nel caso in cui si realizzi un validator e quasi mai utilizzata nel caso di un converter.
In generale, per poter realizzare un Custom Component, si seguono i seguenti passi :
-
sviluppare una classe che rappresenti il componente ed estenda la classe base
del framework UIComponentBase oppure una delle sue derivate;
-
realizzare un Tag Handler;
-
eventualmente, sviluppare uno o più renderer estendendo la classe Renderer;
-
infine, descrivere il tag all’interno di un file TLD;
6.4.1. Class Component
Tutti i componenti standard estendono le classi UIComponentBase oppure
UIComponent. Quando si vuole creare un Custom Component, bisogna estendere una
di queste ultime se lo si vuole realizzare partendo da zero. E’ possibile invece, poter
sfruttare le caratteristiche di un componente standard derivando dalla sua classe. Ad
esempio se bisogna creare un menù editabile, non conviene estendere la classe
UIComponentBase ma la classe UISelectOne, in modo da sfruttarne il suo
comportamento e doverne aggiungere solo le funzionalità necessarie.
Ovviamente, il componente sarà utilizzato all’interno di una pagina ed in generale
sarà associato ad un backing bean, che conterrà in una sua proprietà il valore del
componente (value-binding) e potrebbe avere dei metodi referenziati dal
componente stesso (method-binding).
Il primo passo per la realizzazione della classe del Custom Component è quello di
eseguire l’overriding del metodo getFamily() che restituisce la famiglia di appartenenza
del componente, registrata anche all’interno del file faces-config.xml.
69
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
public final static String COMPONENT_TYPE ="TipoComponente";
public final static String COMPONENT_FAMILY ="FamigliaComponente";
...
...
public String getFamily() {
return COMPONENT_FAMILY;
}
...
<component>
<component-type>TipoComponente</component-type>
<component-class>package.ClasseComponente</component-class>
</component>
Nel caso in cui il componente gestisca in maniera autonoma il rendering, deve
occuparsi sia della fase di decoding che di encoding. Per quanto riguarda la fase di
deconding, basta eseguire l’overriding del metodo decode() che viene invocato nella
fase di Apply Values Change del ciclo di vita di una richiesta. Per quanto concerne
l’encoding, bisogna eseguire l’overriding dei metodi encodeBegin(), encodeChildre() ed
encodeEnd(). C’è da precisare che, nella maggior parte dei casi, basta realizzare soltanto
il primo metodo; i due successivi vengono usati soltanto se il componente ha dei
componenti figli al suo interno.
...
public void decode(FacesContext context) {
...
}
...
...
public void encodeBegin(FacesContext context) throws IOException {
...
ResponseWriter writer = context.getResponseWriter();
writer.startElement("nomeElemento", this);
writer.writeAttribute("nomeAttributo", valore,"nomeAttributo");
...
writer.write(body);
writer.endElement("nomeElemento");
...
}
All’interno di ciascuno di questi metodi, si fa uso di un oggetto ResponseWriter, che
permette di scrivere direttamente su una pagina, mediante uno stream di output, in
un linguaggio XML-like. Si osserva che il metodo startElement() permette di scrivere
sullo stream il tag di apertura, usando una o più volte writeAttribute() è possibile
scrivere gli attributi ed i corrispondenti valori, con il metodo write() si scrive il body
70
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
del tag ed infine, usando endElement() si scrive il tag di chiusura. In una pagina JSP, il
risultato di queste operazioni sarà una cosa del tipo seguente :
<libreria:nomeElemento nomeAttributo="[valore]" />
[body]
</libreria:nomeElemento>
Se il rendering viene delegato ad un renderer, i metodi di decoding e di encoding non
vengono realizzati, ma viene eseguito l’overriding del metodo getRendererType() che
restituisce l’identificativo del renderer adottato.
6.4.2 Tag Handler
La classe Tag Handler associata con un componente, estende la classe base
del framework UIComponentTag e guida la fase Render Response del ciclo di vita di una
richiesta. La prima operazione eseguita è quella di recuperare il tipo di componente
associato al tag mediante il metodo getComponentType().
public String getComponentType() {
return ClasseComponente.COMPONENT_TYPE;
}
Successivamente, mediante il metodo setProperties(), vengono inizializzate le proprietà
del componente con i valori degli attributi del tag che sono stati specificati nella
pagina JSP in cui compare il tag stesso.
protected void setProperties(UIComponent component) {
...
componente.setNomeAttributo(this.nomeAttributo);
...
...
}
Infine, tale classe, mediante il metodo getRendererType(), restituisce il tipo di renderer
adottato, se ne è associato uno al componente, in modo da permettere
all’implementazione JSF di eseguire il deconding e l’encoding di quest’ultimo.
71
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
public String getRendererType() {
return ClasseRenderer.RENDERER_TYPE;
}
Ovviamente, gli attributi di un tag possono avere come valore, non una stringa, ma
un’espressione nel linguaggio EL, per poter eseguire le operazioni di value-binding o
method-bindig e quindi introdurre dei riferimenti alle proprietà di un backing bean
oppure ai suoi metodi.
Per ogni attributo che accetta una espressione EL, all’interno del metodo
setPropterties(), per settare l’attributo, è necessario utilizzare le classi MethodBinding e
ValueBinding. L’oggetto MethodBinding serve per valutare un’espressione relativa ad un
metodo di un backing bean, mentre l’oggetto ValueBinding permette di valutare
un’espressione relativa ad una delle sue proprietà.
E’ raccomandabile che ogni Tag Handler abbia un metodo release() per rilasciare le
risorse allocate, una volta che siano state utilizzate.
6.4.3 Tag Library Descriptor
Per poter utilizzare un componente all’interno di una pagina, è necessario
realizzare un tag che lo rappresenti. Fondamentalmente, il tag non fa altro che
rappresentare il Tag Handler, il quale avrà poi il compito di utilizzare la classe del
componente. Per la descrizione dei tag, vengono utilizzati i file TLD (Tag LIbrary
Descriptor) all’interno dei quali, i tag stessi, vengono elencati con i relativi attributi,
sfruttando una sintassi XML-like.
<tag>
<name>nomeComponente</name>
<tag-class>package.ClasseComponente</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>attributo</name>
<type>package.classeTipoAttributo</type>
</attribute>
...
</tag>
72
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
6.4.4 Classe Renderer
Nel caso in cui il componente non gestisca il decoding e l’encoding in
maniera autonoma, è necessario realizzare un renderer al quale delegare queste
operazioni.
La classe che implementa il renderer estende la classe base Renderer e deve eseguire
l’overriding dei metodi decode(), encodeBegin(), encodeChildren() ed encodeEnd() per portare
a termine il suo compito.
.
public void decode(FacesContext context, UIComponent component) {
...
}
...
...
public void encodeBegin(FacesContext context,
UIComponent component) throws IOException {
...
}
Rispetto alla signature degli stessi metodi all’interno della classe che realizza il
componente, questi ultimi hanno come parametro di ingresso anche l’istanza del
componente da renderizzare.
7. Sicurezza
Per quanto riguarda la sicurezza, un’applicazione realizzata con
JavaServerFaces può utilizzare il protocollo HTTPS per il trasferimento delle pagine
e delle informazioni, in modo da garantire la crittografia dei dati. La gestione della
sicurezza tramite l’SSL (Secure Socket Layer) è completamente indipendente dal
framework ed è praticamente la medesima di una qualsiasi applicazione Web
realizzata in Java. In sostanza, si fa affidamento ai meccanismi del Web Container
sottostante, all’interno del quale va abilitato il supporto per le connessioni basate su
SSL. Una volta effettuata questa operazioni, nell’ambito dell’applicazione è necessario
modificare opportunamente il Deployment Descriptor web.xml, per poter specificare
quali pagine dovranno utilizzare il protocollo HTTPS.
73
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Per questo scopo, si utilizza il tag <security-constraint>, all’interno del quale si
specificano le risorse Web da trasmettere tramite SSL (tag <web-resource-collection>) ed
il tipo di trasporto da utilizzare (tag <transport-guarantee>) che può essere di tre tipi :
-
NONE : utilizza HTTP;
-
INTEGRAL , CONFIDENTIAL : utilizza HTTPS;
<security-constraint>
<display-name>SSL Constraint</display-name>
<web-resource-collection>
<web-resource-name>
Automatic SLL Forwarding
</web-resource-name>
<url-pattern>[pagina.jsp]</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Questo tipo di approccio evidenzia che la sicurezza è strettamente legata
all’architettura sulla quale è in esecuzione l’applicazione e non dal framework con cui
è stata realizzata.
8. Configurazione dell’applicazione
In generale, nell’ambito di una Web application realizzata con JSF, i
compiti principali dell’ Application architect sono tipicamente i seguenti :
-
registrare gli oggetti di back-end in modo che siano accessibili da un qualsiasi
punto dell’applicazione;
-
configurare i backing beans (managed beans) in modo che siano istanziati in
maniera corretta quando le pagine fanno riferimento ad essi;
-
definire la navigazione tra le pagine dell’applicazione;
74
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
-
eseguire il “packaging” dell’applicazione, includendo tutte le pagine, gli
oggetti e gli altri file, in modo che possa essere distribuita in un qualsiasi web
container;
La tecnologia JavaServer Faces mette a disposizione una modalità di configurazione
dell’applicazione che è completamente portabile, mediante un documento XML
tipicamente chiamato faces-config.xml.
In realtà, nel caso di applicazioni di grandi dimensioni, l’applicazione può prevedere
anche più di un file di configurazione, ciascuno dei quali permette di configurare una
parte delle funzionalità dell’applicazione stessa.
E’ da ricordare, inoltre, che l’Application developer può sempre accedere direttamente da
codice al file faces-config.xml, grazie all’utilizzo della classe Application. Infatti, all’avvio
dell’applicazione, un parser XML legge le informazioni del file di configurazione e le
carica nell’unica istanza della classe Application prevista.
8.1 Configurazione dei Backing Beans
Per istanziare i backing beans che vengono utilizzati in un’applicazione JSF
ed assegnarli ad un certo ambito di visibilità (scope), è possibile utilizzare la
corrispondente funzionalità offerta nel file di configurazione XML. In questo modo,
quando una pagina fa riferimento ad un backing bean, l’implementazione JSF lo
inizializza in maniera opportuna in accordo alle informazioni contenute nel file facesconfig.xml.
Attraverso tale funzionalità, si possono ottenere i seguenti vantaggi :
-
registrare i beans in un unico file centralizzato, in modo da essere disponibili
nell’ambito di tutta l’applicazione o comunque essere istanziati solo nel
momento in cui sono necessari;
-
personalizzare le proprietà dei beans, direttamente nel file di configurazione
senza scrivere del codice aggiuntivo in Java;
-
è possibile assegnare dei valori iniziali alle proprietà di un bean, nel momento
in cui viene creato;
75
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
Per registrare un backing bean nel file di configurazione, si utilizza l’elemento XML
<managed-bean>, all’interno del quale si utilizzano ulteriori tag per specificare :
-
il nome da assegnare al bean, per poterlo referenziare all’interno delle pagine
(<managed-bean-name>);
-
la classe che implementa il bean (<managed-bean-class>);
-
l’ambito di visiblità (scope) all’interno dell’applicazione (<managed-beanscope>);
-
le relative proprietà con eventuali valori iniziali (<managed-property>);
Le prime tre informazioni sono strettamente necessarie, mentre l’ultima è facoltativa,
considerando che le proprietà del bean vengono comunque definite nella
corrispondente classe Java. Per quanto riguarda l’ambito di visibilità, esso può essere
del tipo : request, session, application e none (in questo caso il bean viene istanziato ogni
volta che deve essere utilizzato).
<managed-bean>
<managed-bean-name>backingBean</managed-bean-name>
<managed-bean-class>
package.ClasseBackingBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
8.2 Localizzazione, Internazionalizzazione e Messaggi
Una
delle
caratteristiche
offerte
dalla
tecnologia
JSF
è
l’Internazionalizzazione (I18N), che permette di visualizzare il testo della Web
application, in un linguaggio diverso in base alla localizzazione geografica
dell’utilizzatore. Per fare ciò è necessario creare uno o più Resource Bundle, ciascuno
dei quali contiene i messaggi da visualizzare in un certo linguaggio, tra quelli
supportati dall’applicazione. In generale, i Resource Bundles non sono altro che dei
file con estensione “properties”, aventi tutti lo stesso nome più il suffisso relativo al
linguaggio a cui ciascuno di essi fa riferimento.
Per rendere disponibile questa funzionalità all’applicazione, è necessario registrare i
Resource Bundle all’interno del file faces-config.xml mediante l’elemento <message-
76
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
bundle>. Ad esso, vanno poi aggiunti il default Locale e tutti i restanti Locale supportati
dall’applicazione, facendo uso di un solo elemento <default-locale> ed uno o più
<supported-locale>.
<application>
<locale-config>
<default-locale>it</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
<message-bundle>ApplicationResources</message-bundle>
</application>
8.3 Registrare un Custom Validator
Se l’Application developer ha realizzato dei Custom Validators per eseguire
operazioni di validazione, è necessario registrarli all’interno del file di configurazione
mediante l’elemento <validator>, che conterrà ulteriori tag per specificare le seguenti
informazioni :
-
identificativo univoco del validator per referenziarlo all’interno della classe
che realizza il Tag Handler (<validator-id>);
-
la classe che implementa il validator (<validator-class>);
-
gli attributi previsti dal validator, con il relativo nome ed il tipo (<attribute>);
Le prime due informazioni sono necessarie, mentre l’ultima è facoltativa
considerando che gli attributi del validator sono definiti nella classe che lo
implementa e nel suo Tag Handler.
<validator>
<validator-id>idValidator</validator-id>
<validator-class>package.ClasseValidator</validator-class>
</validator>
8.4 Registrare un Custom Converter
Così come nel caso di un validator, anche per la realizzazione di un Custom
Converter, si rende necessaria la registrazione all’interno del file di configurazione,
77
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
mediante l’elemento <converter>. Quest’ultimo, a sua volta, prevede ulteriori elementi
al suo interno, per specificare le seguenti informazioni :
-
identificativo univoco del converter per poterlo referenziare nel tag di un
componente della UI che ne fa uso (<converter-id>);
-
la classe che implementa il converter (<converter-class>);
<converter>
<converter-id>idConverter</converter-id>
<converter-class>package.ClasseConverter</converter-class>
</converter>
8.5 Configurare le Navigation Rules
Come è stato detto nel trattare il Navigation Model, la navigazione
all’interno dell’applicazione è definita da un insieme di regole (navigation-rules) che
permettono di determinare quale sia la pagina successiva, nel momento in cui si clicca
su un bottone oppure su di un link. Tali regole sono configurate all’interno del file
faces-config.xml.
Ogni regola di navigazione specifica in quale direzione muoversi attraverso le pagine,
a partire da una certa pagina. Una volta individuata la regola, sulla base della pagina
attualmente visualizzata, si determina la pagina successiva sulla base di un outcome,
ossia una stringa che viene restituita da un metodo di un backing bean, associato al
componente (bottone o link) su cui si è cliccato.
Ciascuna regola viene definita all’interno del file di configurazione, mediante
l’elemento <navigation-rule>, il quale contiene al suo interno ulteriori tag per
specificare le seguenti informazioni :
-
la pagina dalla quale si parte per la navigazione applicando tale regola (<fromview-id>);
-
le possibili pagine di destinazione, individuate attraverso dei “casi” di
navigazione (<navigation-case>), ciascuno dei quali specifica al suo interno :
l’outcome (<from-outcome>) oppure una action (<from-action>) e la pagina stessa
di destinazione (<to-view-id>);
78
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
<navigation-rule>
<from-view-id>/pagina.jsp</from-view-id>
<navigation-case>
<from-outcome>nomeOutcome</from-outcome>
<to-view-id>/paginaDestinazione.jsp</to-view-id>
</navigation-case>
...
...
</navigation-rule>
8.6 Registrare un Custom Renderer in un Renderer Kit
Un Renderer Kit definisce un insieme di classi Renderer che vengono
utilizzate per poter eseguire la visualizzazione di uno o più componenti della UI, in
maniera diversa in base al dispositivo client con cui si accede alla Web application.
Nel caso in cui l’Application developer crea un Custom Renderer, per la visualizzazione
di un certo componente, è necessario che venga assegnato ad un Renderer Kit,
mediante la registrazione nel file di configurazione.
L’elemento XML adottato è <renderer-kit>, il quale prevede al suo interno uno o più
tag <renderer>, ciascuno dei quali contiene le informazioni seguenti relative ad uno
specifico renderer :
-
la famiglia del componente della UI a cui è associato il renderer (<componentfamily>);
-
il tipo del renderer (<renderer-type>), che viene utilizzato dal Tag Handler
associato al componente, per determinare quale renderer applicare su di esso;
-
la classe che implementa il renderer (<renderer-class>);
-
gli attributi eventuali del renderer (<attribute>) con il proprio nome
(<attribute-name>) e la classe (<attribute-class>);
In generale, non è obbligatorio specificare il Renderer Kit di appartenenza di un
Custom Renderer; in questo caso, esso sarà assegnato a quello di default HTML,
fornito con l’implementazione JSF.
79
Capitolo II – Il framework JavaServer Faces
_________________________________________________________________
<render-kit>
<renderer>
<component-family>FamigliaComponente</component-family>
<renderer-type>TipoRenderer</renderer-type>
<renderer-class>package.ClasseRenderer</renderer-class>
</renderer>
...
...
</render-kit>
8.7 Registrare un Custom Component
Oltre alla registrazione di un Custom Renderer, si rende ovviamente
necessaria anche la registrazione del Custom Component a cui esso è associato,
mediante l’elemento <component>. Per ciascun componente, vengono specificate le
seguenti informazioni :
-
il tipo del componente (<component-type>);
-
la classe che implementa il componente (<component-class>);
-
le proprietà del componente (<property>), per ciascuna delle quali è definito il
nome (<property-name>) e la classe (<property-class>);
Tipicamente, le prime due informazioni sono necessarie, mentre le successive sono
facoltative, in quanto tali proprietà vengono comunque definite all’interno della
classe che implementa il componente.
<component>
<component-type>TipoComponente</component-type>
<component-class>package.ClasseComponente</component-class>
</component>
80
Capitolo III – Il framework Struts
_________________________________________________________________
Capitolo III – Il framework Str uts
1 . Introduzione
Struts è un framework OpenSource per la realizzazione di Web application
secondo il pattern MVC (Model – View – Controller), caratterizzato da una serie di
classi e dalle relative API (Application Program Interface) che permettono di :
-
acquisire i dati dei form riempiti dall’utente durante la navigazione ed eseguire
le elaborazioni su di essi;
-
individuare gli handlers (gestori) , detti anche actions, per esaudire ciascuna
richiesta;
-
definire la navigazione fra le pagine all’interno della Web application;
-
supportare l’internazionalizzazione e l’accessibilità;
Inoltre, include i due seguenti “plug-in” :
-
Tiles : framework per la realizzazione del layout delle pagine con “mattonelle”
(tiles) componibili;
-
Validator : plug-in che fornisce un vasto insieme di validatori, per la
validazione dei dati immessi dall’utente nei form;
Infine, mette a disposizione tre librerie di tag (Tag Libraries) :
-
Struts HTML : per la realizzazione dell’interfaccia utente, con una serie di tag
che permettono di introdurre i componenti della UI all’interno di ciascuna
pagina;
-
Struts Bean : per poter accedere, direttamente da ciascuna pagina, alle
proprietà dei JavaBeans che definiscono il Model dell’applicazione;
-
Struts Logic : per definire dei costrutti di controllo (condizionali e ciclici) che
permettono la costruzione dinamica di una pagina;
81
Capitolo III – Il framework Struts
_________________________________________________________________
Ciò che rende Struts uno degli strumenti maggiormente utilizzati per lo sviluppo di
Web application, è soprattutto il fatto di essere OpenSource. Infatti, milioni di
sviluppatori in tutto il mondo partecipano al miglioramento del framework,
realizzando classi aggiuntive che ne aumentano le potenzialità oppure migliorando
quelle preesistenti. Nel tempo, tutto ciò ha reso Struts un strumento stabile e
fortemente maturo con un curva di apprendimento (learning curve) piuttosto bassa.
Infine, il vantaggio principale che scaturisce dall’utilizzo di Struts, è la netta
separazione tra l’Application processing layer (Model) ed il Presentation layer (View),
favorendo il team-working.
Esso si basa fortemente sugli strumenti che costituiscono principalmente
un’applicazione Web realizzata in Java : le pagine JSP e le Servlet. Infatti, il flusso di
esecuzione all’interno di ciascuna Web application è gestito attraverso una Servlet, in
esecuzione nel Web Container.
Ovviamente, alle numerose classi che costituiscono il framework, è possibile
aggiungere ulteriori classi che definiscono la business-logic, tipicamente realizzate
attraverso dei JavaBeans.
La semplicità di configurazione della Web application da realizzare è garantita dalla
presenza di un file XML (struts-config.xml), nel quale vengono impostati tutti i
parametri e gli elementi costitutivi dell’applicazione stessa.
Infine, dalla versione 1.1, è stata introdotta la possibilità di realizzare un’applicazione
di grandi dimensioni suddividendola in moduli, ciascuno dei quali definisce una parte
delle funzionalità complessive ed ha un proprio file di configurazione autonomo. In
questo modo, si può gestire ciascun modulo separatamente dagli altri ma è
ovviamente garantita la comunicazione fra di essi.
Tutti gli elementi che costituiscono il framework sono raggruppati in otto principali
package :
-
action, actions : contengono le classi che costituiscono il Controller e le classi
che possono essere usate o estese all’interno della propria applicazione;
-
config : contiene le classi che definiscono una rappresentazione “in memoria”,
della configurazione dell’applicazione specificata nel file struts-config.xml;
-
taglib : contiene i Tag Handler, ossia le classi per la gestione delle librerie di
tag di Struts;
82
Capitolo III – Il framework Struts
_________________________________________________________________
-
tiles : include le classi utilizzate dal framework Tiles;
-
upload : contiene le classi per eseguire l’upload di file attraverso un browser
Web;
-
util : include delle classi general-purpose, con delle utility sfruttate dal
framework;
-
validator : contiene le classi specifiche di Struts per lo sviluppo di validatori
personalizzati;
Figura 1 - Packages Architettura Struts
2. Controller, Model and View Components
Basandosi sul pattern MVC (Model – View – Controller), è ovvio che
Struts è caratterizzato da una serie di componenti e di classi, che compongono
ciascuna delle tre parti del pattern stesso :
-
Controller : le classi che gestiscono il flusso di esecuzione dell’applicazione e
garantiscono la comunicazione tra il Model e la View; ad esse si aggiungono
anche una serie di classi di utilità (Utility Classes);
83
Capitolo III – Il framework Struts
_________________________________________________________________
-
Model : le classi che definiscono lo stato dell’applicazione e le funzionalità
della business-logic;
-
View : tipicamente le pagine JSP che utilizzano i tag delle librerie di Struts, per
la realizzazione dell’interfaccia utente (UI);
2.1 Controller Components
Il Controller di Struts si basa sul pattern “Front Controller” della J2EE
(Java2 Enterprise Edition), in modo da poter gestire tutte le richieste in maniera
centralizzata. Oltre ai numerosi vantaggi relativi alle funzionalità dell’applicazione, ne
scaturisce che alcuni servizi come la sicurezza, l’internazionalizzazione ed il logging
sono concentrati nel Controller.
Facendo riferimento al pattern MVC, il Controller di Struts ha i seguenti compiti :
-
ricevere tutte le richieste provenienti dai vari client;
-
per ciascuna richiesta, determinarne il gestore, detto anche action, che avrà il
compito di eseguire le elaborazioni richieste, utilizzando anche i JavaBeans
che costituiscono la business-logic;
-
raccogliere i risultati delle elaborazioni per renderli disponibili al client;
-
determinare la View alla quale passare il controllo per la visualizzazione dei
risultati;
Figura 2 - Pattern MVC
84
Capitolo III – Il framework Struts
_________________________________________________________________
Struts prevede una serie di classi, legate fra loro, per la strutturazione del Controller.
Figura 3 - Class Diagram Controller Components
2.1.1 ActionServlet
La classe ActionServlet rappresenta la Servlet in esecuzione nel Web
Container, alla quale arrivano tutte richieste dei client, dirette all’applicazione stessa.
Quando la classe riceve una request di tipo HTTP (HttpRequest), esegue uno dei
metodi tipici di una Servlet, ossia doGet() oppure doPost(), in base al metodo che è
stato utilizzato per inviare la richiesta. Ciascuno dei due metodi invoca il metodo
process(), il quale si occupa di eseguire le principali operazioni che competono alla
ActionServlet, tra cui individuare il modulo della Web application al quale è destinata la
richiesta, se l’applicazione prevede una suddivisione in più moduli.
Il framework da la possibilità allo sviluppatore di realizzare una classe che estenda
ActionServlet, per poter definire un Controller personalizzato, che va comunque
registrato nel Deployment Descriptor web.xml, per segnalare al Web Container quale
Servlet avviare per gestire l’applicazione.
Struts prevede una particolare fase di inizializzazione, nel momento in cui la prima
richiesta giunge alla Web application. In questa fase, ovviamente, viene istanziata la
ActionServlet ed invocato su di essa il metodo init(), nell’ambito del quale, la Servlet
esegue le seguenti operazioni :
-
inizializza il ResourceBundle interno del framework con i messaggi per la
creazione dei files di log;
85
Capitolo III – Il framework Struts
_________________________________________________________________
-
carica i parametri di configurazione della Servlet dal file web.xml;
-
carica ed inizializza il nome ed il mapping della Servlet;
-
carica
le
informazioni
di
configurazione
del
modulo
principale
dell’applicazione, dal file struts-config.xml, creandone una copia in memoria
nella classe ApplicationConfig, memorizzata nel ServletContext (contesto di
esecuzione della Servlet);
-
carica ogni ResourceBundle assegnato al modulo di default e contenente i
messaggi da visualizzare all’utente;
-
carica le informazioni relative a ciascun data source specificato nel file di
configurazione;
-
inizializza ed avvia i plug-in assegnati al modulo principale;
-
eseguite tutte le operazioni suddette per il modulo di default, esse vengono
ripetute per tutti i moduli componenti l’applicazione;
Figura 4 - Operazioni di inizializzazione della ActionServlet
2.1.2 RequestProcessor
Dalla versione 1.1 del framework, alla classe ActionServlet è stata affiancata la
classe RequestProcessor. Si è resa necessaria tale introduzione, in virtù del fatto che,
86
Capitolo III – Il framework Struts
_________________________________________________________________
proprio da tale versione, è stato introdotto il supporto di realizzazione di
un’applicazione in più moduli separati. In questo caso, a partire dalla classe
ActionServlet, vengono create più istanze della classe RequestProcessor, quanti sono i
moduli dell’applicazione, in modo tale che ciascuno di essi abbia il proprio request
handler, per la gestione delle richieste in ingresso.
Nel momento in cui arriva una richiesta alla ActionServlet, quest’ultima determina il
modulo a cui essa è destinata ed istanzia la relativa classe RequestProcessor, verso la
quale inoltra la richiesta e ne invoca il metodo process(). All’interno di tale metodo,
vengono eseguite le seguenti operazioni :
-
vengono caricate le informazioni per la gestione dei form “multipart”,
qualora la richiesta preveda l’upload di un file;
-
viene determinato il path della richiesta;
-
è individuato il Locale, per gestire l’internazionalizzazione;
-
viene invocato il metodo processPreprocess(), all’interno del quale vengono
eseguite le operazioni preliminari all’invocazione della action che dovrà
gestire la richiesta. Tipicamente, se lo sviluppatore crea un proprio request
handler, estendendo RequestProcessor, inserisce all’interno di questo metodo
tutti i controlli che servono per valutare se la sessione corrente dell’utente è
valida;
-
viene determinato il mapping delle action, per poter individuare quale di
queste dovrà gestire la richiesta;
-
vengono eseguiti i metodi per : individuare il formbean associato alla action
selezionata, caricarlo nello scope specificato nel file di configurazione,
popolarlo con i dati immessi dall’utente e validarlo;
-
viene invocata la action per la gestione della richiesta;
-
terminata l’esecuzione della action, viene eseguito il forward verso la View
per la visualizzazione dei risultati;
87
Capitolo III – Il framework Struts
_________________________________________________________________
Nel caso di realizzazione di un proprio RequestProcessor, la signature del metodo
processPreprocess() soggetto ad overriding è la seguente :
protected boolean processPreprocess(HttpServletRequest request,
HttpServletResponse response)
{
...
}
Si osservi il parametro di ingresso relativo alla request che deve essere gestita, dal
quale poter ricavare eventuali informazioni da controllare prima di una successiva
elaborazione.
2.1.3 Action
La classe Action può essere considerata il “cuore” del framework. Essa
definisce un “bridge” (ponte) tra il Controller ed il Model, in virtù del fatto che riceve
dal primo la richiesta da esaudire ed utilizza le classi del secondo per espletarla.
Per la gestione di una richiesta da parte di una action, viene invocato su di essa il
metodo execute(), all’interno del quale vengono istanziati gli oggetti che compongono
la business-logic ed eseguono l’elaborazione richiesta. Tale metodo restituisce un
oggetto della classe ActionForward, che specifica la direzione verso la quale incanalare
il flusso dell’applicazione. Al termine dell’esecuzione di tale metodo, il controllo
ritorna al Controller che determina, sulla base dell’oggetto ActionForward, a quale
View compete la visualizzazione.
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}
Si osservi che il metodo execute() riceve in ingresso l’oggetto ActionMapping che
contiene il mapping delle action dell’applicazione e serve per individuare i forward,
l’oggetto ActionForm che contiene i dati del form trasmesso dall’utente ed infine, gli
oggetti HttpServletRequest ed HttpServletResponse relativi alla richiesta ed alla risposta.
88
Capitolo III – Il framework Struts
_________________________________________________________________
La classe Action è definita “thread-safe”, nel senso che, nell’ambito di
un’applicazione, viene creata sempre e solo un’unica istanza di ciascuna action. Ciò
vuol dire che tutti i client condividono la medesima istanza di ciascuna di esse e
possono invocare sulla medesima action il metodo execute() contemporaneamente,
proprio perché la gestione avviene con thread separati.
L’elenco delle action istanziate è contenuto all’interno di una HashMap della classe
RequestProcessor. In virtù dell’approccio “thread-safe” con cui vengono gestite le
action, è consigliabile non utilizzare variabili di istanza per ciascuna di esse, che
altrimenti verrebbero condivise da tutti i client.
Inoltre, il framework mette a disposizione delle particolari classi che estendono il
funzionamento della classe Action :
-
ForwardAction;
-
DispatchAction;
-
LookupDispatchAction;
-
SwitchAction:
2.1.3.1 ForwardAction
In moltissime situazioni, c’è la necessità di passare da una pagina JSP
all’altra, senza il bisogno di utilizzare una Action. In generale, invocare direttamente
una pagina JSP è un approccio non consigliato per molteplici motivazioni.
Il Controller ha il compito di selezionare opportunamente il modulo dell’applicazione
a cui è diretta una richiesta per poterne caricare la configurazione ed i messaggi del
ResourceBundle. Se questa fase viene saltata, si corre il rischio che non vengano
visualizzati all’utente i messaggi corretti.
Un’altra motivazione è puramente concettuale, nel senso che, chiamare direttamente
una pagina JSP viola il pattern MVC, poiché non si sfrutta il Controller.
Per risolvere questa problema, è stata introdotta la classe ForwardAction che permette
di eseguire il forward da una pagina all’altra, passando attraverso il Controller.
89
Capitolo III – Il framework Struts
_________________________________________________________________
2.1.3.2 DispatchAction - LookupDispatchAction
In moltissimi casi, un’applicazione Web è caratterizzata da una serie di
funzionalità che sono più o meno logicamente correlate. La soluzione di base sarebbe
quella di definire più action separate, ciascuna delle quali svolga una delle
funzionalità, oppure definire un’unica action ed all’interno del metodo execute() gestire
le diverse funzionalità sulla base dei parametri della request.
La migliore soluzione può essere realizzata utilizzando la classe DispatchAction,
all’interno della quale è possibile avere più metodi, con la stessa signature del metodo
execute(), che implementano le diverse funzionalità.
public class ClasseAction extends DispatchAction {
...
public ActionForward metodo1(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}
public ActionForward metodo2(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}
...
...
}
Per poter distinguere l’invocazione di un metodo da un altro, alla action viene
assegnato un parametro specificato all’interno del file di configurazione mediante
l’attributo parameter. Di volta in volta, tale parametro può assumere un valore diverso,
tipicamente il nome di uno dei metodi della classe DispatchAction, in modo tale da
utilizzare una delle funzionalità implementate.
<action input="pagina.jsp"
name="nomeFormBean" parameter="dispatch"
path="/nomeAction" scope="request"
type="package.ClasseAction">
<forward name="nomeForward1" path="pagina1.jsp"/>
...
<forward name="nomeForwardN" path="paginaN.jsp"/>
</action>
90
Capitolo III – Il framework Struts
_________________________________________________________________
In conclusione, ciascuna request, destinata alla action, dovrà specificare il nome di
quest’ultima, seguito dal parametro con il suo relativo valore, per invocare uno dei
metodi interni alla classe.
<html:form action="/nomeAction.do?dispatch=metodo1">
...
</html:form>
Un ulteriore miglioramento è stato introdotto dalla classe LookupDispatchAction, la
quale prevede il metodo getKeyMethodMap(), che restituisce un oggetto della classe
Map, facendo corrispondere ad un certo messaggio del ResourceBundle, il nome di
uno dei metodi della classe. In questo modo, la request non deve necessariamente
assegnare al parametro suddetto il nome del metodo da invocare, ma anche
eventualmente un messaggio del ResourceBundle.
2.1.3.3 SwitchAction
La classe SwithcAction è stata introdotta dalla versione 1.1 del framework, in
concomitanza con la nuova potenzialità di poter sviluppare le applicazioni di grandi
dimensioni suddividendole in moduli separati. Tale classe, infatti, permette di passare
da un modulo all’altro ed in particolare raggiungere una delle risorse del modulo
scelto. Per fare questo, la action va invocata con due parametri :
-
prefix : definisce il nome del modulo verso cui spostare il controllo;
-
page: l’URI della risorsa a cui accedere, all’interno del modulo scelto;
/switch.do?page=[pagina.jsp]&prefix=[prefissoModulo]
2.1.4 ActionForward
Come visto in precedenza, il metodo execute() della classe Action, che
gestisce una certa richiesta, fornisce come parametro di uscita un oggetto della classe
91
Capitolo III – Il framework Struts
_________________________________________________________________
ActionForward. Tale classe rappresenta un’astrazione logica di una risorsa Web, che
può essere una pagina JSP, una Servlet oppure eventualmente un’altra action.
Essa è “costruita” (wrapper) intorno a ciascuna risorsa, in modo da disaccoppiare
l’applicazione dalla locazione fisica delle stessa, che viene specificata nel file di
configurazione. L’oggetto della classe ActionForward viene restituito dal metodo
execute() della action, utilizzando il metodo findForward() della classe ActionMapping.
Passando a tale metodo il nome con cui l’ActionForward è mappato nel file strutsconfig.xml, viene determinata la risorsa verso la quale inoltrare il flusso
dell’applicazione. Un oggetto ActionForward può essere creato anche direttamente
all’interno del codice, mediante il suo costruttore, specificando l’URL verso il quale
eseguire il forwarding.
2.2 Utility Classes
Nell’ambito della realizzazione di una Web application, ci sono molto
spesso una serie di operazioni che vanno ripetute più volte. Tale situazione si verifica
anche con il framework Struts, il quale raggruppa tutte queste funzionalità in
opportune classi di utilità, in modo da poter essere condivise fra più componenti ed
utilizzate da più applicazioni.
Tali classi sono raggruppate in package separati e le principali sono le seguenti :
-
classe RequestUtils : mette a disposizione una serie di metodi per gestire
ciascuna richiesta pervenuta alla Web application;
-
classe ResponseUtils : ha un ruolo simile alla classe precedente, con la
differenza che è orientata alla gestione delle response;
-
commons-package BeanUtils : per la gestione dei JavaBeans definiti all’interno
dell’applicazione, in particolare per popolare i formbean con i dati immessi
dall’utente ed accedere alle relative proprietà;
92
Capitolo III – Il framework Struts
_________________________________________________________________
2.3 Model Components
Nell’ambito del pattern MVC, il Model è caratterizzato da tutte le classi che
costituiscono
la
business-logic
ed
implementano
le
funzionalità
offerte
dall’applicazione.
Tali componenti devono essere completamente indipendenti dal tipo di framework
che viene adottato, in virtù del fatto che in una architettura a livelli, i livelli superiori
devono essere legati a quelli inferiori, ma non vale il viceversa.
Nel momento in cui, all’interno delle classi della business-logic, utilizziamo elementi
del framework, si viola tale modello e si determina un accoppiamento tra due livelli
che devono essere indipendenti.
Figura 5 - Dipendenza dei livelli
All’interno del Model, si definiscono i cosiddetti business-object (BO), i quali non
rappresentano nient’altro che delle astrazioni software delle entità del mondo reale.
Affinché una classe possa essere considerata un business-object, è necessario che
abbia le seguenti caratteristiche :
-
mantenga uno stato e definisca un comportamento;
-
rappresenti una entità del dominio del problema;
-
sia riutilizzabile;
Strutturando il Model in questo modo, esso diventa assolutamente indipendente dal
framework che verrà adottato per realizzare la Web application. In alcuni casi, si
potrebbe pensare di utilizzarlo anche per lo sviluppo di un’applicazione desktop e
non orientata al Web.
93
Capitolo III – Il framework Struts
_________________________________________________________________
In relazione al framework Struts, quest’ultimo non vincola lo sviluppatore nel dover
realizzare il Model con una particolare tecnologia. I principali strumenti adottati per
la realizzazione dei business-object, sono tipicamente gli Enterprise JavaBeans (EJB)
oppure i più semplici JavaBeans (JB), fortemente affermati nella programmazione
Java.
Mediante questi strumenti, è possibili sviluppare le classi del Model definendone sia i
dati (lo stato dell’applicazione) che i metodi (il comportamento). Infine, per garantire
la persistenza delle informazioni, è necessario fare in modo che tali oggetti siano
associati ad una base di dati. La mappatura tra i due elementi, può essere realizzata in
due modi principali :
-
JDBC : si realizzano ulteriori classi che sfruttano le funzionalità dei driver
JDBC (Java DataBase Connectivity) per accedere alle basi di dati. In questo
modo, ciascun oggetto della business-logic utilizza l’oggetto corrispondente
JDBC per garantirsi la propria persistenza;
-
ORM Frameworks : si utilizzano dei particolari frameworks, detti ORM –
Object to Relational Mapping, i quali eseguono la mappatura in maniera
automatica. Tra i più importanti è da ricordare Hibernate.
2.4 View Components
In generale, la View rappresenta la visualizzazione del Model
dell’applicazione, secondo una certa interfaccia utente. Ciò vuol dire che possono
esistere più View differenti a dispetto di un unico Model.
Tipicamente, nell’ambito di Struts, le differenti Views vengono realizzate attraverso le
pagine JSP, sfruttando le diverse librerie di tag che il framework mette a disposizione.
Un ruolo fondamentale, nell’interazione con l’utente, è giocato dalla classe
ActionForm, che permette di definire i formbean mediante i quali vengono raccolti i
dati che l’utente immette attraverso i form dell’applicazione.
94
Capitolo III – Il framework Struts
_________________________________________________________________
2.4.1 ActionForm
Generalmente, ogni Web application prevede l’interazione con l’utente e
quindi l’immissione, da parte di quest’ultimo attraverso dei form costituiti da uno o
più campi, di dati su cui verranno eseguite le elaborazioni. Una volta che i dati
vengono trasmessi, l’applicazione deve farsi carico di acquisirli, validarli ed in caso di
errore visualizzare un messaggio all’utente ed infine, di elaborarli.
Per poter eseguire tutte queste operazioni nel modo più semplice possibile, Struts
mette a disposizione la classe ActionForm, la quale ha come compito principale quello
di raccogliere i dati dai form riempiti dall’utente e metterli a disposizione di una
action, per eseguirne l’elaborazione. Ulteriore funzionalità fornita da questa classe è la
validazione mediante la quale è possibile controllare che i dati immessi dall’utente
siano corretti ed, in caso di esito negativo, segnalare gli errori a quest’ultimo. In
generale, non bisogna dichiarare un formbean per ogni form HTML previsto
dall’applicazione, perché lo stesso formbean può essere condiviso ed associato a più
action. Ovviamente, è necessario definirne anche l’ambito di visibilità , che può
essere di due tipi :
-
request : i dati del formbean sono memorizzati fino al completamento del ciclo
request-response, dopodichè viene cancellato;
-
session : i dati del formbean sono disponibili durante tutta la sessione utente;
Ciascun formbean prevede un particolare ciclo di vita, nell’ambito del quale si
possono distinguere le seguenti fasi :
-
la richiesta arriva al Controller con i dati di un certo form;
-
viene creato un nuovo formbean oppure riciclato quello esistente;
-
viene invocato il metodo reset() che annulla un eventuale contenuto
precedente del formbean;
-
il formbean viene memorizzato nell’ambito di visibilità (scope), specificato
nel file di configurazione;
-
i dati della richiesta vengono trasferiti nel formbean, che viene così popolato;
95
Capitolo III – Il framework Struts
_________________________________________________________________
-
viene eseguita la validazione dei dati, solo se espressamente specificata nel file
di configurazione;
-
se ci sono errori, il controllo ritorna alla pagina di input dei dati altrimenti
viene invocato il metodo execute() della action, a cui il formbean è associato,
per elaborare i dati;
Figura 6 - Ciclo di vita della ActionForm
La classe ActionForm è , però, una classe astratta, per cui è necessario implementare
una propria classe che la estenda per poter definire un formbean necessario
all’interno dell’applicazione. Tale classe avrà al suo interno una serie di proprietà che
corrispondono ai campi del form ed i relativi metodi getter e setter, per accedere ad
esse. Inoltre, è necessario eseguire l’overriding dei due seguenti metodi :
-
reset() : per poter resettare il contenuto del formbean;
-
validate() : per poter eseguire la validazione dei dati contenuti nel form e
restituire un oggetto ActionErrors con eventuali messaggi di errore, se la
validazione non ha avuto esito positivo;
96
Capitolo III – Il framework Struts
_________________________________________________________________
public void reset(ActionMapping mapping,
HttpServletRequest request) {
...
}
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
...
}
Ogni formbean realizzato va, inoltre, dichiarato all’interno del file di configurazine
XML ed assegnata, sempre all’interno di quest’ultimo, alle action che potranno
eseguire sui dati le corrispondenti elaborazioni.
<form-bean name="nomeFormBean" type="package.ClasseActionForm"/>
E’ da sottolineare, che la signature del metodo execute() di una action, prevede tra i
parametri di ingresso, proprio il formbean con i dati su cui andranno eseguite le
operazioni della business-logic.
2.4.2 ActionErrors
In generale, i dati che vengono immessi dall’utente all’interno di un form
della Web application, sono sottoposti ad un’operazione di validazione. L’esito di
quest’ultima non è sempre positivo ed , in caso di errori, è necessario visualizzare
all’utente dei messaggi di errore, per segnalare che i dati immessi non sono corretti.
Tali errori vengono memorizzati nel sistema, mediante la classe ActionErrors.
Tipicamente, nel momento in cui è richiesta la validazione dei dati, viene invocato il
metodo validate() del formbean, derivato da ActionForm. Se durante la validazione si
verificano uno o più errori, viene creato un oggetto ActionErrors, il quale altro non è
che una lista, all’interno della quale possono essere salvati tali errori con i relativi
messaggi da visualizzare all’utente. La classe prevede il metodo add(), mediante il
quale si può aggiungere un messaggio ed associarlo ad un elemento della View, in cui
verrà eseguita la visualizzazione.
97
Capitolo III – Il framework Struts
_________________________________________________________________
Le classi che permettono di creare dei messaggi di semplice segnalazione o di errore
all’utente sono le seguenti :
-
ActionMessage:
-
ActionError;
2.4.2.1 ActionMessage – ActionError
Il framework Struts prevede la classe ActionError, per creare dei messaggi di
warning o di errore da visualizzare all’utente. Dalla versione 1.1, è stata aggiunta la
classe ActionMessage, per un motivo puramente concettuale. Infatti, facendo uso
soltanto della classe ActionError, anche un messaggio qualsiasi, non di errore,
verrebbe interpretato come tale, dallo sviluppatore che legge o crea il codice. Per
poter distinguere un errore, da un semplice messaggio da visualizzare nella View, è
stata introdotta la classe ActionMessage, la quale altro non è che una generalizzazione
della ActionError. Ovviamente, è stata aggiunta anche la classe ActionMessages che, alla
pari della classe ActionErrors, si fa carico di memorizzare più messaggi all’interno di
una lista.
Figura 7 - Class Diagram Messages/Errors
98
Capitolo III – Il framework Struts
_________________________________________________________________
2.4.3 DynaActionForm
Uno dei problemi che sorge nell’utilizzo della classe ActionForm per la
realizzazione dei formbean, è il numero elevato di classi da creare e da aggiungere al
proprio progetto software. Infatti, se i form HTML della Web application sono
numerosi, altrettanto numerose saranno le classi che dovranno derivare da
ActionForm e realizzare i formbean relativi. Per risolvere questo problema, alcuni
sviluppatori creano un unico formbean, le cui proprietà corrispondono a tutti i campi
di tutti i form HTML Un’altra conseguenza dell’uso di più classi ActionForm, deriva
dal fatto che, se vengono aggiunti o rimossi dei campi ad uno o più form HTML, c’è
bisogno di modificare anche le classi dei formbean corrispondenti e ricompilarle.
Per questi motivi, è stata introdotta la possibilità di realizzare dei formbean dinamici
facendo uso della classe DynaActionForm, la quale altro non è che un’estensione della
classe ActionForm.
Figura 8 - Class Diagram DynaActionForm/ActionForm
Le differenze sostanziali fra queste due classi, riguardano i tre seguenti aspetti :
-
le proprietà del formbean;
-
il metodo validate();
-
il metodo reset();
99
Capitolo III – Il framework Struts
_________________________________________________________________
Le proprietà di un formbean dinamico sono definite all’interno del file di
configurazione struts-config.xml. Durante l’esecuzione della Web application, il
framework crea un’istanza della classe e mette a disposizione dei metodi getter e
setter per accedere a tali proprietà. La modifica oppure l’introduzione di uno o più
proprietà, prevede l’intervento sul file di configurazione e tutto ciò garantisce grande
potenza e flessibilità.
<form-bean name="nomeFormBeanDinamico"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="porprieta1" type="ClasseProprieta1"/>
...
<form-property name="proprietaN" type="ClasseProprietaN"/>
</form-bean>
Il metodo reset() è invocato allo stesso modo della classe ActionForm, con la differenza
che non si ha un maggior controllo delle operazioni che vanno eseguite al suo
interno. Il comportamento di default del metodo, prevede di assegnare alle proprietà
del formbean dinamico, dei valori iniziali che vengono sempre specificati all’interno
del file dello stesso file di configurazione. Qualora si voglia modificare tale
comportamento, è necessario realizzare una classe che estenda DynaActionForm e
quindi eseguire l’overriding del metodo reset(). Infine, la validazione di un formbean
dinamico potrebbe essere eseguita realizzando una classe che estenda DynaActionForm
ed esegua l’overriding del metodo validate(). In generale, per evitare lo sviluppo di
classi aggiuntive, si fa uso del plug-in Validator, il quale mette a disposizione una
serie di regole di validazione già pronte per l’uso.
2.4.4 Tag Libraries
Nell’ambito della View, oltre alle classi che permettono di gestire tutto ciò
che riguarda l’interazione e lo scambio dei dati tra utente ed applicazione, rientrano
anche le librerie di tag che Struts mette a disposizione per la realizzazione della UI.
Queste ultime, non soltanto offrono la possibilità di introdurre gli elementi grafici in
una pagina JSP, ma ne permettono anche la costruzione dinamica, oltre alla
possibilità di accedere alle proprietà dei beans previsti dall’applicazione.
100
Capitolo III – Il framework Struts
_________________________________________________________________
La libreria Struts HTML mette a disposizione tutti gli elementi che permettono di
realizzare i form e che definiscono quella che è la grafica dell’applicazione. Il limite
principale del framework è dettato dalla non indipendenza dal dispositivo con cui si
accede alla Web application, per cui viene fornita una libreria che permette di definire
l’interfaccia utente solo ed esclusivamente per un browser Web.
La libreria Struts Bean dispone di tutti i tag per poter visualizzare e modificare i valori
delle proprietà dei bean previsti dall’applicazione. Ciascun tag ha sempre gli attributi
che permettono di identificare il bean e la proprietà di interesse, separatamente l’uno
dall’altro. Non è supportato l’utilizzo dell’Expression Language, per accedere alle
proprietà di un bean con la consueta “dot notation”, tipica della programmazione ad
oggetti. Per usufruire di questa funzionalità, è necessario utilizzare la versione evoluta
di questa libreria oppure fare affidamento alle librerie JSTL.
Infine, la libreria Struts Logic fornisce una serie di tag che permettono di definire dei
costrutti logici e condizionali all’interno di una pagina JSP, per poter costruire il
contenuto di quest’ultima in maniera dinamica e sulla base di particolari condizioni.
Anche in questo caso, la specifica delle condizioni viene eseguita attraverso gli
attributi dei tag che non supportano l’EL, mediante il quale le operazioni
diventerebbero notevolmente più semplici, potendo utilizzare gli operatori logici del
linguaggio Java.
3. Ciclo di vita di una richiesta
Il ciclo di vita di una richiesta ha una struttura standard, tipica del pattern
MVC. Il client invia la richiesta al Web Container, il quale si fa carico di smistarla
verso la ActionServlet che gestisce l’applicazione. Quest’ultima utilizza l’istanza della
classe RequestProcessor, alla quale trasferisce la richiesta sottoposta al server. In
memoria, è prevista l’immagine del file di configurazione strutturata mediante una
serie di classi, attraverso le quali viene eseguita l’operazione di action mapping, ossia
individuare quale sia la action che deve occuparsi della gestione della richiesta.
Inoltre, vengono istanziati, popolati e validati i formbean che contengono i dati della
richiesta. A questo punto, termina il primo intervento del Controller, il quale invoca
la action individuata per permettere l’esecuzione delle elaborazioni richieste. La
action si pone come un “bridge” tra Controller e Model, utilizzando i formbean,
101
Capitolo III – Il framework Struts
_________________________________________________________________
contenenti i dati da elaborare, e gli oggetti delle business-logic. Al termine
dell’esecuzione della action, viene restituito il forward attraverso il quale, il
Controller, determina la pagina JSP della View verso la quale far proseguire la
navigazione.
Figura 9 - Ciclo di vita di una richiesta
4. Exception Handling
Prima delle versione 1.1, il framework Struts forniva un meccanismo di
gestione delle eccezioni piuttosto semplice, che spingeva gli sviluppatori a realizzare
soluzioni differenti per poter gestire le condizioni di errore nelle proprie applicazioni.
Dalla versione 1.1, è stato introdotto un meccanismo non molto ampio ma
abbastanza efficiente, che permette di gestire le eccezioni in due modalità :
-
dichiarativa : le eccezioni, che possono essere sollevate nell’ambito
dell’applicazione, sono “dichiarate” all’interno del file di configurazione e
gestite in maniera automatica dal framework;
-
programmatica : le eccezioni sono gestite direttamente nel codice delle action,
nella modalità consueta del linguaggio Java;
La gestione delle eccezioni viene eseguita mediante l’utilizzo della classe
ExceptionHandler, della quale Struts ne fornisce una versione di base ma con la
102
Capitolo III – Il framework Struts
_________________________________________________________________
possibilità di estenderla, per poter realizzare un gestore delle eccezioni
personalizzato. Tale classe è dotata del metodo execute(), all’interno del quale viene
creato un oggetto ActionError, per contenere le informazioni riguardanti l’errore
verificatesi e restituisce un oggetto ActionForward che specifica la risorsa verso la quale
proseguire la navigazione per segnalare all’utente il verificarsi dell’eccezione.
4.1 Approccio Dichiarativo
Nel caso in cui un’eccezione non sia gestita in maniera programmatica
all’interno di una action, il RequestProcessor si fa carico di verificare se essa sia
dichiarata all’interno del file di configurazione, utilizzando la classe ExceptionConfig. Il
contenuto di ques’ultima è definito in fase di start-up dell’applicazione, quando viene
eseguito il parsing del file struts-config.xml e le eccezioni dichiarate vengono caricate in
memoria. La classe RequestProcessor prevede il metodo processException(), all’interno del
quale vengono individuate le informazioni relative all’eccezione che è stata sollevata e
viene istanziato l’ExceptionHandler per la sua gestione.
Figura 10 - Gestione delle eccezioni
Uno dei vantaggi principali dell’approccio dichiarativo riguarda soprattutto la
gestione delle eccezioni che si verificano al tempo di esecuzione (runtime). Tali
eccezioni,
facenti
parte
della
classe
RuntimeException,
sono
notoriamente
103
Capitolo III – Il framework Struts
_________________________________________________________________
“unchecked”, ossia non controllate e non possono essere gestite mediante i tipici
blocci try-catch-finally. In questi casi, per evitare che l’applicazione si blocchi fornendo
un messaggio poco user-friendly all’utente, è possibile dichiarare un’eccezione globale
di questo tipo nel file di configurazione, assegnandole una pagina verso la quale
redirezionare l’utente, per segnalargli il problema in maniera più “amichevole”.
<global-exceptions>
<exception bundle="ApplicationResources"
key="chiaveMessaggioErrore"
path="/paginaErrore.jsp"
type="java.lang.RuntimeException"/>
</global-exceptions>
4.2 Approccio programmatico
Un
approccio
alternativo
a
quello
dichiarativo,
è
l’approccio
programmatico. Quest’ultimo prevede che la gestione delle eccezioni venga eseguita
completamente attraverso il codice all’interno di una action e non preveda l’utilizzo
di informazioni del file di configurazione. Ovviamente, tale approccio rende la
gestione molto più complessa, in quanto è lo sviluppatore che deve occuparsi di
catturare un’eccezione, salvare i messaggi di errore negli oggetti ActionError e
produrre gli oggetti ActionForward per far proseguire la navigazione.
I due tipi di approcci non sono mutuamente esclusivi, ma viceversa possono essere
utilizzati contemporaneamente. Infatti, la prima opportunità di catturare
un’eccezione è all’interno della classe Action che la solleva e, nel caso in cui non se ne
sia prevista la gestione, essa viene catturata nel metodo processActionPerfom() della
classe RequestProcessor, la quale proseguirà con l’approccio dichiarativo.
4.3 ModuleException
Il framework mette a disposizione una particolare classe, nota come
ModuleException, per sollevare delle eccezioni che possano poi essere gestite mediante
l’approccio dichiarativo. Infatti, all’interno del metodo execute() di una action, qual’ora
si verificasse una condizione di errore, è possibile sollevare un’eccezione di questo
104
Capitolo III – Il framework Struts
_________________________________________________________________
tipo, che in maniera completamente automatica crea l’oggetto ActionError nel quale è
possibile specificare il messaggio da visualizzare all’utente.
...
ModuleException me = new ModuleException("chiaveMessaggioErrore");
throw me;
...
Tipicamente, tale eccezione sarà dichiarata all’interno del file di configurazione, per
cui sarà il RequestProcessor che si occuperà di catturarla e delegarne la gestione alla
classe ExceptionHandler .
<global-exceptions>
<exception bundle="ApplicationResources"
key="chiaveMessaggioErrore"
path="/paginaErrore.jsp"
type="org.apache.struts.util.ModuleException"/>
</global-exceptions>
L’unico limite nell’utilizzo di questa classe è di determinare un accoppiamento tra
l’applicazione e la modalità di gestione delle eccezioni di Struts, rendendo più
complesso il procedimento di sostituzione del framework adottato, lasciando
inalterato lo strato applicativo sottostante.
5. Internazionalizzazione (I18N)
Tipicamente, gli sviluppatori focalizzano la loro attenzione sulla
realizzazione di un’applicazione per la risoluzione di un certo problema. Nella
maggior parte dei casi, viene perso di vista un aspetto fondamentale che riguarda il
pubblico a cui è diretto l’utilizzo dell’applicazione stessa. Soprattutto nel caso di Web
application fruibili attraverso Internet, si pone il problema di permettere l’utilizzo di
quest’ultima, a persone di paesi e lingue differenti.
L’Internazionalizzazione (I18N) è un processo che prevede lo sviluppo di un
software per poter supportare nel tempo più lingue e stati diversi , in modo tale che
non ci sia bisogno di reingegnerizzare il sistema nel momento in cui sarà necessario
fornire supporto per ulteriori di essi.
105
Capitolo III – Il framework Struts
_________________________________________________________________
Le caratteristiche principali di un software che supporta l’Internazionalizzazione sono
le seguenti :
-
le lingue devono essere supportate senza la necessità di apportare modifiche
al codice;
-
i messaggi da visualizzare agli utenti sono contenuti in risorse esterne e
completamente al di fuori del codice;
Il framework Struts mette a disposizione tali caratteristiche utilizzando le principali
classi Java che si occupano dell’internazionalizzazione : Locale e ResourceBundle.
La classe Locale contiene le informazioni relative appunto al “locale” associato
all’utente che utilizza l’applicazione. Con il termine “locale” si intende una regione
nell’ambito della quale sono condivisi costumi, culture e lingue. Attraverso tale classe,
è possibile risalire alle informazioni relative alla valuta, alla formattazione delle date e
delle ore ed a tante altre informazioni specifiche.
La classe ResourceBundle permette, invece, di definire la risorsa esterna all’interno della
quale sono salvati i messaggi da visualizzare all’utente in una certa lingua. Attraverso
l’utilizzo di questa classe, è possibile accedere ad essi direttamente da codice,
mediante un meccanismo “key-message” (chiave-messaggio), in base al quale,
specificando una chiave, si ricava il messaggio corrispondente associato.
Generalmente, quando un utente accede ad una Web application realizzata con
Struts, quest’ultimo memorizza all’interno della sessione utente, il locale definito dal
browser che quest’ultimo sta adottando. Mediante questa informazione, è quindi
possibile accedere al giusto Resource Bundle, da cui prelevare i messaggi da
visualizzare all’utente nella sua lingua.
Struts prevede la definizione di uno o più file .properties, aventi lo stesso nome ma un
suffisso diverso, che specifica la lingua adottata nei messaggi contenuti nel file,
attraverso le coppie “key-message”.
106
Capitolo III – Il framework Struts
_________________________________________________________________
6. JavaServer Pages Standard Tag Library (JSTL)
Per la realizzazione della View, Struts mette a disposizione alcune librerie di
tag, attraverso le quali, dalle pagine JSP, è possibile eseguire le seguenti operazioni:
-
visualizzare gli elementi costitutivi dei form e che caratterizzano
completamente l’interfaccia utente;
-
accedere alle proprietà dei bean che caratterizzano l’applicazione;
-
eseguire delle operazioni logiche, in modo da permettere la costruzione di
ciascuna pagina in base al verificarsi o meno di determinate condizioni;
Attraverso queste librerie, è possibile eseguire tutte le operazioni necessarie, anche se
manca uno strumento molto potente come l’Expression Language. Quest’ultimo, a
differenza del framework JSF, non è supportato in forma nativa in Struts, per cui
dalle pagine JSP non è possibile accedere a metodi e proprietà dei bean utilizzando le
tipiche espressioni dell’EL, caratterizzate dalla “dot notation”. Per superare questo
limite, è stata realizzata una versione “evoluta” delle librerie del tutto uguali a quelle
di base, con l’unica differenza che i tag supportano l’Expression Language. Nella
maggior parte dei casi, però, si preferisce utilizzare un particolare set di librerie di tag
noto come JSTL (JavaServer Pages Standard Tag Library) che ovviamente supporta
l’EL. Queste librerie sono complessivamente cinque, così definite :
-
Core : per l’accesso alle proprietà dei bean dell’applicazione, per gestire il
flusso di controllo attraverso costrutti condizionali ed iterativi e per la
gestione degli URL ;
-
Internationalization : per la gestione dell’internazionalizzazione (I18N), per la
visualizzazione e formattazione dei messaggi;
-
XML : per la manipolazione di documenti XML direttamente da una pagina
JSP;
-
SQL : per effettuare accessi ed operazioni a basi di dati;
-
Functions : fornisce una serie di funzioni di uso comune da poter applicare a
variabili oppure proprietà dei bean;
107
Capitolo III – Il framework Struts
_________________________________________________________________
Tipicamente, per la realizzazione di un’applicazione con Struts, sono necessarie
soltanto le prime due che vanno a sostituire le librerie HTML, Bean e Logic. La
libreria XML viene utilizzata solo nel caso in cui sia necessario gestire direttamente
da una pagina JSP dei documenti XML, mentre la libreria Functions trova
applicazione qualora si abbia bisogno di funzioni particolari da eseguire. Infine, la
libreria SQL viene utilizzata solo nel caso di applicazioni di dimensioni estremamente
ridotte, in quanto non è mai una buona soluzione, introdurre il codice per accedere
alle basi di dati, all’interno della View. Nella maggior parte dei casi, si preferisce
realizzare delle classi che si occupano esclusivamente dell’accesso ai database, in
modo da separare nettamente queste operazioni dalla presentazione dei risultati.
7. Estensioni con i PlugIn
Il framework Struts mette a disposizione un particolare meccanismo
mediante il quale è possibile estenderne la struttura, ossia la definizione e l’uso del
plug-in. Basti pensare che gli stessi Tiles e Validator sono dichiarati come tali
all’interno del file di configurazione, in quanto non sono parte integrante
dell’architettura di Struts. Ovviamente, lo sviluppatore ha la possibilità di realizzare
una classe che implementi l’interfaccia PlugIn per poter disporre di un proprio plug-in
con cui estendere le funzionalità dell’applicazione sviluppata. L’uso di un plug-in può
essere particolarmente conveniente quando è necessario effettuare una serie di
elaborazioni una sola volta, nella fase di start-up dell’applicazione. Infatti, il
framework effettua il caricamento dei plug-in configurati nella fase di inizializzazione
della Web application, così come la corrispondente eliminazione nel caso di
shutdown oppure riavvio del Web Container. In entrambi i casi, vengono eseguiti i
due corrispondenti metodi di cui deve essere sempre dotata una classe che
rappresenta un plug-in :
-
initi() : viene eseguito all’avvio dell’applicazione e può contenere tutte le
operazioni necessarie allo startup della Web application;
-
destroy() : viene invocato alla chiusura dell’applicazione per “distruggere” il
plug-in;
108
Capitolo III – Il framework Struts
_________________________________________________________________
public void init(ActionServlet actionServlet,
ModuleConfig moduleConfig)
throws ServletException {
...
}
public void destroy() {
...
}
Una volta effettuato l’overriding dei due metodi suddetti, basta dichiarare il plug-in
all’interno del file struts-config.xml.
<plug-in className="package.ClassePlugIn"/>
8. Validator framework
Per poter eseguire la validazione dei dati immessi dall’utente all’interno dei
form, il framework Struts prevede che la classe ActionForm, utilizzata per definire un
formbean, abbia il metodo validate() che venga eseguito subito dopo l’invio del form
stesso. Un approccio di questo tipo è , ovviamente, programmatico e talvolta può
presentare una serie di limitazioni.
In primo luogo, c’è da dire che la maggior parte dei form presenti in una Web
application, hanno dei campi che possono contenere dei dati soggetti allo stesso tipo
di validazione, per cui si è costretti a realizzare più metodi validate() praticamente
uguali. Nel momento in cui c’è la necessità di effettuare una modifica, quest’ultima
andrà eseguita in tutti i metodi realizzati e comporterà la ricompilazione del codice.
Per questi motivi, è stato implementato un particolare framework che permette di
gestire la validazione dei dati in maniera dichiarativa. Dato il suo notevole utilizzo, da
parte degli sviluppatori, si è deciso di considerarlo un progetto Jakarta ed introdurlo
in ogni distribuzione di Struts.
Il framework Validator permette di trasferire la logica della validazione
completamente fuori dalle classi ActionForm, configurando in maniera dichiarativa
tutte le regole di validazione in un file XML. Esso fornisce una serie di funzioni
standard per le validazioni più comuni ma è completamente estendibile, in quanto
109
Capitolo III – Il framework Struts
_________________________________________________________________
permette allo sviluppatore di realizzare e configurare dei metodi di validazione
personalizzati.
La distribuzione del framework prevede una serie di classi ed in particolare due file
XML, che ne permettono la configurazione in maniera semplice :
-
validation-rules.xml;
-
validation.xml;
Il file validation-rules.xml contiene una serie di funzioni che permettono di eseguire le
validazioni tipiche, come ad esempio :
-
valutare se l’input immesso dall’utente sia o meno di un certo tipo (Integer,
Float, Double, Long,…);
-
valutare se un data immessa abbia un formato corretto;
-
valutare se l’input ricada entro un certo range oppure abbia una lunghezza
che rispetto un limite minimo e massimo fissati;
-
valutare se l’utente abbia immesso un valore in un campo che sia
obbligatorio;
-
valutare se un certo dato soddisfi un particolare pattern;
-
valutare se un valore che debba rappresentare una carta di credito oppure un
indirizzo email, abbia un formato corretto;
Ovviamente, a queste funzioni incluse nel framework ne possono essere aggiunte
delle ulteriori, estendendo le classi principali del framework stesso.
Il file validation.xml permette di configurare tutti i form della Web application, i cui
campi debbano essere soggetti a validazione e, per ogni form, specificare per ciascun
campo la funzione di validazione da applicare. Il tag <formset> viene utilizzato per
raggruppare tutti i form suddetti, ciascuno dei quali viene definito mediante il tag
<form>. Inoltre, all’interno di quest’ultimo sono previsti uno o più tag <field> che
permettono di specificare i campi che costituiscono il form in questione. Per
ciascuno di essi è possibile specificarne il nome, mediante l’attributo property, e la
regola di validazione da applicare, mediante l’attributo depends.
110
Capitolo III – Il framework Struts
_________________________________________________________________
<form name="nomeForm">
<field depends="required" property="proprieta1"/>
...
<field depends="required,minlength" property="proprietaN">
</form>
Generalmente, i form e le relative proprietà specificate all’interno di questo file,
devono coincidere con le informazioni dei corrispondenti formbean che sono
configurati all’intero del file struts-config.xml dell’applicazione.
L’ultima considerazione da fare è legata al fatto che il framework Validator è
perfettamente integrato con Struts ed il suo utilizzo prevede che esso venga
dichiarato all’interno del file di configurazione come se fosse un plug-in, specificando
i percorsi dei file XML che lo caratterizzano.
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
9. Tiles framework
Tiles è un framework mediante il quale è possibile realizzare il Presentation
Layer di una Web application, separando il layout dai contenuti (contents). Mentre il
layout definisce la struttura di una pagina, con la caratteristica che più pagine
possono avere il medesimo layout, il contents definisce il contenuto di ciascuna di
esse e può essere diverso da pagina a pagina oppure eventualmente uguale in alcuni
casi. E’ notevolmente importante poter separare l’uno dall’altro, in modo tale che
apportando delle modifiche al primo non sussiste alcuna influenza sul secondo e
viceversa. Il framework permette di costruire le pagine assemblando i cosiddetti
“tiles”, il cui significato è banalmente “mattonelle” evidenziando che sono dei
componenti riutilizzabili che possono essere disposti in una struttura predefinita.
Nella maggior parte dei casi, ogni tile non è nient’altro che una pagina JSP che a sua
volta può essere composta da altri tiles. E’ possibile distinguerne due tipologie :
-
tile Layout : tile che definisce la struttura di una pagina. Esso riceve da una
pagina (tile non-Layout) il contenuto e lo dispone secondo tale struttura;
111
Capitolo III – Il framework Struts
_________________________________________________________________
-
tile non-Layout : tile che utilizza un layout (tile Layout) passando a quest’ultimo
degli attributi che rappresentano il contenuto da disporre secondo una certa
struttura;
Generalmente, nell’ambito di una Web application, il tile Layout è unico e definisce la
struttura di tutte le pagine, mentre ciascuna pagina è definita attraverso un proprio
tile non-Layout.
L’uso dei tiles può essere paragonato all’uso dei metodi in Java. Un metodo in Java è
costituito da un body che ne definisce l’elaborazione e dai parametri di ingresso che
specificano i dati su cui quest’ultima va effettuata. Un tile può essere considerato
come un metodo, in quanto bisogna definirne la struttura e passargli dei parametri,
detti attributi, che ne descrivano il contenuto. Ciascuno di essi è memorizzato nel
context del tile stesso, attraverso la classe ComponentContext facente parte del
framework. Infine, ogni attributo può essere una stringa oppure tipicamente una
pagina JSP.
Nella maggior parte dei casi, il layout utilizzato per ciascuna pagina è proposto in
figura.
Figura 11 - Layout Header/Footer/Menu/Body
Esso prevede fondamentalmente quattro parti : header, footer, menu e body.
Tipicamente, l’header ed il footer sono comuni a tutte le pagine, per cui il loro
contenuto viene definito un’unica volta. Il vantaggio che ne scaturisce è dato dal fatto
che se deve essere apportata una modifica ad uno di essi, quest’ultima va eseguita
112
Capitolo III – Il framework Struts
_________________________________________________________________
un’unica volta e non per tutte le pagine della Web application. Il menu, invece, può
essere lo stesso nell’ambito di tutta l’applicazione e quindi avrà il medesimo
vantaggio di header e footer oppure può variare in relazione alla pagine visitate.
Infine, il body è tipicamente diverso da pagina a pagina.
Per quanto riguarda la relazione con Struts, Tiles è perfettamente integrato con
quest’ultimo, in quanto contenuto in ciascuna distribuzione, e viene dichiarato
all’interno del file di configurazione in termini di plug-in.
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config"
value="/WEB-INF/tiles-defs.xml"/>
<set-property property="moduleAware" value="true"/>
</plug-in>
9.1 Definitions
I tiles possono essere descritti attraverso le cosiddette definitions, dichiarate
in un file XML e che permettono :
-
una dichiarazione centralizzata di una pagina;
-
se si dispone di più tiles non-Layout con un contenuto uguale (es. le pagine
hanno il medesimo header e footer), al posto di definire tale contenuto
pagina per pagina, lo si definisce un’unica volta rendolo comune a tutte le
pagine;
-
supporto alla derivazione, descrivendo una nuova definition che ne estenda
una preesistente, ereditandone le caratteristiche ed aggiungendone delle altre;
Generalmente, il file che contiene le definitions è noto come tiles-defs.xml e ciascuna di
esse è dichiarata attraverso il tag <definition> che mediante i suoi attributi permette di
specificare le seguenti informazioni :
-
nome della definition per referenziarla all’interno di un tile che ne farà uso
(name);
-
percorso del tile Layout che descrive la struttura associata alla definition
(path);
113
Capitolo III – Il framework Struts
_________________________________________________________________
-
definition da cui eseguire la derivazione (extends);
Per specificare gli attributi della definition, è possibile utilizzare uno o più tag <put>,
ciascuna dei quali prevede le seguenti informazioni :
-
nome dell’attributo;
-
valore dell’attributo che può essere una stringa, una pagina JSP oppure
un’altra definition se si prevede di utilizzare la composizione di più
definitions;
<tiles-definitions>
<definition name="page.template" path="/paginaLayout.jsp"/>
<definition name="page.header" path="/header.jsp"/>
<definition name="page.footer" path="/footer.jsp"/>
<definition name="page.menu" path="/menu.jsp"/>
</tiles-definitions>
9.2 Costruzione di una pagina
La costruzione di una pagina JSP secondo un certo layout e con uno
specifico contenuto è realizzata attraverso l’utilizzo di particolari tag della libreria
Struts Tiles. Il tag che permette di inserire un contenuto oppure utilizzare una
definition all’interno di una pagina JSP è <tiles:insert>, il quale prevede le seguenti
informazioni :
-
percorso della pagina da inserire (page);
-
nome dell’attributo (attribute);
-
nome della definition da adottare all’interno di un tile non-Layout (definition);
Ovviamente, la definition utilizzata all’interno di ciscuna pagina avrà dei contenuti
comuni fra le pagine ma queste ultime potrebbero anche avere alcuni contenuti
differenti. Per inserire un contenuto nel layout, specificato da una definition, è
possibile utilizzare il tag <tiles:put>, il quale descrive le seguenti informazioni :
-
nome dell’attributo (name);
114
Capitolo III – Il framework Struts
_________________________________________________________________
-
valore dell’attributo che può essere una stringa oppure una pagina JSP (value);
<tiles:insert definition="page.template">
<tiles:put name="title" value="Titolo"/>
<tiles:put name="body"
value="/BodyContext.jsp"
type="page"/>
</tiles:insert>
Attraverso questo meccanismo, le pagine possono avere contenuti comuni che non
devono ulteriormente specificare in quanto definiti all’interno della definition
utilizzata. Nel caso in cui alcuni contenuti debbano essere differenti, basta utilizzare il
tag <tiles:put> mediante il quale il contenuto specificato va a sostituire quello di
default.
10. Sicurezza
La sicurezza di un’applicazione realizzata con il framework Struts
rappresenta un aspetto completamente indipendente da quest’ultimo e può essere
gestita mediante le funzionalità offerte dal Web Container. Parlare di sicurezza
attraverso la rete significa soprattutto garantire la trasmissione delle informazioni e
dei dati in modalità crittografata, in modo tale da essere inaccessibili dall’esterno. Il
meccanismo principale messo a disposizione si basa sul protocollo SSL (Secure
Socket Layer), sulla base del quale è stata creata in passato una nuova versione del
protocollo HTTP, ossia l’HTTPS. Mediante quest’ultimo, infatti, le informazioni
sono trasmesse dal client al server e viceversa in modalità crittografata, anche sulla
base dell’utilizzo di un regolare certificato digitale. Per poter fare in modo che le
pagine di un’applicazione implementata con Struts, utilizzino tale protocollo, è
necessario in primo luogo abilitarlo all’interno del Web Container e successivamente
modificare il Deployment Descriptor web.xml dell’applicazione stessa. All’interno di
quest’ultimo è possibile dichiarare dei vincoli di sicurezza (tag <security-constraint>) e
le pagine che ne sono soggette (tag <web-resource-collection>), oltre al tipo di trasporto
da utilizzare (tag <transport-guarantee>) che può essere di tre tipi :
-
NONE : utilizza HTTP;
115
Capitolo III – Il framework Struts
_________________________________________________________________
-
INTEGRAL , CONFIDENTIAL : utilizza HTTPS;
<security-constraint>
<display-name>SSL Constraint</display-name>
<web-resource-collection>
<web-resource-name>
Automatic SLL Forwarding
</web-resource-name>
<url-pattern>[pagina.jsp]</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Quanto detto mette in evidenza che la sicurezza di un’applicazione realizzata con
Struts, è gestita allo stesso modo di una qualsiasi applicazione Web in Java e quindi
completamente indipendente dal framework.
11. Configurazione dell’applicazione
Il framework Struts utilizza uno o più file di configurazione per poter
creare e caricare in fase di start-up dell’applicazione, tutte le risorse ed i componenti
necessari a quest’ultima. Tali file permettono di specificare in maniera dichiarativa il
comportamento degli elementi dell’applicazione, evitando che tali specifiche siano
definite all’interno del codice. Questo permette agli sviluppatori di realizzare delle
estensioni e di utilizzarle nella Web application, garantendo che il framework sia
capace di sfruttarle in maniera dinamica. I file di configurazione si basano sul
linguaggio XML e possono essere anche più di uno, nel momento in cui
l’applicazione è realizzata con moduli indipendenti. Ciascuno di essi ha le proprie
informazioni di configurazione, inclusi i Resource Bundles, ed è completamente
indipendente dagli altri. Tutto ciò favorisce lo sviluppo di un’applicazione di grandi
dimensioni, anche da team di lavoro distinti.
Con la versione 1.1 del framework Struts, è stato introdotto il package config,
all’interno del quale ci sono una serie di classi che permettono di memorizzare le
informazioni di configurazione, nel momento in cui queste ultime vengono lette dal
116
Capitolo III – Il framework Struts
_________________________________________________________________
file XML. In questo modo, si ha a disposizione una visione di queste informazioni in
termini di classi, residenti nella memoria e quindi accessibili dallo sviluppatore
direttamente da codice.
Ciascuna classe del package contiene le informazioni che riguardano una parte
specifica del file di configurazione. Dopo che è stato eseguito il parsing e la
validazione del file di configurazione, il framework istanzia ed alloca in memoria, gli
oggetti contenenti le informazioni ad essi pertinenti.
Figura 12 - Class Diagram Configurazione
La classe centrale del package è l’ ApplicationConfig, la quale è legata a tutte le altre
classi contenenti le informazioni di configurazione. Attraverso l’istanza di tale classe,
è possibile accadere a tutte le altre e quindi alle informazioni in esse memorizzate. Se
l’applicazione è sviluppata in moduli, ciascun modulo ha a sua disposizione una
corrispondente istanza di tale classe.
11.1 DataSource
Generalmente, una Web application prevede l’utilizzo di un database
all’interno del quale sono memorizzate le informazioni in maniera permanente.
117
Capitolo III – Il framework Struts
_________________________________________________________________
L’utilizzo di una base di dati, oppure più generalmente di un datasource, può essere
specificato all’interno del file di configurazione. Per questo scopo, è messo a
disposizione il tag <data-source>, che va utilizzato più volte in relazione al numero di
database di cui dispone l’applicazione, distinguendo un datasource dall’altro
attraverso la specifica di una chiave (key). Inoltre, è possibile definire una serie di
proprietà caratteristiche del datasource, utilizzando al suo interno uno o più tag <setproperty>. Le informazioni tipicamente configurate sono le seguenti :
-
una descrizione del datasource;
-
la classe che implementa il driver per l’accesso alla base di dati. In generale,
sono utilizzati i driver JDBC, ma in molti casi si può fare anche uso di driver
specifici per il connection-pooling;
-
lo username e la password per accedere alla base di dati;
-
l’ URL in cui si trova il database;
Tutte queste informazioni sono memorizzate, in fase di start-up dell’applicazione,
nella classe DataSourceConfig, mediante la quale è possibile accedere alle proprietà del
datasource, ed eventualmente modificarle, direttamente da codice.
<data-sources>
<data-source key="database">
<set-property property="driverClassName"
value="com.mysql.jdbc.Driver"/>
<set-property property="url"
value="jdbc:mysql://localhost/database"/>
<set-property property="username" value="admin"/>
<set-property property="password" value="sara"/>
</data-source>
</data-sources>
11.2 FormBean
Ciascun formbean realizzato come estensione della ActionForm ed utilizzato
all’interno dell’applicazione, deve essere specificato nel file di configurazione
mediante l’uso del tag <form-bean>.
118
Capitolo III – Il framework Struts
_________________________________________________________________
Quest’ultimo permette di specificare le seguenti informazioni :
-
il nome del formbean mediante il quale si farà riferimento ad esso nel resto
del file (name). Ad esempio, quando si definisce una action che utilizza i dati
di un certo formbean, va specificato il nome di quest’ultimo;
-
la classe che implementa il formbean (type). Tipicamente, questa può essere la
classe ActionForm oppure DynaActionForm o eventualmente una delle classi
che derivano da esse. In alcuni casi, è invece una classe realizzata dallo
sviluppatore, che comunque estende una delle classi suddette;
<form-bean name="nomeFormBean" type="package.ClasseActionForm"/>
E’ ovvio che, nel caso in cui la classe che implementa il formbean sia stata realizzata
dallo sviluppatore, le proprietà del formbean stesso sono esattamente le proprietà
della classe, che non devono essere ulteriormente specificate nel file di
configurazione. Nel caso in cui, si preferisce adottare ad esempio un formbean
dinamico, è necessario specificare le proprietà del formbean all’interno del file strutsconfig.xml, non essendoci una classe realizzata ad hoc.
Per questo scopo, il tag <form-bean> può contenere uno o più tag <form-property>,
ciascuno dei quali permette di definire una proprietà del formbean, specificandone le
seguenti informazioni :
-
il nome della proprietà (name);
-
la classe (oppure il tipo di dato primitivo) della proprietà (type);
-
l’eventuale valore iniziale, quando il formbean è vuoto (initial);
<form-bean name="nomeFormBeanDinamico"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="porprieta1" type="ClasseProprieta1"/>
...
<form-property name="proprietaN" type="ClasseProprietaN"/>
</form-bean>
Tutte queste informazioni sono memorizzate all’interno delle classi FormBeanConfig e
FormPropertyConfig, che contengono rispettivamente tutto ciò che riguarda in generale
il formbean e le relative proprietà.
119
Capitolo III – Il framework Struts
_________________________________________________________________
11.3 Global Exceptions
Il framework Struts mette a disposizione la possibilità di gestione delle
eccezioni che possono essere sollevate all’interno delle action. Ovviamente, è
possibile definire, per ciascuna action, le eventuali eccezioni che essa può sollevare,
ma in moltissimi casi, esistono delle eccezioni che possono essere sollevate da più
action diverse. In questi casi, la soluzione migliore non è certamente quella che
prevede di specificare la stessa eccezione per ogni action, ma bensì di definire una
eccezione come “globale”. In questo modo, quando una action solleva un’eccezione,
l’ ExceptionHandler valuta in primo luogo se essa è specifica della action che l’ha
sollevata oppure è di tipo “globale” e va gestita in un certo qual modo. Ciascuna
eccezione “globale” viene specificata nel file di configurazione, all’interno del tag
<global-exceptions>, facendo uso del tag <exception>, il quale permette di definire le
seguenti informazioni :
-
la chiave relativa al Resource Bundle e corrispondente al messaggio da
visualizzare, quando l’eccezione viene sollevata (key);
-
il percorso della pagina alla quale l’utente verrà redirezionato (path);
-
la classe “handler” che si occuperà di gestire l’eccezione. Per default, essa è la
classe ExceptionHandler, ma ovviamente lo sviluppatore può realizzarne una
propria estendendo quest’ultima;
-
la classe che rappresenta il tipo di eccezione (type);
La classe che memorizza tutte queste informazioni è la ExceptionConfig.
<global-exceptions>
<exception bundle="ApplicationResources"
key="chiaveMessaggioErrore"
path="/paginaErrore.jsp"
type="org.apache.struts.util.ModuleException"/>
</global-exceptions>
120
Capitolo III – Il framework Struts
_________________________________________________________________
11.4 Global Forwards
Quando una action, all’interno del metodo execute(), termina le operazioni
relative al proprio scopo, essa restituisce un oggetto ActionForward con il quale si
definisce la risorsa verso la quale proseguire la navigazione. Per ciascuna action,
all’interno del file di configurazione, vengono specificati i “forward” ad essa associati.
In alcuni casi, può essere utile fare uso dei forward “globali”, i quali non sono
specifici di una action, ma possono essere referenziati ad una qualsiasi action
all’interno dell’applicazione. Ciascun forward “globale” viene specificato nel file di
configurazione, all’interno del tag <global-forwards>, facendo uso del tag <forward>, il
quale permette di definire le seguenti informazioni :
-
il nome del forward per referenziarlo all’interno di una Action (name);
-
il percorso della risorsa fisica a cui fa riferimento il forward “logico” (path);
Queste informazioni sono memorizzate nella classe ForwardConfig.
<global-forwards>
<forward name="nomeForward" path="pagina.jsp"/>
...
</global-forwards>
11.5 Action Mapping
Il contenuto principale del file di configurazione di Struts è il mapping delle
action, attraverso il quale è possibile specificare tutte le action utilizzate all’interno del
framework, associarle ad un percorso logico per la loro invocazione e specificarne i
forward per proseguire la navigazione da ciascuna di esse.
Per definire ciascuna action, viene utilizzato il tag <action>, mediante il quale sono
descritte le seguenti informazioni :
-
il percorso (URI) della action per poter essere invocata da un qualsiasi punto
dell’applicazione (path);
121
Capitolo III – Il framework Struts
_________________________________________________________________
-
la classe che implementa la action, tipicamente realizzata dallo sviluppatore,
estendendo la classe di base Action oppure una delle sue derivate (type);
-
il nome del formbean, i cui dati saranno oggetto dell’elaborazione della action
(name);
-
la visibilità del formbean (scope), distinguendo fra request e session;
-
la pagina alla quale ritornare il controllo, qualora si verificassero errori di
validazione dei dati nel formbean (input);
-
un eventuale parametro che permette di specificare quale metodo della action
eseguire nel caso in cui si tratti di una DispatchAction;
Inoltre, attraverso l’attributo validate, è possibile specificare se, prima di invocare la
action, debba essere eseguita o meno la validazione dei dati contenuti nel formbean
associato.
Infine, al termine dell’esecuzione del metodo execute(), la action restituisce l’oggetto
ActionForward che specifica la risorsa verso la quale proseguire la navigazione.
Attraverso uno o più tag <forward>, inclusi nel tag <action>, è possibile specificare
tutti i “forward” che può restituire la action stessa. Le informazioni principali sono
tipicamente le seguenti :
-
il nome del forward per referenziarlo all’interno di una action (name);
-
il percorso della risorsa fisica a cui fa riferimento il forward “logico” (path);
Inoltre, è possibile specificare anche le eccezioni che possono essere sollevate da
ciascuna action, facendo uso del tag <exception> così come vengono definite le
eccezioni “globali”.
Tutte le informazioni descritte vengono memorizzate nella classe ActionConfig, in
stretta relazione con le classi ForwardConfig ed ExceptionConfig.
<action input="pagina.jsp"
name="nomeFormBean" parameter="dispatch"
path="/nomeAction" scope="request"
type="package.ClasseAction">
<forward name="nomeForward1" path="pagina1.jsp"/>
...
<forward name="nomeForwardN" path="paginaN.jsp"/>
</action>
122
Capitolo III – Il framework Struts
_________________________________________________________________
11.6 Controller
Il framework, nell’ambito della gestione di tutte le richieste che arrivano alla
Web application, utilizza le versioni di default per le classi ActionServlet e
RequestProcessor, che realizzano il Controller. Nel momento in cui lo sviluppatore
decide di realizzare un Controller personalizzato, non fa altro che estendere la classe
RequestProcessor e definire al suo interno le elaborazioni da eseguire. Nel file di
configurazione, va specificato quale deve essere il Controller da adottare, facendo uso
del tag <controller>, mediante il quale, tra le altre informazioni, va specificata in
particolare la seguente :
-
la classe che implementa il Controller, la quale può essere quella di default
RequestProcessor oppure una classe che derivi da quest’ultima (processorClass);
Le informazioni riguardanti il Controller sono memorizzate nella classe
ControllerConfig.
<controller processorClass="controller.CustomRequestProcessor"/>
11.7 Message resources
Per garantire l’internazionalizzazione, il framework Struts mette a
disposizione la possibilità di realizzare una serie di file, all’interno di ciascuno dei
quali salvare i messaggi da visualizzare all’utente, in una lingua specifica. Tali file sono
anche noti come Resource Bundles o Message Resources e vanno specificati nel file
di configurazione. In realtà, non è necessario definire l’elenco di tutti questi file, ma
unicamente il file associato al linguaggio di default, poiché tutti gli altri avranno
esattamente lo stesso nome, con in più un suffisso che ne distingue la lingua
utilizzata. Per questo scopo, viene adottato il tag <message-resources>, nel quale è
possibile specificare il nome del Resource Bundle, mediante l’attributo parameter.
Tali informazioni sono memorizzate nella classe MessageResourcesConfig.
<message-resources parameter="ApplicationResources"/>
123
Capitolo III – Il framework Struts
_________________________________________________________________
11.8 Plug-In
Dalla versione 1.1 del framework, è stato introdotta la possibilità di
utilizzare dei plug-in, mediante i quali estendere le potenzialità di quest’ultimo. I due
esempi tipici sono il Validator Plug-In, per la validazione dei dati, ed il framework
Tiles, per la definizione del layout dell’applicazione. Lo sviluppatore ha comunque la
possibilità di realizzare una classe che estenda l’interfaccia PlugIn del framework, per
implementare un proprio plug-in che venga eseguito in fase di start-up
dell’applicazione. E’ ovvio che ciascun plug-in utilizzato va specificato nel file di
configurazione, facendo uso del tag <plug-in>, nel quale, tra le altre informazioni, va
segnalata principalmente la seguente :
-
la classe che estende l’interfaccia PlugIn ed implementa il plug-in (className);
Tutte le informazioni relative ad un plug-in sono memorizzate nella classe
PlugInConfig.
<plug-in className="package.ClassePlugIn"/>
124
Capitolo IV – I framework a confronto
_________________________________________________________________
Capitolo IV – I framework a confronto
1. Introduzione
Per molti anni, Struts è stato il framework più popolare ed ampiamente
utilizzato per la realizzazione di Web application mediante il linguaggio Java. In tempi
recenti, è stato introdotto un nuovo framework, JavaServer Faces, che è stato
definito in termini di standard ed ha posto la questione di dover scegliere quale delle
due tecnologie adottare ed in quali condizioni un’applicazione realizzata con Struts
dovesse utilizzare le nuove potenzialità di JSF.
Le principali caratteristiche di Struts possono essere così riassunte :
-
un’architettura basata sul pattern di sviluppo MVC (Model – View –
Controller);
-
capacità di gestione dei form (form management) mediante i cosiddetti
formbean che rappresentano lo stato dei dati di input sul server, ai quali va
aggiunto un framework per la validazione lato client e lato server;
-
presenza del framework Tiles per la definizione del layout delle pagine
mediante dei templates facilmente modificabili, che riducono i tempi di
manutenzione grafica dell’applicazione;
-
librerie di tag da utilizzare nelle pagine JSP per la definizione della View e che
lavorano in stretta collaborazione con la parte di form-management e di
controllo;
A tali caratteristiche, si aggiunge l’elevato livello di maturità che caratterizza il
framework, in quanto è stato realizzato nella sua prima versione nell’anno 2000,
diventando uno standard de facto per lo sviluppo di Web application su piattaforma
J2EE (Java2 Enterprise Edition). Un limite può essere dettato dal fatto che Struts
rappresenti un’implementazione e quindi sia unico, ma comunque migliorabile ed
estendibile.
125
Capitolo IV – I framework a confronto
_________________________________________________________________
Dal lato opposto si pone il framework JavaServer Faces, le cui caratteristiche
peculiari sono le seguenti :
-
architettura basata sul pattern MVC, ma focalizzata in particolar modo alla
View;
-
componenti riutilizzabili ed estendibili per la realizzazione dell’interfaccia
utente (UI);
-
modello di gestione degli eventi e dei corrispondenti handlers, basato su
JavaBeans;
-
utilizzo dell’EL (Expression Language) per realizzare il value-binding e
method-binding, mediante il quale è possibile legare le proprietà dei
componenti della UI, rappresentati con tag nelle pagine JSP, direttamente con
la business-logic, senza che tali componenti abbiano alcuna conoscenza della
struttura delle classi di ques’ultima;
-
ciclo di vita di una richiesta ben definito attraverso una serie di fasi;
-
navigazione delle pagine basata sulla pagina attuale e le possibili destinazioni a
partire da essa;
-
possibilità di gestione dei backing beans (managed beans) costituenti la
business-logic che possono essere istanziati in un qualsiasi momento “on
demand”;
La prima release di questo framework è stata definita nel Marzo del 2004, il che
evidenzia un livello di maturità ancora basso rispetto a Struts. D’altro canto,
JavaServer Faces rappresenta uno standard del quale ne esistono due
implementazioni differenti : JSF RI (Reference Implementation) della Sun
Microsystems e MyFaces di Apache. Inoltre, il creatore di Struts, Craig McClanahan,
ha contribuito alla creazione di JSF portando con se un enorme bagaglio di
esperienza nella realizzazione di framework per lo sviluppo Web. Nella piattaforma
J2EE 5.0 sarà prevista in forma nativa, un’ implementazione della tecnologia
JavaServer Faces. In riferimento al pattern MVC, su cui si basano entrambi i
framework, esso è anche noto come Front Controller, in quanto tutto le richieste che
arrivano alla Web application vengono gestite e distribuite mediante un Controller
126
Capitolo IV – I framework a confronto
_________________________________________________________________
unico dell’applicazione. A questo punto, prendendo in considerazione le
caratteristiche dei due framework, si possono porre le seguenti domande :
-
quale framework adottare per lo sviluppo di una nuova Web application ?
-
disponendo di un’applicazione realizzata in Struts, conviene utilizzare i
componenti aggiuntivi di JSF, svilupparla dall’inizio con ques’ultimo oppure
eseguire una migrazione da un framework all’altro ?
Per rispondere a queste domande, si rende necessario un confronto approfondito tra
queste due tecnologie, nonché bisogna tenere conto delle caratteristiche e delle
dimensioni dell’applicazione da realizzare.
2. Ciclo di vita di una richiesta
Una delle principali differenze tra i due framework risiede nel ciclo di vita
di una richiesta (request life-cycle), ossia cosa accade dal momento in cui arriva una
richiesta (request) all’applicazione fino alla produzione della corrispondente risposta
(response).
In Struts, il ciclo di vita è relativamente semplice e può essere schematizzato nei
seguenti passi principali :
-
il Controller riceve una richiesta in ingresso;
-
i parametri della richiesta vengono trasferiti nel corrispondente formbean;
-
viene determinata la action, che rappresenta un bridge tra Controller e Model,
che dovrà gestire tale richiesta;
-
il formbean viene passato alla action individuata e ne viene avviata
l’esecuzione;
-
all’interno della action vengono utilizzati gli oggetti della business-logic;
-
al termine dell’elaborazione, la action restituisce un “forward” al Controller
che, sulla base di quest’ultimo, determina la View che visualizzerà la risposta
al client;
127
Capitolo IV – I framework a confronto
_________________________________________________________________
1. Richiesta
Client
7. Determinazione
della View
CONTROLLER
2. Trasferimento
dati della richiesta
VIEW
3. Determinazione
della action
action
formbean
6. Restituzione “forward”
al Controller
4. Passaggio del
formbean alla action
5. Utilizzo oggetti
della Business-Logic
MODEL
8. Risposta
Client
Figura 1 - Struts : ciclo di vita di una richiesta
JavaServer Faces ha una gestione molto più complicata, caratterizzata anche dal fatto
che è possibile distinguere due tipi differenti di richieste : initial request e postback.
Inoltre, ciascuna richiesta viene manipolata attraverso sei fasi differenti, i cui passi
principali sono i seguenti :
-
il Controller riceve una richiesta in ingresso;
-
viene ricostruito lo stato iniziale della View, qualora si tratti di una initial
request, oppure uno stato precedente nel caso di un postback;
-
i valori dei parametri della richiesta vengono trasferiti nelle proprietà
corrispondenti dei componenti della UI;
128
Capitolo IV – I framework a confronto
_________________________________________________________________
-
viene eseguita la validazione dei dati;
-
assumendo che i dati siano validi, essi vengono trasferiti dai componenti alle
proprietà dei backing beans ad essi associati;
-
viene eseguita la gestione di eventuali eventi sui componenti della UI e le
elaborazioni della business-logic, specificate nei backing beans;
-
infine, viene eseguita la fase di rendering per la produzione della risposta;
1. Richiesta
Client
8. Risposta
Client
CONTROLLER
Restore View
Apply Request
Values
2. Ripristino
stato View
VIEW
3. Trasferimento
dati della richiesta
Componenti UI
Process
Validations
Update Model
Values
Invoke
Application
4. Validazione dati
5. Trasferimento dati dai
componenti UI ai backing beans
6. Metodi
Business-Logic
MODEL
Backing Beans
Render
Response
7. Rendering
della View
Figura 2 - JSF : Ciclo di vita di una richiesta
129
Capitolo IV – I framework a confronto
_________________________________________________________________
3. Controller Tier
Entrambi i framework prevedono un Controller realizzato attraverso una
Servlet, in esecuzione nel Web Container, la quale ha il compito di acquisire le
richieste provenienti dai client e determinare per ciascuna di esse il corrispondente
handler, facente parte del Model, che dovrà gestirla. Infine, sulla base dei risultati
prodotti, la stessa Servlet si fa carico di determinare la View che rappresenterà la
risposta fornita al client. L’implementazione del Controller è ovviamente differente e
prevede le seguenti classi :
-
Struts : la classe ActionServlet che viene coadiuvata da una o più istanze dalla
classe RequestProcessor;
-
JSF : la classe FacesServlet;
In Struts, la presenza di due classi rappresenta una prerogativa necessaria per la
realizzazione di una Web application in più moduli separati. Infatti, l’istanza della
ActionServlet è unica mentre, per ciascun modulo dell’applicazione , è prevista
un’istanza della classe RequestProcessor. Quando una richiesta arriva al Web Container,
la ActionServlet la smista verso l’istanza della RequestProcessor che è associata al modulo
a cui la richiesta stessa è destinata. Detto ciò, tutti i compiti tipici del Controller
vengono svolti dalla classe RequestProcessor.
Questa differenza può rappresentare un vantaggio per il framework Struts, per
quanto riguarda l’estendibilità del Controller. Infatti, lo sviluppatore deve
semplicemente realizzare una classe che estenda la RequestProcessor ed esegua
l’overriding del metodo processPreprocess(), qualora voglia eseguire delle operazioni
preliminari alla gestione di una richiesta. Viene quindi messo a disposizione un
metodo, tipicamente non utilizzato dal framework, per estendere il Controller.
130
Capitolo IV – I framework a confronto
_________________________________________________________________
Richiesta Client
ActionServlet
RequestProcessor
Punto di estensione
del Controller
MODEL
Figura 3 - Struts : Controller Tier
In JSF, l’estensione è più complicata, in quanto la gestione della richiesta avviene in
più fasi separate. Per questo motivo, è possibile creare un oggetto PhaseListener,
relativo ad una specifica fase ed associarlo all’istanza della classe Lifecycle, che gestisce
il ciclo di vita di una richiesta. In corrispondenza di tale oggetto, è possibile
specificare le elaborazioni da eseguire prima e dopo la fase associata, eseguendo
l’overriding dei metodi afterPhase() e beforePhase().
Rispetto a Struts, tale approccio ha una complessità nettamente superiore, dettata
soprattutto dalla notevole differenza che c’è nel ciclo di vita di una richiesta.
Per questo motivo, in Struts basta estendere la sola classe RequestProcessor ed eseguire
l’overriding del metodo processPreprocess() prima che una richiesta venga gestita, mentre
in JSF, considerando la presenza di più fasi, è possibile intervenire con una maggiore
granularità in corrispondenza di ogni fase, addirittura definendo delle operazioni
specifiche da eseguire prima e dopo ciascuna di esse.
131
Capitolo IV – I framework a confronto
_________________________________________________________________
Richiesta Client
FacesServlet
Lifecycle
Restore View
Apply Request
Values
Punti di estensione
del Controller
Process
Validation
Update Model
Values
Invoke
Application
Render
Response
Figura 4 - JSF : Controller Tier
132
Capitolo IV – I framework a confronto
_________________________________________________________________
4. Interfaccia Utente (UI)
La realizzazione dell’interfaccia utente di una Web application è uno degli
aspetti in cui il framework JavaServer Faces può considerarsi nettamente superiore
rispetto a Struts.
Infatti, JSF introduce il concetto di componente così come nelle applicazioni desktop
è previsto il concetto di controllo, ad esempio con l’utilizzo di Swing. Ciascun
componente rappresenta un elemento costitutivo dell’interfaccia utente e può avere
forme diverse partendo dai componenti più semplici quali un campo di testo, un
radio button, una checkbox, una drop-down list, un bottone, un link fino a
considerare componenti notevolmente complessi che sono realizzati estendendo
oppure collegando tra loro i precedenti. Ovviamente, anche Struts permette di
realizzare un’interfaccia utente caratterizzata da elementi di questo tipo ma ciò che
differenzia i due framework è la diversa implementazione e gestione degli stessi.
Stato
Valori ed
Eventi
JavaBean Class
Component
Validators
Converters
Renderers
Tag XML-like
Tag Handler
Event Listeners
Value & Method
Binding
Backing Bean
Figura 5 - JSF : UI Components
In JSF, i componenti della UI sono definiti attraverso una gerarchia di classi che ne
determinano il comportamento, le funzionalità, la gestione degli eventi e lo stato,
133
Capitolo IV – I framework a confronto
_________________________________________________________________
concetto non presente in Struts, che viene salvato tra una richiesta e l’altra sul server
oppure eventualmente sul client. I componenti che costituiscono una pagina JSF
sono organizzati secondo una struttura ad albero (view) a partire da un nodo radice
(root). Essi sono realizzati attraverso dei JavaBeans che hanno delle proprietà, che
rappresentano i propri attributi, dei metodi, che ne definiscono le funzionalità ed
infine dei listeners per la gestione dei corrispondenti eventi. Inoltre, la loro
visualizzazione può essere eseguita in maniera autonoma oppure delegata ai
renderers. Il vantaggio principale di questa caratteristica è dato dal fatto che è
possibile definire una sola volta il comportamento di un componente ma
associandogli differenti renderers, per la visualizzazione su dispositivi client che
utilizzano linguaggi di markup diversi. Ciò permette alla tecnologia JSF di supportare
lo sviluppo di Web application, utilizzabili con device differenti, quali personal
computer, palmari e cellulari, partendo da componenti comuni ma sfruttando
visualizzazioni diversificate.
Renderer HTML
JavaBean Class
Component
Renderer WML
Figura 6 - JSF : Rendering per device differenti
Nel caso delle semplici pagine JSP, ogni componente viene introdotto mediante
l’utilizzo di un tag corrispondente, nel quale è possibili fissare gli attributi del
componente stesso. L’implementazione JSF – RI fornisce le classi di base dei
componenti ed in un più un renderer kit e la libreria di tag associata, per la
visualizzazione degli stessi, con client HTML. Nulla vieta di realizzare un renderer kit
ed i corrispondenti tag che permettano la visualizzazione dei componenti con un
134
Capitolo IV – I framework a confronto
_________________________________________________________________
linguaggio di markup diverso, quale XML oppure WML. Struts, invece, mette a
disposizione una libreria di tag per i client HTML, ma non fornisce il supporto di
indipendenza dai client, nel senso che non è possibile permette la visualizzazione
dell’applicazione, da un dispositivo diverso da un browser web.
Tag XML-like
Tag Handler
FormBean
Figura 7 - Struts : Elementi UI
Infine, JSF fornisce allo sviluppatore la possibilità di estendere le classi che
implementano i componenti, per realizzarne di propri e personalizzati, caratteristica
assolutamente non presente in Struts. Ad esempio, se si vuole realizzare un form
costituito da più campi di input, che magari dovrà essere utilizzato in più pagine, con
JSF si può realizzare un unico componente e quindi un unico tag da immettere nelle
pagine JSP. La logica ed il comportamento, interni al componente, permetteranno di
trattare i dati come un unico input. Con Struts, sarà necessario introdurre i controlli
separatamente nelle pagine ed utilizzare più tag, uno per ogni campo di input ed
inoltre, si avrà l’onere di raggruppare i dati ottenuti. Un caso tipico può essere quello
relativo ad un componente che permetta all’utente di selezionare una data, ad
esempio quella di nascita. Con JSF, si realizza un unico Custom Component
(DateSelectComponent) ed il relativo Tag Handler, per disporre di un unico tag mediante
il quale inserire l’elemento all’interno della pagina. Quest’ultimo è costituito da tre
drop-down list, relative al giorno, al mese e all’anno, che sono trattate come un unico
controllo della UI. La data selezionata viene gestita automaticamente dal componente
che produce un oggetto java.util.Date, il quale viene immediatamente memorizzato in
una corrispondente proprietà di un backing bean, mediante il value-binding.
Con Struts, è necessario realizzare tre drop-down list separate i cui valori sono
copiati in tre proprietà distinte di un formbean. Sarà compito della action eseguita,
prelevare questi valori e comporli in modo da generare un unico oggetto java.util.Date
da passare alla business-logic.
135
Capitolo IV – I framework a confronto
_________________________________________________________________
DateSelect
Component Class
java.util.Date Object
giorno
mese
anno
FormBean
Backing Bean
java.util.Date Object
JSF
Business Object
Action Struts
Struts
Figura 8 - JSF e Struts : esempio di componente composto
Quanto detto, evidenzia il fatto che JSF sia nettamente orientato alla realizzazione
della View di una Web application, permettendo una flessibilità ed una espandibilità
nettamente superiori a Struts.
5. Events e Listeners
Un aspetto innovativo di JSF rispetto a Struts è l’introduzione del concetto
di evento associato ad un componente. Tale concetto è da sempre presente nelle
applicazioni desktop, in cui su di un controllo dell’interfaccia utente può scatenarsi
136
Capitolo IV – I framework a confronto
_________________________________________________________________
un evento, come la pressione di un bottone oppure il cambiamento del contenuto di
un campo di input. L’applicazione prevede una serie di listeners che intercettano gli
eventi e ne eseguono la gestione, effettuando delle elaborazioni. Tale approccio è da
sempre noto come “event-driven”, ossia pilotato da eventi, nel senso che ogni
computazione eseguita dal software è avviata al verificarsi di un evento su un
controllo dell’interfaccia utente.
In Struts tale concetto non esiste, in quanto l’unico evento che viene considerato tale
è la semplice richiesta HTTP, per cui l’invio dei dati di un form, la pressione di un
bottone, il click su un collegamento ipertestuale, vengono trattati come semplici
richieste HTTP.
Con JSF, il modello “event-driven” è applicato anche nelle Web application, per cui
alla normale gestione delle richieste HTTP, si è aggiunta la particolare gestione degli
eventi. Ciò vuol dire che ogni tipo di azione che l’utente esegue attraverso
l’interfaccia può essere trattata come una normale richiesta oppure gestita attraverso i
listeners associati agli eventi scatenati. Tali listeners possono essere realizzati
attraverso dei metodi dei backing beans, la cui tipica applicazione è la realizzazione
della navigazione tra le pagine, oppure mediante delle classi specifiche, che
implementano delle particolari interfacce del framework.
Il vantaggio sostanziale degli eventi è dettato dal fatto che un evento, scatenato su un
certo componente, può essere gestito anche in modalità “immediata”, senza che la
richiesta HTTP sottostante segua tutto il ciclo di vita previsto da JSF.
Con JavaServer Faces, la navigazione è completamente gestita attraverso il
meccanismo degli eventi di tipo “action”, ossia riferiti alla pressione di un bottone
oppure il click su di un link. Infatti, nel momento in cui si vogliono inviare i dati di
un form oppure si vuole passare ad una nuova pagina attraverso un collegamento
ipertestuale, viene generato un evento di questo tipo che prevede l’esecuzione di un
metodo di un backing bean associato al componente, che eseguirà delle elaborazioni
e restituirà l’outcome per il proseguimento della navigazione. Questo evento può essere
gestito anche creando una classe che implementa l’interfaccia ActionListener , anche se
in tal caso non potrà essere utilizzato per la navigazione ma esclusivamente per
eseguire particolari elaborazioni alla pressione di un pulsante oppure di un link.
137
Capitolo IV – I framework a confronto
_________________________________________________________________
Evento action
Evento action
Backing Bean
Outcome
ActionListener
Figura 9 - JSF : Evento "action"
In Struts, una situazione di questo tipo viene gestita avviando una action così come
in tutti gli altri casi.
pressione
Action
Forward
Figura 10 - Struts : Avvio di una action
E’ comunque da sottolineare che la presenza dell’evento “action” per la gestione
della navigazione non differenzia di molto i due framework, in quanto se da un lato si
avvia l’esecuzione di un metodo di un backing bean, dall’altro c’è l’esecuzione di una
action. La differenza si evidenzia quando la pressione di un pulsante deve
comportare un’elaborazione immediata rimanendo alla medesima pagina (postback).
Concettualmente, ciò è possibile con JSF tenendo conto del fatto che sul server è
residente lo stato di tutti i componenti come se fosse in esecuzione un’applicazione
desktop e quindi la richiesta inviata servirà semplicemente a notificare l’evento da
gestire. Con Struts si esegue una normale action, in quanto l’evento è gestito come
una tipica richiesta HTTP e si forza il concetto di navigazione sulla stessa pagina.
La differenze sostanziali tra una action di Struts ed un ActionListener di JSF possono
essere così riassunte :
-
La action implementa parte della Business-Logic, l’ActionListener rientra nella
User Interface Logic;
-
In una action non si ha l’accesso al componente che intercettato l’evento;
viceversa ciò è possibile con un ActionListener;
138
Capitolo IV – I framework a confronto
_________________________________________________________________
-
La action restituisce sempre il “forward” per la navigazione mentre un
ActionListener non partecipa alla fase di navigazione;
L’altro tipo di evento previsto in JSF è il “value-change”, che viene scatenato nel
momento in cui cambia il contenuto di un componente. Ciò vuol dire che, quando
l’utente modifica il valore immesso in un campo ed invia la richiesta, viene scatenato
l’evento ed in maniera automatica verrà avviato il listener per la sua gestione.
Quest’ultimo può essere realizzato mediante un metodo di un backing bean oppure
attraverso una classe che implementa l’interfaccia ValueChangeListener.
Evento
value-change
Backing Bean
ValueChangeListener
Figura 11 - JSF : Evento "value-change"
In Struts, per realizzare un qualcosa di simile, bisogna avviare una solita action che
abbia la possibilità di confrontare il valore precedente con il valore attuale del
componente ed in caso di differenza gestire l’evento simulato. Tutto ciò avviene in
maniera completamente automatica in JSF, considerando che c’è la gestione dello
stato dei componenti che viene memorizzato fra una richiesta e l’altra.
Ulteriore tipologia di evento prevista in JSF è quella relativa alle fasi che
caratterizzano il ciclo di vita di una richiesta. Infatti, l’inizio e la fine di ciascuna fase
determinano il verificarsi di un corrispondente evento al quale può essere associato
un listener per eseguirne una particolare gestione. In questo modo, si può intervenire
in maniera molto specifica durante la manipolazione di una richiesta, in una qualsiasi
delle fasi. Ovviamente, questa caratteristica non è prevista in Struts, in cui è possibile
intervenire nel ciclo di vita di una richiesta, soltanto prima dell’avvio della sua
gestione e non durante.
139
Capitolo IV – I framework a confronto
_________________________________________________________________
6. Mappatura delle richieste sulla Business-Logic
Uno degli aspetti che differenzia notevolmente Struts e JSF è soprattutto la
modalità con cui tutte le richieste dei client vengono mappate in corrispondenza degli
oggetti della business-logic che dovrà gestirle.
Il framework Struts prevede un forte utilizzo del file di configurazione XML, in
quanto è all’interno di quest’ultimo che viene eseguita l’operazione di “actionmapping”, attraverso la quale si fa corrispondere ad una certa richiesta, pervenuta per
un determinato URL, la corrispondente action da eseguire per la sua gestione. Per
ogni action, viene inoltre specificato il formbean che conterrà i dati su cui essa dovrà
eseguire le elaborazioni. All’arrivo di una richiesta, quindi, grazie al “mapping”
caricato in memoria in fase di start-up, viene popolato il formbean con i dati
trasmessi ed individuata e successivamente avviata la action per la relativa gestione.
L’espandibilità fornita dal framework, prevede che ogni classe che debba gestire una
richiesta, estenda la classe Action oppure una delle sue derivate, così come ogni classe
che definisce un formbean debba derivare dalla classe ActionForm oppure da una delle
classi che la estendono.
formbean
Action 1
struts-config.xml
formbean
Action 2
Richiesta
Action Mapping
formbean
Action N
Controller
Figura 12 - Struts : Mapping delle actions
Con JSF, l’approccio è completamente differente, in quanto vengono definiti i
backing beans, anche noti come managed beans, all’interno del file di configurazione
XML ed ogni richiesta prevede l’esecuzione di uno dei metodi di questi ultimi. Essi
sono associati ai componenti dell’interfaccia utente, nel senso che il valore di un
140
Capitolo IV – I framework a confronto
_________________________________________________________________
componente può corrispondere alla proprietà di un bean, così come l’evento
verificatosi su un componente può comportare l’esecuzione di un metodo del bean
stesso. Tutto ciò è garantito mediante il “value-binding” e “method-binding” facendo
uso dell’Expression Language.
In questo modo, i dati della richiesta vanno a popolare i campi di un backing bean e
le elaborazioni da eseguire su di essi sono implementate all’interno di un metodo di
quest’ultimo. In pratica, i backing bean sono una combinazione tra i formbean e le
action di Struts, non separando operazioni e dati e sono concettualmente simili alle
classi di “code-behind” dei WebForms della tecnologia ASP.Net. La loro gestione è
completamente automatica e gestita in maniera trasparente dal framework, che si
preoccupa di crearne le istanze sulla base dell’ambito di visiblità (scope) che viene
specificato nel file di configurazione.
faces-config.xml
Backing Bean 1
Backing Bean 2
Richiesta
CONTROLLER
Backing Bean N
Figura 13 - JSF : Backing Beans
Sulla base di questa differenza tra i due framework, la business-logic può essere
collocato nell’applicazione in più modi diversi.
Nel caso di Struts, si possono individuare le seguenti possibili soluzioni :
1. si definiscono gli oggetti della business-logic, che utilizzano le classi di
accesso alla base di dati, che sono completamente indipendenti dal
framework adottato. Le action non fanno altro che acquisire i dati dai
141
Capitolo IV – I framework a confronto
_________________________________________________________________
formbean, trasferirli negli oggetti della business-logic ed invocare i metodi su
di essi;
2. gli oggetti della business-logic vengono implementati estendendo la classe
ActionForm e quindi trattati come formbean. In questo modo, le loro
proprietà sono automaticamente popolate dal framework al momento
dell’invio della richiesta ed è poi compito delle action invocare su di essi i
metodi per le elaborazioni;
Action
Action
formbean
Business Object
(formbean)
Business Object
DBAccess Object
DBAccess Object
Figura 14 – Struts : Locazione della Business-Logic
La prima soluzione prevede una marcata indipendenza dagli oggetti della businesslogic rispetto alle classi tipiche del framework, per cui tali oggetti possono essere
utilizzati anche per sviluppare l’applicazione con un framework diverso. La seconda
soluzione ha il vantaggio di ridurre il numero di classi da adottare, in quanto i
formbean diventano gli oggetti della business-logic, ma ha lo svantaggio di rendere
non più portabili tali oggetti tra un framework e l’altro.
142
Capitolo IV – I framework a confronto
_________________________________________________________________
La tecnologia JSF prevede le seguenti soluzioni :
1. i backing beans coincidono perfettamente con gli oggetti della business-logic.
Essi acquisiscono i dati della richiesta nelle loro proprietà ed attraverso i
propri metodi eseguono le elaborazioni su di essi;
2. si definiscono gli oggetti della business-logic in maniera indipendente dal
framework e poi separatamente si introducono i backing beans, i quali non
fanno altro che invocare i metodi dei primi;
Business Object
(Backing Bean)
Backing Bean
Business Object
DBAccess Object
DBAccess Object
Figura 15 - JSF : Locazione della Business-Logic
La prima soluzione, maggiormente adottata, mette in risalto l’enorme potenza del
framework, incapsulando dati ed operazioni , anche se a scapito della riusabilità, in
quanto all’interno dei metodi degli oggetti della business-logic si sfruttano le classi
tipiche del framework. La seconda soluzione favorisce l’utilizzo delle classi della
business-logic con framework diversi, senza necessità di dover riprogettare il
software, ma prevede anche una certa duplicazione e ridondanza, in quanto le
proprietà dei backing beans saranno presumibilmente uguali alle proprietà degli
oggetti della business-logic, così come i loro metodi non faranno nient’altro che
invocare i metodi di questi ultimi.
143
Capitolo IV – I framework a confronto
_________________________________________________________________
Attraverso l’utilizzo dei managed beans, JSF fornisce il supporto per l’Inversion of
Control (IoC), anche noto come Dependency Injection, in quanto le istanze degli oggetti
vengono create automaticamente dal framework quando necessario, senza la
necessità di intervento da parte dello sviluppatore. In un certo senso, anche Struts
fornisce un supporto di questo tipo, istanziando i formbean e le action, ma il
concetto di IoC è molto più ampio, così come viene interpretato in JSF.
7. Conversione
I dati che l’utente immette nei form, che costituiscono l’interfaccia della
Web application, sono generalmente destinati ad essere trasferiti all’interno degli
oggetti della business-logic, in maniera diretta o indiretta, per poi essere soggetti alle
elaborazioni richieste. Facendo riferimento alla fase di immissione dei dati, all’interno
dei campi dell’interfaccia utente, essi sono sempre rappresentati attraverso delle
semplici stringhe per poi essere trasferiti al server attraverso la rete. Le proprietà dei
bean, a cui i valori sono destinati, possono essere di tipo qualsiasi e non
necessariamente di tipo stringa, per cui è richiesta un’operazione di conversione.
Per quanto riguarda questo aspetto, il framework JavaServer Faces è ancora una volta
superiore rispetto a Struts, mettendo a disposizione dei meccanismi allo stesso tempo
potenti e semplicemente espandibili.
Infatti, JSF fornisce in primo luogo un insieme di convertitori per i tipi di dato più
comuni, ai quali sono associati una serie di tag in modo da poter utilizzare ciascun
convertitore all’interno di una pagina JSP, in corrispondenza di un certo
componente. Ogni convertitore viene utilizzato sia nella fase di decoding, per
trasferire il valore del componente nella corrispondente proprietà del backing bean
associato, sia nella fase di encoding per svolgere la funzione inversa. L’operazione di
conversione, quindi, prevede di passare da un valore stringa ad un tipo di dato
specifico nel primo caso oppure, viceversa, da un certo tipo di dato ad una stringa nel
secondo caso.
Struts supporta un meccanismo di conversione molto più semplice, implementato
attraverso le classi del progetto “common-beanutils” che forniscono supporto per i
tipi di dati semplici e non complessi come ad esempio una data, invece supportata da
144
Capitolo IV – I framework a confronto
_________________________________________________________________
JSF. Per questo motivo, si preferisce sempre fare in modo che i formbean, che
ricevono i dati di input, abbiano tutte le proprietà di tipo stringa in modo che non sia
eseguita alcuna conversione a partire dai valori del form. Successivamente, in fase di
trasferimento di tali valori verso gli oggetti della business-logic, si eseguono le
opportune conversioni.
Con JSF, invece, c’è la possibilità di realizzare dei convertitori personalizzati ed i
corrispondenti tag, per tipi di dati non previsti dal framework, che magari possono
far parte dell’applicazione realizzata. Lo sviluppo di un Custom Converter prevede la
realizzazione di una classe che implementa l’interfaccia Converter ed eventualemente,
di un Tag Handler per la definizione di un tag con cui associare il convertitore ad un
componente in un pagina JSP.
Valore
Struts
Common-beanutils
JSF
Converter
formbean
Backing Bean
Punto di estensione
Figura 16 - JSF e Struts : Conversione
8. Validazione
In generale, tutti i sistemi software prevedono un’operazione di validazione,
attraverso la quale valutare se i dati immessi dall’utente siano corretti rispetto a ciò
che ci si attende. In questo modo, è possibili evitare errori di elaborazione, dovuti a
valori non validi, in quanto tale controllo viene eseguito a priori.
Per quanto concerne tale aspetto, in riferimento al confronto tra i due framework in
questione, si può dire che Struts ha delle potenzialità superiori rispetto a JSF, il quale
però fornisce un meccanismo di estensione delle funzionalità di base, molto più
semplice.
145
Capitolo IV – I framework a confronto
_________________________________________________________________
In Struts, le funzionalità di base per la validazione sono integrate all’interno dei
formbean, in quanto la classe ActionForm prevede un metodo validate(), del quale
eseguire l’overriding per potervi immettere il codice che effettui la validazione dei
dati del form stesso.
Action
formbean
validate()
Figura 17 - Struts : Validazione formbean con il metodo validate()
Ovviamente, questo tipo di approccio non può essere adottato per i formbean
dinamici, che non prevedono l’implementazione di una classe. Per questo motivo,
nella maggior parte dei casi, la validazione dei dati è realizzata sfruttando un plug-in
esterno, noto come Validator, che è stato integrato nel framework a partire dalla
versione 1.1. Tale plug-in si basa sull’utilizzo di due file di configurazione XML, i
quali permettono rispettivamente di :
-
dichiarare quali sono i form ed i corrispondenti campi che dovranno essere
soggetti alla validazione e quali saranno le funzioni di validazione da adottare
per ciascuno di essi;
-
definire tali funzioni, dette anche regole di validazione;
Il plug-in Validator mette a disposizione una serie di regole di validazione predefinite
più comuni : dal controllo che il valore di un campo non sia vuoto fino al controllo
che un valore, che dovrebbe rappresentare un indirizzo email oppure il codice di
carta di credito, abbia un formato corretto passando per i semplici controlli per cui
un valore immesso sia di un certo tipo oppure soddisfi un certo pattern. Ovviamente,
146
Capitolo IV – I framework a confronto
_________________________________________________________________
è possibile integrare queste regole, realizzando delle funzioni personalizzate che
permettano di eseguire delle operazioni di validazione non previste dal plug-in.
Action
formbean
Validator
PlugIn
validation-rules.xml
validation.xml
Figura 18 - Struts : Validazione formbean con il plug-in Validator
Il framework JSF, invece, fornisce soltanto tre validatori standard relativi al controllo
che un certo valore rientri in un range oppure che abbia una lunghezza compresa tra
un minimo ed un massimo prefissati. Per poter eseguire delle operazioni di
validazione personalizzate, è possibile utilizzare i metodi dei backing beans oppure
realizzare delle classi che implementano l’interfaccia di base Validator.
Valore
Validator
Backing Bean
Punto di estensione
Figura 19 - JSF : Validazione
Per quanto concerne questo aspetto del confronto, Struts fornisce numerosi
validatori standard ed inoltre,
oltre alla validazione lato server, supporta la
validazione lato client, non prevista in JSF. Infatti, nella libreria HTML è fornito un
147
Capitolo IV – I framework a confronto
_________________________________________________________________
tag che ha la capacità di generare in maniera automatica il codice Javascript di una
qualsiasi regola di validazione.
9. Navigazione
Le applicazioni Web, sviluppate prima dell’introduzione di framework
specifici, hanno sempre previsto la cosiddetta navigazione statica nell’ambito della
quale, per poter passare da una pagina all’altra, è necessario utilizzare i collegamenti
ipertestuali, specificando per ciascuno di essi la pagina di destinazione.
Struts e JavaServer Faces introducono il concetto di navigazione dinamica, in cui la
pagina di destinazione è determinata in seguito ad una elaborazione eseguita dalla
business-logic. Inoltre, in entrambi i framework, la navigazione attraverso le pagine è
specificata all’interno del file di configurazione, per cui si parla di “navigazione
dichiarativa”, anche se utilizzando due modalità differenti.
Il framework JSF prevede tre elementi fondamentali :
-
pagina di origine;
-
outcome;
-
pagina di destinazione;
che vengono definiti attraverso le regole di navigazione (navigation-rules) ed i “casi” di
navigazione (navigation-case). Più precisamente, ciascuna regola di navigazione è
caratterizzata dalla pagina di origine e da una o più pagine di destinazione, verso le
quali proseguire la navigazione sulla base dell’outcome che viene manipolato.
Quest’ultimo può essere specificato direttamente all’interno di un tag di una pagina
JSP, relativamente ad un link oppure ad un bottone, oppure può essere determinato
in seguito all’esecuzione di un metodo di un backing bean.
Nota la pagina di origine, la classe NavigationHandler si fa carico di acquisire l’outcome
prodotto e cercarlo tra i casi di navigazione specificati nella copia in memoria del file
di configurazione. Una volta trovato l’outcome, ad esso corrisponderà la pagina di
destinazione verso la quale redirezionare il flusso dell’applicazione. Tale classe è
assolutamente espandibile, permettendo allo sviluppatore di eseguire delle operazioni
preliminari al proseguimento della navigazione.
148
Capitolo IV – I framework a confronto
_________________________________________________________________
Outcome
Start Page
faces-config.xml
NavigationRule 1
Start Page
NavigationHandler
NavigationCase 1
Outcome 1
Dest Page 1
NavigationCase N
Outcome N
Destination Page
Dest Page N
Figura 20 - JSF : Navigazione
In Struts, la navigazione si basa sul concetto di “forward” che può essere locale
oppure eventualmente globale. Infatti, una volta avviata l’esecuzione del metodo
execute() di una action, quest’ultimo produce in uscita un oggetto ActionForward che
individua appunto un elemento XML di tipo “forward” definito nel file di
configurazione. Tale elemento avrà un nome e la pagina di destinazione verso la
quale proseguire la navigazione. Esso può essere locale, nel senso che può essere
riferito solo ed esclusivamente da una certa action, oppure globale in quanto può
essere condiviso tra più action differenti.
149
Capitolo IV – I framework a confronto
_________________________________________________________________
struts-config.xml
ActionForward
Action 1
CONTROLLER
Forward 1
Dest Page 1
Forward N
Dest Page N
Destination Page
Global Forwards
Forward 1
Dest Page 1
Figura 21 - Struts : Navigazione
10. Expression Language
L’Expression Language è un linguaggio attraverso il quale è possibile fare
riferimento ai JavaBeans previsti dall’applicazione, all’interno dei tag di una pagina
JSP. L’utilizzo di questo linguaggio è previsto in forma nativa nel framework
JavaServer Faces ma non in Struts.
La maggior parte dei tag che caratterizzano le librerie di JSF, in corrispondenza di
specifici attributi, supportano il “value-binding” ed il “method-binding”, attraverso i
quali si può fare riferimento alle proprietà oppure ai metodi dei backing bean. Tale
riferimento viene esplicitato attraverso l’utilizzo dell’Expression Language, facendo
150
Capitolo IV – I framework a confronto
_________________________________________________________________
uso della tipica “dot notation” che, attraverso un punto, separa il nome del bean dalla
proprietà o dal metodo a cui si è interessati.
TAG JSF
Attributo
#{backingBean.proprieta}
Value-binding
BackingBean
proprieta
TAG JSF
metodo
Attributo
#{backingBean.metodo}
Method-binding
Figura 22 - JSF : Value/Method binding con l' EL
Questa potenzialità non è prevista in Struts, se non attraverso l’utilizzo delle librerie
JSTL (JavaServer Pages Standard Tag Library) oppure attraverso un’ estensione
particolare delle librerie proprie del framework.
La prima soluzione prevede di utilizzare i tag appartenenti alle librerie JSTL che sono
completamente indipendenti dal framework. La modalità di utilizzo dell’EL
all’interno di questi tag è la stessa di JSF.
La seconda soluzione prevede di utilizzare le stesse librerie di Struts ma con
l’estensione all’Expression Language. Infatti, le tre librerie di base previste non
supportano tale linguaggio, ma ne sono state create delle versioni “evolute”, con
suffisso “el”, che forniscono le medesime funzionalità delle prime, ma con in più la
possibilità di utilizzare l’Expression Language in corrispondenza dei propri attributi.
E’ comunque da sottolineare che, seppure utilizzando l’EL, con Struts non ci si può
riferire ad un metodo di un bean, in quanto è sempre prevista l’esecuzione di una
action.
151
Capitolo IV – I framework a confronto
_________________________________________________________________
TAG Struts
Attributo
Attributo
proprieta
bean
Struts
Bean
proprieta
TAG JSTL / Struts-EL
Attributo
#{bean.proprieta}
Struts-EL/JSTL
Figura 23 - Struts : Riferimenti ai beans con e senza EL
In relazione a tale aspetto, si può dire che JSF è avvantaggiato rispetto a Struts
perché, mentre il primo fornisce il supporto dell’EL in forma nativa, con il secondo è
necessario l’utilizzo di librerie esterne o estensioni di quelle interne.
11. Eccezioni
Uno degli aspetti che rappresenta un netto vantaggio di Struts rispetto a
JSF, è la gestione delle eccezioni. Infatti, il framework Struts permette di dichiarare,
all’interno del file di configurazione, le eccezioni che potranno essere sollevate
dall’applicazione ed i corrispondenti gestori.
152
Capitolo IV – I framework a confronto
_________________________________________________________________
In particolare, sono previste le due seguenti classi :
ModuleException : permette di definire una eccezione alla quale associare un
-
messaggio di errore prelevato dal Resource Bundle;
ExceptionHandler : permette di gestire una qualsiasi eccezione dichiarata nel
-
file di configurazione;
In pratica, all’interno del file struts-config.xml può essere dichiarata un’eccezione che
tipicamente è del tipo ModuleException oppure una classe che la estende. Inoltre, ad
essa viene associato un gestore che può essere quello di default oppure una classe che
estenda ExceptionHandler. Nel momento in cui, durante l’esecuzione dell’applicazione,
viene sollevata un’eccezione di questo tipo, essa viene intercettata e gestita in maniera
completamente automatica, senza la necessità di blocchi try-catch-finally all’interno del
codice.
Exception
ExceptionHandler
struts-config.xml
Global Exceptions
Exception 1
Error Page 1
Exception N
Error Page N
Error Page
Figura 24 - Struts : Eccezioni dichiarative
Questa potenzialità non è assolutamente prevista in JSF, nell’ambito del quale le
eccezioni devono essere completamente gestite dallo sviluppatore, secondo le
funzionalità offerte dal linguaggio Java.
153
Capitolo IV – I framework a confronto
_________________________________________________________________
BackingBean
metodo
catch (Exception)
Outcome
NavigationHandler
Error Page
Figura 25 - JSF : Eccezioni programmatiche
12. Internazionalizzazione (I18N)
L’internazionalizzazione è una caratteristica comune di JSF e Struts che
viene praticamente gestita allo stesso modo. Infatti, entrambi i framework offrono la
possibilità di definire uno o più Resource Bundle (Message Resource), all’interno dei
quali ci sono i messaggi di testo che devono essere visualizzati nelle pagine
dell’applicazione, in lingue diverse. In questo modo, sulla base della locazione
geografica dell’utente, il sistema riesce ad utilizzare il Resource Bundle corretto,
contenente i messaggi nella lingua adatta. L’accesso al file .properties, contenete i
messaggi, è effettuato allo stesso modo ossia specificando la chiave (key) associata al
messaggio da visualizzare. Il meccanismo può essere schematizzato in questo modo :
-
il Locale (localizzazione geografica dell’utente) permette di individuare il
Resource Bundle da utilizzare;
-
la chiave (key) permette di individuare il messaggio da visualizzare,
nell’ambito del Resource Bundle precedentemente selezionato;
154
Capitolo IV – I framework a confronto
_________________________________________________________________
Key = msg.benvenuto
Message Resources
Resource Bundle IT
Benvenuto !
Resource Bundle EN
Welcome !
Resource Bundle FR
Bienvenu !
Resource Bundle DE
Willkommen !
Locale
Figura 26 - JSF e Struts : Internazionalizzazione
13. Sicurezza
Una delle più importanti garanzie che deve fornire una Web application ai
propri visitatori è la sicurezza nella comunicazione e nello scambio dei dati. In
moltissimi casi, l’applicazione prevede il trasferimento di informazioni sensibili, come
ad esempio il numero di una carta di credito, per le quali si rende necessaria
un’operazione di crittografia. Mediante quest’ultima, è possibile rendere i dati
illeggibili a chiunque li intercetti durante il trasferimento, a meno del destinatario che
ha a propria disposizione la chiave per decrittografarne il contenuto. Il meccanismo
che permette di garantire la sicurezza nelle comunicazioni in rete prevede l’utilizzo
del protocollo SSL (Secure Sochet Layer) ed in particolare del protocollo HTTPS
(HTTP basato su SSL). Per quanto riguarda questo aspetto, i due framework a
confronto sono perfettamente uguali, in quanto non prevedono approcci differenti
per garantire la sicurezza delle pagine delle Web application realizzate. La tecnica
adottata è quella comune a tutte le applicazioni Web implementate in Java e fa uso
delle funzionalità messe a disposizione dal Web Container. La sicurezza, quindi, è
155
Capitolo IV – I framework a confronto
_________________________________________________________________
gestita allo stesso modo, in quanto tale compito è completamente demandato
all’ambiente di esecuzione delle applicazioni, all’interno del quale viene abilitato il
supporto al protocollo SSL. Le Web application prevedono alcune semplici
modifiche al Deployment Descritpor web.xml, all’interno del quale va specificato il
livello di protezione e quali sono le pagine che ne devono essere soggette. In questo
modo, ogni qual volta arriva una richiesta ad una pagina tra quelle suddette, il Web
Container esegue la redirezione sulla porta impostata per il protocollo SSL e la
trasmissione avverrà attraverso l’HTTPS.
Richiesta pagina SSL
Web Application
Web Container
Deployment Descriptor
Connector HTTPS
Pagine SSL
https://WebApplication/...
Figura 27 - JSF e Struts : Sicurezza
14. Configurazione
La configurazione di una Web application, realizzata con Struts oppure JSF,
è uno degli aspetti in cui i due framework sono piuttosto simili. Infatti, entrambi
prevedono la configurazione attraverso un file XML, per quanto concerne tutte le
caratteristiche principali dell’applicazione. Nella fase di start-up, per ciascuno di essi è
prevista un’operazione di lettura e parsing del file, per poter generare una copia in
156
Capitolo IV – I framework a confronto
_________________________________________________________________
memoria delle informazioni di configurazione all’interno di specifiche classi. Ciò che
cambia tra i due framework è soltanto la sintassi XML ed ovviamente le
caratteristiche che possono essere configurate, che dipendono dalle potenzialità che
ha ciascuno dei due.
Classi in memoria
struts-config.xml
ApplicationConfig
Configurazione
ActionConfig
…
…
…
…
parsing
ControllerConfig
faces-config.xml
Application
Configurazione
Lifecycle
…
…
…
…
parsing
NavigationHandler
Figura 28 - JSF e Struts : Configurazione
15. Web Application Layout
Per quanto riguarda la definizione del layout delle pagine che compongono
l’applicazione, la distribuzione di Struts ingloba il framework Tiles. Quest’ultimo
permette di definire la struttura di una pagina JSP, mediante una tecnica di
composizione di più parti separate, i “tiles” appunto, che sono praticamente ulteriori
pagine JSP. In questo modo, è possibile evitare la replicazione dei contenuti e
157
Capitolo IV – I framework a confronto
_________________________________________________________________
facilitare la manutenzione, in quanto la modifica di un gruppo di informazioni va
eseguita una ed una sola volta.
JavaServer Faces non dispone di questo supporto, però è comunque possibile
importare le librerie di Tiles all’interno di un progetto JSF, per poterne sfruttare le
potenzialità.
Potendo utilizzare Tiles con entrambi i framework, sembrerebbe non esserci alcuna
differenza tra essi sotto questo punto di vista. In realtà, essendo Tiles inglobato in
Struts, c’è una perfetta integrazione con la modalità di navigazione prevista da
quest’ultimo. Infatti, se un’applicazione realizzata in Struts prevede l’utilizzo di Tiles,
la classe che si occupa delle gestione delle richieste, non è esattamente la
RequestProcessor ma la più specifica TilesRequestProcessor, contenuta nelle librerie di Tiles.
Questa classe gestisce le richiesta allo stesso modo della precedente e garantisce una
perfetta sinergia con le operazioni di forwarding tra le pagine, così come previsto in
Struts. Inoltre, la sua dichiarazione viene effettuata all’interno del file di
configurazione di Struts come se fosse semplicemente un plug-in.
CONTROLLER
Richiesta
TilesRequestProcessor
Figura 29 - Struts : Integrazione con Tiles
Invece, per poter utilizzare Tiles all’interno di JSF, è necessario dichiararlo nel
Deployment Descriptor attraverso una Servlet, la nota TilesServlet, che viene avviata
immediatamente dopo la FacesServlet. Ciò mette in evidenza che, mentre in Struts le
classi di quest’ultimo e Tiles comunicano internamente al framework, in JSF invece si
ha a che fare con due Servlet indipendenti che scambiano informazioni.
Richiesta
CONTROLLER
TilesServlet
FacesServlet
Figura 30 - JSF : Interazione con la TilesServlet
158
Capitolo IV – I framework a confronto
_________________________________________________________________
16. Migrazione da Struts a JavaServer Faces
In passato, molti sviluppatori hanno scelto Struts per la realizzazione di
Web application, sulla base delle notevoli funzionalità offerte da quest’ultimo e dai
tools di sviluppo forniti dalle case produttrici. Ad oggi, in virtù dell’introduzione del
framework JavaServer Faces, ogni team di sviluppo deve prendere in considerazione
la possibilità di migrare verso questa nuova tecnologia, in riferimento ad
un’applicazione realizzata con Struts. La migrazione è consigliata soprattutto nel caso
in cui, la Web application debba essere ulteriormente potenziata, nel qual caso si può
fare uso degli strumenti innovativi di JSF. Nel caso in cui, debba essere previsto
esclusivamente un processo di manutenzione, si può pensare di mantenere
l’architettura attuale realizzata in Struts.
16.1 Strategie di migrazione
L’architettura fortemente espandibile di JSF mette a disposizione diversi
approcci per poter essere adottata in applicazioni preesistenti. L’approccio
maggiormente conservativo prevede semplicemente di utilizzare i componenti di JSF,
senza alcun altra caratteristica del framework. L’altra possibilità è quella di eseguire
una migrazione incrementale oppure completa.
16.1.1 Components Only
Utilizzare i componenti JSF in un’applicazione realizzata con un altro
framework, fornisce il vantaggio di poter sfruttare componenti eventualmente già
presenti sul mercato, senza la necessità di riscriverli per la propria applicazione. Tutto
ciò comporta un enorme beneficio, soprattutto nel caso in cui si ha a che fare con
un’applicazione di grandi dimensioni e tempi di sviluppo piuttosto stringenti.
Struts mette a disposizione una libreria chiamata Struts-Faces, mediante la quale è
possibile costruire componenti della UI come in JSF, ma continuando ad utilizzare
contemporaneamente le action. Ciò è possibile grazie a particolari listeners JSF, che
159
Capitolo IV – I framework a confronto
_________________________________________________________________
entrano in gioco garantendo l’esecuzione del tipico ciclo di vita di una richiesta
previsto in Struts, in maniera del tutto trasparente rispetto all’esecuzione delle action.
Questo tipo di evoluzione, è possibile in virtù del fatto che sia Struts che JSF sono
implementati mediante l’utilizzo delle proprie Servlets che sono in esecuzione
all’interno della stessa applicazione, in modo da poter condividere le variabili e la
logica applicativa.
Client
Faces
request
Faces
response
FacesServlet
Event
Listeners
Struts
response
Struts
request
ActionServlet
Specialized RequestProcessor
Figura 31 - Migrazione "Components Only"
Ogni Struts request viene inoltrata verso la ActionServlet, la quale non utilizza il
RequestProcessor di default, ma bensì una versione specifica, per poter intercettare
eventuali eventi sui componenti JSF. Se la richiesta non prevede l’intervento di questi
ultimi, viene prodotta una Struts response. Viceversa, se viene scatenato quale evento
su un componente della UI, realizzato con JSF, il controllo passa alla FacesServlet la
quale produrrà una Faces response. E’ ovvio che se a monte, arriva una Faces
request, essa viene gestita direttamente dalla FacesServlet, la quale attraverso i listeners,
passa il controllo al RequestProcessor che avvierà le action Struts per la gestione della
richiesta. Al termine dell’esecuzione, si potrebbe generare una Struts response oppure
una Faces response.
160
Capitolo IV – I framework a confronto
_________________________________________________________________
E’ da mettere in evidenza che, grazie all’utilizzo di componenti JSF, si elimina il
limite di Struts che riguarda la non indipendenza dal dispositivo client. Infatti , è
possibile accedere alla Web application, non necessariamente attraverso un browser
Web ma eventualmente mediante cellulari, palmari o dispositivi di questo genere.
16.1.2 Incremental migration
Quando si ha come obiettivo una migrazione verso l’architettura JSF, il
primo approccio può essere quello incrementale, mediante il quale si possono trarre i
principali vantaggi di JSF ma con un impatto minimo sull’infrastruttura preesistente.
Tale migrazione è utile quando c’è la necessità di introdurre nuove funzionalità
nell’applicazione e contemporaneamente eseguire l’upgrade verso JSF.
La migrazione incrementale prevede come primo passo l’utilizzo di componenti JSF,
così come la component-only, e poi successivamente lo spostamento della businesslogic all’interno dei backing bean. Inoltre, essa può essere eseguita convertendo parte
dell’application logic dopo aver realizzato le pagine basate sui componenti JSF,
oppure eseguire queste operazioni contemporaneamente. Ciò è possibile perché tutto
il codice necessario è all’interno delle stessa applicazione, per cui le parti che
utilizzano JSF e le parti che utilizzano un altro framework, come Struts, condividono
i medesimi oggetti.
Dalla figura seguente, si osserva che gli event-listeners di JSF e le classi della logica
applicativa di un altro framework, in questo caso le action di Struts, condividono le
medesime classi della business-logic e le classi per l’accesso alla base di dati. Tutto ciò
garantisce la convivenza di due framework nell’ambito della medesima applicazione.
161
Capitolo IV – I framework a confronto
_________________________________________________________________
Client
Faces
request
Faces
response
Non-Faces
request
Non-Faces
response
FacesServlet
Non-FacesServlet
Business-Logic
& Data Access
Event
Listeners
Application
Logic
State &
Application
Beans
Web Application
Figura 32 - Migrazione : Incremental migration
Nel caso di una Faces request, la FacesServlet utilizza i listener degli eventi che
sfruttano i beans e gli oggetti della business-logic, oltre che dell’accesso alla base di
dati. Nel caso di un Non-Faces request, per esempio orientata a Struts, ci sarà una
certa logica applicativa, le action nel caso di Struts, che accederà ai medesimi oggetti
suddetti. Si riesce a far convivere porzioni di codice di JSF e di Struts, facendo
riferimento agli stessi oggetti della business-logic.
Di seguito, si evidenziano le corrispondenze che ci sono tra Struts e JSF e quindi
quali sono i compiti da svolgere, nel caso di una migrazione incrementale dall’uno
all’altro.
162
Capitolo IV – I framework a confronto
_________________________________________________________________
Struts
Configuration
Migration Layers
(forwards, actions, etc.)
JavaServer Faces
Configuration
(navigation rules, backing
beans, etc.)
JSP pages
JSP pages
(with Struts tags)
(with JSF component tags)
Application Layer
Application Layer
(actions, action forms,etc.)
Business Layer
(JBs, EJBs, Web services)
Integration Layer
(Data Access Objects)
Data Service
(DataBase, JBs,
EJBs, Web services)
(backing beans,
event listeners, etc.)
Business Layer
(JBs, EJBs, Web services)
Integration Layer
(Data Access Objects)
Data Service
(DataBase, JBs,
EJBs, Web services)
Figura 33 - Migrazione : Migration Layers
Come si può osservare, i livelli contenenti la business-logic e le classi per l’accesso
alle basi di dati, sono perfettamente coincidenti e quindi non c’è bisogno di alcun
accorgimento nel passaggio da un framework all’altro.
163
Capitolo IV – I framework a confronto
_________________________________________________________________
Ciò che ovviamente va rivisto sono :
-
il livello applicativo : in Struts sono previste le action ed i formbean, mentre in
JSF i backing beans ed i listeners;
-
le pagine JSP : Struts fornisce i tag delle proprie librerie, neutre JSF mette a
disposizione i componenti evoluti della UI;
-
configurazione : i file di configurazione XML utilizzano degli elementi
completamente differenti;
16.1.3 Full migration
La migrazione può essere eseguita in maniera completa in una sola volta, al
posto di una migrazione incrementale in più passi successivi. Questo tipo di
soluzione può essere adottata quando i tempi di sviluppo a disposizione sono
piuttosto ampi, in quanto deve essere rivista la completa architettura
dell’applicazione. Dal punto di vista concettuale, essa è simile alla migrazione
incrementale, considerando i livelli da modificare o meno, passando da Struts a JSF.
La differenza sostanziale sta nel fatto che non è necessario utilizzare una libreria di
integrazione, in quando il vecchio framework viene completamente sostituito.
164
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Capitolo V – Case Study : Analisi e Progettazione
1. Introduzione
La presentazione dei due principali framework, quali Struts e JavaServer
Faces, utilizzati per la realizzazione di Web application ha come obiettivo principale
la possibilità di poterne effettuare un confronto. Una volta evidenziate le potenzialità
dell’uno e dell’altro, si rende necessario lo sviluppo di un’applicazione con ciascuno
di essi, in modo da individuare pregi e difetti di entrambi e vantaggi o svantaggi
dell’uno rispetto all’altro. Tale confronto è relativo a tutti gli aspetti che riguardano la
realizzazione di una Web application, con strumenti che si basano sul pattern MVC,
quali appunto i framework presi in considerazione.
In questa sede, è stata realizzata un’applicazione Web che permetta agli utilizzatori di
usufruire di contenuti audio, quali brani musicali in formato MP3 (MPEG Layer 3),
mettendo a disposizione degli utenti e dell’amministratore del sistema una serie di
funzionalità definite dalle specifiche assegnate.
La Web application è stata realizzata con l’utilizzo di entrambi i framework,
usufruendo , lì dove possibile, di tutte le potenzialità di ciascuno di essi.
Le fasi di sviluppo hanno seguito il tipico ciclo di vita del software secondo il
modello “a cascata”, Waterfall Model, e possono essere riassunte di seguito :
-
studio di fattibilità;
-
analisi e specifica dei requisiti;
-
progettazione;
-
codifica ed implementazione;
-
testing;
-
messa in esercizio;
-
manutenzione;
Lo studio di fattibilità, in questo caso, è stato immediatamente superato, in quanto
non c’erano da fare considerazioni riguardo le possibili soluzioni da adottare, le
165
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
risorse finanziarie ed umane a disposizione, tenendo conto che sono stati fissati a
priori gli strumenti da utilizzare.
L’Analisi e la specifica dei requisiti ha previsto la realizzazione del Documento di
Specifica dei Requisiti Software (SRS – Software Requirements Specification),
elencando tutte le funzionalità fornite dal sistema software sia all’utente che
all’amministratore e considerando per ciascuna di esse, una breve descrizione, gli
input previsti, le elaborazioni eseguite ed i possibili output prodotti.
Nella fase di progettazione, sono stati realizzati i principali diagrammi UML (Unified
Modelling Language) previsti per lo sviluppo, quali :
-
Class Diagram;
-
Use Case Diagram;
-
Sequence Diagram;
-
Activity Diagram;
-
Statechart Diagram;
Ad essi, vanno poi aggiunti il Conceptual Data Model ed il Physical Data Model, per
la descrizione concettuale e fisica della base di dati utilizzata dalla Web application.
Lo sviluppo ha poi previsto due distinte fasi di codifica, realizzando l’applicazione
con entrambi i framework. Facendo riferimento alla struttura del Model prevista dal
pattern MVC, il sottolivello di Data Access è stato realizzato separatamente dagli altri
e le classi che ne sono scaturite, sono state utilizzate per entrambe le
implementazioni. Per quanto concerne i sottolivelli superiori, Business-Logic e
External Interface, si è preferita una modalità di “fusione”, più legata a JavaServer
Faces che non a Struts.
La fase di testing ha permesso la correzione di errori e problemi rilevati durante il
funzionamento del software.
Infine, non sono state previste delle vere e proprie fasi di messa in esercizio e
manutenzione.
Lo strumento software di tipo CASE, che è stato utilizzato per la realizzazione di
tutti i diagrammi della fase di progettazione, è il noto Sybase Power Designer.
166
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
2. Requisiti
Il case study (caso di studio) preso in esame, prevede lo sviluppo di una
Web application che permette all’utenza in generale, di usufruire di contenuti audio,
quali brani musicali in formato MP3 (MPEG Layer 3).
Gli utilizzatori possono avere permessi di accesso diversi e quindi funzionalità
differenziate, sulla base della distinzione dei seguenti ruoli :
-
utente;
-
amministratore;
Per ciascuno di essi, le funzionalità accessibili nell’applicazione sono descritte di
seguito.
Utente :
-
registrazione “base” per l’ascolto in streaming dei brani musicali e la gestione
di playlist personalizzate;
-
registrazione “estesa” che permetta l’acquisto dei brani musicali e la
possibilità di eseguirne il download, oltre alle funzionalità di base;
-
acquisto e successive ricariche di una scheda prepagata “virtuale”, mediante
pagamento con carta di credito, che permetta l’acquisto dei brani musicali;
-
accesso all’archivio musicale, con possibilità di fissare diversi criteri di ricerca
dei brani desiderati e di visionarne le informazioni, per poterne eseguire
l’ascolto, l’acquisto ed il download;
-
gestione di una o più playlist, con la possibilità di ascolto, nonchè di
aggiungere ed eliminare da ciascuna di esse dei brani musicali;
-
gestione dei propri dati personali per un eventuale aggiornamento;
-
richiesta di una mail, contenente username e password di accesso, in caso di
dimenticanze;
-
operazioni di login e logout;
167
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore :
-
gestione completa dell’archivio musicale, con la possibilità di inserire,
modificare e cancellare i brani, usufruendo della funzionalità automatica del
sistema di garantire coerenza tra i tag ID3v1 degli stessi e le informazioni
immesse nella base di dati;
-
accesso all’archivio musicale, con possibilità di fissare diversi criteri di ricerca
dei brani desiderati e di visionarne le informazioni, per poterne eseguire
l’ascolto;
-
gestione degli utenti registrati, con la possibilità di visionarne i dati ed
eseguire le operazioni di cancellazione e sblocco, qualora un utente abbia
commesso più di due tentativi errati di accesso al sistema;
-
gestione dei propri dati di accesso per un eventuale aggiornamento;
-
operazioni di login e logout;
Sulla base di tali requisiti è stato redatto il Documento di Specifica dei Requisiti
Software (SRS), di fondamentale importanza per le fasi successive di sviluppo.
3. Progettazione
La fase di progettazione ha previsto la realizzazione dei principali
diagrammi UML, in relazione soprattutto all’analisi del software e non tanto alla sua
corrispondente implementazione. Essi costituiscono un’astrazione di alto livello del
sistema e sono completamente indipendenti da quelli che possono essere gli
strumenti utilizzati nella codifica.
3.1 Use Case Diagrams
I diagrammi dei casi d’uso (Use Case Diagrams) costituiscono uno
strumento utile per catturare il comportamento esterno del sistema da sviluppare,
senza dover specificare come tale comportamento debba essere realizzato; il sistema
è visto come una scatola nera (black-box). Essi forniscono una descrizione dei
168
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
“modi” in cui il sistema potrà essere utilizzato, ossia ciò che l’utente può fare su di
esso e come quest’ultimo risponde alle sollecitazioni. La realizzazione dei diagrammi
ha previsto un approccio top-down, partendo dallo scenario di carattere generale, in
cui le modalità d’uso logicamente correlate sono accorpate, fino ad una
decomposizione in cui sono descritti i casi di utilizzo non ulteriormente
scomponibili.
3.1.1 Generale
Facendo riferimento ai requisiti assegnati, è stato definito un Use Case
Diagram Generale, che si pone al livello di astrazione più elevato del sistema,
mettendo in evidenza tutte quelle che sono le modalità di utilizzo dello stesso, da
parte dell’utente e dell’amministratore. Questi ultimi rappresentano gli attori che
possono accedere alle funzionalità offerte dal sistema, di cui alcune sono condivise
ossia accessibili da entrambi, mentre altre sono prerogativa esclusiva di uno dei due
ruoli.
Verifica Copertura Carta Credito
<<include>>
Registrazione
Gestione Scheda Prepagata
Gestione Dati Personali
Amministratore
Login Sistema
Utente
Logout Sistema
Azioni su brani MP3
Gestione Utenti
Gestione Archivio brani MP3
Figura 1 - Use Case Diagram Generale
169
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
A partire da questo diagramma, è possibile effettuare una decomposizione scendendo
ad un livello di astrazione minore, in cui si prendono in considerazione nel dettaglio
le modalità di utilizzo del sistema.
In particolare, le modalità accessibili esclusivamente dall’utente sono le seguenti :
-
Gestione Scheda Prepagata;
-
Registrazione;
-
Azioni su brani MP3;
3.1.2 Gestione Scheda Prepagata
La modalità di “Gestione Scheda Prepagata” è relativa a tutte le azioni che
l’utente può eseguire in relazione alla scheda prepagata, ossia l’acquisto, la ricarica e la
visualizzazione delle informazioni.
Acquisto Scheda Prepagata
<<include>>
Verifica Copertura Carta Credito
<<extend>>
Ricarica Scheda Prepagata
Utente
Visualizzazione Informazioni Scheda
Figura 2 - Use Case Diagram Gestione Scheda Prepagata
170
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.1.3 Registrazione
La modalità di “Registrazione” può essere considerata atomica e non
ulteriormente decomponibile, facendo riferimento alla procedura eseguita dall’utente
per registrarsi ed usufruire dei servizi della Web application.
3.1.4 Azioni su Brani
Infine, la modalità delle “Azioni su brani MP3” è da considerarsi la più
complessa, in quanto al suo interno prevede tutte le possibili azioni che l’utente può
eseguire all’interno dell’applicazione sui contenuti audio offerti. In particolare, sono
da evidenziare le opportunità di visualizzare le informazioni di un brano, l’ascolto in
streaming di quest’ultimo, il relativo acquisto e download, nonché la visualizzazione
dell’elenco dei brani disponibili per genere oppure in base a dei criteri di ricerca
prefissati. E’ prevista inoltre la modalità “Gestione Playlist”, che non può essere
considerata atomica ma che è possibile ulteriormente decomporre scendendo ad un
livello di astrazione molto più basso.
Acquisto/Download brano MP3
<<include>>
Ascolto brano MP3
<<include>>
Visualizzazione Informazioni brano MP3
Utente
Ricerca brani MP3
<<include>>
Gestione Playlist
<<extend>>
Visualizzazione brani MP3
Figura 3 - Use Case Diagram Azioni su Brani MP3
171
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.1.5 Gestione Playlist
Per quanto riguarda la modalità “Gestione Playlist”, essa comprende tutte
le azioni che l’utente può eseguire sulle playlist, in particolare :
-
creazione di una nuova playlist specificandone il nome;
-
visualizzazione dell’elenco delle playlist create in precedenza dall’utente;
-
visualizzazione dei brani MP3 contenuti in una specifica playlist;
-
azioni di visualizzazione e ricerca dei brani all’interno dell’archivio, con la
possibilità di aggiungere uno o più di essi all’interno di una playlist specificata;
-
possibilità di rimuovere uno o più brani da una playlist;
-
ascolto della playlist;
-
cancellazione di uno o più playlist;
Sulla base dei suddetti modi d’uso, lo Use Case Diagram assume una forma
abbastanza complessa ed ampia.
Osservandone la struttura, si evidenzia la presenza di due scenari distinti associati alle
modalità d’uso di cancellazione di una playlist e di inserimento di un brano MP3. Nel
primo caso, è possibile cancellare una o più playlist selezionandole dall’elenco,
oppure visualizzare l’elenco dei brani di una playlist e richiedere la cancellazione di
quest’ultima. Nel secondo caso, è possibile inserire uno o più brani MP3
selezionandoli da un elenco, visualizzato al termine di una ricerca, oppure inserire un
singolo brano dalla schermata di visualizzazione delle informazioni corrispondenti.
Secondo la sintassi UML, entrambi i casi d’uso “includono” le modalità di utilizzo
che danno luogo ai due scenari suddetti.
172
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Ha due scenari alternativi, in
base alla visualizzazione di più
playlist o della singola playlist
Visualizzazione Elenco Playlist
Creazione Playlist
<<include>>
Cancellazione Playlist
Ricerca brani MP3
<<extend>>
Ascolto Playlist
Visualizzazione brani MP3
<<include>>
<<include>>
<<include>>
Utente
Inserimento brano MP3 Playlist
Visualizzazione brani MP3 Playlist
<<include>>
<<include>>
<<include>>
Cancellazione brano MP3 Playlist
Ha due scenari alternativi, in
base alla visualizzazione di
più brani o del singolo brano
<<include>>
Visualizzazione Informazioni brano MP3
Figura 4 - Use Case Diagram Gestione Playlist
3.1.6 Gestione Utenti
Considerando nuovamente il diagramma dei casi d’uso Generale, si evince
che ci sono le modalità “Gestione Utenti” e “Gestione Archivio brano MP3” che
sono accessibili solo ed esclusivamente dall’amministratore.
173
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
In particolare, “Gestione Utenti” comprende alcune azioni basilari che possono
essere eseguite sugli utenti registrati, in particolare la visualizzazione di un elenco di
questi ultimi, la cancellazione, la visualizzazione dei dati anagrafici di un singolo
utente e l’operazione di sblocco, qualora l’utente abbia commesso due tentativi errati
consecutivi di accesso al sistema e sia stato bloccato.
Visualizzazione Dati Anagrafici Utente
<<include>>
Sblocco Utente
<<include>>
Cancellazione Utente
Ha due scenari alternativi, in
base alla visualizzazione di più
utenti o del singolo utente
<<include>>
Amministratore
<<include>>
Visualizzazione Utenti
Figura 5 - Use Case Diagram Gestione Utenti
3.1.7 Gestione Archivio Brani
La modalità d’uso più complessa è certamente la “Gestione Archivio Brani
MP3”, nell’ambito della quale, l’amministratore esegue tutte le operazioni di gestione
dell’archivio del sistema contenente i brani in formato MP3. In particolare, le
operazioni possibili sono le seguenti :
-
visualizzazione dei brani in base ad un genere oppure sulla base di criteri di
ricerca opportunamente fissati;
-
visualizzazione e modifica delle informazioni di un brano;
174
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
-
inserimento di un nuovo brano MP3 in archivio con l’upload del file MP3
associato;
-
cancellazione di uno o più brani dall’archivio;
-
ascolto di un singolo brano MP3;
Visualizzazione Informazioni brano MP3
<<include>>
<<include>>
Ascolto brano MP3
Ha due scenari alternativi, in
base alla visualizzazione di
più brani o del singolo brano
<<include>>
Cancellazione brano MP3
<<include>>
Amministratore
Visualizzazione brani MP3
<<include>>
Inserimento brano MP3
<<extend>>
<<include>>
Ricerca brani MP3
Modifica Informazioni brano MP3
Figura 6 - Use Case Diagram Gestione Archivio Brani MP3
175
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.1.8 Casi d’uso comuni : Login, Logout, Gestione Dati Personali
Infine, le modalità di utilizzo del sistema che sono comuni all’utente ed
all’amministratore, riguardano il “Login Sistema” ed il “Logout Sistema” che
possono essere considerate atomiche e la “Gestione Dati Personali” che comprende
le operazioni di gestione dei propri dati di registrazione e di accesso per entrambi i
ruoli. In particolare, l’amministratore ha la possibilità di modificare esclusivamente la
propria Password, non essendo registrati per quest’ultimo altri dati nel database. Per
quanto riguarda l’utente, il tutto dipende dal tipo di registrazione che ha effettuato in
precedenza : nel caso di registrazione “base” può eseguire le stesse azioni
dell’amministratore, viceversa nel caso di registrazione “estesa”, essendo stati
registrati anche i dati anagrafici, ha ovviamente la possibilità di modificarli. Un modo
di utilizzo ulteriore disponibile soltanto all’utente, riguarda la possibilità di richiedere
una mail contenente Username e Password di accesso in caso di dimenticanza.
Modifica Username/Password
<<extend>>
Amministratore
Utente
Modifica Dati Anagrafici
Richiesta Username/Password
Figura 7 - Use Case Diagram Gestione Dati Personali
176
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.2 Class Diagram
Mediante il Class Diagram è possibile definire tutte quelle che sono le entità
caratteristiche del sistema software e le relazioni che ci sono tra di esse. Ciascuna
entità è ovviamente modellabile attraverso il concetto di classe, che ne definisce le
caratteristiche (i dati) ed il comportamento (le operazioni). Ovviamente, anche il
Class Diagram può essere realizzato a diversi livelli di astrazione, passando da un
livello elevato, definito di seguito, ad un livello più basso e strettamente legato alla
fase di implementazione e quindi relazionato al framework ed al linguaggio utilizzato.
Attraverso questo diagramma è possibile modellare la vista statica del sistema,
tenendo anche conto di quelle che sono le funzionalità offerte da quest’ultimo e rese
disponibili attraverso le entità che lo compongono.
Sulla base delle specifiche definite per l’applicazione, il sistema prevede le seguenti
entità e le relative classi che le modellano :
-
Ruolo : definisce un generico utilizzatore del sistema, da distinguere tra utente
ed amministratore;
-
Utente : generico utente registrato che accede al sistema;
-
Amministratore : amministratore del sistema;
-
Accesso : classe astratta che contiene le informazioni relative all’accesso al
sistema da parte di un utilizzatore qualsiasi;
-
AccessoUtente : informazioni di accesso di un utente;
-
AccessoAmministratore : informazioni di accesso dell’amministratore;
-
CartaCredito : contiene le informazioni della carta di credito con cui l’utente
può acquistare una scheda prepagata;
-
SchedaPrepagata : scheda attraverso la quale l’utente può acquistare e scaricare i
brani MP3;
-
Ricarica : singola operazione di ricarica della scheda;
-
BranoMP3 : contiene le informazioni relative ad un singolo brano MP3
presente nell’archivio;
-
FileMP3 : rappresenta il file MP3 fisico associato ad un certo brano;
-
Download : generica operazione di download di un brano;
-
Playlist : definisce una playlist creata da uno specifico utente;
177
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Il diagramma definito di seguito si pone ad un livello di astrazione intermedio,
nell’ambito del quale i membri di ciascuna classe (campi e metodi), fanno riferimento
al linguaggio utilizzato nell’implementazione, ossia il Java. Ovviamente, astraendosi
da quest’ultimo, è facile osservare che la struttura del sistema che ne scaturisce è
completamente indipendente dall’implementazione.
In riferimento alle dipendenze che ci sono tra le varie classi, si possono fare le
seguenti osservazioni :
-
le
classi
AccessoUtente
ed
AccessoAmministratore
costituiscono
una
specializzazione della classe Accesso, più da un punto di vista concettuale che
pratico;
-
la classe Ruolo generalizza le classi Utente ed Amministratore, in quanto queste
ultime definiscono un particolare tipo di utilizzatore del sistema, l’uno
diverso dall’altro ma con alcune caratteristiche comuni;
-
la classe Ricarica è di tipo associativo, in quanto l’Utente è legato alla
SchedaPrepagata, non soltanto sulla base di un’operazione di acquisto ma anche
di ricarica;
-
la classe Download è di tipo associativo, nell’ambito della relazione che c’è tra
Utente e BranoMP3;
-
tra Playlist e BranoMP3 c’è un legame di tipo “aggregation”, tenendo conto
che una playlist è costituita da uno o più brani, ma che comunque eliminando
una playlist (il “tutto”) non elimino i brani dall’archivio (le “parti”),
differentemente da quanto accade in una “composition”;
Le altre tipologie di relazioni previste sono autoesplicative, in quanto esprimono il
legame tra un’entità e le altre, sulla base delle specifiche e delle funzionalità del
sistema. Infine, alle classi suddette sono associate, per ciascuna di esse, le
corrispondenti classi per l’accesso alla base di dati per garantire la permanenza delle
informazioni.
178
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Accesso
#
#
#
#
#
#
{abstract}
#
#
#
#
#
dataOraLogin
dataOraLogout
loginValido
tentativo
indirizzoIP
:
:
:
:
:
java.util.Date
java.util.Date
boolean
byte
java.lang.String
<<Override>>
<<Override>>
<<Override>>
<<Override>>
<<Override>>
<<Override>>
# inserisci () : Accesso
# aggiorna () : Accesso
# leggi ()
: Accesso
login ()
: Ruolo
logout ()
: void
modificaUserNamePassword () : Ruolo
blocca ()
: void
sblocca ()
: void
controlloBlocco ()
: Ruolo
1..1
<<extends>>
0..*
AccessoAmministratore
<<extends>>
<<extends>>
# <<Override>> inserisci () : Accesso
# <<Override>> aggiorna () : Accesso
# <<Override>> leggi ()
: Accesso
AccessoUtente
CartaCredito
# <<Override>> inserisci () : Accesso
# <<Override>> aggiorna () : Accesso
# <<Override>> leggi ()
: Accesso
-
0..*
tipo
numero
codiceSegreto
dataScadenza
:
:
:
:
java.lang.String
java.lang.String
java.lang.String
java.util.Date
Ruolo
+ verificaCopertura () : boolean
0..*
1..1
1..1
Utente
+
+
+
+
+
+
#
#
#
#
#
#
nome
cognome
indirizzo
citta
provincia
CAP
stato
telefono
dataNascita
sesso
email
dataOraRegistrazione
acquistoMP3
<<Override>>
<<Override>>
<<Override>>
<<Override>>
<<Override>>
<<Override>>
:
:
:
:
:
:
:
:
:
:
:
:
:
<<extends>>
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.util.Date
char
java.lang.String
java.util.Date
boolean
registrazione ()
elimina ()
modificaDatiAnagrafici ()
visualizzaElencoUtenti ()
visualizzaDatiAnagrafici ()
richiediUserNamePassword ()
login ()
logout ()
modificaUserNamePassword ()
blocca ()
sblocca ()
controlloBlocco ()
#
#
#
#
userName
password
bloccato
loggedIn
:
:
:
:
java.lang.String
java.lang.String
boolean
boolean
#
#
#
#
#
#
login ()
: Ruolo
logout ()
: void
modificaUserNamePassword () : Ruolo
blocca ()
: void
sblocca ()
: void
controlloBlocco ()
: Ruolo
SchedaPrepagata
- importoResiduo : float
- dataOraAcquisto : java.util.Date
- dataScadenza
: java.util.Date
1..1
0..1
Ricarica
:
:
:
:
:
:
:
:
:
:
:
:
Utente
void
Utente
java.util.List
Utente
void
Ruolo
void
Ruolo
void
void
Ruolo
- importo : float
- dataOra : java.util.Date
1..1
+
+
+
+
+
+
+
ricarica ()
acquista ()
elimina ()
visualizzaInfo ()
controlloScadenza ()
controlloImportoResiduo ()
aggiornaImportoResiduo ()
:
:
:
:
:
:
:
SchedaPrepagata
SchedaPrepagata
void
SchedaPrepagata
boolean
boolean
SchedaPrepagata
+ esegui () : Ricarica
0..*
Download
- dataOrtaAcquisto : java.util.Date
+ inserisci () : Download
0..*
Playlist
0..*
- nome
: java.lang.String
- dataOraCreazione : java.util.Date
BranoMP3
-
genere
titolo
autore
album
durata
costo
dimensione
nomeFileMP3
:
:
:
:
:
:
:
:
java.lang.String
java.lang.String
java.lang.String
java.lang.String
java.sql.Time
float
long
java.lang.String
+
+
+
+
+
+
+
+
+
inserisci ()
:
elimina ()
:
ascolta ()
:
acquista ()
:
modificaInfo ()
:
visualizzaInfo ()
:
ricerca ()
:
visualizzaElencoBraniMP3 () :
avviaDownload ()
:
BranoMP3
void
FileMP3
BranoMP3
BranoMP3
BranoMP3
java.util.List
java.util.List
void
+
+
+
+
+
+
+
+
0..*
0..*
inserisciBrano ()
:
eliminaBrano ()
:
ascolta ()
:
elimina ()
:
crea ()
:
visualizzaElencoPlaylist ()
:
visualizzaElencoBraniMP3Playlist () :
visualizzaInfo ()
:
void
void
FileMP3
void
Playlist
java.util.List
java.util.List
Playlist
FileMP3
1..1
1..1
-
nomeFile
filePath
dimensione
tagTitolo
tagAutore
tagAlbum
:
:
:
:
:
:
java.lang.String
java.lang.String
long
java.lang.String
java.lang.String
java.lang.String
+
+
+
+
+
+
leggiT ag ()
: T ag
aggiornaT ag () : FileMP3
riproduci ()
: void
upload ()
: FileMP3
download ()
: FileMP3
elimina ()
: void
Figura 8 - Class Diagram
179
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3 Activity Diagrams – Sequence Diagrams
Facendo riferimento a quelle che sono le funzionalità offerte dal sistema e
le modalità di utilizzo di quest’ultimo, attraverso gli Activity Diagrams è possibile
modellare le azioni necessarie per compiere un’attività ed il flusso di controllo tra di
esse. Ciascuna “activity” rappresenta un’azione che viene eseguita dal sistema oppure
dall’utilizzatore e può essere atomica oppure scomposta in più “action” elementari.
Nella gestione del flusso di controllo, è possibile definire esecuzioni parallele di
operazioni e la loro sincronizzazione, nonché esecuzioni condizionali. Inoltre,
attraverso lo strumento dell’ “object flow” è possibile specificare quali sono gli
oggetti del sistema che entrano in gioco per ciascuna azione eseguita e quale sia il
loro stato.
Invece, attraverso i Sequence Diagrams è possibile descrivere la vista dinamica del
sistema, enfatizzando le interazioni dovute allo scambio di messaggi tra gli oggetti e il
loro ordinamento temporale. Ciascun diagramma evidenzia il modo in cui uno
scenario, ossia uno specifico percorso in un caso d’uso, viene risolto dalla
collaborazione tra un insieme di oggetti. Generalmente, però, al posto di realizzare
un diagramma per ciascuno scenario, si preferisce definire un unico diagramma
all’interno del quale vengono descritte le situazioni alternative, facendo uso dei
numeri di sequenza sui messaggi.
E’ da osservare che nell’ambito dei Sequence Diagrams sono previsti degli oggetti di
tipo “Interfaccia”, che definiscono le parti del sistema che interagiscono con l’utente,
ossia la cosiddetta UI (User Interface). In questa fase, non viene specificata la
tipologia di interfaccia utente, in modo da poter sfruttare i diagrammi realizzati anche
con implementazioni diverse. E’ ovvio che, nel caso di una Web application,
l’interfaccia utente sia caratterizzata da pagine Web e dai relativi form che le
compongono.
E’ stato definito un Activity Diagram di carattere generale, che si pone ad un elevato
livello di astrazione e che descrive tutte le possibili azioni ed il relativo flusso, che
possono essere eseguite da un utente non registrato, da un utente registrato ed
ovviamente dall’amministratore.
180
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
[Utente registrato - password
dimenticata]
[Utente non registrato]
Registrazione
Richiedi Password
[Utente registrato oppure
Amministratore - login]
Inserimento Username e Password
[Non prevede
acquisto/download di brani
MP3]
[Prevede acquisto/download
di brani MP3]
Acquisto Scheda Prepagata
[1° errore - Password errata
oppure Ruolo già loggato]
[Username e Password corretti]
Verifica copertura Carta di Credito
[2° errore - Password errata]
Utente/Amministratore bloccato
[Carta di Credito scoperta]
[Carta di Credito coperta]
Login Sistema
Richiesta Servizio
Attività comuni a
Utente e
Amministratore
Gestione Dati Personali
[Amministratore]
[Utente]
Ascolto brani MP3
Logout Sistema
Visualizzazione/Ricerca brani MP3
Attività distinte fra
Utente e
Amministratore
Gestione Scheda Prepagata
Acquisto/Download brani MP3
Gestione Archivio brani MP3
Gestione Playlist
Gestione Utenti
Figura 9 - Activity Diagram Generale
A partire da esso, è possibile scendere ad un livello di dettaglio maggiore,
specificando la sequenza delle azioni per ogni funzionalità del sistema.
181
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.1 Login
Per quanto riguarda il Login dell’utente e dell’amministratore, le azioni da
eseguire sono praticamente le stesse a meno degli oggetti che entrano in gioco.
Una volta inseriti Username e Password, il sistema ne effettua il controllo della
correttezza, valutando in primo luogo se lo Username esiste e successivamente
verificando la validità della Password. Ovviamente, a colui che tenta di accedere,
viene sempre dato un messaggio generico di errore, senza mai specificare quale dei
due parametri sia errato.
Per evitare tentativi di accesso continuamente errati, magari eseguiti non
effettivamente dalla persona titolare dell’account, il sistema blocca l’utilizzatore dopo
due tentativi di accesso consecutivi errati. Tale blocco può essere rimosso
esclusivamente contattando l’amministratore del sistema, che ha i diritti di accesso
alla gestione degli utenti.
Ovviamente, nel caso in cui Username e Password siano corretti, si valuta comunque
se è attivo un blocco causato da tentativi errati precedenti ; nel caso di login
consentito, si esegue l’aggiornamento delle informazioni di accesso.
La monitorizzazione e registrazione degli accessi, validi o non validi, relativi agli
utilizzatori della Web application, può essere considerato uno strumento mediante il
quale sia possibile eseguire delle statistiche o comunque ricercare eventuali frodi e
tentativi di accesso non legittimi al sistema.
Nell’ambito del Sequence Diagram, è possibile osservare lo scenario di “Username
errata” e quello di “Username corretta”, nell’ambito del quale si possono verificare le
seguenti situazioni distinte :
-
Password errata al 1° tentativo;
-
Password errata al 2° tentativo che comporta il blocco dell’utilizzatore;
-
Password corretta ma l’utilizzatore è bloccato;
-
Utilizzatore già loggato;
-
Login consentito;
182
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Inserimento Username e Password
:Utente
[letto] : 1
Controllo Username e Password
[Username corretta 1° tentativo]
[Username errata]
[Username corretta 2° tentativo]
:AccessoUtente
[creato]
[1° errore - Password errata oppure Utente già loggato]
[Username e Password corretti]
:Utente
[letto] : 2
Controllo blocco
[Utente bloccato]
[Utente non bloccato]
[2° errore - Password errata]
Login Sistema
:AccessoUtente
[aggiornato]
Visualizzazione Menu Utente
Utente/Amministratore bloccato
Aggiornamento del numero di
tentativi errati di accesso
:Utente
[bloccato]
Figura 10 - Activity Diagram Login Utente
183
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Sistema
Inserimento Username e Password
:Amministratore
[letto] : 1
Controllo Username e Password
[Username corretta 1° tentativo]
[Username errata]
[Username corretta 2° tentativo]
:AccessoAmministratore
[creato]
[1° errore - Password errata oppure Amministratore già loggato]
[Username e Password corretti]
:Amministratore
[letto] : 2
Controllo blocco
[Amministratore bloccato]
[Amministratore non
bloccato]
[2° errore - Password errata]
Login Sistema
:AccessoAmministratore
[aggiornato]
Visualizzazione Menu Amministratore
Utente/Amministratore bloccato
Aggiornamento del
numero di tentativi errati
di accesso
:Amministratore
[bloccato]
Figura 11 - Activity Diagram Login Amministratore
184
Utente
2: create
10.4.1: noti fi ca Utente gi à l oggato
10.3.3.1.1: utente bl occato : i m pedi to l 'accesso
10.2.5: noti fi ca bl occo utente
10.1.1: segnal azi one errore
9.1.1: segnal azi one errore
Scenari o 1 :
Usernam e errata
5: esegui l ogi n
4: i nseri m ento Usernam e e Password
3: ri chi esta i nseri m ento Usernam e e Password
1: ri chi esta di l ogi n
Interfacci a Hom e
Scenari o 2 :
Usernam e corretta
9.1: err: Usernam e errata
7: l ogi n( )
6: create
:Utente
17: destroy
16: i nseri m ento esegui to
Sequenza azi oni com uni a tutti gl i
scenari , per l 'aggi ornam ento del l e
i nform azi oni di accesso
8: l eggi ( )
:AccessoUtente
9: cari ca dati
10.3.3.2.1: create
10.3.3: cari ca dati
10.3.2: l eggi ( )
10.2.3: aggi ornam ento esegui to
10.2.2: scri vi ( )
9.2.1.1: i ni zi al i zzazi one esegui ta
9.2.1: create
15: destroy
14: i nseri m ento esegui to
11: i nseri sci ( )
10.3.3.2.2: vi sual i zzazi one m enu Utente
10.3.3.2: l ogi n consenti to
10.4: err: Utente gi à l oggato
10.3.3.1: err: Utente bl occato
10.3.1: control l oBl occo( )
10.3: Password corretta
10.2.4: bl occo esegui to
10.2.1: bl occa( )
10.2: err: Password errata al 2° tentati vo
10.1: err: Password errata al 1° tentati vo
Interfacci a Logi n
AccessoDB
13: i nseri m ento esegui to
12: i nseri sci ( )
Lo creo sol o i n caso di
scenari o "Usernam e
corretta - 1° tentati vo".
Se sono al 2° tentati vo,
gi à l 'ho creato a quel l o
precedente.
UtenteDB
Interfacci a M enu Utente
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 12 - Sequence Diagram Login Utente
185
Interfacci a Logi n
10.4.1: noti fi ca Am m i ni stratore gi à l oggato
10.3.3.1.1: bl occato : i m pedi to l 'accesso
10.2.5: noti fi ca bl occo am m i ni stratore
10.1.1: segnal azi one errore
9.1.1: segnal azi one errore
Scenari o 1 :
Usernam e errata
5: esegui l ogi n
4: i nseri m ento Usernam e e Password
3: ri chi esta i nseri m ento Usernam e e Password
2: create
Interfacci a Hom e
1: ri chi esta di l ogi n
Am m i ni stratore
16: i nseri m ento esegui to
Sequenza azi oni com uni a tutti
gl i scenari , per l 'aggi ornam ento
del l e i nform azi oni di accesso
17: destroy
9.2.1: create
:AccessoAm m i ni stratore
9: cari ca dati
8: l eggi ( )
10.3.3.2.1: create
10.3.3: cari ca dati
10.3.2: l eggi ( )
10.2.3: aggi ornam ento esegui to
10.2.2: scri vi ( )
9.2.1.1: i ni zi al i zzazi one esegui ta
:Am m i ni stratore
15: destroy
14: i nseri m ento esegui to
11: i nseri sci ( )
10.3.3.2.2: vi sual i zzazi one m enu Am m i ni stratore
10.3.3.2: l ogi n consenti to
10.4: err: Am m i ni stratore gi à l oggato
10.3.3.1: err: Am m i ni stratore bl occato
10.3.1: control l oBl occo( )
10.3: Password corretta
10.2.4: bl occo esegui to
10.2.1: bl occa( )
10.2: err: Password errata al 2° tentati vo
10.1: err: Password errata al 1° tentati vo
Scenari o 2 :
Usernam e corretta
9.1: err: Usernam e errata
7: l ogi n( )
6: create
13: i nseri m ento esegui to
12: i nseri sci ( )
Lo creo sol o i n caso di
scenari o "Usernam e
corretta - 1° tentati vo".
Se sono al 2° tentati vo,
gi à l 'ho creato a quel l o
precedente.
Am m i ni stratoreDB
AccessoDB
Interfacci a M enu Am m i ni stratore
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 13 - Sequence Diagram Login Amministratore
186
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.2 Logout
Anche la funzionalità Logout prevede le medesime azioni per l’utente e
l’amministratore, a meno degli oggetti che vengono utilizzati per le operazioni
necessarie.
Utente
Sistema
Registrazione informazioni di logout
Richiesta di Logout
:AccessoUtente
[aggiornato]
Inserisce data ed ora di logout
Figura 14 - Activity Diagram Logout Utente
Amministratore
Richiesta di Logout
Sistema
Registrazione informazioni di logout
:AccessoAmministratore
[aggiornato]
Inserisce data ed ora di logout
Figura 15 - Activity Diagram Logout Amministratore
187
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Interfaccia Home
:Utente
:AccessoUtente
AccessoDB
UtenteDB
Utente
1: richiesta di logout
2: logout( )
3: aggiorna( )
4: modifica( )
5: aggiornamento eseguito
6: aggiornamento eseguito
7: destroy
8: modifica()
9: aggiornamento eseguito
10: notifica logout
11: destroy
12: visualizzazione home
Figura 16 - Sequence Diagram Logout Utente
Interfaccia Home
:Amministratore
:AccessoAmministratore
AccessoDB
AmministratoreDB
Amministratore
1: richiesta di logout
2: logout( )
3: aggiorna( )
4: modifica( )
5: aggiornamento eseguito
6: aggiornamento eseguito
7: destroy
8: modifica()
9: aggiornamento eseguito
10: notifica logout
11: destroy
12: visualizzazione home
Figura 17 - Sequence Diagram Logout Amministratore
188
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.3 Registrazione
Per quanto riguarda la registrazione dell’utente, per poter usufruire dei
servizi della Web application, ne sono previste due tipologie : la versione “base” ed
“estesa”, che differiscono dal fatto che quest’ultima fornisce in più la possibilità di
acquisto e download dei brani MP3.
La registrazione di base prevede l’immissione da parte dell’utente, soltanto dei dati di
accesso, Username e Password, oltre che dell’indirizzo email. In questo modo, si ha
la possibilità di usufruire dei servizi in maniera del tutto gratuita, con la limitazione di
poter esclusivamente ascoltare i brani in streaming, senza la possibilità di download.
L’utente ha poi la possibilità di decidere se voler usufruire della funzionalità di
acquisto e download dei brani, nel qual caso deve immettere anche i dati anagrafici.
Oltre a questi ultimi, sono necessarie le informazioni relative alla scheda prepagata da
acquistare e della carta di credito da utilizzare per il pagamento, della quale il sistema
esegue l’operazione di verifica della copertura.
Ovviamente, sono previste tutte le operazioni di validazione dei dati, necessarie a
garantire che i dati immessi dall’utente rispettino i formati attesi dall’applicazione.
Al termine della registrazione, viene eseguito il login automatico al sistema,
visualizzando all’utente le voci di menù relative alle funzionalità abilitate.
Per quanto riguarda il Sequence Diagram, si evidenziano i due possibili scenari
relativi alla registrazione “base” ed “estesa”, oltre alla funzionalità di login
automatico, che non prevede tutti i controlli tipici di questa operazione, trattandosi di
un nuovo utente. Il diagramma, inoltre, ha un riferimento al Sequence Diagram che
riguarda l’acquisto della scheda prepagata, in quanto questa operazione può essere
eseguita dall’utente anche in un secondo momento e non necessariamente in fase di
registrazione. Per questo motivo è prevista una funzionalità a parte con gli Activity e
Sequence Diagrams corrispondenti.
189
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Controllo correttezza dati
Inserimento dati Anagrafici
[Dati non corretti]
[Dati corretti]
Registrazione dati Anagrafici
:Utente
[creato]
[Prevede acquisto/download
di brani MP3]
Inserimento dati Carta di Credito ed Importo Scheda
Controllo correttezza dati carta
:CartaCredito
[creato]
[Non prevede acquisto/download di brani MP3]
Verifica copertura Carta di Credito
[Carta di Credito scoperta]
[Carta di Credito coperta]
Registrazione Acquisto
:SchedaPrepagata
[acquistata]
Login Automatico
Visualizzazione Menu Utente
:AccessoUtente
[creato]
:Utente
[registrato]
Figura 18 - Activity Diagram Registrazione
190
2: create
11: notifica registrazione eseguita
:Utente
19: destroy
18: inserimento eseguito
Esecuzione del Login in
automatico
10: registrazione eseguita
7: registrazione( )
UtenteDB
20: create
17: destroy
16: inserimento eseguito
13: inserisci( )
12: create
9: inserimento eseguito
8: inserisci( )
6.2.1.2: esegui acquisto scheda
Interfaccia AcquistoRicarica Scheda
21: visualizzazione menu Utente
6.2.1.4: destroy
Sequence Diagram Acquisto
Scheda Prepagata
6.2.1.1: create
6.2: create
6: controllo correttezza dati
Interfaccia Registrazione
6.2.1.3: notifica acquisto eseguito
Scenario : l'Utente prevede di
acquistare MP3
6.1: err: dati non corretti
5: esegui registrazione
4: inserimento dati
3: richiesta inserimento dati
Utente
1: richiesta di registrazione
Interfaccia Home
14: inserisci( )
15: inserimento eseguito
:AccessoUtente
AccessoDB
Interfaccia Menu Utente
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 19 - Sequence Diagram Registrazione
191
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.4 Richiesta Username / Password
Nel caso in cui un utente registrato abbia perso oppure dimenticato le
informazioni relative all’accesso, è possibile utilizzare la funzionalità del sistema che
permette di inviare una mail contenente tali informazioni.
L’utente deve semplicemente fornire al sistema l’indirizzo email con cui ha effettuato
la registrazione, dopodichè il sistema stesso eseguo il controllo di correttezza del
formato dell’indirizzo e verifica che quest’ultimo sia correttamente registrato. In caso
di esito positivo, l’utente riceverà una mail con tutte le informazioni richieste.
Utente
Sistema
Controllo correttezza dati
Inserimento indirizzo Email
[Dati non corretti]
[Dati corretti]
Controllo indirizzo Email
[Indirizzo email non presente in archivio]
:Utente
[letto]
[Indirizzo email presente in archivio]
Invio Email con Username e Password
Figura 20 - Activity Diagram Richiesta Username/Password
192
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Interfaccia Home
UtenteDB
Utente
1: richiesta Username e Password
2: create
Interfaccia Richiesta Username/Password
3: richiesta inserimento email
4: inserimento email
5: esegui richiesta
6: controllo formato email
6.1: err: formato email non valido
6.2.1: create
:Utente
6.2.2: richiediUserNamePassword( )
6.2.3: leggi( )
6.2.4: carica dati
6.2.4.1.1: utente non registrato
6.2.4.1.2: err: indirizzo email non presente in archivio
6.2.4.2.1: invio mail
6.2.4.2.2: invio email eseguito
6.2.4.2.3: notifica invio mail
6.2.5: destroy
Figura 21 - Sequence Diagram Richiesta Username/Password
3.3.5 Acquisto, Ricarica e Visualizzazione Info Scheda Prepagata
L’acquisto di una scheda prepagata si rende necessario nel momento in cui
l’utente abbia intenzione di acquistare e scaricare brani MP3. L’operazione di
acquisto può essere eseguita in fase di registrazione oppure in un secondo momento,
quando l’utente ha già effettuato in passato la registrazione base.
Le informazioni necessarie al sistema per svolgere la funzionalità sono relative
all’importo della scheda ed alla carta di credito, mediante la quale eseguire il
pagamento. Una volta verificata ed accertata la copertura di quest’ultima, viene
completato l’acquisto della scheda.
193
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Controllo correttezza dati
Inserimento dati Carta di Credito ed Importo Scheda
[Dati non corretti]
[Dati corretti]
:CartaCredito
[creato]
Verifica copertura Carta di Credito
[Carta di Credito scoperta]
[Carta di Credito coperta]
Registrazione Acquisto
:SchedaPrepagata
[acquistata]
Visualizzazione Menu Utente
Figura 22 - Activity Diagram Acquisto scheda prepagata
194
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Interfaccia AcquistoRicarica Scheda
SchedaPrepagataDB
Utente
1: richiesta inserimento dati
2: inserimento dati
3: esegui acquisto scheda
4: controllo correttezza dati
4.1: err: dati non corretti
4.2.1: create
:CartaCredito
4.2.2: verificaCopertura( )
4.2.2.1.1: err: carta di credito scoperta
4.2.2.1.2: err: carta di credito scoperta
4.2.2.2.1: carta di credito coperta
4.2.2.2.2: destroy
4.2.2.2.3: create
:SchedaPrepagata
4.2.2.2.4: acquista( )
4.2.2.2.5: inserisci( )
4.2.2.2.6: acquisto eseguito
4.2.2.2.7: acquisto eseguito
4.2.2.2.8: destroy
4.2.2.2.9: notifica acquisto eseguito
Figura 23 - Sequence Diagram Acquisto scheda prepagata
La scheda prepagata viene utilizzata per l’acquisto ed il download dei brani MP3
disponibili nell’archivio, per cui l’importo residuo è destinato a diminuire nel tempo.
Il sistema fornisce una funzionalità di ricarica, mediante la quale l’utente ha la
possibilità di ricaricare la scheda aumentandone l’importo.
L’operazione di ricarica è del tutto simile a quella di acquisto, nel senso che le
informazioni necessarie riguardano l’importo della ricarica e la carta di credito
necessaria al pagamento. Una volta eseguiti i dovuti controlli di copertura di
quest’ultima, la ricarica viene eseguita e registrata dal sistema ed inoltre, viene
aggiornato l’importo residuo della scheda, nonché prolungata la data di scadenza.
195
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Controllo correttezza dati
Inserimento Dati Carta di Credito ed Importo Ricarica
[Dati non corretti]
[Dati corretti]
:CartaCredito
[creato]
Verifica copertura Carta di Credito
[Carta di Credito scoperta]
[Carta di Credito coperta]
:Ricarica
[eseguita]
Aggiornamento importo,
scadenza e data/ora
Esecuzione Ricarica
:SchedaPrepagata
[ricaricata]
Figura 24 - Activity Diagram Ricarica scheda prepagata
196
4.1: err: dati non corretti
3: esegui ricarica scheda
2: inserimento dati
1: richiesta inserimento dati
4.2.2.2.16: notifica ricarica eseguita
4.2.2.1.2: err: carta di credito scoperta
Utente
:CartaCredito
4.2.2.2.15: destroy
4.2.2.2.14: ricarica eseguita
4.2.2.2.4: ricarica( )
4.2.2.2.3: create
4.2.2.2.2: destroy
4.2.2.2.1: carta di credito coperta
4.2.2.1.1: err: carta di credito scoperta
4.2.2: verificaCopertura( )
4.2.1: create
4: controllo correttezza dati
Interfaccia AcquistoRicarica Scheda
4.2.2.2.10: destroy
4.2.2.2.9: ricarica eseguita
4.2.2.2.6: esegui( )
4.2.2.2.5: create
4.2.2.2.7: inserisci( )
4.2.2.2.12: modifica( )
4.2.2.2.8: inserimento eseguito
:Ricarica
4.2.2.2.13: aggiornamento importo residuo eseguito
4.2.2.2.11: aggiornaImportoResiduo( )
:SchedaPrepagata
RicaricaDB
SchedaPrepagataDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 25 - Sequence Diagram Ricarica scheda prepagata
197
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
L’applicazione prevede di visualizzare tra le voci di menu, le informazioni relative ad
un eventuale scheda prepagata acquistata dall’utente, senza che quest’ultimo attivi
una particolare funzionalità del sistema.
Tali informazioni riguardano l’importo residuo e la data di scadenza ed un eventuale
messaggio di avvertimento per l’utente, qualora la scheda sia scaduta.
Utente
Sistema
Caricamento dati
Richiesta visualizzazione informazioni
:SchedaPrepagata
[letto]
Visualizzazione informazioni Scheda
Figura 26 - Activity Diagram Visualizzazione info scheda prepagata
Interfaccia Home
Utente
SchedaPrepagataDB
1: richiesta informazioni scheda
2: create
Interfaccia Info Scheda
3: create
:SchedaPrepagata
4: visualizzaInfo( )
5: leggi( )
6: carica dati
7: controlloScadenza( )
8: informazioni scheda
9: destroy
10: visualizzazione informazioni scheda
Figura 27 - Sequence Diagram Visualizzazione info scheda prepagata
198
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.6 Visualizzazione e Ricerca Brani
Per poter accedere all’archivio dei brani e visualizzarne il contenuto, il
sistema mette a disposizioni due modalità :
-
visualizzazione dei brani sulla base di un genere musicale;
-
ricerca dei brani sulla base dei criteri impostati relativi al titolo, autore, album
e genere musicale;
Gli Activity Diagrams che descrivono queste funzionalità sono due, in quanto fanno
riferimento alla richiesta da parte dell’utilizzatore ed alle operazioni eseguite dal
sistema. Si è preferita una scomposizione in questi termini, poiché tali diagrammi
diventano componenti dei diagrammi che descrivono funzionalità più complesse che
prevedono la visualizzazione dei brani. In questo modo si riesce a modellare il
sistema mediante livelli di astrazione successivi. Il Sequence Diagram, invece,
evidenzia i due possibili scenari sulla base dei quali l’utilizzatore può richiedere la
visualizzazione dei brani presenti all’interno dell’archivio.
199
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Selezione modalità visualizzazione brani MP3
Richiesta ricerca Brano
Richiesta visualizzazione brani MP3 per genere
Inserimento criteri di ricerca
Figura 28 - Activity Diagram Richiesta Visualizzazione e ricerca brani MP3
[Richiesta
ricerca]
[Richiesta visualizzazione per
genere]
Ricerca brani MP3
Caricamento elenco brani MP3
:BranoMP3
[letto]
Visualizzazione brani MP3
Figura 29 - Activity Diagram Visualizzazione e ricerca brani MP3
200
1.1.3: create
Scenario 1 : Visualizzazione Brani
MP3 per genere
1.2.1: create
Interfaccia Ricerca MP3
1.2.8.2.2: visualizzazioni brani relativi ai criteri di ricerca impostati
1.2.8.1.2: notifica assenza brani per i criteri di ricerca impostati
1.2.4: esegui ricerca
1.2.3: inserimento criteri di ricerca
1.2.2: richiesta inserimento criteri di ricerca
1.2: richiesta ricerca brani MP3
1.2.5: create
1.2.9: destroy
1.2.8.2.1: brani caricati
1.2.8.1.1: err: assenza brani
1.2.6: ricerca( )
1.1.8: destroy
1.1.7.2.1: brani caricati
1.1.7.1.1: err: assenza brani
1.1.6: leggi( )
BranoMP3DB
1.2.8: carica dati
1.2.7: leggi( )
1.1.7: carica dati
:BranoMP3
1.1.5: visualizzaElencoBraniMP3( )
1.1.4: create
Interfaccia Elenco Brani MP3
Scenario 2 : Visualizzazione Brani
MP3 sulla base di una ricerca
personalizzata
1.1.7.2.2: visualizzazione brani del genere selezionato
1.1.7.1.2: notifica assenza brani per il genere selezionato
1.1.2: esegui visualizzazione
1.1.1: selezione genere
Utente/Amministratore
1.1: richiesta visualizzazione elenco brani per genere
Interfaccia Home
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 30 - Sequence Diagram Visualizzazione e ricerca Brani MP3
201
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.7 Inserimento, Modifica ed Eliminazione Brano dall’Archivio
Nell’ambito della gestione dell’archivio dei brani, l’amministratore ha
ovviamente la possibilità di inserire un nuovo brano MP3. Le informazioni richieste
dal sistema riguardano il titolo, l’autore, l’album, il genere musicale, la durata oltre al
costo, necessario per l’acquisto del brano, ed al file MP3 che bisogna caricare sul
server.
Le informazioni suddette non sono tutte strettamente necessarie, se non il genere ed
il costo. La durata può anche non essere impostata, così come le informazioni
caratteristiche del brano. Una scelta di questo tipo potrebbe portare a pensare ad un
grave errore di progettazione, permettendo il caricamento di brani senza specificarne
il titolo, l’autore e l’album di appartenenza.
In realtà, il sistema prevede un meccanismo di accesso ai cosiddetti tag ID3v1,
caratteristici dei file in formato MP3 (MPLEG Layer 3), che contengono tutte le
informazioni caratteristiche del brano, tra cui appunto il titolo, l’autore e l’album. In
questo modo, si da all’amministratore la possibilità di non specificare tali
informazioni in fase di inserimento, se queste ultime possono essere ricavate dai tag
stessi. Nel caso in cui anche questi siano vuoti, si segnala all’utente che le
informazioni sono necessarie. E’ ovvio che viene garantita sempre la coerenza tra le
informazioni del brano inserite nell’archivio ed i tag del file MP3 corrispondente, per
cui se le informazioni del brano sono specificate dall’amministratore, il sistema
provvede ad aggiornarne i valori nei corrispondenti tag. Questo meccanismo
permette di risparmiare una grande quantità di tempo, se si dispone di un gruppo di
brani, le cui informazioni principali sono già specificate attraverso i tag ID3v1.
Il Sequence Diagram evidenzia le possibili situazioni di caricamento del singolo
brano, attraverso due scenari distinti.
202
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Sistema
Controllo correttezza dati
Inserimento informazioni brano e file MP3
[Dati non corretti]
[Dati corretti]
:FileMP3
[upload]
Controllo informazioni brano MP3 e upload file
[Informazioni brano inserite]
Scrivi informazioni nei tag MP3
[Informazioni brano non inserite]
Ricava informazioni dai tag MP3
:FileMP3
[aggiornato]
:FileMP3
[letto]
Registrazione dati in archivio
:BranoMP3
[creato]
Figura 31 - Activity Diagram Inserimento brano MP3 in archivio
203
2: create
6.2.11: notifica inserimento eseguito
In base al fatto che l'Amministratore abbia inserito
o meno le informazioni del brano, queste vengono
scritte o ricavate nei/dai tag MP3
6.1: err: dati non validi
5: esegui inserimento brano
4: inserimento informazioni e selezione brano da caricare
6.2.10: inserimento eseguito
6.2.7: inserisci( )
6.2.6: create
6.2.5: destroy
6.2.4.2.2: informazioni brano scritte nei tag MP3
6.2.4.2.1: aggiornaTag( )
6.2.4.1.2: informazioni brano ricavate dai tag MP3
6.2.4.1.1: leggiTag( )
6.2.4: verifica informazioni brano
6.2.3: termine upload
6.2.2: upload( )
6.2.1: create
6: controllo correttezza dati
Interfaccia Inserimento Brano MP3
3: richiesta inserimento informazioni e selezione brano
Amministratore
1: richiesta inserimento brano MP3
Interfaccia Home
:FileMP3
6.2.8: inserisci( )
6.2.9: inserimento eseguito
:BranoMP3
BranoMP3DB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 32 - Sequence Diagram Inserimento brano MP3 in archivio
204
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Una volta che un brano è stato inserito, è ovviamente disponibile una funzionalità
mediante la quale l’amministratore può visualizzare e modificare le informazioni dello
stesso. Così come per l’inserimento, viene sempre garantita la coerenza tra le
informazioni memorizzate nella base di dati ed i tag ID3v1 del file MP3, i quali
vengono aggiornati nel caso in cui l’amministratore decidesse di modificare il titolo,
l’autore e l’album.
La visualizzazione dei dati prevede un Activity Diagram che diventa componente in
quello di modifica, considerando che la funzionalità di visualizzazione è utilizzata in
molteplici situazioni.
Caricamento dati brano MP3
:BranoMP3
[letto]
Visualizzazione dati MP3
Figura 33 - Activity Diagram Visualizzazione info brano MP3
Inoltre, l’Activity Diagram relativo alla funzionalità di modifica sfrutta i diagrammi di
visualizzazione e ricerca dei brani, tra i quali selezionare il brano di cui modificarne le
informazioni.
205
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Sistema
Richiesta visualizzazione brani MP3
Visualizzazione elenco brani MP3
[Richiesta
[Richiesta visualizzazione per
ricerca]
genere]
Selez ione modalità vis ualizz azione brani MP3
Ricerca brani MP 3
Caricamento elenco brani MP3
:BranoMP 3
[letto]
Ric hiesta ricerca Bran
Ric hiesta v isualiz zaz ione brani MP3 per gene
Visualizzazione brani MP 3
Inserimento c riteri di ricerc a
[Assenza brani]
[Presenza brani]
Visualizzazione dati brano MP3
Selezione brano MP3
Caricamento dati brano MP3
:BranoMP3
[letto]
Vis ualizz azione dati MP3
Inserimento nuovi dati
Controllo correttezza dati
[Dati non corretti]
:FileMP3
[aggiornato]
[Dati corretti]
Registrazione nuovi dati
:BranoMP3
[aggiornato]
Figura 34 - Activity Diagram Modifica brano MP3
206
2.2: visualizzazione elenco brani
2.1: err: assenza brani
2: create
2.2.9: inserimento nuove informazioni del brano
2.2.11.2.10: notifica aggiornamento eseguito
2.2.11.1: err: dati non validi
2.2.10: esegui aggiornamento informazioni brano
2.2.2: create
Interfaccia Elenco Brani MP3
2.2.8: visualizzazione informazioni brano
2.2.1: selezione brano da modificare
Sequence Diagram
Visualizzazione Brani MP3 per
Genere o Ricerca
personalizzata
Amministratore
1: richiesta visualizzazione brani
Interfaccia Home
2.2.11.2.9: destroy
2.2.11.2.2: modifica( )
2.2.6: carica dati
2.2.5: leggi( )
2.2.11.2.7: destroy
2.2.11.2.6: aggiornamento eseguito
2.2.11.2.5: aggiornaTag( )
2.2.11.2.4: create
2.2.11.2.3: aggiornamento eseguito
:BranoMP3
2.2.11.2.8: aggiornamento eseguito
2.2.11.2.1: modificaInfo( )
2.2.11: controllo correttezza dati
2.2.7: informazioni brano
2.2.4: visualizzaInfo( )
2.2.3: create
Interfaccia Info Brano MP3
BranoMP3DB
:FileMP3
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 35 - Sequence Diagram Modifica brano MP3
207
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
L’ultima funzionalità fondamentale per la gestione dell’archivio permette
l’eliminazione di un brano MP3. Tale operazione è prevista secondo due possibili
modalità :
-
eliminazione di uno o più brani selezionandoli dall’elenco attualmente
visualizzato;
-
eliminazione di un singolo brano nell’interfaccia di visualizzazione delle
informazioni dello stesso;
Tali modalità sono descritte attraverso i due corrispondenti scenari all’interno del
Sequence Diagram
Nel momento in cui l’amministratore richiede l’eliminazione di uno o più brani, per
garantire la coerenza delle informazioni in archivio e dei file MP3 presenti nel file
system del server, il sistema esegue le seguenti attività su ciascun di essi :
-
cancella le informazioni del brano dalla base di dati;
-
elimina il file MP3 ad esso associato;
-
aggiorna le informazioni di composizione delle playlist degli utenti;
L’ultima operazione non è strettamente legata all’azione di cancellazione del brano,
ma serve ad evitare che all’interno delle playlist degli utenti rimanga un riferimento ad
un brano non più presente in archivio e per il quale non è disponibile il file MP3 da
ascoltare.
208
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Richiesta visualizzazione brani MP3
Sistema
Visualizzazione elenco brani MP3
[Richiesta
ricerca]
[Richiesta visualizzazione per
genere]
Selez ione modalità vis ualizz az ione brani MP3
Ricerca brani MP3
Caricamento elenco brani MP 3
:B ranoMP 3
[letto]
Ric hiesta ric erca Bran
Ric hies ta v isualiz zazione brani MP3 per gene
V isualizzazione brani MP 3
Inserimento c riteri di ric erca
[Assenza brani]
[Presenza brani]
Visualizzazione dati brano MP3
Caric amento dati brano MP3
Selezione brano MP3
:BranoMP3
[letto]
Selezione dei brani MP3 da cancellare
Vis ualizz az ione dati MP3
Richiesta cancellazione brano/i MP3
Cancellazione brano MP3
:BranoMP3
[cancellato]
:FileMP3
[cancellato]
:Playlist
[aggiornato]
Figura 36 - Activity Diagram Eliminazione brano MP3 dall'archivio
209
2.2.2.2.20: noti fi ca el i m inazi one eseguita
2.2.2.2.9: ri chi esta cancell azione brano
2.2.2.2.19: destroy
2.2.3: destroy
2.2.4: destroy
2.2.2.2.17: el i m inazi one esegui ta
2.2.2.2.10: el i m ina( )
:Fil eM P3
BranoM P3DB
2.2.2.2.13: el im i na( )
2.2.2.2.12: el i mi nazi one esegui ta
2.2.2.2.11: el im i na( )
2.2.2.2.6: cari ca dati
2.2.2.2.5: l eggi ( )
2.2.2.1.9: el i m inazi one esegui ta
2.2.2.1.8: el i m ina( )
2.2.2.1.7: el i m inazi one eseguita
2.2.2.1.6: el i m ina( )
2.2.2.1.5: el i m inazi one eseguita
2.2.2.1.4: el i m ina( )
2.2.2: create
2.2.2.2.16: el im i nazione esegui ta
2.2.2.2.15: el im i na( )
2.2.2.2.14: el i mi nazi one esegui ta
:BranoM P3
2.2.2.2.7: i nform azi oni brano
2.2.2.2.4: vi suali zzaInfo( )
Interfaccia Info Brano M P3
2.2.2.1.10: el im i nazione esegui ta
2.2.2.1.3: el i m ina( )
2.2.1: create
2.2.2.2.18: el im i nazione esegui ta
2.2.2.2.3: create
Interfacci a Elenco Brani M P3
2.2.2.2.8: vi sual i zzazi one i nform azi oni brano
Scenari o 2 : el i m inazi one di brani
sel ezi onandone uno e
vi suali zzandone le i nform azi oni
2.2.2.2.2: richiesta vi sual i zzazi one info brano
2.2.2.2.1: sel ezi one brano M P3
2.2.2.1.11: noti fi ca el i m inazi one eseguita
Scenari o 1 : eli m i nazi one di brani
selezionandol i dal l'el enco
2.2.2.1.2: esegui cancell azione
2.2.2.1.1: sel ezi one brano/i da cancel lare
2.2: vi sual i zzazi one el enco brani
2.1: err: assenza brani
Sequence Di agram
Visual izzazi one Brani M P3 per
Genere o Ri cerca
personal i zzata
2: create
Interfaccia Hom e
1: richiesta vi sual i zzazi one brani
Am m i ni stratore
Com posizionePlayl istDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 37 - Sequence Diagram Eliminazione brano MP3 dall'archivio
210
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.8 Ascolto di un singolo Brano
Tra i servizi offerti dalla Web application, c’è la possibilità da parte
dell’utente di poter ascoltare una sequenza di brani che compongono una propria
playlist.
La funzionalità di ascolto è messa a disposizione anche nel caso di un singolo MP3,
sia per l’utente che per l’amministratore. Per poter usufruire di questa funzione, è
ovviamente necessario accedere alle informazioni del singolo brano che si desidera
ascoltare. Una volta effettuata tale richiesta, il sistema eseguirà il caricamento di un
player MP3, che permetterà lo streaming del file associato al brano. L’avvio
dell’ascolto, non impedisce all’utente di poter proseguire la navigazione all’interno
dell’applicazione, usufruendo degli altri servizi.
211
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente/Amministratore
Richiesta visualizzazione brani MP3
Sistema
Visualizzazione elenco brani MP3
[Richiesta
Selez ione modalità v is ualiz z az ione brani MP3
[Richiesta visualizzazione per
ricerca]
genere]
Ricerca brani MP3
Caricamento elenco brani MP3
:BranoMP3
Ric hiesta ric erc a Bran
[letto]
Ric hiesta v is ualizz az ione brani MP3 per gener
Visualizzazione brani MP3
Ins erimento c riteri di ric erc a
[Assenza brani]
[Presenza brani]
Selezione brano MP3
Visualizzazione dati brano MP3
Caric amento dati brano MP3
:BranoMP3
[letto]
Richiesta ascolto brano MP3
Vis ualiz z az ione dati MP3
Riproduzione brano MP3
:FileMP3
[streaming]
Figura 38 - Activity Diagram Ascolto singolo brano MP3
212
Utente
2: create
2.2.17: riproduzione brano
2.2.11: richiesta ascolto brano
2.2.4: create
Interfaccia Elenco Brani MP3
2.2.10: visualizzazione informazioni brano
2.2.3: richiesta visualizzazione info brano
2.2.2: selezione brano MP3
2.2.1: visualizzazione elenco brani
2.1.1: err: assenza brani
Sequence Diagram
Visualizzazione Brani MP3
per Genere o Ricerca
1: richiesta visualizzazione brani
Interfaccia Home
2.2.19: fine riproduzione
2.2.16: riproduzione
2.2.12: ascolta( )
2.2.9: informazioni brano
2.2.6: visualizzaInfo( )
2.2.5: create
Interfaccia Info Brano MP3
2.2.15: riproduzione
2.2.14: riproduci( )
2.2.13: create
:FileMP3
2.2.8: carica dati
2.2.7: leggi( )
2.2.18: fine riproduzione
:BranoMP3
BranoMP3DB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 39 - Sequence Diagram Ascolto singolo brano MP3
213
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.9 Gestione Playlist
La gestione delle playlist rappresenta il servizio principale offerto dalla Web
application per gli utenti registrati, anche esclusivamente con la modalità base.
Attraverso questo servizio è possibile :
-
creare ed eliminare le proprie playlist preferite;
-
inserire e cancellare brani da ciascuna playlist;
-
ascoltare una playlist;
L’operazione di creazione è relativamente semplice, in quanto l’unica informazione
associata ad una playlist è il nome che può essere specificato dall’utente.
Utente
Inserimento informazioni Playlist
Sistema
Controllo correttezza dati
[Dati non corretti]
[Dati corretti]
Registrazione informazioni Playlist
:Playlist
[creato]
Figura 40 - Activity Diagram Creazione playlist
214
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Interfaccia Home
PlaylistDB
Utente
1: richiesta creazione playlist
2: create
Interfaccia Creazione Playlist
3: richiesta inserimento informazioni playlist
4: inserimento informazioni playlist
5: esegui creazione playlist
6: controllo correttezza dati
6.1: err: dati non validi
6.2.1: create
:Playlist
6.2.2: crea( )
6.2.3: inserisci( )
6.2.4: inserimento eseguito
6.2.5: inserimento eseguito
6.2.6: destroy
6.2.7: notifica creazione playlist
Figura 41 - Sequence Diagram Creazione playlist
Una volta create una o più playlist, è possibile visualizzarne l’elenco ed accedere a
ciascuna di esse per visualizzarne i brani MP3 che la compongono. Gli Activity
Diagram seguenti fanno riferimento a quanto detto e sono molto semplici in virtù del
fatto che sono utilizzati come parti componenti dei diagrammi più complessi che
prevedono queste funzionalità.
Caricamenti elenco Playlist dall'archivio
:Playlist
[letto]
Visualizzazione Playlist
Figura 42 - Activity Diagram Visualizzazione elenco playlist
215
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Caricamento elenco brani MP3 in Playlist
:BranoMP3
[letto]
Visualizzazione contenuto Playlist
Figura 43 - Activity Diagram Visualizzazione elenco brani MP3 nella playlist
Per quanto riguarda i corrispondenti Sequence Diagram, non è previsto quello
relativo alla visualizzazione delle playlist, in quanto le azioni necessarie vengono
svolte direttamente nei diagrammi delle funzionalità che lo prevedono. Viceversa, è
definito un diagramma la visualizzazione dei brani all’interno di una playlist, in
quanto comporta uno scambio di messaggi molto più complessi che vale la pena
mettere in risalto.
La funzionalità di eliminazione delle playlist prevede due distinte modalità :
-
eliminazione di una o più playlist selezionandole dall’elenco;
-
eliminazione di una singola playlist, visualizzandone l’elenco dei brani che la
compongono;
In entrambi i casi, per ciascuna playlist ne vanno eliminate le informazioni
caratteristiche e quelle relative alla composizione, ovviamente non cancellando
dall’archivio i brani MP3.
216
2: create
6.2.3: selezione playlist
3: create
6.2.4: create
:Playlist
6.2.9.2.2: visualizzazione brani nella playlist
6.2.9.1.2: notifica playlist vuota
6.2.1: playlist caricate
6.1.1: err: assenza playlist
4: visualizzaElencoPlaylist( )
Interfaccia Elenco Playlist
6.2.2: visualizzazione elenco playlist
6.1.2: notifica assenza playlist
Utente
1: richiesta elenco playlist
Interfaccia Home
6.2.10: destroy
6.2.9.2.1: brani caricati
6.2.9.1.1: err: playlist vuota
6.2.9: carica dati
6.2.8: leggi( )
6.2.7: carica dati
6.2.6: leggi( )
6.2.5: visualizzaElencoBraniMP3Playlist( )
Interfaccia Elenco Brani MP3
6: carica dati
5: leggi( )
PlaylistDB
ComposizionePlaylistDB
BranoMP3DB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 44 - Sequence Diagram Visualizzazione elenco brani MP3 nella playlist
217
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Visualizzazione elenco Playlist
Richiesta visualizzazione elenco Playlist
Caric amenti elenc o Play list dall'arc hivio
:Play lis t
[letto]
Vis ualiz zazione Play lis t
[Assenza Playlist]
[Presenza Playlist]
Selezione Playlist
Visualizzazione elenco brani MP3 in Playlist
Caricamento elenco brani MP3 in Playlist
Selezione delle Playlist da cancellare
:BranoMP3
[letto]
Visualizzazione contenuto Playlist
Richiesta cancellazione Playlist
Cancellazione Playlist
:Playlist
[eliminato]
Figura 45 - Activity Diagram Eliminazione playlist
218
Interfaccia Home
2: create
6.2.2.2.13: visualizzazione elenco playlist
6.2.2.2.12: destroy
6.2.3: destroy
6.2.2.2.11: notifica eliminazione eseguita
6.2.2.2.4: richiesta di cancellazione della playlist
:Playlist
6.2.2.2.10: eliminazione eseguita
6.2.2.2.5: elimina( )
Interfaccia Elenco Brani MP3
6.2.2.1.8: eliminazione eseguita
6.2.2.1.3: elimina( )
6.2.1: playlist caricate
6.1.1: err: assenza playlist
4: visualizzaElencoPlaylist( )
3: create
Sequence Diagram
Visualizzazione Brani Playlist
6.2.2.2.3: visualizzazione elenco brani contenuti nella playlist
Scenario 2 : eliminazione di Playlist
selezionandone una e
visualizzandone il contenuto
6.2.2.2.1: selezione playlist e richiesta visualizzazione brani contenuti
6.2.2.2.2: create
Interfaccia Elenco Playlist
6.2.2.1.9: notifica eliminazione eseguita e visualizzazione elenco playlist
Scenario 1 : eliminazione di Playlist
selezionandole dall'elenco
6.2.2.1.2: esegui cancellazione
6.2.2.1.1: selezione playlist da cancellare
6.2.2: visualizzazione elenco playlist
6.1.2: notifica assenza playlist
Utente
1: richiesta elenco playlist
6.2.2.2.9: eliminazione eseguita
6.2.2.2.8: elimina( )
6.2.2.2.7: eliminazione eseguita
6.2.2.2.6: elimina( )
6.2.2.1.7: eliminazione eseguita
6.2.2.1.6: elimina( )
6.2.2.1.5: eliminazione eseguita
6.2.2.1.4: elimina( )
6: carica dati
5: leggi( )
PlaylistDB
ComposizionePlaylistDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 46 - Sequence Diagram Eliminazione playlist
Ovviamente l’utente ha la possibilità di inserire uno o più brani all’interno di una
playlist, secondo le due seguenti modalità, evidenziate nel Sequence Diagram :
-
selezionando uno o più brani dall’elenco corrente;
-
inserendo un singolo brano, dall’interfaccia di visualizzazione delle
informazioni;
219
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Richiesta visualizzazione brani MP3
Selez ione modalità v isualiz zaz ione brani MP3
Visualizzazione elenco brani MP3
[Richiesta
ricerca]
[Richiesta visualizzazione per
genere]
Ricerca brani MP3
Caricamento elenco brani MP3
:BranoMP3
Richies ta ric erca Bran
[letto]
Ric hies ta vis ualizz az ione brani MP3 per gene
Visualizzazione brani MP3
Ins erimento c riteri di ric erc a
[Assenza brani]
[Presenza brani]
Visualizzazione dati brano MP3
Selezione brano MP3
Caricamento dati brano MP3
:BranoMP3
[letto]
Selezione dei brani MP3 da inserire
Visualiz zaz ione dati MP3
Richiesta inserimento brano/i MP3
Inserimento brano/i MP3 nella Playlist
:Playlist
[aggiornato]
Figura 47 - Activity Diagram Inserimento brano MP3 nella playlist
Ovviamente, si esegue l’aggiornamento della composizione della playlist.
220
1: richiesta visualizzazione brani
2: create
Interfaccia Elenco Brani MP3
2.2.2.2.3: create
2.2.2.2.17: visualizzazione elenco brani
2.2.3: destroy
:BranoMP3
2.2.2.2.15: inserimento eseguito
2.2.2.2.12: inserisciBrano( )
2.2.2.2.9: destroy
2.2.2.2.8: informazioni brano
2.2.2.2.5: visualizzaInfo( )
2.2.2.2.4: create
Interfaccia Info Brano MP3
2.2.2.1.6: inserimento eseguito
2.2.2.1.3: inserisciBrano( )
2.2.1: create
2.2.2.2.16: notifica brano inserito nella playlist selezionata
2.2.2.2.11: selezione playlist e richiesta inserimento brano
2.2.2.2.10: visualizzazione informazioni brano
Scenario 2 : inserimento di un brano in
una playlist, selezionandolo e
visualizzandone le informazioni
2.2.2.2.2: richiesta visualizzazione informazioni brano
2.2.2.2.1: selezione brano da inserire nella playlist
2.2.2.1.7: notifica brano/i inserito/i nella playlist selezionata
Scenario 1 : inserimento di brani in una
playlist, selezionandoli dall'elenco
2.2.2.1.2: esegui inserimento brano/i nella playlist
2.2.2.1.1: selezione playlist e brani da introdurre
2.2.2: visualizzazione elenco brani
2.1: err: assenza brani
Sequence Diagram
Visualizzazione Brani MP3 per
Genere o Ricerca
personalizzata
Utente
Interfaccia Home
2.2.2.1.4: modifica( )
ComposizionePlaylistDB
2.2.2.2.14: aggiornamento eseguito
2.2.2.2.7: carica dati
2.2.2.2.13: modifica( )
2.2.2.1.5: aggiornamento eseguito
2.2.2.2.6: leggi( )
:Playlist
BranoMP3DB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 48 - Sequence Diagram Inserimento brano MP3 nella playlist
221
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
L’eliminazione dei brani da una playlist prevede unicamente la possibilità di
selezionarli dall’elenco.
Utente
Sistema
Visualizzazione elenco Playlist
Richiesta visualizzazione elenco Playlist
Caricamenti elenco Play lis t dall'arc hiv io
:Play list
[letto]
[Assenza Playlist]
Vis ualiz zaz ione Playlis t
[Presenza Playlist]
Selezione Playlist
Visualizzazione elenco brani MP3 in Playlist
Richiesta visualizzazione brani MP3 in Playlist
Caricamento elenco brani MP3 in Playlist
:BranoMP3
[letto]
[Assenza Brani]
Visualizzazione contenuto Playlist
[Presenza Brani]
Selezione dei brani MP3 da cancellare
Richiesta cancellazione brano/i MP3
Cancellazione brano/i MP3 da Playlist
:Playlist
[aggiornato]
Figura 49 - Activity Diagram Eliminazione brani MP3 dalla playlist
222
Utente
2: create
4.1.7: notifica eliminazione brano/i selezionato/i
4.1.2: richiesta cancellazione brano/i selezionato/i
4.1.1: selezione brano/i da cancellare
4: visualizzazione elenco brani contenuti nella playlist
Sequence Diagram
Visualizzazione Brani Playlist
1: richiesta visualizzazione brani in una playlist
Interfaccia Home
4.1.6: brano/i eliminato/i
4.1.3: eliminaBrano( )
3: create
Interfaccia Elenco Brani MP3
:Playlist
4.1.5: eliminazione eseguita
4.1.4: elimina( )
ComposizionePlaylistDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 50 - Sequence Diagram Eliminazione brani MP3 dalla playlist
223
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
L’ultima funzionalità relativa alle playlist è relativa all’ascolto, ed è fornita dal sistema
mediante l’ausilio di un player MP3 che viene avviato nel momento in cui ne viene
fatta richiesta dall’utente.
Utente
Sistema
Visualizzazione elenco Playlist
Richiesta visualizzazione elenco Playlist
Caric amenti elenco Play list dall'arc hiv io
:Playlist
[letto]
Vis ualiz zazione Playlist
[Assenza Playlist]
[Presenza Playlist]
Visualizzazione elenco brani MP3 in Playlist
Selezione Playlist
Caricamento elenco brani MP3 in Playlist
:BranoMP3
[letto]
Visualizzazione contenuto Playlist
Richiesta ascolto Playlist
Riproduzione Playlist
:FileMP3
[streaming]
Figura 51 - Activity Diagram Ascolto playlist
224
Utente
2: create
14: riproduzione playlist
5: richiesta ascolto playlist
4: visualizzazione brani contenuti nella playlist
Sequence Diagram
Visualizzazione Brani Playlist
1: richiesta visualizzazione brani playlist
Interfaccia Home
17: fine riproduzione
13: riproduzione
Per ogni brano
della playlist
6: ascolta( )
3: create
Interfaccia Elenco Brani MP3
:Playlist
11: riproduzione
10: riproduci( )
9: create
:FileMP3
15: fine riproduzione
:BranoMP3
16: fine riproduzione
12: riproduzione
8: ascolta( )
7: create
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 52 - Sequence Diagram Ascolto playlist
225
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.10 Acquisto/Download Brano
Se l’utente ha effettuato una registrazione “estesa” oppure, partendo da una
registrazione “base”, ha deciso di acquistare una scheda prepagata in un secondo
momento, automaticamente acquisisce il diritto di poter acquistare e scaricare i brani
MP3 oltre che di ascoltarli in streaming.
L’utente può effettuare l’acquisto di un brano partendo dalla visualizzazione di un
elenco di brani ottenuti sulla base di una ricerca oppure contenuti all’interno delle
proprie playlist precedentemente create. Selezionando il brano di interesse, accede
alla scheda contenente le informazioni dello stesso ed ha poi la possibilità di
confermarne l’acquisto.
Ovviamente, il sistema esegue i dovuti controlli, verificando che l’importo residuo
presente sulla scheda sia sufficiente all’acquisto. Nel caso di esito negativo, si invita
l’utente alla ricarica della scheda mentre nel caso di esito positivo lo si abilita al
download del brano. Contestualmente all’avvio del download, viene aggiornato
l’importo residuo della scheda e viene registrato l’acquisto eseguito dall’utente, in
modo da avere a disposizione un archivio storico con gli acquisti eseguiti e poter, ad
esempio, generare delle statistiche dei brani maggiormente scaricati.
226
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Sistema
Richiesta visualizzazione brani MP3
Visualizzazione elenco brani MP3
Richiesta visualizzazione elenco Playlist
Visualizzazione elenco Playlist
[Assenza Brani]
[Presenza Brani]
[Assenza Playlist]
[Presenza Playlist]
Selezione Playlist
Richiesta visualizzazione brani MP3 in Playlist
Visualizzazione elenco brani MP3 in Playlist
[Assenza Brani]
[Presenza Brani]
Selezione brano MP3
Visualizzazione dati brano MP3
Richiesta Download brano MP3
Controllo Importo residuo su Scheda
:SchedaPrepagata
[letto]
[Importo insufficiente]
:FileMP3
[download]
[Importo sufficiente]
Registrazione Acquisto/Download brano MP3
:Download
[registrato]
:SchedaPrepagata
[aggiornato]
Avvio Download
Registrazione acquisto brano
MP3 ed aggiornamento Importo
residuo della Scheda
Figura 53 - Activity Diagram Acquisto/Download brano MP3
227
Utente
2: create
2.2.2: selezione brano MP3
2.2.1: visualizzazione elenco brani
2.2.16.2.22: notifica termine del download
2.2.16.2.14: esegui download
2.2.16.2.13: notifica acquisto eseguito ed abilitazione al download
2.2.16.1.3: notifica importo insufficiente per acquisto/download brano
2.2.11: richiesta acquisto/download brano
2.2.4: create
Interfaccia Elenco Brani MP3
2.2.10: visualizzazione informazioni brano
2.2.3: richiesta visualizzazione info brano
Sequence Diagram
Visualizzazione Brani MP3
per Genere,Ricerca o in
una Playlist
2.1: err: assenza brani
Interfaccia Home
1: richiesta visualizzazione brani
2.2.5: create
2.2.6: visualizzaInfo( )
2.2.16.2.21: destroy
2.2.16.2.20: termine download
2.2.16.2.15: avviaDownload( )
2.2.16.2.12: acquisto effettuato
:SchedaPrepagata
2.2.16.1.1: err: importo insufficiente
2.2.14: controlloImportoResiduo( )
2.2.13: create
2.2.16.2.11: destroy
2.2.16.2.10: inserimento eseguito
2.2.16.2.7: inserisci( )
2.2.16.2.6: create
2.2.16.2.5: destroy
2.2.16.2.4: aggiornamento eseguito
2.2.16.2.1: aggiornaImportoResiduo( )
:BranoMP3
2.2.16.1.2: err: importo residuo insufficiente
2.2.12: acquista( )
2.2.9: informazioni brano
Interfaccia Info Brano MP3
2.2.7: leggi( )
2.2.15: leggi( )
2.2.16.2.8: inserisci( )
2.2.16.2.3: aggiornamento eseguito
2.2.16.2.2: modifica( )
2.2.16: carica dati
2.2.16.2.19: destroy
2.2.16.2.18: termine download
2.2.16.2.17: download( )
2.2.16.2.16: create
2.2.16.2.9: inserimento eseguito
:Download
2.2.8: carica dati
DownloadDB
BranoMP3DB
SchedaPrepagataDB
:FileMP3
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 54 - Sequence Diagram Acquisto/Download brano MP3
228
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.11 Modifica Dati Personali
L’utente e l’amministratore hanno entrambi l’opportunità di modificare i
propri dati di accesso. In particolare, l’amministratore ha esclusivamente la possibilità
di modificare la password, in quanto non ci sono ulteriori informazioni ad esso
associate. Viceversa, per l’utente si possono presentare due scenari differenti:
-
nel caso in cui non possegga una scheda prepagata, avrà la possibilità di
modificare la propria password e l’indirizzo email, ma non lo username;
-
nel caso in cui possegga una scheda prepagata, avrà ovviamente la possibilità
di modificare i dati di accesso suddetti oltre a tutte le informazioni
anagrafiche, fornite nella fase di acquisto della scheda;
In entrambi i casi, il sistema visualizza i dati attuali, permettendo all’utilizzatore di
modificarne i valori e confermarne l’aggiornamento.
A questo punto, l’applicazione esegue in primo luogo un controllo di correttezza sui
dati, per verificare che siano del formato atteso ed in particolare chiede
all’utilizzatore, utente o amministratore che sia, di inserire una conferma della
password scelta. Ovviamente, viene verificato che la password scelta e la sua
conferma coincidano, altrimenti non si consente la modifica dei propri dati.
La funzionalità di modifica dei dati, può essere considerata del tutto simile, senza
alcuna distinzione, tra l’utente e l’amministratore, tenendo esclusivamente conto dei
limiti di aggiornamento che può eseguire il secondo.
Si è preferito comunque sviluppare gli Activity e Sequence Diagram in maniera
separata, considerando che gli oggetti in gioco sono sostanzialmente diversi, poiché
fanno riferimento a due utilizzatori differenti.
229
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Utente
Richiesta modifica dati personali
Sistema
Caricamento dati attuali
:Utente
[letto]
Inserimento nuovi dati
Visualizzazione dati attuali
Controllo correttezza dati
[Dati non corretti]
[Dati corretti]
Controllo Password vecchia
[Password errata]
[Password corretta]
Controllo Password nuova e conferma
[Password nuova e conferma non coincidono]
[Password nuova e conferma coincidono]
Registrazione nuovi dati
:Utente
[aggiornato]
Visualizzazione Menu Utente
Figura 55 - Activity Diagram Modifica dati personali Utente
230
2: create
11.2.2.2.6: aggiornamento dati eseguito
11.2.2.1.2: notifica Password nuova e Conferma non coincidono
11.2.1.2: notifica Password corrente errata
11.1: err: dati non validi
10: esegui modifica dati
9: inserimento nuovi dati
3: create
12: destroy
11.2.2.2.5: aggiornamento eseguito
11.2.2.2.2: modificaDatiAnagrafici( )
11.2.2.2.1: Password e Conferma coincidono
11.2.2.1.1: err: Password nuova e Conferma diverse
11.2.1.1: err: Password corrente errata
11.2: modificaUserNamePassword( )
11: controllo correttezza dati
7: dati attuali Utente
4: visualizzaDatiAnagrafici( )
Interfaccia Modifica Dati Personali
8: visualizzazione dati attuali dell'Utente
Utente
1: richiesta modifica dati personali
Interfaccia Home
:Utente
5: leggi( )
11.2.2.2.4: aggiornamento eseguito
11.2.2.2.3: modifica( )
6: carica dati
UtenteDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 56 - Sequence Diagram Modifica dati personali Utente
231
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Sistema
Inserimento Password vecchia, nuova e conferma
Controllo Password vecchia
:Amministratore
[letto]
[Password errata]
[Password corretta]
Controllo Password nuova e conferma
[Password nuova e conferma non coincidono]
[Password nuova e conferma coincidono]
Registrazione nuova Password
:Amministratore
[aggiornato]
Visualizzazione Menu Amministratore
Figura 57 - Activity Diagram Modifica password Amministratore
232
2: create
8.2.2.4: aggiornamento Password eseguito
8.2.1.2: notifica Password nuova e Conferma non coincidono
8.1.2: notifica Password corrente errata
5: esegui cambio Password
4: inserimento dati
9: destroy
8.2.2.3: aggiornamento eseguito
8.2.2.1: modifica( )
8: carica dati
7: leggi( )
AmministratoreDB
8.2.2.2: aggiornamento eseguito
:Amministratore
8.2.1.1: err: Password nuova e Conferma diverse
8.1.1: err: Password corrente errata
6: modificaUserNamePassword( )
Interfaccia Modifica Password
3: richiesta inserimento dati per cambio Password
Amministratore
1: richiesta modifica Password
Interfaccia Home
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 58 - Sequence Diagram Modifica password Amministratore
233
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.3.12 Gestione Utenti
L’amministratore ha accesso ad una particolare sezione della Web
application, mediante la quale può effettuare delle semplici operazioni relative alla
gestione degli utenti.
La prima funzionalità disponibile è quella che permette la visualizzazione dell’elenco
degli utenti registrati, con la possibilità di selezionare uno o più utenti e di eseguirne
la cancellazione dal sistema.
A partire da tale elenco, è inoltre possibile selezionare uno degli utenti per poterne
visualizzare le informazioni di registrazione, ovviamente esclusa la password di
accesso al sistema. Le informazioni visualizzate dipendo dal tipo di registrazione che
ha eseguito l’utente e dal fatto che possegga o meno una scheda prepagata. In virtù di
questa distinzione, saranno visualizzate solo le informazioni di accesso oppure anche
i dati anagrafici.
In corrispondenza dell’interfaccia di visualizzazione dei dati del singolo utente,
l’amministratore può eseguire due semplici operazioni :
-
eliminare l’utente;
-
sbloccare l’utente, qualora quest’ultimo risulti bloccato in virtù del fatto che
sono stati eseguiti due accessi consecutivi errati al sistema;
Il Sequence Diagram evidenzia i due scenari possibili per la cancellazione di uno o
più utenti, nonché la funzionalità di sblocco.
234
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Amministratore
Sistema
Richiesta visualizzazione elenco Utenti
Caricamento elenco Utenti
:Utente
[letto] : 1
[Assenza Utenti]
Visualizzazione elenco Utenti
[Presenza Utenti]
Selezione Utente
:Utente
[cancellato]
Richiesta cancellazione Utente
Richiesta visualizzazione dati Utente
Cancellazione Utente dall'archivio
Caricamento dati Utente
:Utente
[letto] : 2
[Cancella Utente]
Richiesta sblocco Utente
Visualizzazione dati Utente
[Uscita dal servizio]
Sblocco Utente
:Utente
[sbloccato]
Visualizzazione Menu Amministratore
Figura 59 - Activity Diagram Gestione Utenti
235
Interfacci a Home
2: create
7.2.7.2.5: noti fi ca sbl occo esegui to
7.2.7.2: ri chi esta sbl occo utente
7.2.7.1.6: vi sual i zzazi one el enco utenti regi strati
7.2.7.1: ri chi esta el i m i nazi one utente
7.2.7: vi sual i zzazi one dati anagrafi ci utente
Scenari o 2 : cancel l azi one di un
si ngol o Utente oppure sbl occo di un
Utente
7.2.1: ri chi esta vi sual i zzazi one dati anagrafi ci di un Utente sel ezi onato
7.3: destroy
7.2.7.2.4: sbl occo esegui to
7.2.7.2.1: sbl occa( )
7.2.7.1.4: el i mi nazi one esegui ta
7.2.7.1.1: el i m i na( )
7.2.6: dati anagrafi ci utente
7.2.3: vi sual i zzaDati Anagrafi ci ( )
Interfacci a Anagrafi ca Utente
7.1.5: el i mi nazi one esegui ta
7.1.2: el i mi na( )
6.2.1: el enco utenti regi strati
6.1: err: non ci sono utenti regi strati
4: vi sual i zzaEl encoUtenti ( )
3: create
7.2.7.1.5: noti fi ca el i mi nazi one esegui ta
7.2.2: create
Interfacci a El enco Utenti
7.1.6: noti fi ca el i mi nazi one esegui ta e vi sual i zzazi one el enco utenti regi strati
Scenari o 1 : cancel l azi one utenti
sel ezi onandol i dal l 'el enco
7.1.1: sel ezi one utente/i da cancel l are
6.2.2: vi sual i zzazi one el enco utenti regi strati
6.1.1: noti fi ca errore non ci sono utenti regi strati
Ammi ni stratore
1: ri chi esta vi sual i zzazi one el enco utenti
:Utente
5: l eggi ( )
7.2.7.2.3: aggi ornamento esegui to
7.2.7.2.2: modi fi ca( )
7.2.7.1.3: el i m i nazi one esegui ta
7.2.7.1.2: el i m i na( )
7.2.5: cari ca dati
7.2.4: l eggi ( )
7.1.4: el i mi nazi one esegui ta
7.1.3: el i mi na( )
6: cari ca dati
UtenteDB
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Figura 60 - Sequence Diagram Gestione Utenti
236
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.4 Statechart Diagrams
Gli Statechart Diagrams costituiscono uno strumento mediante il quale è
possibile descrive una state machine, enfatizzando il flusso di controllo tra gli state.
Una state machine definisce un comportamento che specifica i vari state che un
oggetto può assumere durante la sua vita in risposta a certi eventi. Ogni state
rappresenta una condizione di un oggetto, in cui sono soddisfatti certi requisiti ,
mentre un evento è la specificazione di un accadimento significativo, posizionabile
nel tempo e nello spazio, che determina una transizione di stato da parte dell’oggetto.
Quest’ultima esprime il fatto che, un oggetto a partire da un certo stato ed al
verificarsi di un determinato evento passa in uno stato differente, poiché sono
cambiate le condizioni in cui si trova. Sulla base di quanto detto, un diagramma di
questo tipo può rappresentare un’estensione della descrizione di un automa a stati
finiti.
Considerando il case study sviluppato, sono stati definiti gli Statechart Diagrams per
quegli oggetti che possono compiere delle transizioni significative durante la vita della
Web application. In particolare sono :
-
Amministratore;
-
Utente;
-
BranoMP3;
-
CartaCredito;
-
Playlist;
-
SchedaPrepagata
Per
quanto
riguarda
l’Amministratore,
quest’ultimo
può
trovarsi
fondamentalmente in due possibili stati : loggato e bloccato. Ovviamente, bisogna
tener conto che la condizione di Amministratore non loggato rappresenta il punto di
inizio del diagramma. Lo stato “loggato” si raggiunge dopo aver eseguito
correttamente il login, mentre lo stato “bloccato” dopo aver commesso due errori
consecutivi di accesso.
237
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
/ 2 errori consecutivi di login
Bloccato
/ login
Loggato
/ sblocco
/ logout
Figura 61 - Statechart Amministratore
L’Utente prevede una situazione leggermente complicata, in quanto si parte
da uno stato iniziale in cui l’utente non è registrato. Una volta eseguita la
registrazione, l’utente passa nello stato “registrato” ed all’interno di esso può evolvere
tra gli stessi stati dell’amministratore, ossia “loggiato” e “bloccato”, sulla base dei
medesimi eventi.
Lo Statechart Diagram prevede una struttura innestata, nell’ambito della quale
all’interno dello stato “registrato” è previsto un ulteriore diagramma che descrive le
possibili transizioni di stato dell’utente che ha eseguito la registrazione.
238
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
/ registrazione Utente
Registrato
/ 2 errori consecutivi di login
/ login
Loggato
Bloccato
/ logout
/ sblocco
/ cancellazione Utente
Figura 62 - Statechart Utente
Il BranoMP3 ha un’evoluzione notevolmente complicata, considerando che
si parte da una condizione in cui il brano non è stato inserito nell’archivio ed
eseguendo tale operazione, si passa allo stato “archiviato”. In corrispondenza di tale
stato, il brano può subire diverse transizioni :
-
passare nello stato di “in ascolto”;
-
passare nello stato di “acquistato”;
-
passare nello stato “in playlist”;
239
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Lo stato “acquistato” a sua volta prevede la possibilità, da parte del brano, di passare
nello stato di “downloading”, considerando che la condizione necessaria per scaricare
un brano è effettuarne l’acquisto. Allo stesso modo, lo stato “in playlist” permette al
brano di passare nello stato “in ascolto” ed “acquistato”, per poter esplicitare il fatto
che l’ascolto e l’acquisto di un brano MP3 possono essere eseguiti nei casi in cui
l’utente abbia o meno delle playlist preferite.
/ inserimento brano
Archiviato
/ ascolta
/ aggiungi a playlist
/ acquista
Acquistato
In Playlist
/ ac quis ta
/ as c olta
/ avvio download
In Ascolto
Ac quis tato2
Downloading
/ termine download
/ acquis to es eguito
in As c olto
/ fine asc olto
/ fine ascolto
/ acquisto eseguito
/ cancella da playlist
/ cancellazione brano
Figura 63 - Statechart BranoMP3
240
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
/ acquista
/ avvio download
/ ascolta
Downloading
Acquistato2
/ termine download
/ acquisto eseguito
in Ascolto
/ fine ascolto
Figura 64 - Statecharts BranoMP3 acquistato/in playlist
L’oggetto CartaCredito è un’evoluzione abbastanza semplice, in quanto
l’unico stato in cui può transitare è “in verifica”, nell’ambito del quale il sistema sta
valutando se la carta di credito sia coperta o meno.
/ verifica copertura
In Verifica
/ termine verifica
Figura 65 - Statechart CartaCredito
241
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
La Playlist può essere paragonato al BranoMP3 ma con una complessità
inferiore. Eseguendo l’operazione di creazione, la Playlist passa nello stato
“archiviata”, nell’ambito del quale può trovarsi o meno nello stato di “ascolto”.
/ creazione
Archiviata
/ ascolta
Ascolto
/ f ine ascolto
/ cancellazione
Figura 66 - Statechart Playlist
L’oggetto SchedaPrepagata prevede probabilmente una delle evoluzioni più
complesse. Effettuando l’operazione di acquisto, da parte dell’utente, la scheda passa
nello stato “acquistata”, all’interno del quale può effettuare diverse transizioni.
242
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
/ acquisto
Acquistata
/ scaduta
Figura 67 - Statechart SchedaPrepagata
Lo stato “acquistata” è composto, per cui all’interno di esso può essere definito un
ulteriore Statechart Diagram certamente più complesso.
/ scadenza scheda
/ richiesta ricarica
Scaduta
/ acquisto brano
/ richiesta ricarica
In Uso
/ importo residuo aggiornato
/ importo residuo esaurito
Ricaricata
/ richiesta ricarica
Esaurita
/ termine ricarica
Figura 68 - Statechart SchedaPrepagata acquistata
243
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
All’interno del diagramma si possono evidenziare i seguenti stati :
-
“scaduta” : quando la data odierna va oltre la data di scadenza della scheda;
-
“in uso” : quando ne viene aggiornato l’importo residuo, perché è stato
effettuato l’acquisto di un brano MP3;
-
“esaurita” : quanto l’importo residuo è azzerato;
-
“ricaricata” : quando viene eseguita un’operazione di ricarica;
3.5 Conceptual Data Model
La definizione del modello concettuale rappresenta il primo passo verso la
progettazione della base di dati. Esso permette di descrivere tutte quelle che sono le
entità del mondo reale e le relazioni che ci sono fra di esse. Inoltre, per ciascuna
entità o relazione che sia, è possibile definirne gli attributi caratteristici. In un certo
senso, lo stesso Class Diagram può essere considerato in moltissimi casi il modello
concettuale di un database, poiché le entità e le relazioni rappresentate sono
praticamente le stesse, a meno di un formalismo differente.
Facendo riferimento alla Web application in esame, le entità del modello sono le
seguenti :
-
AccessoUtente ed AccessoAmministratore : rappresentano le informazioni di
accesso
dell’utente
e
dell’amministratore.
Esse
rappresentano
una
specializzazione dell’entità Accesso, alla quale sono legate con una relazione del
tipo Generalizzazione/Specializzazione.
-
Utente ed Amministratore : definiscono le informazioni di un utente e
dell’amministratore. Sono una specializzazione dell’entità Ruolo;
-
BranoMP3 : contiene le informazioni di un brano MP3;
-
Playlist : rappresenta la generica playlist creata da un utente;
-
SchedaPrepagata : rappresenta le informazioni della scheda prepagata;
E’ da osservare che, rispetto al Class Diagram non è presente l’entità CartaCredito, in
virtù del fatto che l’applicazione non memorizza in maniera permanente le sue
244
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
informazioni all’interno della base di dati, ma utilizza sempre un oggetto in memoria
che al termine dei controlli necessari viene distrutto.
Inoltre, le relazioni che legano queste entità sono :
-
LoginLogout Utente : associa a ciascun Utente le relative informazioni di accesso
dell’entità AccessoUtente;
-
LoginLogout Amministratore : associa l’Amministratore alle informazioni relative
agli accessi eseguiti dell’entità AccessoAmministratore;
-
Download : associa l’Utente con un BranoMP3. E’ da osservare che nel Class
Diagram, questa entità è rappresentata da una classe associativa;
-
Creazione : lega l’Utente con la Playlist. Essa non è presente nel Class Diagram;
-
Composizione : descrive la composizione di una playlist, associando un
BranoMP3 con la Playlist di appartenenza. E’ prevista anche nel Class Diagram
ma con un formalismo diverso, la relazione di “aggregazione”;
-
Acquisto e Ricarica : legano l’Utente con la SchedaPrepagata. E’ da osservare che
tra queste due entità sussistono due relazioni, poiché da un punto di vista
concettuale sono differenti e ciascuna di esse ha delle informazioni proprie,
diverse dall’altra;
Infine, per ciascuna entità e per ciascuna relazione sono specificati gli attributi che le
caratterizzano con il corrispondente tipo di dato. E’ da osservare che alcune relazioni
non hanno attributi, in quanto servono ad esprimere esclusivamente un’associazione
tra due entità ma non hanno informazioni proprie. Nel modello logico, alcune di
queste sono destinate a scomparire, ossia LoginLogout Utente e LoginLogout
Amministratore, mentre Composizione sarà necessaria per definire la relazione molti-amolti che esiste tra BranoMP3 e Playlist.
245
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Accesso
dataOraLogin
dataOraLogout
loginValido
tentativo
indirizzoIP
DT
DT
BL
BT
VA15
<<extends>>
AccessoUtente Accesso
<<extends>>
AccessoAmministratore Accesso
Ruolo
AccessoUtente
userName
password
bloccato
loggedIn
1,1
AccessoAmministratore
VA20
VA15
BL
BL
1,1
LoginLogout Amministratore
LoginLogout Utente
<<extends>>
Amministratore Ruolo
<<extends>>
Utente Ruolo
0,n
Amministratore
0,n
Utente
nome
cognome
indirizzo
citta
provincia
CAP
stato
telefono
dataNascita
sesso
email
dataOraRegistrazione
acquistoMP3
VA15
VA15
VA50
VA30
VA30
VA5
VA15
VA15
D
A1
VA50
DT
BL
Download
0,n
BranoMP3
dataOraAcquisto DT
0,n
0,n
genere
titolo
autore
album
durata
costo
dimensione
nomeFileMP3
VA15
VA50
VA30
VA50
T
DC3,2
I
VA255
0,n
Creazione
dataOraCreazione DT
0,1
0,n
Composizione
Ricarica
Acquisto
importo DC5,2
dataOra DT
dataOraAcquisto DT
0,n
Playlist
1,1
1,1
nome VA15
SchedaPrepagata
importoResiduo DC5,2
dataScadenza D
0,n
Figura 69 - Conceptual Data Model
246
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
3.6 Physical Data Model
Per completare la progettazione della base di dati, è necessario effettuare la
trasformazione del modello concettuale nel modello logico, anche detto modello
fisico. Quest’ultimo è costituito da una serie di tabelle e le relative colonne che
prendono il posto delle entità e delle relazioni con i relativi attributi, presenti nel
modello concettuale. La trasformazione viene eseguita sulla base di una serie di
regole, che permettono di adattare il mondo reale, rappresentato dal modello
concettuale, all’implementazione fisica che verrà successivamente adottata per uno
specifico DBMS (DataBase Management System).
Le principali operazioni di trasformazione sono le seguenti :
-
eliminare tutte le relazioni del tipo Generalizzazione/Specializzazione, sulla
base di tre possibili alternative;
1. accorpamento delle entità figlie nel padre, con l’introduzione di un
attributo che le possa distinguere;
2. accorpamento del padre nelle entità figlie;
3. sostituzione delle generalizzazioni con semplici associazioni;
-
scegliere uno o più attributi di ciascuna entità che possano costituirne una
chiave primaria, ossia tale da individuare ogni istanza dell’entità stessa in
maniera univoca. Nel caso in cui l’entità non sia caratterizzata da attributi con
questo tipo di funzionalità, è possibile introdurre un nuovo attributo che
abbia il solo ruolo di chiave primaria;
-
ogni entità va rappresentata con una tabella, le cui colonne sono esattamente
gli attributi dell’entità stessa;
-
una relazione uno-a-molti tra due entità non viene rappresentata con una
tabella ma viene assorbita dall’entità lato “uno”;
-
una relazione molti-a-molti viene rappresentata attraverso una tabella che sarà
legata alle due tabelle relative alle entità in gioco, sulla base delle loro chiavi
primarie;
-
una relazione uno-a-uno non viene rappresentata attraverso una tabella ma è
assorbita indifferentemente da una delle entità legate;
247
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Accesso
idAccesso
idRuolo
ruolo
dataOraLogin
dataOraLogout
loginValido
tentativo
indirizzoIP
int
<pk>
int
<fk1,fk2>
char
datetime
datetime
bool
tinyint unsigned
varchar(15)
ruolo : distingue tra le entità figlie (AccessoUtente ed
AccessoAmministratore)
idRuolo : è l'ID di un Utente o di un Amministratore
FK_IDAMMINISTRATORE
FK_IDUTENTE
Download
idUtente
int
<fk1>
idBranoMP3
int
<fk2>
dataOraAcquisto datetime
Amministratore
idAmministratore
userName
password
bloccato
loggedIn
int
<pk>
varchar(20)
varchar(15)
bool
bool
FK_IDUT ENT E
FK_IDBRANOMP3
Utente
idUtente
nome
cognome
indirizzo
citta
provincia
CAP
stato
telefono
dataNascita
sesso
email
dataOraRegistrazione
acquistoMP3
userName
password
bloccato
loggedIn
BranoMP3
int
<pk>
varchar(15)
varchar(15)
varchar(50)
varchar(30)
varchar(30)
varchar(5)
varchar(15)
varchar(15)
date
char
varchar(50)
datetime
bool
varchar(20)
varchar(15)
bool
bool
idBranoMP3
genere
titolo
autore
album
durata
costo
dimensione
nomeFileMP3
int
<pk>
varchar(15)
varchar(50)
varchar(30)
varchar(50)
time
decimal(3,2)
int unsigned
varchar(255)
FK_IDBRANOMP3
FK_IDUTENTE
ComposizionePlaylist
idPlaylist
int <fk1>
idBranoMP3 int <fk2>
FK_IDUT ENT E
Ricarica
idRicarica
idSchedaPrepagata
importo
dataOra
int
<pk>
int
<fk>
decimal(5,2)
datetime
FK_IDPLAYLIST
Playlist
SchedaPrepagata
idSchedaPrepagata
idUtente
importoResiduo
dataScadenza
dataOraAcquisto
FK_IDSCHEDAPREPAGATA
int
<pk>
int
<fk>
decimal(5,2)
date
datetime
idPlaylist
idUtente
nome
dataOraCreazione
int
<pk>
int
<fk>
varchar(15)
datetime
Figura 70 - Physical Data Model
248
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
Sulla base delle regole suddette, il modello logico risultante ha le seguenti
caratteristiche :
-
in tutte le tabelle è stato introdotto un attributo (colonna) che ne rappresenti
la chiave primaria, con un nome del tipo “idNomeTabella” per esprimere che
si tratta di un identificativo univoco;
-
la relazione Generalizzazione/Specializzazione avente come padre l’entità
Accesso e come figlie le entità AccessoUtente ed AccessoAmministratore è stata
eliminata accorpando queste ultime nel padre. Per poter distinguere le
occorrenza dell’una e dell’altra, è stata introdotto l’attributo “ruolo” nella
tabella Accesso definitiva. La scelta della soluzione da adottare è basata sul
fatto che le due entità figlie sono caratterizzate da occorrenza
concettualmente diverse ma che hanno le medesime informazioni;
-
la relazione Generalizzazione/Specializzazione avente come padre l’entità
Ruolo e come figlie le entità Utente ed Amministratore è stata eliminata
accorpando all’interno di queste ultime, l’entità padre. Tutto ciò determina la
presenza di due tabelle distinte per l’utente e per l’amministratore ed è da
sottolineare che la scelta fatta è motivata dalla presenza di informazioni
completamente diverse che caratterizzano i due utilizzatori;
-
le relazioni uno-a-molti da Utente ed Amministratore verso Accesso, sono state
risolte introducendo all’interno di quest’ultima tabella una chiave esterna
“idRuolo”
che
corrisponde
alle
chiavi
primarie
“idUtente”
ed
“idAmministratore”. E’ da osservare che l’identificazione univoca di un
accesso, appartenente ad un utente oppure all’amministratore, è individuata
dalla coppia “idRuolo-ruolo”;
-
la relazione molti-a-molti tra Utente e BranoMP3 è stata trasformata nella
tabella Download contenente le chiavi primarie di queste ultime. Esse,
considerate in coppia, formano la chiave primaria della tabella stessa;
-
la relazione uno-a-molti tra Utente e Playlist è stata assorbita dal lato uno
(Playlist) trasferendone il proprio attributo. Per questo motivo, la tabella
Playlist ha una chiave esterna che la lega alla tabella Utente;
249
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
-
la relazione molti-a-molti tra BranoMP3 e Playlist relativa alla composizione di
quest’ultima è stata trasformata nella tabella Composizione, che contiene
semplicemente le chiavi primarie delle due tabelle legate;
-
la relazione uno-a-uno tra Utente e SchedaPrepagata poteva essere risolta
attraverso una sola tabella, ma in questo caso si sarebbe persa la differenza
concettuale che c’è tra le due entità. Per questo motivo sono state definite
due tabelle separate e la relazione è stata assorbita dal lato SchedaPrepagata,
contenendo attributi che riguardano strettamente quest’ultima;
-
la relazione molti-a-molti tra Utente e SchedaPrepagata relativa alle operazioni di
ricarica è stata trasformata nella tabella Ricarica. Essa prevede una chiave
esterna che la lega alla tabella SchedaPrepagata. Il legame con la tabella Utente è
stato eliminato in quanto, non solo dal punto di vista concettuale la ricarica è
strettamente legata alla scheda, ma anche perché si sarebbe venuta a creare
un’inutile relazione circolare. E’ sempre possibile passare dall’Utente alla
Ricarica attraverso la SchedaPrepagata;
Oltre queste trasformazioni, sono stati introdotti dei particolari vincoli (costraints) di
“cascade” sugli eventi “onDelete”, in modo da non lasciare informazioni inutili che
rendano il database “sporco”. Qui di seguito sono elencate le tabelle interessate, le
chiavi esterne e le motivazioni dei vincoli :
-
le due chiavi esterne della tabella Composizione, in modo che se viene
cancellato un brano MP3 dall’archivio, esso scompare anche dalle
composizioni delle playlist. Inoltre, se viene cancellata una playlist, vengono
cancellati tutti i riferimenti ai brani che la componevano;
-
le due chiavi esterne della tabella Download, in modo che se si cancella un
utente si perdono anche le tracce dei brani scaricati, così come se viene
cancellato un brano non si hanno più riferimenti agli utenti che ne hanno
eseguito il download;
-
la chiave esterna della tabella SchedaPrepagata verso Utente, in modo che
cancellando un utente vengono automaticamente eliminate le informazioni di
un’eventuale scheda prepagata ad esso associata;
250
Capitolo V – Case Study : Analisi e Progettazione
_________________________________________________________________
-
la chiave esterna della tabella Ricarica, in modo che cancellando una scheda
prepagata vengono eliminate anche tutte le operazioni di ricarica eseguite su
di essa;
-
la chiave esterna della tabella Playlist, in modo che cancellando un utente
siano eliminate anche le playlist ad esso associate;
Attraverso i legami che ci sono tra le tabelle ed i vincoli di “cascade” definiti sugli
eventi “onDelete”, si determinano delle operazioni di cancellazione a catena che
permettono di lasciare nel database solo ed esclusivamente i dati necessari. Ad
esempio, cancellando un utente vengono eliminate le playlist ad esso associate e
quindi le informazioni della loro composizione, nonché un eventuale scheda
prepagata con tutte le operazioni di ricarica ed infine le operazioni di download dei
brani MP3. Questo è il più completo degli scenari che si possa presentare nelle
operazioni di cancellazione delle informazioni dalla base di dati.
251
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Capitolo VI – Case Study : Implementazioni a confronto
1. Introduzione
Il confronto tra due tecnologie, che nel caso specifico sono i due
framework di sviluppo Web Struts e JavaServer Faces, può essere considerato
effettivamente valido soltanto nel momento in cui viene supportato da una prova sul
campo. Infatti, non basta semplicemente descrivere in maniera puramente discorsiva
le caratteristiche dell’uno e dell’altro framework, ma è necessario applicare le due
tecnologie ad un medesimo caso di studio, per poter dare maggior risalto al
confronto teorico.
Per questo motivo, la Web application precedentemente progettata è stata
implementata sia con Struts che JSF, in modo da valutare con quali modalità i due
framework permettano di realizzare le medesime funzionalità. Ovviamente, facendo
seguito alla stessa fase di Progettazione, il sistema software risultante ha
un’architettura diversa per ciascuna tecnologia, sulla base delle potenzialità che
differenziano l’una dall’altra.
I termini di paragone possono riguardare :
-
la semplicità con cui un framework permetta di realizzare una funzionalità
rispetto all’altro, attraverso gli strumenti che fanno parte della propria
architettura;
-
la necessità da parte di un framework di utilizzare strumenti esterni alla
propria implementazione;
-
la possibilità di estensione e la flessibilità di un framework rispetto all’altro, in
modo da poter definire degli strumenti di sviluppo personalizzati;
Sulla base di questi aspetti può essere impostato un confronto pratico, che non faccia
altro che confermare quanto descritto nel Capitolo IV.
252
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda il caso di studio preso in esame, gli strumenti software utilizzati
per lo sviluppo e gli ambienti di esecuzione sono i seguenti :
-
Piattaforma J2SE (Java 2 Second Edition);
-
Ambiente IDE Eclipse 3.1 con i plug-in di Exadel Studio, per lo sviluppo
grafico dei file di configurazione di JavaServer Faces e Struts, e UML Omondo,
per la realizzazione dei Class Diagrams per le classi implementate;
-
Web Container/Server Jakarta Apache Tomcat 5.0.28;
La piattaforma J2SE (Java2 Standard Edition) rappresenta la base per lo sviluppo e
l’esecuzione delle applicazioni Java, in quanto mette a disposizione la JVM (Java
Virtual Machine), oltre a tutte le classi principali e le librerie del linguaggio.
Un’estensione di questa piattaforma è rappresentata dalla J2EE (Java2 Enterprise
Edition) che fornisce il supporto per strumenti avanzati come i Web Services, gli EJB
(Enterprise Java Beans) e JavaServer Faces. In questo caso, non si è reso necessario
l’utilizzo della piattaforma J2EE, in quanto la distribuzione del framework JSF può
essere gestita anche semplicemente mediante le librerie JAR (Java ARchive) che
contengono le classi dell’architettura. Nelle successive versioni della piattaforma Java,
in particolare a partire dalla Java5, JSF ne diventerà parte integrante.
Per l’ambiente di sviluppo IDE (Integrated Development Environment), la scelta è
caduta sul progetto OpenSource Eclipse 3.1, dopo un rapido confronto con
l’antagonista NetBeans. Ha nettamente prevalso il primo, considerando il supporto
fornito per lo sviluppo di applicazioni Web basate appunto su Struts e JSF, grazie al
plug-in free di Exadel. Il secondo, invece, fino alla versione 4.1 non ha ancora fornito
tale supporto, introdotto a partire dalla versione 5 in fase di Beta Testing. Prendendo
in esame tale versione, la semplicità ed il supporto offerti da Eclipse 3.1 sono
comunque nettamente superiori.
L’ambiente è stato ulteriormente ampliato utilizzando il plug-in free di Omondo per
la realizzazione dei diagrammi UML, a partire dalle classi implementate. Tale
strumento è stato utilizzato solo ed esclusivamente per generare i Class Diagrams a
livello di implementazione.
253
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda il Web Container, la scelta è ovviamente caduta sul progetto
OpenSource Jakarta Apache Tomcat 5.0.28, sicuramente tra i migliori per
l’esecuzione di applicazioni Web realizzate in ambiente Java.
E’ altresì necessario specificare che, per quanto riguarda Struts, è stata utilizzata la
versione 1.1 mentre per JavaServer Faces è stata scelta l’implementazione JSF-RI
(Refernce Implementation) 1.0 e non MyFaces. In questo modo, è possibile
confrontare due tecnologie realizzate da sviluppatori diversi, in quanto Struts rientra
tra i progetti Jakarta, così come MyFaces, mentre JSF-RI è stato realizzato dalla Sun
Microsystems.
2. Struttura dell’applicazione
Il primo aspetto preso in considerazione riguarda la struttura
dell’applicazione, in termini di eventuali moduli che la compongono, oltre che delle
pagine, le immagini, gli eventuali fogli di stile (CSS) e di tutti gli altri elementi che ve
ne fanno parte.
Per quanto riguarda l’implementazione con JSF, l’architettura del sistema prevede un
unico modulo al quale è ovviamente associato un file di configurazione (facesconfig.xml). I file componenti il progetto riguardano l’applet che implementa il player
MP3 per l’ascolto dei brani, i templates che definiscono il layout delle pagine
mediante l’utilizzo di Tiles ed il relativo file delle definizioni (tiles-defs.xml), le pagine
ed i relativi contenuti, le immagini, il foglio di stile (styles.css) per la formattazione della
grafica ed un Tag Library Descriptor (components.tld) che contiene i tag associati ai
componenti della UI implementati. Infine, oltre alla librerie che contengono le classi
costituenti l’architettura del framework, sono utilizzati i seguenti gruppi di ulteriori
librerie :
-
JavaMail : framework per l’invio delle mail basato su JAF (JavaBeans
Activation Framework);
-
JDBC MySQL Connector : contiene le classi relative ai driver JDBC (Java
DataBase Connectivity) per l’accesso alla base di dati realizzata con il DBMS
MySQL;
254
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
Tiles : framework per la definizione del layout delle pagine;
-
Java MP3 Tag Library : classi per l’accesso ai tag ID3v1 dei file MP3;
-
Commons Project File Upload e Tomahawk : contiene una serie di funzionalità
aggiuntive, tra cui il componente per eseguire l’upload di un file sul server;
Per quanto riguarda l’implementazione con Struts, l’applicazione ha un’architettura
che prevede tre moduli distinti :
-
default : modulo principale che fornisce le funzionalità generiche di login,
registrazione di un nuovo utente e richiesta dei dati di accesso via mail;
-
user :
modulo contenente tutte le funzionalità disponibili ad un utente
registrato;
-
admin : modulo che fornisce le funzionalità per l’amministratore;
Ciascuno di questi moduli ha il proprio file di configurazione all’interno del quale
descrivere il mapping delle action, i forward, le pagine e le eccezioni.
Il modulo “default” viene avviato al momento della prima richiesta di un client. Nel
momento in cui l’utilizzatore effettua un’operazione di login, in base al fatto che si
tratti di un utente oppure dell’amministratore, viene eseguito lo “switch” verso il
modulo corrispondente. Invece, se viene eseguita un’operazione di registrazione,
poiché questa è seguita da un login automatico, si passa direttamente al modulo
“user”. Il passaggio inverso dai moduli “user” e “admin” verso il modulo “default” viene
effettuato in seguito ad un’azione di logout.
Attraverso la scomposizione in moduli, non soltanto si ha il notevole vantaggio di
raggruppare concettualmente le funzionalità legate ad un particolare utilizzatore ma
anche quello di dover gestire tre file di configurazione differenti di dimensione
ridotta, in luogo di un unico file di grandi dimensioni.
La struttura in termini di file prevede, similmente a JSF, l’applet che implementa il
player MP3, i templates per il layout delle pagine mediante Tiles ed il relativo file
delle definizioni (tiles-defs.xml), le pagine ed i relativi contenuti, le immagini, il foglio di
stile (styles.css) per la formattazione della grafica. Tali file sono opportunamente
separati in corrispondenza dei tre moduli.
255
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Oltre alle librerie proprie di Struts, che includono Tiles ed il plug-in Validator, sono
utilizzati anche i seguenti gruppi di librerie :
-
JavaMail : framework per l’invio delle mail basato su JAF (JavaBeans
Activation Framework);
-
JDBC MySQL Connector : contiene le classi relative ai driver JDBC (Java
DataBase Connectivity) per l’accesso alla base di dati realizzata con il DBMS
MySQL;
-
Java MP3 Tag Library : classi per l’accesso ai tag ID3v1 dei file MP3;
-
JSTL : contiene i tag, che sfruttano l’Expression Language, per la costruzione
del contenuto delle pagine;
Rispetto all’implementazione in JSF, si evince che il framework Tiles è incluso nella
distribuzione di Struts ed è perfettamente integrato con quest’ultimo, così come non
è necessario il Commons Project File Upload, in quanto la libreria Struts HTML
fornisce un tag per l’upload di file. L’utilizzo di JSTL può essere considerato non
necessario, in quanto le librerie del framework forniscono tutto il necessario, anche
se JSTL supporta l’Expression Language che permette di semplificare l’accesso alle
proprietà dei JavaBeans mediante l’utilizzo della “dot notation”.
Il plug-in Exadel dell’ambiente Eclipse mette a disposizione la possibilità di realizzare
i file di configurazione di Struts in modalità grafica, stabilendo le relazioni che ci sono
tra le pagine, le action ed i forward. La medesima funzionalità non è offerta per
JavaServer Faces, per cui di seguito viene riportata la struttura dei tre moduli che
costituiscono la Web application in Struts.
256
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 1 - Struts : Modulo "default"
257
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 2 - Struts : Modulo "admin"
258
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 3 - Struts : Modulo "user"
259
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda il modulo “default”, si osserva che dalla homepage sia possibile
accedere alla funzionalità di login e di registrazione, seguita dall’eventuale acquisto
della scheda prepagata. Inoltre, è possibile richiedere l’invio di una mail contenente i
dati di accesso in caso di dimenticanza. Si osservi che sono definiti due forward,
associati ad una SwitchAction, che permettono di passare al modulo “user” oppure
“admin”. Infine, è definita un’eccezione globale nel caso si verifichi un errore di
accesso alla base di dati.
La struttura del modulo “user” prevede l’accesso alle seguenti funzionalità :
-
modifica dei dati dell’utente;
-
acquisto e ricarica della scheda prepagata;
-
visualizzazione e ricerca dei brani MP3;
-
gestione delle playlist;
-
ascolto brani e playlist;
-
operazione di logout, associata ad una SwitchAction, che permette di tornare al
modulo “default”;
Anche in questo caso è definita un’eccezione globale nel caso si verifichi un errore di
accesso alla base di dati.
Infine, l’architettura del modulo “admin” fornisce i seguenti servizi :
-
modifica dei dati dell’amministratore;
-
gestione degli utenti;
-
visualizzazione e ricerca dei brani MP3;
-
inserimento, modifica ed ascolto dei brani MP3;
-
operazione di logout, associata ad una SwitchAction, che permette di tornare al
modulo “default”;
Analogamente agli altri due moduli, è definita un’eccezione globale che viene
sollevata qualora si verifichi un errore di accesso alla base di dati.
Per completare l’analisi della struttura complessiva della Web application, bisogna
descrivere quelli che sono i package contenenti le classi ed il loro ruolo.
260
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Le due implementazioni hanno dei package comuni, in base al fatto che le
funzionalità sono sostanzialmente le stesse. Ovviamente, le classi contenute
all’interno di essi possono presentare delle differenze. Nel dettaglio, i package
comuni sono i seguenti :
-
accesso : classi relative alle informazioni di accesso dell’utente e
dell’amministratore;
-
brani : classi relative ai brani ed i corrispondenti file MP3;
-
cartacredito : classe relativa alla carta di credito;
-
database : classi relative all’accesso alla base di dati. E’ da sottolineare che
questo package è perfettamente uguale nelle due implementazioni, a meno
della tipologia di eccezioni sollevate nel caso si verifichi un errore di accesso
al database. Facendo riferimento al pattern MVC ed in particolare ai
sottolivelli del Model, si osserva che questo package costituisce il Data Access
Sublayer, completamente indipendente dai sottolivelli che lo precedono;
-
download : classe relativa all’acquisto e download dei brani;
-
exception : classi che implementano delle eccezioni personalizzate, estendendo
la classe di base Exception. Anche questo package è perfettamente uguale nelle
due implementazioni;
-
listeners : classi che intervengono in particolari situazioni di controllo;
-
mail : classe per l’invio delle mail;
-
playlist : classi per la gestione delle playlist;
-
ruolo : classi che implementano i possibili utilizzatori del sistema;
-
scheda : classi relative alla scheda prepagata ed alle corrispondenti ricariche;
I package specifici dell’implementazione con JavaServer Faces sono i seguenti :
-
components : classi che implementano dei Custom Components, realizzati per
l’interfaccia utente (UI);
-
validators : classi che implementano alcuni Custom Validators, utilizzati per la
validazione dei dati;
261
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Infine, i package relativi all’implementazione con Struts sono :
-
defaultactions : classi che implementano le action del modulo “default”;
-
adminactions : classi che implementano le action del modulo “admin”;
-
useractions : classi che implementano le action del modulo “user”;
-
commonactions : classi che implementano alcune action comuni a più moduli;
-
controller : classe che realizza un Controller personalizzato;
-
formbean : classi che implementano alcuni dei formbean, mentre i restanti sono
di tipo dinamico ed dichiarati esclusivamente nel file di configurazione;
-
plugin : classe che realizza un plug-in per l’inizializzazione di alcuni dati;
Un’ ulteriore considerazione riguarda l’internazionalizzazione (I18N), supportata
dalla Web application attraverso la definizione di due Resource Bundle. In
particolare, ne è previsto uno per la localizzazione di default, ossia l’Italia, e l’altro per
un’ulteriore localizzazione supportata, in lingua Inglese. I file che contengono i
messaggi sono perfettamente identici nelle due implementazione, a meno di alcuni
messaggi relativi agli errori di validazione, che hanno chiavi diverse in relazione al
framework utilizzato.
Infine, ci sono da motivare le scelte relative alla realizzazione del Model,
sostanzialmente diverso tra le due implementazioni.
In entrambi i casi, il sottolivello Data Access è completamente indipendente dagli
altri e le classi che lo implementano sono perfettamente uguali tra le due
implementazioni. Questo ne favorisce la portabilità, qualora si prenda in
considerazione l’ipotesi di realizzare la Web application con un ulteriore framework
differente. Per quanto riguarda i sottolivelli di Business Logic ed External Interface,
si è fatta una scelta diversa per evidenziare le due possibili modalità di approccio che
meglio si adattino ai due framework : separazione e fusione.
Per quanto riguarda JavaServer Faces, si è utilizzato l’approccio di “fusione”,
realizzando i backing beans in modo tale da contenere la business-logic e
l’interfacciamento con le classi del framework. Tale scelta ha il vantaggio di non
dover realizzare un ulteriore strato di classi che implementi l’External Interface
sublayer, il cui scopo sia quello di invocare i metodi sulle classi della business-logic ed
utilizzare gli oggetti interni al framework. Lo svantaggio è ovviamente la perdita di
262
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
portabilità, in quanto i backing beans utilizzano delle classi che non sarebbero
presenti in framework diversi.
Nel caso di Struts, la scelta è in un certo senso obbligatoria, in quanto le classi che
implementano le action accedono agli oggetti propri del framework ed invocano i
metodi
delle
classi
della
business-logic,
fungendo
automaticamente
da
interfacciamento. La Business-logic, invece, prevede delle classi completamente
indipendenti dal framework, in quanto non hanno l’onere di accedere agli oggetti di
quest’ultimo, grazie all’intervento delle action. Il vantaggio è rappresentato dalla
portabilità in quanto il medesimo strato di business-logic può essere adottato con
framework differenti, lo svantaggio è dato dalla presenza dello strato in più delle
action, che comunque è previsto dalla struttura del framework.
Si osserva che le scelte hanno i propri pregi e difetti e ciascuna di esse può essere
considerata ugualmente valida così come le altre. In molti casi, la propensione verso
una di esse può dipendere dal framework e dalle dimensioni dell’applicazione da
realizzare.
3. Controller
Ciascuno dei due framework fornisce le proprie classi di base che
implementano la struttura del Controller di default. Seppur in maniera
completamente diversa, è possibile intervenire in Struts e JSF per poter
personalizzare tali classi, in modo da aggiungere particolari funzionalità che vanno
applicate durante la fase di comunicazione tra Model e View. Nel caso di studio in
esame, si è reso necessario l’intervento sul Controller, per poter gestire due situazioni
particolarmente delicate :
-
la gestione delle sessioni non concluse correttamente dell’utilizzatore;
-
la possibilità di accesso a pagine protette senza la necessaria operazione di
login;
La prima problematica è stata risolta allo stesso modo nelle due implementazioni, in
quanto è più legata alla gestione delle Servlet che non alle classi di uno specifico
263
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
framework. Il secondo problema è stato affrontato in maniera completamente
diversa, considerando la differente architettura che assume il Controller in Struts e
JSF.
3.1 Gestione delle sessioni
Uno dei principali problemi da cui sono afflitte tutte le Web application, è
la gestione delle sessioni che non vengono concluse correttamente da un utente. Nel
caso specifico, quando l’utilizzatore, utente o amministratore che sia, effettua il login
al sistema, vengono memorizzate all’interno della base di dati le informazioni relative
all’accesso, ossia la data ed l’ora di ingresso, l’indirizzo IP del client ed il numero di
tentativi effettuati. Inoltre, viene settato un flag nel database che indica che l’utente è
online, in modo che un tentativo fraudolento di accesso da parte di un secondo
utente che disponga dei dati del primo, venga ovviamente bloccato. Nell’effettuare
correttamente la fase di logout, le informazioni di accesso vengono aggiornate
settando opportunamente la data e l’ora di uscita dal sistema, nonché viene azzerato
il flag nel database per segnalare che l’utente è offline. Ci sono moltissime situazioni
in cui un utente chiude direttamente il browser, senza completare correttamente il
logout. In questo caso è necessario intervenire per ristabilire la coerenza delle
informazioni contenute nel database rispetto alla realtà. L’evento di chiusura del
browser non può essere intercettato dal server, sul quale è in esecuzione la Web
application, ma ovviamente solo dal client. Il linguaggio di scripting lato client, che
permette di eseguire elaborazioni su quest’ultimo è ovviamente il JavaScript, il quale
però non mette a disposizione la possibilità di intercettare un semplice evento come
la chiusura di una finestra del browser, a meno che questa azione non venga eseguita
sempre mediante codice. Per questo ed altri motivi, è stato introdotto il concetto di
sessione, mediante la quale si stabilisce un legame tra l’utente che utilizza
l’applicazione ed il server, su cui quest’ultima è in esecuzione. Alla sessione è
associato un concetto di timeout, per cui se non si rileva attività da parte dell’utente
fino allo scattare di quest’ultimo, ne viene eseguita l’invalidazione. E’ in
corrispondenza di questo evento, che si può intervenire effettuando le operazioni che
garantiscano la coerenza delle informazioni nel sistema. Da qui, la necessità di
264
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
realizzare un listener, che allo scadere del timeout di sessione, intervenga per poter
permettere allo sviluppatore di effettuare delle elaborazioni necessarie.
La realizzazione di un listener di questo tipo è favorita dall’utilizzo dell’interfaccia
HttpSessionListener e della classe HttpSessionEvent. La prima mette a disposizione i
metodi da eseguire al momento della creazione e distruzione di una sessione, mentre
la seconda permette di ricavare un riferimento alla sessione stessa.
Per entrambe le implementazioni è stata realizzata la classe InactivityListener,
nell’ambito della quale il metodo sessionCreated() ha il compito di settare il timeout di
sessione e sessionDestroyed() ha l’onere di cambiare lo stato del flag nel database, per
segnalare che l’utente è offline. Quest’ultimo metodo viene appunto invocato nel
momento in cui scatta il timeout, in quanto l’utente non sta più generando attività sul
server e presumibilmente ha chiuso il browser senza eseguire correttamente il logout.
Figura 4 - JSF e Struts : InactivityListener
Questo aspetto non può essere considerato un termine di confronto tra i due
framework, in quanto le classi in gioco non sono specifiche di Struts e JSF, ma
rientrano nell’architettura delle Servlet in generale.
Inoltre, la configurazione che specifica l’utilizzo del listener è uguale per entrambi i
framework e non prevede l’intervento sui file faces-config.xml e struts-config.xml, ma
bensì sul Deployment Descriptor web.xml mediante la seguente dichiarazione :
<listener>
<listener-class>listeners.InactivityListener</listener-class>
</listener>
265
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
3.2 Protezione pagine
La seconda problematica in cui è necessario l’intervento sul Controller,
riguarda la possibilità che un utilizzatore voglia accedere alle pagine protette
dell’applicazione, senza avere eseguito correttamente l’operazione di login.
Ovviamente, il sistema deve intercettare un’azione di questo tipo, redirezionando
l’utente alla homepage, nella quale è costretto ad eseguire l’accesso. Dall’analisi del
problema, si evince che l’intervento deve essere eseguito per ciascuna richiesta che
arrivi dal client, in modo da sincerarsi che l’utilizzatore sia correttamente loggato,
qualunque sia la pagina a cui vuole accedere, escluse le pagine relative alla
registrazione ed alla richiesta dei dati di accesso via mail.
I due framework prevedono una risoluzione della problematica completamente
differente, data la diversa struttura del Controller, i punti in cui è possibile estendere
quest’ultimo ed il differente ciclo di vita a cui è sottoposta una generica richiesta.
Per quanto riguarda JavaServer Faces, è noto che la gestione di una richiesta del
client viene eseguita attraverso sei fasi distinte. In corrispondenza di ciascuna di esse,
può essere utilizzato un listener che permetta di eseguire delle operazioni prima e
dopo l’esecuzione della fase stessa. La soluzione adottata prevede la realizzazione
della classe LoginCheck che implementa l’interfaccia PhaseListener ed esegue i controlli
necessari prima della fase di Render Response. Essa prevede che il metodo
afterPhase() sia vuoto, mentre all’interno del metodo beforePhase() ci sia il controllo che
l’utilizzatore, utente o amministratore che sia, risulti correttamente loggato oppure la
richiesta si riferisca a pagine non protette da login. Nel caso di esito positivo, la
navigazione procede normalmente, altrimenti viene ricavato un riferimento al
NavigationHandler, il quale permette di spostare il flusso dell’applicazione verso la
homepage. Le informazioni relative all’evento verificatesi, ossia l’esecuzione della
fase di Render Response, sono contenute nella classe PhaseEvent.
266
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 5 - JSF : LoginCheck
La configurazione del listener prevede di associare quest’ultimo all’istanza della classe
Lifecycle che si occupa di gestire il ciclo di vita di ogni singola richiesta.
<lifecycle>
<phase-listener>listeners.LoginCheck</phase-listener>
</lifecycle>
La soluzione con Struts è completamente diversa, in quanto il ciclo di vita di una
richiesta è certamente più semplice e prevede esclusivamente l’intervento della classe
RequestProcessor. Per questo motivo, dovendo eseguire delle operazioni di controllo
prima che la richiesta venga elaborata, la soluzione prevede di realizzare la classe
CustomRequestProcessor che estende la classe base RequestProcessor. In realtà, osservando
il codice, si evince che la classe estesa è TilesRequestProcessor che comunque deriva da
RequestProcessor. E’ necessaria la derivazione dalla prima, in quanto l’utilizzo di Tiles
per il layout prevede l’intervento del proprio Controller. Il metodo che contiene il
codice delle operazioni da eseguire è processPreprocess(), il quale viene appunto eseguito
prima di iniziare la gestione della richiesta. Se l’utilizzatore risulta correttamente
267
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
loggato, la navigazione prosegue normalmente altrimenti si viene redirezionati alla
homepage.
Figura 6 - Struts : CustomRequestProcessor
E’ da osservare che la classe CustomRequestProcessor è registrata nei moduli “admin” e
“user” e non nel modulo “default”, in quanto quest’ultimo non contiene pagine
protette, per cui può utilizzare il RequestProcessor di base. In entrambi i file di
configurazione struts-config-user.xml e struts-config-admin.xml è presente la seguente
dichiarazione :
<controller processorClass="controller.CustomRequestProcessor"/>
4. View
La realizzazione dell’interfaccia utente (UI) è sicuramente uno degli aspetti
nei quali si evidenzia la netta differenza tra JavaServer Faces e Struts, in quanto il
primo è strettamente orientato allo sviluppo del Presentation Layer dell’applicazione.
Per quanto riguarda la produzione delle pagine JSP, l’implementazione in Struts ha
previsto l’utilizzo delle librerie di tag JSTL, in particolare Core e Formatting, oltre alla
libreria Struts HTML. La libreria Core sostituisce completamente le librerie Struts
Bean e Struts Logic per l’accesso alle proprietà dei bean e la definizione di costrutti
condizionali all’interno di ciascuna pagina. La libreria Formatting viene utilizzata
soprattutto per la visualizzazione dei messaggi all’utente, prelevandoli dal Resource
268
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Bundle. Infine, la libreria Struts HTML contiene tutti i tag necessari alla costruzione
dei form per l’immissione dei dati, così come i tag per la visualizzazione dei messaggi
di errore. La formattazione delle pagine ha previsto prevalentemente l’uso di tag
HTML, in particolar modo l’utilizzo delle tabelle.
L’implementazione in JSF ha previsto l’utilizzo delle due librerie proprie del
framework, ossia Core ed HTML, la prima per quanto riguarda aspetti avanzati come
l’uso dei validatori mentre la seconda per la costruzione dei form, la visualizzazione
dei messaggi e la formattazione del contenuto delle pagine.
Con entrambi i framework è stato previsto l’utilizzo di Tiles, del quale è stato
necessario importarne la libreria in JSF ma non in Struts, essendo incluso nella
distribuzione di quest’ultimo.
Inoltre, sfruttando l’enorme potenzialità di JSF, sono stati realizzati dei Custom
Components ed il relativo Tag Library Descriptor, in modo da utilizzare questi
componenti all’interno delle pagine con un corrispondente tag.
Infine, l’implementazione mediante Struts ha previsto l’utilizzo dei formbeans per
l’acquisizione dei dati dei form, mentre con JSF è bastato utilizzare i backing beans e
le relative proprietà.
4.1 Le librerie Standard
Per quanto riguarda le librerie di tag standard che i due framework mettono
a disposizione, si può affermare che nessuno dei due prevalga sull’altro. Sia JSF che
Struts hanno i propri vantaggi e svantaggi, per quanto concerne i tag che possono
essere utilizzati per definire gli elementi costitutivi di ciascuna pagina JSP.
E’ da osservare, però, che mentre JSF utilizza solo ed esclusivamente le proprie
librerie, Core ed HTML, invece con Struts si preferisce utilizzare le librerie JSTL,
Core e Formatting, in luogo di Struts Bean e Struts Logic, considerando il supporto
per l’Expression Language.
Inoltre, c’è una differenza in termini di configurazione delle librerie da adottare, in
quanto JSF non prevede alcun tipo di modifica nel Deployment Descriptor web.xml,
mentre Struts prevede l’elenco delle librerie che verranno utilizzate nell’applicazione.
269
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<taglib>
<taglib-uri>/WEB-INF/struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
...
<taglib>
<taglib-uri>/WEB-INF/c</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>
...
4.1.1 I form : contenuto e layout
Per quanto riguarda la costruzione dei form, entrambi i framework
dispongono di tag equivalenti, ovviamente con sintassi diversa. Un limite di JSF è,
però, rappresentato dalla mancanza di un tag che permetta di selezionare un file
all’interno del file system locale, per poi tresferirlo sul server. Nel caso di studio in
esame, tale funzionalità si è resa necessaria per l’inserimento di un brano all’interno
dell’archivio e quindi il caricamento sul server del file MP3 associato. Per ovviare a
questo problema, è stato previsto l’utilizzo del tag <t:inputFileUpload> facente parte
del progetto Tomahawk. Quest’ultimo prevede una particolare libreria di tag con
funzionalità evolute che rientra nell’implementazione di JavaServer Faces realizzata
dal gruppo Apache, ossia MyFaces. Ovviamente, oltre al TLD (Tag Library
Descriptor) è prevista una libreria di classi che permettono di gestire i corrispondenti
tag. Insieme al progetto Tomahawk, si è resa necessaria l’importazione del Commons
Project File Upload, sempre del gruppo Apache, contenente le classi che permettono
di gestire il caricamento del file sul server. Tale aspetto rappresenta un vantaggio per
Struts, in quanto all’interno della libreria standard Struts HTML è previsto il tag
<html:file> che fornisce tale funzionalità. Inoltre, il Commons Project File Upload è
contenuto all’interno della distribuzione del framework e non deve essere importato
dall’esterno così come nella JSF – RI della Sun Microsystems.
Figura 7 - Form upload file
270
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Da un punto di vista puramente grafico, si evince che non sussiste alcuna differenza
tra le due implementazioni, anche se il procedimento adottato per usufruire di questa
funzionalità è ben diverso tra i due framework.
Una differenza sostanziale riguarda la definizione della struttura dei form ed il
posizionamento degli elementi all’interno della pagina. L’implementazione in Struts
ha previsto il semplice utilizzo delle tabelle messe a disposizione del linguaggio
HTML, in quanto il framework non dispone di tag particolari per poter svolgere un
compito di questo tipo.
<html:form styleId="regForm" action="/registrazione.do">
<table>
<tr>
<td colspan="3" class="formsHeaderText">
<fmt:message key="regHeader"/>
</td>
</tr>
<tr>
<td class="columsLabelForm">
<fmt:message key="regUsernameLabel"/> *
</td>
<td class="columsInputForm">
<html:text property="userName" maxlength="20"/>
</td>
<td class="errorMessage">
<html:errors property="userName"/>
<html:errors property="registrazione"/>
</td>
...
Ben diversa è l’implementazione in JSF, poichè quest’ultimo introduce il concetto di
Panel per la formattazione dei contenuti. Tale concetto è ben noto nell’ambito dello
sviluppo delle applicazione desktop tramite le librerie AWT e Swing ed è stato
introdotto nelle Web application, come passo verso un’unificazione tra le due
tipologie di applicazioni. La libreria JSF HTML fornisce i tag <h:panelGrid> e
<h:panelGroup> di cui il primo definisce appunto un Panel, costituito da un fissato
numero di colonne, all’interno del quale vengono disposti gli elementi mentre il
secondo permette di raggruppare più campi, facendo in modo che nel Panel vengano
trattati come un unico elemento. Inoltre, all’interno del Panel è possibile specificare
le intestazioni delle colonne, mediante il tag <f:facet>, così come gli stili da applicare,
definiti all’interno di un file CSS esterno.
271
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<h:form id="regForm">
<h:panelGrid columns="3" headerClass="formsHeaderText"
columnClasses="columsLabelForm,
columsInputForm, columsErrorForm">
<f:facet name="header">
<h:outputText value="#{bundle.regHeader}" />
</f:facet>
<h:outputText value="#{bundle.regUsernameLabel} * "/>
<h:inputText id="userName"
value="#{utente.userName}"
required="true"
maxlength="20"/>
<h:panelGroup>
<h:message for="userName"
styleClass="errorMessage" />
<h:message for="regForm" id="regError"
styleClass="errorMessage"/>
</h:panelGroup>
...
4.1.2 Costruzione condizionale dei contenuti
Un’ ulteriore notevole differenza riguarda la costruzione condizionale di
una pagina, che consiste nel fare in modo che un certo contenuto sia visualizzato o
meno a seconda del verificarsi di opportune condizioni. Per quanto riguarda JSF,
l’unica possibilità è quella di utilizzare l’attributo rendered di cui è dotato ciascun tag
della libreria JSF HTML. Tale attributo può assumere un valore booleano che indica
appunto se il tag ed il relativo contenuto debba essere renderizzato o meno. Facendo
uso dell’Expression Language e del value-binding, è possibile definire un’espressione
nella quale entrino in gioco le proprietà dei backing beans, in modo da esprimere
condizioni complesse sulla base delle quali visualizzare o meno il componente.
Nell’esempio che segue, il contenuto del Panel viene visualizzato soltanto nel caso in
cui l’utente abbia effettuato il login.
<h:panelGrid rendered="#{utente.loggedIn}">
...
</h:panelGrid>
Il framework Struts, invece, dispone della libreria Struts Logic all’interno della quale
ci sono una serie di tag che permettono di definire dei costrutti condizionali e ciclici.
Come già detto in precedenza, però, tale libreria non supporta l’Expression
Language, per cui un qualsiasi riferimento agli attributi di un bean, deve essere
272
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
eseguito utilizzando attributi distinti dei tag. Per ovviare a questo limite, si utilizzano
appunto le librerie JSTL ed in particolare la libreria Core, la quale contiene anche una
serie di tag per la costruzione condizionale dei contenuti. Un esempio è caratterizzato
dal tag <c:if> che definisce il tipico costrutto if…then dei linguaggi di
programmazione.
<c:if test="${requestScope.emailInviata == true}">
<div class="Text"><fmt:message key="richiestaOk"/></div>
</c:if>
...
4.1.3 DataTable JSF e Cicli JSTL
Nell’ambito della Web application realizzata, si è più volte posto il
problema di visualizzare un elenco di elementi in forma tabellare, come nel caso dei
brani MP3, le playlist e gli utenti registrati.
L’implementazione JSF ha previsto l’utilizzo del potentissimo tag <h:dataTable>, il
quale permette di specificare la lista degli elementi da visualizzare ed eventualmente le
informazioni di formattazione. Inoltre, ciascuna colonna viene definita con il tag
<h:column>, all’interno del quale ne viene specificato un’eventuale intestazione ed il
relativo contenuto.
<h:dataTable value="#{sessionScope.braniMP3}"
var="branoMP3"
headerClass="headerDataTable"
columnClasses="linkDataTable, infoDataTable,
infoDataTable, checkBoxDataTable"
rowClasses="rowDataTable">
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.titoloLabel}" />
</f:facet>
<h:commandLink action="#{branoMP3.visualizzaInfo}">
<h:outputText value="#{branoMP3.titolo}"/>
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.autoreLabel}" />
</f:facet>
<h:outputText value="#{branoMP3.autore}" />
</h:column>
...
273
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Dall’esempio si osserva che l’attributo value specifica una variabile di sessione che
contiene l’elenco dei brani MP3, mentre l’attributo var definisce il nome della
variabile che identifica ciascun elemento all’interno della lista. Nel momento in cui si
clicca sul titolo di un brano, per poterne visualizzare le informazioni, l’oggetto
corrente specificato nell’attributo var viene trasferito tra i parametri della request, per
cui sarà disponibile alla pagina di visualizzazione.
Nel caso di Struts, si è reso necessario l’utilizzo del tag <c:forEach> che permette di
realizzare un vero e proprio ciclo for all’interno di una pagina. Esso permette di
specificare la lista degli elementi da scorrere attraverso l’attributo items ed una
variabile che individua l’oggetto corrente attraverso l’attributo var.
<table width="500">
...
<c:forEach items="${sessionScope.braniMP3}" var="branoMP3">
<tr class="rowDataTable">
<td class="linkDataTable">
<html:link action="/branoMP3.do?dispatch=visualizza"
paramName="branoMP3" paramProperty="id"
paramId="idBranoMP3">
<c:out value="${branoMP3.titolo}" />
</html:link>
</td>
<td class="infoDataTable">
<c:out value="${branoMP3.autore}" />
</td>
<td class="infoDataTable">
<c:out value="${branoMP3.album}" />
</td>
...
</c:forEach>
</table>
Dall’esempio, si evince che il tag viene utilizzato all’interno di una tabella per
effettuarne una costruzione riga per riga. Il notevole svantaggio che c’è rispetto
all’implementazione JSF, è che nel momento in cui si clicca sul titolo di un brano,
l’oggetto corrente non viene posto nella request, per cui è possibile superare questo
limite inserendo nel link alla pagina di visualizzazione delle informazioni del brano,
una query string in cui compaia l’identificativo del brano selezionato. Infine, sarà
compito della action invocata, ricavare l’id dalla request e leggere le informazioni del
brano dalla base di dati per poi visualizzarle.
274
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
4.2 Tiles
Il framework Tiles è stato utilizzato con entrambe le implementazioni per
poter dare alla Web application una struttura basata sul concetto di template, in
modo che nel momento in cui si renda necessaria una modifica al contenuto delle
pagine, questa debba essere eseguita una sola volta e non replicata. Tale framework è
incluso nella distribuzione di Struts con il quale si integra perfettamente, soprattutto
per quanto riguarda la navigazione, mentre è da importare nel progetto con JSF. La
differenza sostanziale sta nella configurazione di Tiles, che è completamente diversa
tra un framework e l’altro.
Nel caso di JavaServer Faces è necessario modificare il Deployment Descriptor
web.xml, che di per se non rappresenta un elemento intrinseco di JSF ma di una
generica Web application in Java. Questo mette in evidenza il fatto che per JSF, il
framework Tiles è uno strumento del tutto esterno ad esso e va quindi specificato a
livello di applicazione. In particolar modo, viene dichiarato attraverso la TilesServlet,
che viene avviata subito dopo la FacesServlet e che ha come parametro iniziale il file
XML delle definizioni dei layouts.
<servlet>
<servlet-name>TilesServlet</servlet-name>
<servlet-class>
org.apache.struts.tiles.TilesServlet
</servlet-class>
<init-param>
<param-name>definitions-config</param-name>
<param-value>/WEB-INF/tiles-defs.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Si osservi che la classe TilesServlet fa parte della distribuzione di Tiles all’interno di
Struts.
Il fatto che Tiles venga dichiarato mediante una Servlet mette in evidenza che non c’è
integrazione con JSF, nel senso che i due framework comunicano fra loro attraverso
uno scambio di informazioni tra Servlet e quindi al di fuori dell’architettura dello
stesso JavaServer Faces.
Il framework Struts prevede la dichiarazione dell’utilizzo di Tiles all’interno del
proprio file di configurazione, struts-config.xml, in termini di plug-in.
275
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config"
value="/WEB-INF/tiles-defs.xml"/>
<set-property property="moduleAware" value="true"/>
</plug-in>
Con questo tipo di approccio, il TilesRequestProcessor prende il posto del RequestProcessor
di Struts dal quale deriva, per cui le richieste pervenute all’applicazione sono gestite
direttamente nel framework, sia per quanto riguarda l’elaborazione che la
visualizzazione del layout delle pagine.
Prendendo in considerazione proprio il layout, le relative componenti sono note
come “tiles”, ossia mattonelle, da qui il nome del framework. Inoltre, è stata scelta la
struttura maggiormente utilizzata nelle applicazioni, che prevede le seguenti quattro
parti fondamentali : un’ intestazione (Header), un fondo pagina (Footer), un menu ed
un body.
Figura 8 - Layout Web Application
276
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
L’Header ed il Footer sono componenti comuni di tutte le pagine, mentre possono
variare il menu, in relazione al tipo di utilizzatore, ma soprattutto il body che
rappresenta ogni volta un contenuto differente.
Il layout è definito attraverso un unico file e ciascuna pagina dell’applicazione lo
utilizza, inserendo di volta in volta le quattro componenti suddette. In questo modo,
tutte le pagine hanno la stessa struttura ma con contenuti diversi. Per quanto riguarda
l’Header ed il Footer, il vantaggio principale è quello di poter eseguire una modifica
su ciascuno di essi una sola volta, senza la necessità di replicarla su tutte le pagine. Lo
stesso tipo di vantaggio può essere considerato in relazione al menu, essendo anche
quest’ultimo comune a tutte le pagine accessibili da un certo tipo di utilizzatore.
Il file delle definizioni, tiles-defs.xml, è leggermente diverso tra le due implementazioni,
in quanto entrambi definiscono le parti fisse di ciascuna pagina, ossia il file contente
il layout, l’Header ed il Footer, ma si differenziano per la specifica del menu. Infatti,
in JSF è stato previsto un unico file di menu, il cui contenuto viene visualizzato o
meno a seconda dell’utilizzatore che accede al sistema.
<tiles-definitions>
<definition name="page.template"
path="/templates/mainLayout.jsp"/>
<definition name="page.header" path="/templates/header.jsp"/>
<definition name="page.footer" path="/templates/footer.jsp"/>
<definition name="page.menu" path="/templates/menu.jsp"/>
</tiles-definitions>
Invece, in Struts sono stati usati tre file distinti contenenti i menu diversi per i tre
moduli.
<tiles-definitions>
<definition name="page.template"
path="/templates/mainLayout.jsp"/>
<definition name="page.header" path="/templates/header.jsp"/>
<definition name="page.footer" path="/templates/footer.jsp"/>
</tiles-definitions>
Ciascuna delle pagine della Web application utilizza il layout fissato e, per ciascuna
definition, specifica il “tile” da inserire all’interno del layout stesso.
277
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Nel caso di JSF, la struttura di ogni pagina è di questo tipo :
<tiles:insert definition="page.template">
<tiles:put name="title" value="Titolo Registrazione"/>
<tiles:put name="body"
value="/context/registrazioneContext.jsp"
type="page"/>
</tiles:insert>
e come si può osservare non viene specificato il menu, oltre all’Header ed al Footer.
Con Struts, invece, si ha una cosa del tipo :
<tiles:insert definition="page.template">
<tiles:put name="title" value="Titolo Registrazione"/>
<tiles:put name="body"
value="/context/registrazioneContext.jsp"
type="page"/>
<tiles:put name="menu" value="/templates/menu.jsp"
type="page"/>
</tiles:insert>
in cui vengono specificati tutti i “tile” da utilizzare, tranne l’Header ed il Footer.
4.3 JavaServer Faces Custom Components
Il framework JSF mette a disposizione una potenzialità notevole che
consiste nel poter estendere le classi dei componenti della UI, per implementare
componenti personalizzati, molto più potenti, da utilizzare nella propria interfaccia
utente. Per ciascuno di essi, è necessario eseguire le seguenti fasi :
-
realizzare la classe che definisce il comportamento del componente, oltre alle
fasi di decoding e di encoding se vanno gestite in maniera autonoma;
-
viceversa, realizzare la classe renderer che si occupi delle operazioni di
decode ed encode;
-
realizzare la classe che costituisce il Tag Handler, per poter gestire il tag
associato al componente;
-
definire le proprietà del tag all’interno di un file TLD (Tag Library
Descriptor);
278
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Nella Web application in questione, sono stati realizzati i seguenti componenti :
-
DateSelectComponent : componente che visualizza tre drop-down list
contenente giorni, mesi ed anni, per la selezione di una data. Utilizzato, ad
esempio, per l’immissione della data di nascita e della data di scadenza della
carta di credito. Inoltre permette di visualizzare un’etichetta associata ed un
eventuale messaggio di errore;
-
DDListComponent : componente che visualizza semplicemente una drop-down
list ma con la possibilità di specificarne un’etichetta e visualizzare un
eventuale messaggio di errore;
-
TimeSelectComponent : componente che permetta la selezione di una durata, per
esempio del brano MP3, attraverso due drop-down list che contengono
minuti e secondi. Inoltre, permette di visualizzare un’etichetta al fianco delle
drop-down list;
Le classi che implementano i suddetti componenti estendono la classe UIInput e non
direttamente la classe di base UIComponent, in modo tale da poter sfruttare il
comportamento di default di un componente di input, potenziandone le
caratteristiche. Inoltre, i componenti DateSelectComponent e TimeSelectComponent
svologono in maniera autonoma le operazioni di deconding e di encoding, per cui
non hanno bisogno di un renderer. Viceversa, il componente DDListComponent
delega tali operazioni ad una classe renderer corrispondente, implementata
estendendo la classe base Renderer. Ovviamente, ciascun componente prevede un
proprio Tag Handler realizzato mediante una classe che estende UIComponentTag.
4.3.1 DateSelectComponent
L’implementazione di questo componente è stata presa in considerazione,
per poter permettere all’utente di specificare in maniera piuttosto banale la propria
data di nascita e la data di scadenza della carta di credito, nelle fasi di registrazione e
di acquisto o ricarica della scheda prepagata.
279
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 9 – JSF : Esempi d'uso del DateSelectComponent
Si può osservare che il componente prevede la visualizzazione di un’ etichetta, una
serie di drop-down list ed un eventuale messaggio di errore. Inoltre, la sua
introduzione all’interno di una pagina JSP, prevede un unico tag ed attraverso i
relativi attributi è possibile specificare il testo dell’etichetta e quali drop-down list
visualizzare, tra quelle del giorno, del mese e dell’anno. Nel caso della data di nascita
sono necessarie tutte mentre nel caso della scadenza della carta di credito bastano le
ultime due.
<components:dateSelect id="dataNascita"
value="#{utente.dataNascita}"
showDay="true"
showMonth="true"
showYear="true"
type="birth"/>
L’ulteriore vantaggio è dato dal fatto che una volta selezionata ed inviata la data,
tramite un form, il componente non prevede due o tre valori separati che
rappresentano giorno, mese ed anno ma bensì un unico valore di tipo Date. Se si
fosse pensato di utilizzare i tag delle librerie di base, sarebbero stati necessari due o
tre tag <h:selectOneListbox> oppure <h:selectOneMenu> per le drop-down list, più un
tag <h:outputText> per l’etichetta. Inoltre, i valori ottenuti sul server sarebbero stati
completamente indipendenti e si sarebbero rese necessarie ulteriori elaborazioni per
comporli e ricavare una data valida. Questo componente permette di sottolineare le
potenzialità di JSF nella costruzione della View ed i notevoli vantaggi che comporta
per il Page author. Per quanto riguarda lo sviluppo, la prima classe realizzata è quella
relativa al componente vero e proprio, ossia DateSelectComponent. Ques’ultima estende
la classe UIInput, in modo da ereditarne il comportamento di base, al quale aggiunge
le proprie caratteristiche specifiche.
280
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 10 - JSF : DateSelectComponent, DateSelectTag
Gli attributi principali della classe servono per specificare l’etichetta da visualizzare al
fianco del componente, quali campi visualizzare tra giorno, mese ed anno ed infine
che tipo di data dovrà contenere, nascita o scadenza, in modo da generare l’elenco
degli anni in maniera differente. L’operazione di deconding viene eseguita all’interno
del componente stesso attraverso il metodo decode(), all’interno del quale vengono
ricavati dalla richiesta i parametri che rappresentano i valori del giorno, del mese e
dell’anno, i quali vengono utilizzati per creare un oggetto Calendar che rappresenti la
data selezionata. Si evince quindi che il componente restituisce un valore di tipo Date,
che può essere destinato direttamente ad una proprietà di un backing bean dello
stesso tipo. L’operazione di validazione è pressoché superflua, considerando che il
componente “guida” l’utente nella scelta della data ed inoltre va sottolineato che, nel
caso di data incoerente (es. 31 febbrario 2006), lo stesso oggetto Calendar, in maniera
del tutto automatica, ripristina la data valida più vicina. La fase di encoding viene
eseguita attraverso dei metodi privati, invocati nel metodo principale encodeBegin(),
generando i tag HTML per la visualizzazione dell’etichetta e le drop-down list. Al
componente è associato il Tag Handler realizzato mediante la classe DateSelectTag che
281
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
estende UIComponentTag. Essa dispone di tutti gli attributi di cui sarà dotato il tag
nella pagina JSP, ma in particolar modo del metodo setProperties(), che ha il compito di
caricare i valori di tali attributi che il Page author specifica nel tag, in corrispondenza
dei campi della classe DateSelectComponent. Inoltre, è previsto il metodo release(), che
permette di rilasciare le risorse allocate per gli attributi, una volta che il componente
sia stato renderizzato. Infine, per la descrizione del tag relativo a questo componente
così come agli altri, è stato creato un Tag Library Descriptor (components.tld) in cui c’è
la descrizione degli attributi associati al tag stesso.
<tag>
<name>dateSelect</name>
<tag-class>components.DateSelectTag</tag-class>
<attribute>
<name>id</name>
<description>Identificativo del component</description>
</attribute>
<attribute>
<name>value</name>
<description>Valore del component</description>
</attribute>
...
E’ ovviamente necessaria la registrazione del componente all’interno del file di
configurazione, specificandone la classe che lo implementa.
<component>
<component-type>DateSelect</component-type>
<component-class>
components.DateSelectComponent
</component-class>
</component>
282
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
4.3.2 DDListComponent
La realizzazione di questo componente potrebbe sembrare assolutamente
superflua, considerando che le librerie di base mettono a disposizione i tag
<h:selectOneListbox> e <h:selectOneMenu>, per la visualizzazione della drop-down list,
insieme ai tag <f:selectItem> e <f:selectItems>, per specificare gli elementi contenuti
nella lista.
<components:dropDownList id="stato"
value="#{utente.stato}"
items="#{itemsBean.stati}"
required="true"/>
Figura 11 – JSF : Esempio d'uso del DDListComponent
I vantaggi principali ottenuti dall’utilizzo del componente sono relativi alla possibilità
di visualizzare un’etichetta ed un eventuale messaggio di errore, ma soprattutto di
poter specificare la lista degli elementi da visualizzare, non mediante ulteriori tag, ma
bensì con un proprio attributo (items).
Per quanto riguarda l’implementazione, si è pensato di delegare la fase di deconding e
di encoding ad un renderer, in modo da evindeziare il differente approccio rispetto al
DateSelectComponent. Tale modalità ha il notevole vantaggio di poter associare ad un
medesimo componente più renderers differenti, magari relativi a linguaggi di markup
diversi. In questo modo, il comportamento viene definito una sola volta ma le
visualizzazioni sono molteplici, in virtù della possibilità di accedere alla Web
application con dispositivi client diversi.
L’implementazione necessita quindi di tre o più classi : una relativa al componente,
una relativa al corrispondente Tag Handler ed una o più classi relative ai renderer.
Nel caso di studio in esame, è stato realizzato un unico rendeder per il linguaggio di
markup HTML, assumendo che l’applicazione sia accessibile solo ed esclusivamente
mediante un browser Web.
283
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 12 – JSF : DDListComponent, DDListTag, DDListRenderer
La classe DDListComponent, che estende UIInput, non prevede tutti gli attributi del
componente, in quanto alcuni di essi possono essere direttamente gestiti dal Tag
Handler, per cui in molti casi si preferisce ometterli nella definizione del
componente. Essa prevede il metodo validateValue(), il quale esegue una validazione
del valore immesso dall’utente, invocando semplicemente la versione della
superclasse. Si osservi che in questo caso, mancano i metodi relativi al deconding ed
all’encoding, poiché tali fasi vengono eseguite dal renderer.
La classe DDListTag, che deriva da UIComponentTag, specifica tutti gli attributi del
componente che saranno presenti nel tag corrispondente ed implementa i tipici
metodi setProperties() e release(), per caricare i valori degli attributi nel componente e
rilasciare le risorse allocate.
Infine, la classe DDListRenderer estende la classe base Renderer per poter implementare
il renderer HTML associato al componente. Essa prevede al suo interno il tipico
284
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
metodo encodeBegin(), il quale utilizza dei metodi privati per la visualizzazione del
componente. Inoltre, è stato eseguito l’overidding del metodo getConvertedValue(), per
poter gestire all’interno del renderer stesso la conversione del valore selezionato. In
molte situazioni, tale operazione non è strettamente necessaria, in quanto è il
framework che esegue le conversioni in maniera automatica. In questo caso, si rende
necessaria l’operazione di conversione in quanto il componente viene utilizzato per
visualizzare sia liste con valori numerici (es. importo scheda prepagata) che stringhe
(es. stato).
La descrizione del tag è contenuta all’interno del file components.tld e per quanto
riguarda la configurazione, è necessario registrare sia il componente che il renderer.
Quest’ultimo va tipicamente inserito all’interno di un Render Kit, in base al
dispositivo client di accesso, ma in questo caso è stato registrato in quello di
“default” relativo al linguaggio HTML.
<renderer>
<component-family>DropDownList</component-family>
<renderer-type>DropDownListRenderer</renderer-type>
<renderer-class>components.DDListRenderer</renderer-class>
</renderer>
4.3.3 TimeSelectComponent
Questo componente è stato realizzato per uno scopo ben preciso, ossia
permettere all’amministratore di specificare la durata di un brano MP3,
semplicemente selezionando i valori di minuti e secondi mediante due drop-down
list.
<components:timeSelect id="durata"
value="#{branoMP3.durata}"/>
Figura 13 – JSF : Esempio d'uso del TimeSelectComponent
Il tipico vantaggio è sempre quello di evitare l’utilizzo di più tag, soprattutto per la
visualizzazione delle due drop-down list e del loro contenuto. Inoltre, il componente
restituisce automaticamente un oggetto di tipo Time, in luogo di due valori distinti
285
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
che rappresentano i minuti ed i secondi. Per quanto riguarda l’implementazione, esso
è stato realizzato in modo tale da gestire in maniera autonoma le fasi di decondig e di
encoding.
Figura 14 – JSF : TimeSelectComponent, TimeSelectTag
La classe TimeSelectComponent estende UIInput e definisce i metodi necessari per le
operazioni di decode e di encode. In particolare, il metodo decode() ricava dalla request
i parametri relativi ai minuti ed i secondi selezionati e li compone in modo da ricavare
un unico oggetto Time. La fase di encoding, ovviamente, esegue l’operazione inversa,
qualora si debbano visualizzare le informazioni di un brano MP3, tra cui appunto la
durata. Inoltre, lo stesso metodo genera automaticamente la lista dei valori da poter
selezionare.
Il Tag Handler è realizzato mediante la classe TimeSelectTag, che estende
UIComponentTag, la quale contiene tutti gli attributi previsti nel tag ed i tipici metodi
per gestire il caricamento dei valori di questi ultimi all’interno del componente e per
rilasciare le risorse allocate.
Il tag associato è ovviamente descritto all’interno del file components.tld ed il
componente è registrato all’interno del file di configurazione.
286
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 15 - JSF : Custom Components
4.3.4 …e Struts ?
Il framework Struts non mette assolutamente a disposizione un
meccanismo che permetta di implementare dei componenti personalizzati come in
JSF. La realizzazione dell’interfaccia utente può essere svolta utilizzando tutti quelli
che sono i tag della libreria Struts HTML, senza possibilità di estensione. Tale limite
si è evidenziato soprattutto per alcuni campi necessari nei form, come ad esempio la
data di nascita, la data di scadenza della carta di credito e la durata di un brano MP3.
Con JavaServer Faces, queste necessità particolari sono state risolte attraverso la
realizzazione di corrispondenti Custom Components, mentre nel caso di Struts, si è
preferito utilizzare dei semplici campi di testo.
Figura 16 - Struts : Esempio campo di input di una data
287
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Si sarebbe potuto pensare di servirsi dei tag relativi alle drop-down list, ma in quel
caso sarebbe stato necessario far gestire alla action ricevente, l’operazione di
comporre i valori separatamente ricavati dalla request per ottenere un unico valore
corrispondente. L’utilizzo di un semplice campo di testo ha permesso di avvalersi di
una particolare regola di validazione, prevista nel plug-in Validator, relativa alle date.
In questo modo, si può comunque effettuare un opportuno controllo per verificare
che l’utente abbia immesso una data valida.
4.4 I formbean di Struts
In riferimento all’acquisizione dei dati contenuti nei form ed inviati
dall’utente, il framework Struts introduce il concetto di formbean, il quale altro non è
che una particolare classe le cui proprietà sono destinate a contenere i valori dei
campi del form stesso. Nel momento in cui viene inviata una richiesta, è compito del
RequestProcessor popolare il formbean ed effettuare la validazione dei dati in esso
contenuti, per poi passarlo alla action che dovrà occuparsi di gestire la richiesta.
In generale, un formbean può essere di due tipi :
-
statico : realizzato attraverso una classe che estende la classe ActionForm
oppure una delle sue derivate e poi dichiarato nel file di configurazione;
-
dinamico : dichiarato direttamente all’interno del file di configurazione, senza
la necessità di implementare una classe corrispondente;
Tipicamente, si preferisce utilizzare i formbean dinamici, anche se sussistono alcune
situazioni in cui si rende necessaria l’implementazione delle classi per quelli statici.
Anche nel caso della Web application realizzata, si è fatto uso di entrambe le
tipologie di formbean, dinamici lì dove possibile e statici lì dove fossero necessari per
un certo motivo.
288
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
4.4.1 Login, Registrazione e Richiesta password
La funzionalità di Login prevede un semplice form con due campi,
all’interno dei quali specificare lo Username e la Password.
Figura 17 - Form di Login
Ad esso è stato associato un formbean di tipo statico, implementando la classe
LoginForm che estende la classe base ActionForm. E’ stata scelta questa soluzione, in
quanto facendo riferimento alla fase di registrazione, quando l’utente termina la
procedura, viene eseguita un’operazione di login automatico per cui era necessario
riempire il form di login direttamente dal codice. Attraverso la realizzazione della
classe LoginForm, è stato possibile istanziare un oggetto di questo tipo, popolarlo con
i dati di accesso ed invocare la action che si occupasse dell’azione di login.
Figura 18 - Struts : LoginForm
L’implementazione è notevolmente semplice, in quanto le proprietà della classe non
sono altro che i campi previsti nel form : userName e password. Non è stato effettuato
l’overriding del metodo validate(), in quanto la validazione dei dati immessi non è
necessaria per due motivi :
289
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
Lo username e la password possono contenere caratteri alfanumerici
qualsiasi;
-
Se non viene immesso alcun valore, si impedisce semplicemente l’accesso;
Infine, il formbean è stato registrato all’interno del modulo “default”, dal quale è
accessibile la funzionalità di login, specificandone il nome e la classe che lo
implementa.
<form-bean name="loginForm" type="formbean.LoginForm"/>
La funzionalità di Registrazione prevede in primo luogo il form per i dati di accesso
che sono indispensabili e poi eventualmente il form di acquisto della scheda
prepagata, qualora l’utente voglia avvalersi di questo servizio. Poiché quest’ultima
funzionalità è disponibile anche per un utente già registrato, ma non ancora in
possesso di una scheda, verrà trattata successivamente.
Figura 19 - Form di Registrazione
Ad esso è associato un formbean realizzato mediante la classe RegistrazioneForm, la
quale estende ValidatorForm e non semplicemente ActionForm. L’implementazione
della classe si è resa necessaria per una sorta di “bug” documentato di Struts, dovuto
alla presenza della checkbox con la quale l’utente può scegliere se proseguire la
procedura di registrazione, acquistando anche la scheda prepagata. Dalla
documentazione ufficiale di Struts si legge “ATTENZIONE : per poter acquisire
correttamente il valore di una chechbox non selezionata, l’ActionForm associato al
290
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
form in questione deve contenere, all’interno del metodo reset(), un’istruzione che
setti a false il valore della checkbox”, da qui il motivo della classe. Inoltre, quest’ultima
deriva da ValidatorForm, in quanto la validazione dei dati viene eseguita attraverso il
plug-in Validator e non mediante il metodo validate().
Figura 20 - Struts : RegistrazioneForm
La classe realizzata ha delle proprietà che corrispondono ai campi del form ed il
metodo reset() per il motivo suddetto. Ovviamente, il formbean è registrato nel file di
configurazione allo stesso modo del bean precedente.
Infine, la funzionalità di richiesta della password prevede che l’utente inserisca molto
semplicemente l’indirizzo email con cui si è registrato per poter ricevere una mail con
i dati di accesso.
Figura 21 - Form di Richiesta Username/Password
In questo caso è bastato realizzare un formbean dinamico semplicemente
dichiarando nel file di configurazione e specificandone le proprietà relative.
<form-bean name="richiediPasswordForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="email" type="java.lang.String"/>
</form-bean>
291
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Come si può osservare, il formbean sarà un’istanza della classe DynaValidatorForm
essendo dinamico e poiché su di esso verrà eseguita la validazione attraverso il plugin Validator. Inoltre, viene specificata l’unica proprietà che ne fa parte con il relativo
tipo.
4.4.2 Acquisto/Ricarica scheda prepagata
La funzionalità di acquisto della scheda prepagata è accessibile in fase di
registrazione oppure in un qualsiasi momento, nel caso di un utente registrato che
non ha deciso di usufruire di questo servizio in precedenza. Essa prevede un form
all’interno del quale l’utente deve immettere i propri dati personali, l’importo della
scheda e le informazioni della carta di credito.
Figura 22 - Form di Acquisto scheda prepagata
292
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Il form è associato ad un formbean di tipo dinamico, dichiarato nei file di
configurazione del modulo “default” e “admin”, da cui la funzionalità è accessibile.
Tale formbean è del tipo DynaValidatorForm, tenendo sempre conto che la
validazione viene eseguita mediante il plug-in Validator. Inoltre, le sue proprietà
corrispondono perfettamente ai campi del form.
<form-bean name="acquistoSchedaForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="dataScadenzaCC" type="java.lang.String"/>
<form-property name="dataNascita" type="java.lang.String"/>
<form-property initial="M" name="sesso"
type="java.lang.String"/>
...
</form-bean>
La funzionalità di ricarica della scheda prepagata prevede un semplice form
all’interno del quale l’utente deve specificare l’importo della ricarica e le informazioni
della carta di credito.
Figura 23 - Form di Ricarica scheda prepagata
Anche in questo caso è stato definito un formbean dinamico, del tipo
DynaValidatorForm, dichiarato solo ed esclusivamente nel file di configurazione del
modulo “user”.
293
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
4.4.3 Modifica dati utente ed amministratore
Attraverso la corrispondente funzionalità, l’utente ha la possibilità di
modificare i propri dati di accesso ed i dati anagrafici, nel caso abbia a disposizione
una scheda prepagata della quale ne abbia effettuato l’acquisto. Il form previsto è una
sorta di unione tra il form di registrazione e quello per l’acquisto di una scheda
prepagata, a meno di un campo in più che prevede l’immissione della conferma della
password scelta. Un parte di esso è visibile nella figura seguente.
Figura 24 - Frammento del Form di Modifica dati Utente
Il formbean ad esso associato è dinamico e del tipo DynaValidatorForm e le sue
proprietà corrispondono ai campi del form. Esso è dichiarato sempre allo stesso
modo nel file di configurazione del modulo “user”.
Un’analoga funzionalità è prevista per l’amministratore, il quale però ha la possibilità
di modificare solo ed esclusivamente la password, non essendo associate ad esso
ulteriori informazioni. Il form è perfettamente uguale a quello previsto per l’utente ed
il formbean associato è comunque di tipo dinamico, ma dichiarato ovviamente nel
file di configurazione del modulo “admin”.
4.4.5 Visualizzazione e ricerca dei brani
La visualizzazione dell’elenco dei brani presenti in archivio è prevista sulla
base di due modalità differenti, di cui la prima permette di scegliere un genere
294
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
musicale mentre la seconda di impostare dei criteri di ricerca più precisi basati sul
titolo, l’autore e l’album.
Il form della prima modalità è banale in quanto è caratterizzato da un'unica dropdown list all’interno della quale selezionare il genere musicale a cui si è interessati.
Figura 25 - Form di Visualizzazione brani MP3 per genere
Il formbean associato è del tipo DynaValidatorForm ed ha ovviamente un’unica
proprietà associata al campo del form.
La seconda modalità di visualizzazione prevede un form leggermente più complesso,
in quanto, oltre al genere è possibile impostare criteri di ricerca specifici sulle altre
informazioni del brano.
Figura 26 - Form di Ricerca brani MP3
Esso prevede un formbean dinamico con le proprietà genere, titolo, autore ed album
relative ai campi del form. Esso è registrato correttamente sia nel modulo “admin”
che “user”.
<form-bean name="ricercaBraniMP3Form"
type="org.apache.struts.action.DynaActionForm">
<form-property name="genere" type="java.lang.String"/>
<form-property name="titolo" type="java.lang.String"/>
<form-property name="autore" type="java.lang.String"/>
<form-property name="album" type="java.lang.String"/>
</form-bean>
295
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Una volta eseguita la richiesta di visualizzazione oppure terminata la ricerca, se ci
sono dei brani che soddisfano i criteri impostati, viene visualizzato un elenco degli
stessi. Nel caso in cui l’utilizzatore sia l’amministratore oppure un utente che ha delle
playlist create in precedenza, al fianco dei brani sono visualizzate delle checkbox che
permettono all’amministratore di selezionare i brani da eliminare ed all’utente di
selezionare i brani da aggiungere ad un certa playlist.
Figura 27 - Form di Visualizzazione ed eliminazione brani MP3 dall'archivio
Figura 28 - Form di Visualizzazione ed inserimento dei brani MP3 in una playlist
Ovviamente, le checkbox devono far parte di un form che verrà inviato alla action
che dovrà occuparsi dell’elaborazione. Avendo utilizzato il tag <html:multibox> per la
generazione delle checkbox, il formbean è stato implementato mediante la classe
BraniMP3Form che estende ActionForm, che ha le seguenti proprietà :
-
idBraniMP3Selezionati : un array di stringhe che contiene gli identificativi dei
brani scelti, riempito automaticamente dal framework sulla base delle
checkbox selezionate;
-
idPlaylist : contiene l’identificativo della playlist scelta dall’utente all’interno
della quale immettere i brani selezionati;
296
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Ovviamente, la prima proprietà è utilizzata sia nel caso di accesso dell’amministratore
che dell’utente, mentre la seconda solo ed esclusivamente in quest’ultimo caso.
Figura 29 - Struts : BraniMP3Form
Il formbean è registrato nei file di configurazione del modulo “admin” e “user”.
4.4.6 Inserimento/Modifica brani
Per effettuare l’inserimento di un nuovo brano all’interno dell’archivio,
l’amministratore ha a disposizione un form nel quale poter inserire le informazioni
del brano e selezionare il file MP3 di cui eseguirne il caricamento sul server. Per
quanto riguarda la modifica, tale funzionalità è disponibile nell’interfaccia che
visualizza le informazioni di un certo brano e da essa è possibile eseguire anche le
operazioni di eliminazione ed ascolto. Il form è praticamente uguale al precedente,
salvo il fatto che non prevede il campo di selezione del file MP3.
Figura 30 - Form di Inserimento brano MP3
297
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 31 - Form di Modifica brano MP3
I formbean associati ai due form sono sostanzialmente simili a meno del fatto che
quello relativo alla modifica del brano, prevede la proprietà dispatch, la quale è
associata ad un campo hidden che ovviamente non è visibile. La necessità di questa
proprietà è legata alla presenza di due pulsanti di submit, “modifica” ed “elimina”,
all’interno di quest’ultimo. Tali pulsanti non avviano due action differenti, ma come
si vedrà di seguito è definita un’unica action che contiene una serie di metodi che
eseguono le possibili azioni su un brano MP3, per cui la proprietà dispatch è necessaria
per distinguere quale metodo invocare. Alla pressione di uno dei due pulsanti, viene
assegnato un valore appropriato a tale proprietà e quest’ultima viene inserita nella
query string. Il RequestProcessor, sulla base di tale valore, avvia l’esecuzione del metodo
corrispondente della action invocata. Viceversa, al pulsante di “ascolto” non è legata
alcuna action, in quanto la sua pressione comporta l’apertura di una finestra pop-up
all’interno della quale viene caricato il player MP3 ed avviato l’ascolto del brano.
I formbean sono ovviamente dinamici e dichiarati unicamente nel file di
configurazione del modulo “admin”.
4.4.7 Gestione Playlist
Per quanto riguarda la creazione di una playlist, è previsto un semplice
form costituito da un unico campo all’interno del quale specificarne il nome.
298
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 32 - Form di Creazione playlist
Il formbean associato è di tipo statico ed è stato implementato mediante la classe
PlaylistForm che deriva da ValidatorForm, per poter effettuare la validazione sul nome
della playlist.
Figura 33 - Struts : PlaylistForm
E’ inoltre prevista un’ ulteriore proprietà, idPlaylistSelezionate, la quale viene utilizzata
per la selezione delle playlist da cancellare. Infatti, l’utente ha la possiblità di
visualizzare l’elenco di tutte le playlist create in precedenza ed , attraverso delle
checkbox, può selezionare quali playlist eliminare.
Figura 34 - Form di Visualizzazione ed eliminazione delle playlist
Così come nel caso della gestione dei brani, il framework riempie automaticamente
l’array di stringhe idPlaylistSelezionate, con gli identificativi delle playlist scelte
attraverso le checkbox selezionate. Il formbean in questione, quindi, viene utilizzato
299
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
nella gestione delle due funzionalità suddette ed è registrato ovviamente solo nel
modulo “user”.
4.4.8 Gestione Utenti
L’amministratore dispone di semplici funzionalità per poter gestire gli
utenti registrati. In particolare, è possibile visualizzare l’elenco degli utenti e
selezionare quelli da cancellare attraverso delle checkbox.
Figura 35 - Form di Visualizzazione ed eliminazione degli utenti
Per poter eseguire l’operazione di eliminazione, viene invocata una particolare action,
la quale riceve un formbean implementato attraverso la classe UtentiForm che deriva
da ActionForm e che ha una proprietà, idUtentiSelezionati, che contiene l’elenco degli
identificativi degli utenti scelti per la cancellazione.
Figura 36 - Struts : UtentiForm
Inoltre, è prevista la proprietà dispatch, in quanto la action che si occupa della
cancellazione permette di eseguire tutte le operazioni possibili sull’oggetto Utente. Per
questo motivo, assegnando il valore opportuno a questa proprietà all’interno della
300
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
query string, è possibile segnalare al RequestProcessor, quali dei metodi della action debba
essere avviato. Infine, il formbean è registrato unicamente nel modulo “admin”.
4.4.9 … e JavaServer Faces ?
Rispetto a Struts, il framework JSF ha una gestione completamente diversa
dai form. Dal punto di vista puramente grafico, questi ultimi sono sostanzialmente
identici a meno della possibilità di utilizzare i Custom Components che sono stati
realizzati con JavaServer Faces. Per quanto riguarda le operazioni di acquisizione dei
dati, quest’ultimo non prevede assolutamente il concetto di formbean. I campi di
ciascun form sono associati alle proprietà dei backing beans, così come la pressione
di un bottone per l’invio dei dati non prevede l’esecuzione di una action esterna ai
bean, ma bensì di uno dei metodi del backing bean stesso. Tutto ciò ha il vantaggio di
non dover utilizzare un oggetto intermedio, il formbean appunto, che abbia il
compito del trasferimento dei dati dall’utente alla elaborazione da eseguire.
Ad esempio, considerando la funzionalità di login, essa prevede il medesimo form
dell’implementazione in Struts, con la differenza che i valori di Username e Password
sono destinati all’interno delle proprietà del backing bean ruolo della classe Ruolo ed
alla pressione del pulsante, viene invocato il metodo login() dell’oggetto.
<h:form id="loginForm"...
...
<h:outputText value="#{bundle.menuUsernameLabel}" />
<h:inputText id="userName" value="#{ruolo.userName}"/>
<h:outputText value="#{bundle.menuPasswordLabel}" />
<h:inputSecret id="password" value="#{ruolo.password}"/>
<h:outputText value="" />
<h:commandButton action="#{ruolo.login}"
value="#{bundle.menuButtonLoginLabel}"
styleClass="buttonForm"/>
</h:form>
In questo modo, i dati sono immediatamente disponibili e l’elaborazione da eseguire
su di essi si trova all’interno della classe stessa. Il backing bean è dichiarato all’interno
del file di configurazione, specificandone anche l’ambito di visibilità (scope).
301
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<managed-bean>
<managed-bean-name>ruolo</managed-bean-name>
<managed-bean-class>ruolo.Ruolo</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Questo tipo di approccio è utilizzato in tutte le altre funzionalità e può essere
considerato un vantaggio a favore del framework JavaServer Faces.
4.5 Player MP3
Il Player MP3 adottato per l’ascolto dei brani MP3 e delle playlist è
implementato mediante un’applet, JLGUIApplet, disponibile gratuitamente su
Internet. Attraverso il file di inizializzazione jlgui.ini, esso mette a disposizione la
possibilità di modificare una serie di opzioni tra cui, in particolre, il percorso del file
MP3 da ascoltare oppure del file M3U che contiene l’elenco dei brani, nel caso si
tratti di una playlist. L’ascolto di un singolo brano prevede la definizione del percorso
del file MP3 associato all’interno del file system mentre nel caso in cui l’utente
desideri ascoltare una propria playlist, l’applicazione non fa altro che leggere la
composizione della stessa dalla base di dati e creare un file M3U con i percorsi dei
brani in modo da renderli accessibili al player.
Dal punto di vista dell’interfaccia utente, viene aperta una finestra pop-up all’interno
della quale viene caricata l’applet. Da qui, l’utente ha la possibilità di interagire con
quest’ultima modificando la sequenza dei brani, utilizzando i controlli di volume e di
bilanciamento, nonché di sfruttare l’equalizzatore messo a disposizione. E’ da
osservare che, con questo approccio, l’utente ha comunque la possibilità di
proseguire la navigazione all’interno del sistema, proseguendo l’ascolto della propria
playlist.
L’unico limite del player è che il percorso che specifica la locazione del file da
ascoltare, deve fare riferimento al medesimo host con cui si accede alla Web
application e specificato nella barra degli indirizzi del browser.
302
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 37 - Player MP3
4.6 Internazionalizzazione (I18N)
Attraverso il meccanismo dell’Internazionalizzazione (I18N), è possibile
visualizzare il testo presente nella Web application in lingue diverse, in relazione alla
localizzazione geografica da cui si collega l’utente oppure sulla base delle
impostazioni della lingua del browser. Nel caso dell’applicazione realizzata, si è
previsto il supporto per la lingua italiana, considerata di default, e per la lingua
inglese. In questo modo, senza la necessità di dover sviluppare due volte la medesima
Web application, è possibile comunque garantire l’utilizzo di quest’ultima a persone
di lingua differente. Per quanto riguarda questo aspetto, i framwork Struts e JSF sono
perfettamente identici, in quanto forniscono tale supporto allo stesso modo, anche in
virtù del fatto che questo concetto è proprio del linguaggio Java.
In entrambe le implementazioni sono stati realizzati due Resource Bundle contenenti
i messaggi da visualizzare nelle due lingue. Ciascuno di essi è costituito da una serie di
coppie “key-message”, attraverso le quali è possibile visualizzare un certo messaggio
semplicemente specificando la chiave ad esso associata.
303
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
...
regStatoLabel=Stato :
regTelefonoLabel=Telefono :
regDataNascitaLabel=Data di nascita :
...
ResourceBundle IT
...
regStatoLabel=State :
regTelefonoLabel=Phone Number :
regDataNascitaLabel=Date of birth :
...
ResourceBundle EN
Come si può osservare, in entrambi i file (con estensione properties) le chiavi sono
perfettamente identiche mentre i messaggi sono in lingua diversa. Inoltre, i file stessi
hanno
praticamente
il
medesimo
nome,
ossia
ApplicationResources
ed
ApplicationResources_en, a meno del file in lingua inglese che ha il suffisso “en”.
Tipicamente, il file che non ha alcun suffisso è quello relativo alla lingua di default
mentre i file associati alle altre lingue devono avere lo stesso nome del primo ma
seguito da un suffisso che identifica la lingua.
Entrambi i framework hanno previsto la registrazione dei Resource Bundle, con una
leggera differenza. Nel caso di JSF è stato necessario specificare la localizzazione
(Locale) di default e quella supportata, oltre al nome del file contenente i messaggi.
<application>
<locale-config>
<default-locale>it</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
<message-bundle>ApplicationResources</message-bundle>
</application>
Invece, Struts ha previsto semplicemente la dichiarazione del Resource Bundle.
<message-resources parameter="ApplicationResources"/>
Per quanto riguarda l’utilizzo dell’internazionalizzazione all’interno delle pagine
dell’applicazione, le librerie di entrambi i framework mettono a disposizione un tag
che permette di specificare quale sia il bundle dal quale prelevare i messaggi.
304
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
JavaServer Faces prevede l’utilizzo del tag <f:loadBundle> in cui l’attributo basename
specifica il nome del Resource Bundle mentre var permette di assegnargli un nome
mediante il quale farvi riferimento all’interno della pagina JSP.
<f:loadBundle basename="ApplicationResources" var="bundle" />
Nell’implementazione in Struts è stato utilizzato il tag <fmt:setBundle> della librearia
Formatting JSTL, il quale prevede l’unico attributo basename per specificare il nome
del bundle.
Per poter individuare un messaggio da visualizzare, viene utilizzato un approccio
differente. Con JSF si utilizza l’Expression Language e la tipica “dot notation”,
specificando il nome del bundle e la chiave del messaggio da visualizzare.
<h:outputText value="#{bundle.regAnagraficaHeader}" />
Viceversa, con Struts non si fa uso dell’EL ma attraverso un particolare tag si
specifica semplicemente la chiave associata al messaggio.
<fmt:message key="regAnagraficaHeader"/>
Utilizzando il medesimo strumento, seppure con sintassi leggermente diverse, dal
punto di vista grafico le due implementazioni forniscono il medesimo risultato.
Figura 38 - Esempio di Form con localizzazioni differenti
Un limite legato all’Internazionalizzazione riguarda il fatto che, nel caso in cui la
navigazione tra le pagine non sia definita attraverso collegamenti ipertestuali ma
attraverso elementi grafici, non è possibile visualizzare un elemento al posto di un
altro in base alla differente lingua di accesso. I Resource Bundle supportano il
305
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
contenuto testuale e non eventuali immagini che costituisco i bottoni per la
navigazione.
5. Validazione
La validazione dei dati immessi nei form da parte dell’utente è uno degli
aspetti su cui si differenziano maggiormente i framework a confronto. La differenza
sostanziale risiede nel fatto che JSF mette a disposizione un proprio meccanismo per
la validazione e per la sua estensione mentre Struts, nella maggior parte dei casi, si
affida al plug-in Validator anche se è previsto un metodo di validazione interno al
framework. Le scelte fatte nelle due implementazioni sono fondate sulla riusabilità e
sulla rapidità di sviluppo, sfruttando lì dove possibile tutti gli strumenti a
disposizione.
5.1 JavaServer Faces Custom Validators
JavaServer Faces mette a disposizione soltanto tre validatori standard che
permettono di valutare se un certo valore ha una certa lunghezza entro un minimo ed
un massimo prefissati oppure se il medesimo valore rientra in un certo range. Per
quanto riguarda l’obbligatorietà di un campo, quest’ultima viene specificata mediante
l’attributo required del tag associato al componente in questione.
Un esempio di obbligatorietà di un campo può essere la richiesta dello Username in
fase di registrazione, come mostrato in figura.
Figura 39 - JSF : Esempio di campo obbligatorio
Per quanto riguarda il controllo che un valore di un campo debba avere una
lunghezza minima prefissata, si può fare riferimento al tag <f:validateLength>
utilizzato in fase di registrazione per la richiesta della password, per la quale è stata
fissata una lunghezza minima di 5 caratteri alfanumerici.
306
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<h:inputSecret id="password"
value="#{utente.password}"
required="true"
maxlength="15">
<f:validateLength minimum="5"/>
</h:inputSecret>
Figura 40 - JSF : Esempio di ValidateLength
L’ultimo validatore standard, relativo al controllo che un certo valore rientri in un
range fissato, è stato utilizzato nella fase di inserimento di un nuovo brano MP3 in
archivio nell’ambito della specifica del costo di quest’ultimo. Tale validatore è fornito
dal framework attraverso i tag <f:validateDoubleRange> e <f:validateLongRange>, sulla
base del tipo di dato del valore da validare.
<h:inputText id="costo"
value="#{branoMP3.costo}"
required="true"
size="5">
<f:validateDoubleRange minimum="0.0"/>
</h:inputText>
Figura 41 - JSF : Esempio di ValidateDoubleRange
Considerando il numero limitato di controlli standard che possono essere eseguiti, il
framework mette a disposizione due meccanismi per la realizzazione di ulteriori
validatori. Il primo consiste nel realizzare un metodo che esegua la validazione
all’interno di un backing bean, il secondo prevede lo sviluppo di una classe che
implementi l’interfaccia Validator, alla quale può poi essere associato o meno un tag.
Tipicamente la prima soluzione è strettamente limitata all’uso dello specifico backing
bean e non permette di utilizzare il validatore su più componenti che prevedono lo
stesso tipo di controllo, a meno di non effettuare un copia-incolla del metodo di
validazione nei vari backing beans. Per questo motivo, si è preferita la seconda
soluzione grazie alla quale un unico validatore può essere facilmente associato a più
componenti.
307
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
L’implementazione in JSF ha previsto lo sviluppo dei tre seguenti validatori :
-
EmailValidator : permette di valutare se il formato di un indirizzo email sia o
meno corretto;
-
SeqCifreValidator : per valutare se un certo valore è rappresentato da una
sequenza di cifre;
-
TelefonoValidator : per verificare se un numero di telefono abbia un formato
valido, del tipo prefisso-numero;
5.1.1 EmailValidator
Questo validatore viene utilizzato nella fase di registrazione di un utente
oppure nel momento in cui quest’ultimo richiede l’invio di una mail con i propri dati
di accesso, specificando il proprio indirizzo. La classe EmailValidator implementa
l’interfaccia Validator della quale esegue l’overriding del metodo validate() per valutare
se l’indirizzo email immesso dall’utente abbia un formato corretto.
Figura 42 - JSF : EmailValidator
308
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per poter effettuare il controllo, all’interno del metodo validate() viene utilizzato lo
strumento delle Regular Expression (Espressione Regolare) fornito dal linguaggio Java.
In particolare, si specifica quale sia il pattern a cui deve essere conforme un indirizzo
email per essere considerato corretto e si valuta se il valore immesso dall’utente
corrisponda ad esso.
...
Pattern mask = Pattern.compile("\\w+@{1}\\w+\\.{1}\\w+");
Matcher matcher = mask.matcher(value.toString());
// se il valore non corrisponde al pattern
if (!matcher.matches()){
...
...
throw new ValidatorException(msg);
}
...
Si osserva che se il valore immesso dall’utente non è conforme al pattern specificato,
viene sollevata un’ eccezione la quale contiene il messaggio da visualizzare all’utente.
Tale messaggio viene prelevato dal Resource Bundle.
Il validatore ha ovviamente previsto una registrazione all’interno del file di
configurazione, così come tutti gli elementi personalizzati che si creano con JSF.
<validator>
<validator-id>emailValidator</validator-id>
<validator-class>validators.EmailValidator</validator-class>
</validator>
Per quanto riguarda il suo utilizzo all’interno di una pagina JSP, si è preferito non
realizzare un tag appropriato ma di utilizzare il tag standard messo a disposizione da
JSF, ossia <f:validator>, il quale prevede l’attributo validatorId che permette di
specificare l’identificativo del validatore da utilizzare, così come è stato registrato.
<h:inputText id="email"
value="#{utente.email}"
required="true"
maxlength="50">
<f:validator validatorId="emailValidator"/>
</h:inputText>
309
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
L’immissione da parte dell’utente di un indirizzo con un formato errato, prevede una
segnalazione del tipo mostrato in figura.
Figura 43 - JSF : Esempio d'uso dell'EmailValidator
5.1.2 SeqCifreValidator
Nell’ambito dell’applicazione realizzata, ci sono una serie di campi dei form
che prevedono l’immissione di un valore caratterizzato solo ed esclusivamente da una
sequenza di cifre, come ad esempio il C.A.P ed il numero della carta di credito.
Per verificare che l’utente immetta un valore corretto, è stato realizzata la classe
SeqCifreValidator che implementa l’interfaccia Validator.
Figura 44 - JSF : SeqCifreValidator
All’interno del metodo validate() viene definito il pattern a cui deve essere conforme
un valore caratterizzato esclusivamente da cifre e viene sollevata un’eccezione
310
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
qualora il controllo abbia esito negativo, in modo da visualizzare un messaggio di
errore all’utente.
...
Pattern mask = Pattern.compile("\\d+");
Matcher matcher = mask.matcher(value.toString());
// se il valore non corrisponde al pattern
if (!matcher.matches()){
...
...
throw new ValidatorException(msg);
}
...
Infine, eseguita la registrazione nel file di configurazione, il validatore viene utilizzato
mediante il tag <f:validator>.
<h:inputText id="cap"
value="#{utente.cap}"
maxlength="5"
size="5">
<f:validator validatorId="seqCifreValidator" />
</h:inputText>
Nel caso in cui il controllo abbia un esito negativo, viene visualizzato un opportuno
messaggio di errore prelevato dal Resource Bundle.
5.1.3 TelefonoValidator
Generalmente, il valore di un campo che deve rappresentare un numero di
telefono è caratterizzato da un formato particolare del tipo “prefisso-numero”.
Nel caso dell’applicazione realizzata, una situazione di questo tipo si verifica nella
fase di registrazione di un utente o comunque nell’acquisto di una scheda prepagata,
in cui tra i dati facoltativi c’è anche la richiesta del numero di telefono.
Per poter garantire che l’utente immetta un valore valido, si è resa necessaria la
realizzazione di un validatore opportuno mediante la classe TelefonoValidator che
implementa l’interfaccia Validator.
311
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 45 - JSF : TelefonoValidator
Il criterio adottato per la validazione è il medesimo degli altri validatori ed è basato
sulla definizione di un pattern a cui deve essere conforme un numero di telefono per
essere considerato valido.
...
Pattern mask = Pattern.compile("\\d+-{1}\\d+");
Matcher matcher = mask.matcher(value.toString());
// se il valore non corrisponde al pattern
if (!matcher.matches()){
...
...
throw new ValidatorException(msg);
}
...
Allo stesso modo, il validatore è stato registrato nel file di configurazione ed
utilizzato nelle pagine JSP mediante il tag <f:validator>.
<h:inputText id="telefono"
value="#{utente.telefono}"
maxlength="15">
<f:validator validatorId="telefonoValidator" />
</h:inputText>
312
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Nel caso di esito negativo della validazione, il messaggio di errore prelevato dal
Resource Bundle è del tipo in figura.
Figura 46 - JSF : Esempio d'uso del TelefonoValidator
5.2 Plug-in Validator Struts
Per poter effettuare la validazione dei dati contenuti nei form, il framework
Struts mette a disposizione un proprio meccanismo che è strettamente legato ai
formbeam associati a questi ultimi. Nell’ambito della realizzazione di un formbean
mediante l’implementazione di una classe che estende ActionForm oppure una delle
sue derivate, è possibile effettuare l’overriding del metodo validate() all’interno del
quale va immesso il codice per la validazione. Tale metodo viene invocato
automaticamente nel framework subito dopo che il formbean sia stato popolato. Con
questo meccanismo, similmente a quanto accade in JSF, se esistono dei form distinti
aventi dei campi che prevedono le medesime validazioni, è necessario riscrivere il
metodo validate() per tutti i formbean associati. Per evitare problemi di manutenzione
del software, il framework ingloba il plug-in Validator all’interno della propria
distribuzione, il quale rappresenta uno strumento notevolmente potente.
La prima considerazione da fare è che il plug-in va registrato come tale all’interno del
file di configurazione dell’applicazione, specificando il percorso del file delle regole di
validazione (validator-rules.xml) e del file in cui sono dichiarati i form da validare
(validation.xml).
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
Per quanto riguarda le regole di validazione, queste ultime non sono state
assolutamente modificate e non ne sono state create delle ulteriori, in quanto il plugin mette a disposizione le funzionalità di validazione più comuni, tra cui anche il
313
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
controllo di correttezza di un indirizzo email. Le principali validation-rules utilizzate
sono le seguenti :
-
required : controlla che un campo non sia vuoto, in quanto è obbligatoria
l’immissione di un valore;
-
email : verifica che un valore abbia il formato corretto di un indirizzo email;
-
minlength : valuta se il valore di un campo rispetti una lunghezza minima
prefissata;
-
mask : controlla che un certo valore sia conforme ad un pattern specificato;
-
date : verifica che un campo contenga una data corretta, secondo un certo
formato;
-
float : valuta che un certo valore sia del tipo float;
La disponibilità di queste regole non ha reso necessaria l’estensione del plug-in,
realizzando delle funzioni che implementassero ulteriori regole di validazione. Da
questo punto di vista, il framework Struts si può considerare superiore a JSF,
tenendo conto che i validatori standard di quest’ultimo sono soltanto tre.
Un’analisi più attenta è richiesta dal file validation.xml, all’interno del quale sono stati
dichiarati tutti i form ed i relativi campi sui quali devono essere applicate delle regole
di validazione specifiche. Tali form devono corrispondere esattamente ai formbean
registrati nel file di configurazione, così come le proprietà di questi ultimi devono
coincidere con i campi soggetti a validazione.
Ad esempio, considerando il form per la registrazione di un utente, esso è dichiarato
all’interno del file con una sintassi di questo tipo.
<form name="registrazioneForm">
<field depends="required" property="userName"/>
<field depends="required,minlength" property="password">
<var>
<var-name>minlength</var-name>
<var-value>5</var-value>
</var>
<arg0 key="${var:minlength}"
name="minlength"
resource="false"/>
</field>
<field depends="required,email" property="email"/>
</form>
314
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Il nome specificato per il form deve coincidere con quello del formbean ad esso
associato. Per ciascun campo ne viene specificato il nome, coincidente con la
proprietà corrispondente nel formbean suddetto,
e la regola di validazione da
applicare. Sulla base di quanto detto, si osserva che i campi previsti dal form sono
tutti obbligatori, regola required, ed inoltre al campo relativo all’indirizzo email è stato
applicata la regola email. Infine, per quanto riguarda la password è stata utilizzata
anche la regola di lunghezza minima, minlength, per la quale è stato dichiarato un
parametro di ingresso indicante il valore di quest’ultima; nel caso specifico, si prevede
che la password non sia lunga meno di 5 caratteri alfanumerici.
Una regola particolarmente utilizzata è quella che permette la validazione di un valore
in relazione ad un certo pattern specificato. Tale regola, nota come mask, prevede un
parametro di ingresso che rappresenta il pattern per il controllo della conformità. Il
caso principale di utilizzo è stato quello relativo ai valori che dovevano essere
caratterizzati esclusivamente da una sequenza di cifre (es. C.A.P, numero della carta
di credito, etc..) oppure nel caso del numero di telefono.
<form name="acquistoSchedaForm">
<field depends="required" property="nome"/>
<field depends="required" property="cognome"/>
...
...
<field depends="mask" property="cap">
<var>
<var-name>mask</var-name>
<var-value>[0-9]+</var-value>
</var>
<msg key="cifreError" name="mask"/>
</field>
...
<field depends="mask" property="telefono">
<var>
<var-name>mask</var-name>
<var-value>[0-9]+-{1}[0-9]+</var-value>
</var>
<msg key="numTelefonoError" name="mask"/>
</field>
...
</form>
La funzione mask ha previsto di volta in volta in ingresso, un pattern differente in
relazione al valore da validare. Infine, una regola di validazione particolarmente
interessante è quella relativa alla validazione di una data. Nell’implementazione in
JSF, non si è reso necessario un controllo di questo tipo, in quanto il Custom
315
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Component realizzato impedisce la selezione di una data non valida. Nel caso di
Struts, si è deciso di utilizzare un semplice campo di testo per l’inserimento di una
data, in modo da poter utilizzare questa potente regola di validazione disponibile nel
plug-in.
...
<field depends="date" property="dataNascita">
<var>
<var-name>date</var-name>
<var-value>dd/MM/yyyy</var-value>
</var>
</field>
...
Si osserva che la funzione date prevede un parametro di ingresso che definisce
secondo quale pattern la data debba essere considerata corretta.
Infine, un ulteriore vantaggio dell’uso del plug-in Validator è dato dal fatto che
quest’ultimo supporta anche la validazione lato client., in quanto le regole di
validazione non prevedono soltanto una serie di classi e metodi che le implementano
ma anche i corrispondenti codici in Javascript. Per poter usufruire di questa
funzionalità è necessario utilizzare il tag <html:javascript> all’interno della pagina JSP
di interesse, specificando il nome del form su cui effettuare la validazione.
6. Model
Il Model può essere considerato il cuore dell’applicazione realizzata, in
quanto è costituito da tutte quelle classi che definiscono la business-logic. Così come
anticipato in precedenza, l’implementazione in JSF ha previsto lo sviluppo dei
backing beans e dei relativi metodi che realizzano le funzionalità del sistema.
Con Struts si è resa necessaria la realizzazione delle action, per cui le classi della
business-logic risultano notevolmente più “leggere”. Ovviamente, la logica che è alla
base delle funzionalità è praticamente la stessa, con la differenza che in JSF è
completamente incapsulata nei metodi dei backing beans mentre in Struts è
distribuita fra gli oggetti della business-logic e le action. Queste ultime prevedono
tutto ciò che riguarda l’accesso agli elementi del framework, mentre i primi eseguono
316
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
le operazioni previste dall’applicazione. Infine, sono state implementate alcune classi
comuni tra le due implementazioni e che hanno i seguenti ruoli :
-
una serie di eccezioni che possono essere sollevate da particolari elaborazioni;
-
una serie di classi che gestiscono le operazioni di accesso alla base di dati;
6.1 Classi Exception
L’applicazione prevede alcune funzionalità nell’ambito delle quali si
possono verificare delle condizioni di errore che vanno opportunamente gestite. Uno
dei metodi più “eleganti” è l’utilizzo del meccanismo delle eccezioni messo a
disposizione dal linguaggio Java. Per questo motivo, sono state realizzate le seguenti
classi che estendono la classe base Exception :
-
PasswordErrata : eccezione che si verifica nel caso in cui un utilizzatore abbia
tentato un accesso al sistema sbagliando la password;
-
UsernameErrata : eccezione sollevata nel momento in cui un utilizzatore tenta
di effettuare il login con una username non registrata;
-
UsernameEsistente : eccezione che si verifica in fase di registrazione, quando
l’utente ha specificato una username già presente nella base di dati;
-
RuoloBloccato : eccezione sollevata quando un utilizzatore tenta di eseguire il
login con username e password corretti, ma il suo account risulta bloccato a
causa di tentativi di accesso errati in precedenza;
-
RuoloLoggato : eccezione che viene sollevata nel momento in cui un
utilizzatore tenta di accedere al sistema ma risulta già loggato;
Queste classi sono perfettamente identiche tra le due implementazioni ed inoltre
sono praticamente tutte una semplice estensione della classe Exception alla quale non
aggiungono alcuna funzionalità. Lo scopo della loro realizzazione è soprattutto
concettuale, per poter distinguere all’interno del codice le eccezioni di tipo diverso.
Soltanto la classe PasswordErrata è leggermente diversa dalla altre, in quanto ha la
proprietà idRuolo che permette di individuare l’utilizzatore che ha immesso lo
317
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
username corretto ma la password sbagliata, per cui bisogna tenere conto dei
tentativi di accesso errati e bloccarlo nel caso in cui sia necessario.
Figura 47 - JSF e Struts : Classi Exception
6.2 Classi di interfacciamento con il DataBase
Nella realizzazione di un sistema software che debba funzionare in locale
oppure in rete, ci sono tipicamente degli oggetti per i quali va garantita la persistenza
attraverso l’utilizzo delle basi di dati. Per poter gestire le operazioni di lettura e
scrittura nel database, sono previste due possibili soluzioni :
-
ogni oggetto gestisce la propria persistenza in maniera autonoma, prevedendo
dei metodi che accedono alla base di dati;
-
ogni oggetto delegata la gestione delle propria persistenza ad un’altra classe
che mette a disposizione una serie di metodi di accesso al database;
Con lo scopo di disaccoppiare le funzionalità della business-logic dalle operazioni di
accesso alla base di dati, generalmente si preferisce adottare la seconda soluzione. Ciò
è stato fatto anche nella Web application realizzata, implementando il sottolivello
Data Access del Model attraverso un’ulteriore insieme di classi, una per ciascuna
corrispondente classe della business-logic.
318
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per l’accesso vero e proprio alla base di dati, sono state utilizzate le seguenti classi
JDBC (Java DataBase Connectivity) :
-
Connection : rappresenta una connessione alla base di dati;
-
Statement : definisce una generica query da eseguire sul database;
-
ResultSet : rappresenta un gruppo di record, risultato di una query eseguita
sulla base di dati;
-
DriverMananger : classe che stabilisce la connessione con la base di dati
utilizzando i driver JDBC;
-
SQLException : definisce un’eccezione generica che è sollevata nel caso in cui
si verifichi un errore di accesso al database;
Ogni classe realizzata prevede una serie di proprietà private che rappresentano la
connessione (conn), una generica query (stmt), un resultSet (rs) ed infine la stringa di
interrogazione (sQuery).
Per poter garantire l’utilizzo dell’applicazione con un qualsiasi tipo di DBMS (es.
MySQL, MS SQL Server, MS Access, Oracle, …) e facilitarne il passaggio dall’uno
all’altro, è stata realizzata la classe astratta InfoDBMS che non ha metodi ma
eslusivamente le seguenti proprietà :
-
driver : il driver da utilizzare per la connessione al database;
-
connString : la stringa di connessione che specifica l’URL del database;
-
user : il nome dell’utente che accede al database con opportuni privilegi;
-
userPassword : la password dell’utente suddetto;
Le classi che si interfacciano con il database utilizzano le proprietà della classe
suddetta, per impostare i parametri di accesso con i quali stabilire la connessione alla
base di dati. In questo modo, è possibile utilizzare di volta in volta un DBMS
differente, semplicemente modificando i campi statici all’interno della classe
InfoDBMS, senza alcun intervento all’interno delle altre classi. Un ulteriore vantaggio
è dato dal fatto che la configurazione è completamente centralizzata in un’unica
classe.
319
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 48 - JSF e Struts : InfoDBMS
Per quanto riguarda l’implementazione dei metodi di accesso, la struttura tipica di
ciascuno di essi è la seguente.
...
try {
Class.forName(InfoDBMS.driver);
conn=DriverManager.getConnection(InfoDBMS.connString,
InfoDBMS.user,
InfoDBMS.userPassword);
stmt=conn.createStatement();
... creazione della query string ...
rs=stmt.executeQuery(sQuery);
... gestione del resultset ...
} catch (SQLException e) {
... gestione eccezioni ...
} finally {
try {if (rs !=null) rs.close();} catch (SQLException se) {}
try {if (stmt !=null) stmt.close();} catch (SQLException se) {}
try {if (conn !=null) conn.close();} catch (SQLException se) {}
}
...
Viene eseguita un’operazione di caricamento dei Driver JDBC e di apertura della
connessione alla base di dati specificata, dopodichè si crea la query string contenente
l’interrogazione, la si esegue e si manipola il gruppo di record risultanti. E’ prevista
inoltre la gestione di un’eventuale eccezione sollevata e la chiusura definitiva degli
oggetti utilizzati.
Per quanto riguarda le informazioni di accesso alla Web application è stata
realizzata la classe AccessoDB, la quale dispone dei metodi per inserire, aggiornare e
leggere un record nella tabelle degli accessi. Il metodo inserisci() ed aggiorna()
320
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
prevedono in ingresso un oggetto della classe Accesso, oltre all’identificativo del ruolo
a cui le informazioni si riferiscono e la tipologia del ruolo stesso, utente oppure
amministratore. Essi non restituiscono alcun valore, in quanto il loro scopo è
eseguire un’operazione di scrittura nella base di dati. Il metodo leggi() prevede soltanto
gli ultimi due parametri suddetti, accede al database e restituisce l’oggetto Accesso
corrispondente. Infine, ci sono due metodi privati che permettono la conversione e la
formattazione degli oggetti Date, sottolineando però che le date memorizzate
all’interno del database non sono di tipo stringa.
Figura 49 - JSF e Struts : AccessoDB
Le informazioni che riguardano l’amministratore sono gestite attraverso la
classe AmministratoreDB che mette a disposizione i metodi per eseguire l’operazione
di login, per leggere ed aggiornare un record ed infine bloccare l’amministratore.
321
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 50 - JSF e Struts : AmministratoreDB
In particolare, il metodo login() prevede in ingresso la username e la password
dell’amministratore e ne verifica la validità, con la possibilità di sollevare una delle
eccezioni introdotte in precedenza, se si verifica una particolare condizione di errore.
Ovviamente, questo metodo è invocato dalla funzionalità della business-logic che
permette di effettuare il login ed il suo scopo è solo ed esclusivamente di accesso alla
base di dati. I metodi leggi() e blocca() prevedono in ingresso l’identificativo
dell’amministratore di cui leggere le informazioni oppure da bloccare, mentre
aggiorna() riceve un oggetto Amministratore.
In maniera del tutto analoga è definita la classe UtenteDB che permette di
garantire la persistenza delle informazioni dell’utente. Esso mette a disposizione i
metodi tipici per la lettura, l’aggiornamento, l’inserimento e l’eliminazione di un
record. I metodi leggi() ed elimina() prevedono in ingresso l’identificativo dell’utente di
cui leggere le informazioni oppure da eliminare, mentre i metodi aggiorna() ed inserisci()
prevedono un oggetto Utente. E’ da osservare che l’operazione di inserimento è
piuttosto generica, in quanto essa viene utilizzata nella funzionalità di registrazione
della business-logic, certamente più complessa.
Il metodo login() opera allo stesso modo come per la classe AmministratoreDB. Inoltre
sono previsti i seguenti ulteriori metodi :
-
blocca() : permette di bloccare o di sbloccare un utente;
322
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
elencoUtenti() : produce la lista degli utenti registrati;
-
esisteUsername() : verifica l’esistenza di uno username in fase di registrazione.
-
esisteEmail() : verificano l’esistenza di un indirizzo email. Viene utilizzato nella
funzionalità di richiesta via mail delle informazioni di accesso da parte
dell’utente e restituisce l’identificativo di quest’ultimo in caso di esito
positivo;
Figura 51 - JSF e Struts : UtenteDB
La gestione della permanenza di tutto ciò che è strettamente legato ai brani MP3
viene eseguita mediante le tre seguenti classi :
-
BraniMP3DB;
-
PlaylistDB;
-
ComposizionePlaylistDB;
323
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Attraverso la classe BranoMP3DB è possibile gestire le informazioni di
ciascun brano all’interno dell’archivio. Oltre ai tipici metodi di inserimento,
eliminazione, lettura ed aggiornamento è previsto il metodo ricerca() che permette di
caricare dal database una lista di brani. Esso viene utilizzato sia nel caso in cui si
richieda di visualizzare i brani sulla base di un genere specificato, sia nel caso in cui
viene effettuata un’operazione di ricerca in base a dei criteri specificati. I parametri di
ingresso previsti sono relativi al genere, il titolo, l’autore e l’album dei brani da
cercare.
Figura 52 - JSF e Struts ; BranoMP3DB
Per quanto riguarda la gestione della permanenza delle informazioni delle
playlist, è stata realizzata la classe PlaylistDB che prevede le operazioni di inserimento,
eliminazione e lettura oltre al metodo elencoPlaylist() che genera l’elenco delle playlist
archiviate. In particolare, il metodo inserisci() prevede come parametri di ingresso un
oggetto Playlist e l’identificativo dell’utente a cui esso è associato.
324
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 53 - JSF e Struts : PlaylistDB
L’ultima classe, ComposizionePlaylistDB, non ha una classe corrispondente
nella business-logic e mette a disposizione i metodi per poter inserire ed eliminare un
brano MP3 da una playlist specificata oltre al metodo per generare l’elenco dei brani
appartenenti ad essa. Il metodo inserisci() ha in ingresso l’identificativo della playlist e
l’identificativo del brano da introdurre, allo stesso modo opera il metodo elimina(),
mentre il metodo composizionePlaylist() riceve in ingresso l’identificativo di una playlist
e restituisce l’elenco dei brani MP3 che sono al suo interno.
325
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 54 - JSF e Struts : ComposizionePlaylistDB
Per quanto concerne le informazioni relative alla scheda prepagata, alle ricariche ed
all’acquisto dei brani MP3, sono state realizzate le seguenti classi :
-
SchedaPrepagataDB;
-
RicaricaDB;
-
DownloadDB;
La classe SchedaPrepagataDB fornisce i metodi base per l’inserimento, la
lettura, l’aggiornamento e l’eliminazione di ciascun record che contiene le
informazioni relative ad una generica scheda prepagata. In particolare, il metodo
inserisci() prevede un oggetto SchedaPrepagata e l’identificativo dell’utente che ne ha
effettuato l’acquisto.
326
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 55 - JSF e Struts : SchedaPrepagataDB
La classe RicaricaDB permette di inserire all’interno della base di dati le
informazioni relative ad una ricarica eseguita su una scheda prepagata. Non è prevista
un’operazione di cancellazione, in quanto nella definizione della tabella
corrispondente nel database è stato specificato un vincolo di “cascade” sull’evento
“onDelete” sulla chiave esterna verso la tabella della scheda prepagata. In questo
modo, effettuando una cancellazione di una scheda prepagata, vengono cancellati
direttamente dal DBMS tutti i record delle corrispondenti ricariche. In questo modo
si garantisce la coerenza delle informazioni nella base di dati, senza dare l’onere di
questa operazione alle classi del software.
327
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 56 - JSF e Struts : RicaricaDB
Infine, la classe DownloadDB mette a disposizione un unico metodo che
permette di inserire un nuovo acquisto di un brano MP3 e quindi il relativo
download. Non prevede alcun metodo di eliminazione in quanto la tabella
corrispondente ha due chiavi esterne verso le tabelle relative ai brani ed agli utenti
con un vincolo di “cascade” sull’evento “onDelete”. In questo modo, eliminando un
brano MP3 oppure un utente, vengono cancellati tutti i record relativi ai
corrispondenti download direttamente dal DBMS. Anche in questo caso, si
garantisce la coerenza delle informazioni nel database, sollevando l’esecuzione di
queste operazioni dalle classi del software.
328
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 57 - JSF e Struts : DownloadDB
6.3 Le Action di Struts
Prima di analizzare le funzionalità offerte dal sistema e come esse sono
state implementate all’interno della business-logic, per quanto riguarda il framework
Struts si rende necessario un approfondimento sulle action che assumono un ruolo di
collegamento (bridge) tra il Controller ed il Model vero e proprio. Bisogna tenere
conto del fatto che all’interno di esse è prevista una parte del codice che interagisce
con gli oggetti del framework ed utilizza i metodi delle classi della business-logic, che
è in parte inevitabilmente presente in ciascuna action.
Sono state suddivise in più package, a secondo che vengano utilizzate all’interno di
uno specifico modulo dell’applicazione oppure siano comuni a più moduli.
Di seguito è riportato l’elenco dei suddetti package :
-
package defaultactions
-
LoginAction : gestisce l’operazione di login al sistema;
-
RegistrazioneAction : esegue la registrazione di un utente;
-
RichiediPasswordAction : fornisce la funzionalità di richiesta dei dati di
accesso via mail;
329
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
package adminactions
-
AmministratoreAction
:
esegue
tutte
le
funzionalità
relative
all’amministratore;
-
-
package useractions
-
PlaylistAction : offre le funzionalità di gestione delle playlist;
-
RicaricaSchedaAction : gestisce l’operazione di ricarica di una scheda;
package commonactions
-
AcquistoSchedaAction : effettua l’operazione di acquisto di una scheda
prepagata;
-
BranoMP3Action : fornisce tutte le funzionalità relative ai brani MP3;
-
UtenteAction : mette a disposizione le funzionalità che riguardano gli
utenti;
-
LogoutAction : permette di eseguire l’operazione di logout;
E’ da sottolineare che, per interazioni con gli oggetti del framework, si intende dire
che all’interno di ciascuna action vengono eseguite le operazioni di accesso alle
variabili di sessione e di ciascuna richiesta oltre al salvataggio dei messaggi di errore
da visualizzare all’utente. Tali operazioni prevedono l’utilizzo delle classi di Struts o
comunque legate alle Servlet in generale, per cui non sono eseguite all’interno degli
oggetti della business-logic in modo da favorire il disaccoppiamento di quest’ultima
dal framework stesso.
Tali action sono state effettivamente implementate, ciascuna attraverso una
corrispondente classe, ma ad esse va aggiunta la action switch appartenente alla classe
SwitchAction che è stata soltanto dichiarata nei file di configurazione dei tre moduli ed
il cui scopo è quello di permettere il passaggio fra un modulo e l’altro.
Ciascuna delle action suddette è stata ovviamente dichiarata all’interno di uno o più
moduli e ad essa sono stati associati i forward che permettono la navigazione
all’interno della Web application.
330
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 58 - Struts : Action ed interazione con le classi del Model
331
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
La classe LoginAction deriva dalla classe base Action, per cui prevede l’unico
metodo execute() all’interno del quale ci sono le elaborazioni effettuate dalla action
stessa. Inoltre, prevede due metodi privati che permettono di gestire le condizioni di
password errata e di login effettuato in maniera corretta.
Figura 59 - Struts : LoginAction
Il metodo execute() contiene tutte le operazioni necessarie per valutare la username e
la password immessa dall’utilizzatore, invocando il metodo login() della classe Ruolo,
permettendo l’accesso nel caso di esito positivo oppure catturando una delle
eccezioni relative alle possibili condizioni di errore e salvandone i corrispondenti
messaggi. Il metodo privato loginCorretto() ha il compito di salvare le informazioni
332
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
relative all’accesso mediante la classe Accesso e le sue derivate e di inserire in sessione
le informazioni dell’utente oppure dell’amministratore che ha effettuato il login. Il
metodo passwordErrata() segnala l’errore di password errata, ne tiene traccia mediante
la classe Accesso e blocca eventualmente l’utilizzatore nel caso di due tentativi errati
consecutivi. Infine, all’interno del metodo execute(), se il login va a buon fine per un
utente, vengono caricate in sessione le informazioni di un’eventuale scheda prepagata
associata a quest’ultimo ed eventualmente segnalata la sua scadenza. L’ultima
operazione eseguita è l’utilizzo del forward verso la action switch per passare al
modulo corretto, a seconda che l’accesso sia stato eseguito da un utente oppure
dall’amministratore.
La registrazione della action nel file di configurazione del modulo di default permette
di associarle il formbean loginForm ed il forward in caso di errore.
<action input="/pages/home.jsp" name="loginForm" path="/login"
scope="request" type="defaultactions.LoginAction">
<forward name="failure" path="/pages/home.jsp"/>
</action>
La classe RegistrazioneAction estende anch’essa la classe Action ed all’interno
del proprio metodo execute() gestisce le operazioni che riguardano la registrazione
dell’utente, intercettando l’eventuale errore nel caso in cui la username scelta sia già
presente in archivio oppure completando l’operazione in maniera corretta. Essa
permette il passaggio alla action per la gestione dell’acquisto della scheda prepagata,
se l’utente sceglie di voler usufruire di tale servizio. Infine, una volta completata la
registrazione in maniera corretta viene invocato un forward per richiamare la action
LoginAction ed eseguire il login automatico al sistema.
Attraverso la dichiarazione del file di configurazione del modulo “default” viene
assegnato il formbean registrazioneForm ed i forward per la navigazione.
<action input="/pages/registrazione.jsp" name="registrazioneForm"
path="/registrazione" scope="session"
type="defaultactions.RegistrazioneAction"
validate="true">
<forward name="login" path="/login.do"/>
<forward name="acquistoScheda"
path="/pages/acquistoScheda.jsp"/>
<forward name="failure" path="/pages/registrazione.jsp"/>
</action>
333
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 60 - Struts : RegistrazioneAction
La classe RichiediPasswordAction estende Action ed all’interno del metodo
execute(), utilizza il metodo richiediUsernamePassword() della classe Utente, facente parte
della business-logic, per inviare la mail con i dati di accesso. Ovviamente, nel caso in
cui l’indirizzo email specificato non risulti registrato all’interno dell’archivio, viene
salvato un messaggio di errore.
Figura 61 - Struts : RichiediPasswordAction
334
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
La registrazione viene eseguita soltanto del file struts-config.xml associando alla action il
formbean richiediPasswordForm.
<action input="/pages/richiestaPassword.jsp"
name="richiediPasswordForm" path="/richiediPassword"
scope="request" type="defaultactions.RichiediPasswordAction"
validate="true">
<forward name="eseguita" path="/pages/richiestaPassword.jsp"/>
</action>
La classe AmministratoreAction deriva da DispatchAction, in quanto non ha il
compito di effettuare un unico tipo di elaborazione ma di svolgere tutte le principali
funzionalità legate all’amministratore. Ovviamente, una cosa di questo tipo non può
essere gestita attraverso la derivazione dalla classe Action che contiene un unico
metodo execute() o comunque sarebbe necessario definire all’interno di quest’ultimo
una serie di costrutti condizionali per poter distinguere che tipo di operazioni
effettuare. La soluzione più “elegante” per ovviare a questo problema è l’uso della
classe DispatchAction che non prevede un unico metodo execute() ma più metodi,
ciascuno dei quali realizza una specifica funzionalità. Quando tale action viene
invocata, attraverso una particolare parametro dispatch è possibile distinguere di volta
in volta quale dei suoi metodi eseguire.
In particolare, la classe AmministratoreAction prevede i due seguenti metodi :
-
visualizza() : esegue le operazioni necessarie alla visualizzazione delle
informazioni dell’amministratore;
-
modifica() : effettua le elaborazioni relative alla modifica della password
richiesta dall’amministratore, ovviamente segnalando eventuali condizioni di
errore;
335
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 62 - Struts : AmministratoreAction
Essa è registrata esclusivamente nel modulo “admin” associandole il formbean
modificaPasswordForm ed i forward in caso di visualizzazione/modifica oppure di
insuccesso dovuto ad errori nell’aggiornamento. E’ da osservare la dichirazione del
parametro dispatch attraverso l’attributo parameter.
<action input="/pages/modificaDatiAmministratore.jsp"
name="modificaPasswordForm" parameter="dispatch"
path="/amministratore" scope="request"
type="adminactions.AmministratoreAction"
validate="false">
<forward name="visualizzaDati"
path="/pages/modificaDatiAmministratore.jsp"/>
<forward name="failure"
path="/pages/modificaDatiAmministratore.jsp"/>
</action>
Anche la classe PlaylistAction estende DispatchAction, in quanto mette a
disposizione tutte le funzionalità relative alla gestione delle playlist.
336
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Essa è costituita dai seguenti metodi, invocati sulla base di un opportuno parametro
dispatch :
-
visualizzaElencoPlaylist() : permette di caricare l’elenco delle playlist relative
all’utente in sessione oppure di segnalarne l’assenza;
-
eliminaPlaylists() : gestisce l’eliminazione di più playlist selezionate dall’elenco,
ritornando poi alla visualizzazione dell’elenco aggiornato;
-
crea() : esegue le operazioni relative alla creazione della playlist per l’utente in
sessione;
-
elimina() : gestisce l’eliminazione della playlist corrente;
-
visualizzaElencoBraniMP3Playlist() : permette la visualizzazione dell’elenco dei
brani MP3 contenuti nella playlist corrente oppure di segnalarne l’assenza;
-
ascolta() : gestisce la creazione sul file system del server di un file M3U
contente i percorsi ai file MP3 da eseguire ed avvia il player MP3 per l’ascolto
della playlist;
Figura 63 - Struts : PlaylistAction
337
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Essa è registrata esclusivamente nel modulo “user” associandole il formbean
playlistForm per la creazione e cancellazione delle playlist ed i forward per le richieste
di visualizzazione.
<action name="playlistForm" parameter="dispatch" path="/playlist"
scope="request" type="useractions.PlaylistAction"
validate="false">
<forward name="visualizzaElencoPlaylist"
path="/pages/gestionePlaylist.jsp"/>
<forward name="failure" path="/pages/gestionePlaylist.jsp"/>
<forward name="visualizzaElencoBraniPlaylist"
path="/pages/visualizzaElencoBraniPlaylist.jsp"/>
</action>
La classe RicaricaSchedaAction deriva da Action e di conseguenza prevede
soltanto il metodo execute(), in quanto il suo unico scopo è quello di gestire le
operazioni per la ricarica di una scheda prepagata. Essa ovviamente ha dei legami di
dipendenza con la classe Ricarica, CartaCredito e SchedaPrepagata della business-logic. La
prima
e la seconda per poterle istanziare rispettivamente con l’importo scelto
dall’utente e le informazioni della carta di credito e l’ultima per poter eseguire
l’operazione di ricarica vera e propria della scheda prepagata, la quale opera sugli
oggetti suddetti.
Figura 64 - Struts : RicaricaSchedaAction
Anche in questo caso la dichiarazione della action compare solo nel modulo “user”
con il formbean ricaricaSchedaForm associato.
338
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<action input="/pages/ricaricaScheda.jsp"
name="ricaricaSchedaForm"
path="/ricaricaScheda" scope="request"
type="useractions.RicaricaSchedaAction" validate="true">
<forward name="success" path="/home.jsp"/>
</action>
La classe AcquistoSchedaAction deriva da Action e mette a disposizione la
funzionalità di acquisto di una scheda prepagata sia nella fase di registrazione per un
nuovo utente sia per un utente già registrato ma che vuole usufruire del servizio di
download dei brani MP3. All’interno del metodo execute(), si valuta in quale delle due
possibili situazioni la action è stata invocata, per determinare se si rende necessaria
una preventiva operazione di registrazione dell’utente oppure direttamente l’acquisto
della scheda prepagata. Negli oggetti del tipo SchedaPrepagata e CartaCredito vengono
copiate le informazioni relative agli importi ed alla carta di credito, prelevate dal
formbean, per poi eseguire l’acquisto. In caso di registrazione, il metodo termina
invocando la action per l’esecuzione del login in automatico.
La action è stata registrata sia nel modulo “default” che “user” considerando le due
possibili situazioni in cui è previsto l’acquisto della scheda prepagata.
Figura 65 - Struts : AcquistoSchedaAction
339
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
La classe BranoMP3Action è una delle più complesse in quanto deriva da
DispatchAction e mette a disposizione una serie di metodi che permettono di gestire
tutte le possibili funzionalità sui brani MP3. Tali metodi sono i seguenti :
-
visualizzaElencoBraniMP3() : permette la visualizzazione dei brani MP3 sulla
base del genere specificato, inserendo la lista ricavata dal database all’interno
di una variabile di sessione;
-
ricercaBraniMP3() : esegue la ricerca dei brani sulla base dei criteri di ricerca
fissati ed opera allo stesso modo del metodo precedente;
-
eliminaBraniMP3() : gestisce l’eliminazione di più brani contemporaneamente,
selezionati dall’elenco corrente. Oltre alla cancellazione delle informazioni
dall’archivio, vengono cancellati anche i file MP3 corrispondenti dal file
system del server;
-
inserisci() : permette l’inserimento di un brano in archivio nonché il
caricamento del corrispondente file MP3 sul server e la gestione della
coerenza dei tag ID3v1 con le informazioni inserite;
-
visualizza() : esegue il caricamento delle informazioni di uno specifico brano in
una variabile di sessione, garantendo una visualizzazione diversa a seconda
che la richiesta sia stata fatta dall’utente oppure dall’amministratore;
-
elimina() : permette di effettuare l’eliminazione del brano corrente
dall’archivio, nonché la cancellazione del file MP3 associato;
-
modifica() : permette all’amministratore di modificare le informazioni di un
brano, aggiornando anche i tag ID3v1 del file MP3 corrispondente;
-
inserisciBraniMP3Playlist() : effettua l’inserimento di una serie di brani
selezionati dall’elenco corrente all’interno di una playlist scelta e salvata in
sessione;
-
eliminaBraniMP3Playlis() : permette l’eliminazione di più brani da una playlist,
selezionandoli dall’elenco di composizione;
-
inserisciPlaylist() : permette di inserire il brano corrente all’interno di una
playlist selezionata;
-
acquista() : effettua l’operazione di acquisto di un brano MP3 e ne abilita la
funzionalità di download;
340
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Essa è praticamente legata a tutte le classi che riguardano i brani, il loro acquisto e la
composizione delle playlist. Infine, essa è dichiarata sia nel modulo corrispondente
all’utente che all’amministratore ovviamente garantendo l’esecuzione di metodi
diversi.
Figura 66 - Struts : BranoMP3Action
La classe UtenteAction estende DispathAction e fornisce tutte le funzionalità
strettamente legate all’utente. Essa prevede i seguenti metodi :
-
visualizza() : permette il caricamento dei dati dell’utente in sessione per
permetterne la modifica oppure esclusivamente la visione all’amministratore;
341
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
modifica() : effettua l’operazione di aggiornamento dei dai dell’utente,
segnalando eventuali condizioni di errore;
-
elimina() : permette all’amministratore di eliminare l’utente selezionato;
-
visualizzaUtenti() : esegue il caricamento dell’elenco degli utenti registrati in
una variabile di sessione, per la successiva visualizzazione;
-
eliminaUtenti() : permette all’amministratore di eliminare uno o più utenti
selezionati dall’elenco;
-
sblocca() : esegue l’operazione di sblocco di un utente;
Si osservi che essa è strettamente legata solo ed esclusivamente alla classe Utente della
business-logic, in quanto utilizza i metodi di quest’ultima che agiscono sull’utente.
Inoltre, anche in questo caso la registrazione è stata effettuata nei moduli “admin” e
“user”.
Figura 67 - Struts : UtenteAction
342
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
L’ultima classe, LogoutAction, deriva da Action in quanto attraverso l’unico
metodo execute() permette all’utente oppure all’amministratore di eseguire il logout dal
sistema.
Figura 68 - Struts : LogoutAction
Invoca il metodo di logout() della classe Utente oppure Amministratore ed utilizza la
classe Playlist per eliminare eventuali file MP3 di playlist ascoltate dall’utente. La
dichiarazione nel modulo “user” e “admin” associa ad essa il forward verso la action
switch per ritornare al modulo “default”.
Considerando l’operazione di passaggio da un modulo all’altro durante la
navigazione, è stata realizzata la action switch del tipo SwitchAction, la quale viene
invocata con una sintassi di questo tipo :
/switch.do?page=[pagina.jsp]&prefix=[prefissoModulo]
in cui il parametro prefix permette di specificare il modulo verso il quale eseguire il
passaggio (/admin, /user oppure una stringa vuota per il modulo di default) mentre
page indica la pagina verso la quale essere redirezionati all’interno del modulo stesso.
343
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
6.4 Business-Logic e funzionalità del sistema
Considerando le due implementazioni con JSF e Struts, le classi che
costituiscono la business-logic sono caratterizzate dalle seguenti differenze :
-
con JSF costituiscono a tutti gli effetti i backing beans, per cui la maggior
parte dei metodi restituiscono gli outcome per la navigazione essendo invocati
direttamente dalle pagine JSP; con Struts vengono utilizzate all’interno delle
action per cui non devono assolutamente occuparsi della navigazione;
-
con JSF i metodi accedono agli oggetti del framework, così come alle variabili
di sessione e di ciascuna richiesta; con Struts tali operazioni vengono eseguite
dalle action in modo che gli oggetti della business-logic siano disaccoppiati
dal framework stesso;
Facendo riferimento alle elaborazioni eseguite per ciascuna funzionalità, basta
osservare che nel caso di JSF sono concentrate nei metodi delle classi stesse, mentre
con Struts sono distribuite tra questi ultimi e le action. Inoltre, è da sottolineare che
dal punto di vista concettuale sono sostanzialmente identiche, tenendo comunque
conto che la Web application è la medesima.
Una precisazione è doverosa per quanto riguarda l’inserimento e la lettura degli
oggetti del sistema all’interno delle variabili di sessione. Queste ultime sono
ampiamente utilizzate per memorizzare alcuni oggetti della business-logic che
contengono le informazioni associate all’utilizzatore corrente, di cui bisogna
mantenerne lo stato durante la navigazione. Per poter gestire le operazioni di lettura e
scrittura in sessione, le classi sono state dotate di alcuni metodi statici che
ovviamente necessitano dell’accesso all’istanza della classe HttpSession. Questo tipo di
operazione non comporta nulla sull’implementazione con JSF, mentre sembrerebbe
introdurre una contraddizione nell’implementazione con Struts, perché in questo
modo si introduce un legame con il framework. La scelta è stata fatta per rendere più
“snello” il codice all’interno delle action ma ciò non toglie che, a meno dei metodi
statici suddetti, le classi della business-logic dell’implementazione in Struts sono
assolutamente indipendenti dal framework e riutilizzabili con framework diversi.
344
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Tali metodi statici, previsti esclusivamente per alcune classi, hanno una nomenclatura
di questo tipo :
-
getClasseSession : permette di recuperare dalla sessione un oggetto
appartenente a questa classe;
-
removeClasseSession : elimina dalla sessione l’oggetto della classe;
-
putClasseSession : inserisce all’interno della sessione un oggetto di questa
classe;
-
isClasseSession : verifica se un oggetto della classe è presente all’interno della
sessione corrente;
Pagina JSP
Pagina JSP
Oggetto BL
(Backing Bean)
Action
Elaborazioni
Oggetto BL
Elaborazioni
Figura 69 - JSF e Struts : Accesso agli oggetti della Business-Logic
Di seguito sono descritte le classi che compongono il Model in entrambe le
implementazioni, evidenziando l’interazione tra di esse e le differenze che sussistono
tra le loro realizzazioni in un’implementazione e nell’altra.
345
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
6.4.1 Package accesso
Questo package contiene le classi che permettono di gestire le informazioni
che riguardano tutte le operazioni di login e di logout eseguite dagli utenti e
dall’amministratore. Esso è caratterizzato dalla classe astratta Accesso dalla quale
derivano le classi AccessoUtente ed AccessoAmministratore per distingure, unicamente da
un punto di vista concettuale, le informazioni di accesso dell’utente e
dell’amministratore.
In entrambe le implementazioni, le proprietà delle classi sono le seguenti :
-
id : identificativo dell’accesso;
-
dataOraLogin, dataOraLogout : data ed ora in cui è stato eseguito il login ed il
logout;
-
loginValido : valore booleano che indica se l’accesso è andato a buon fine o
meno;
-
tentativo : intero che indica in corrispondenza di quale tentativo c’è stato
l’accesso oppure eventualmente il blocco;
-
indirizzoIP : indirizzo IP del client;
Ovviamente, nella classe Accesso i metodi sono tutti astratti ma sono implementati
all’interno delle classi derivate e sono i seguenti :
-
inserisci() : permette di inserire le informazioni relative ad un’azione di login.
Prevede in ingresso l’identificativo dell’utilizzatore che ha effettuato l’accesso;
-
leggi() : permette di leggere le informazioni dell’accesso di un utilizzatore,
specificando in ingresso il suo identificativo;
-
aggiorna() : permette di aggiornare le informazioni dell’accesso in fase di
logout, ricevendo in ingresso l’identificativo dell’utilizzatore che sta
abbandonando il sistema;
Nelle due implementazioni, queste classi sono perfettamente uguali considerando che
non sono utilizzate direttamente dalle pagine JSP oppure dalle action, ma da altre
classi della business-logic ed in particolar modo dagli oggetti Ruolo, Utente ed
346
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Amministratore. La differenza sostanziale è relativa ai metodi che accedono alla
sessione, in quanto con JSF si utilizza la classe del framework FacesContext, mentre
con Struts direttamente l’oggetto HttpSession.
Figura 70 – JSF : package accesso
347
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 71 - Struts : package accesso
Questo package non rappresenta un termine di paragone tra le due implementazioni
e potrebbe essere banalmente interscambiato facendo gli opportuni accorgimenti
nell’accesso alle variabili di sessione.
6.4.2 Package ruolo
Il package ruolo contiene le classi relative agli utilizzatori della Web
application. In particolare, la classe Ruolo generalizza le due sottoclassi Utente ed
Amministratore, tenendo conto del fatto che prima di essere registrato o comunque di
348
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
eseguire il login, un utilizzatore dell’applicazione non può essere classificato. In
entrambe le implementazioni, essa prevede le seguenti proprietà :
-
id : identificativo univoco del ruolo;
-
userName : username del ruolo;
-
password : password di accesso del ruolo;
-
bloccato : indica se il ruolo risulta bloccato o meno;
-
loggedIn : indica se il ruolo è loggato o meno al sistema;
-
tipo : è presente soltanto nell’implementazione in Struts per poter distinguere
un utente e l’amministratore in fase di login, considerando che tale
operazione viene gestita da una action esterna;
Ovviamente, esse sono ereditate dalle classi Utente ed Amministratore essendo
informazioni comuni ad entrambi, con la differenza che mentre la seconda non
aggiunge ulteriori proprietà, la prima ha delle proprietà in più che rappresentano tutti
i dati anagrafici dell’utente. Inoltre, sono previste le proprietà dataOraRegistrazione ed
acquistoMP3 che indica se l’utente ha deciso di usufruire del servizio di acquisto e
download dei brani. Nell’implementazione in JSF, la classe Utente necessita di una
proprietà in più, elimina, che tiene conto del fatto che l’utente sia stato selezionato o
meno all’interno dell’elenco degli utenti registrati per poter essere cancellato. Tale
proprietà non si è resa necessaria in Struts, grazie all’utilizzo delle multibox, come
visto nella descrizione della View.
Prima di descrivere in linea generale il comportamento dei metodi previsti nelle
classi, è opportuno osservare le dipendenze che ci sono tra di esse e le altre classi del
Model oltre ad eventuali classi del framework adottato, in modo da poter
comprendere alcune differenze tra le due implementazioni.
Nell’implementazione con JSF, le classi utilizzano fortemente FacesContext per poter
accedere alle variabili di sessione, mentre con Struts soltanto le classi Utente ed
Amministratore accedono alle istanze di HttpServletRequest ed HttpSession. Queste ultime
sono state utilizzate per far gestire a tali classi la propria permanenza in sessione ma,
come anticipato, non sono strettamente necessarie e potrebbero essere usate dalle
action esterne. La classe Ruolo non è assolutamente legata a queste classi, in quanto il
suo uso principale avviene nella action di login , LoginAction, che gestisce la
349
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
persistenza in sessione delle informazioni di un utente oppure dell’amministratore,
utilizzando i metodi delle classi corrispondenti. In entrambe le implementazioni, la
classe Ruolo utilizza le classi UtenteDB ed AmministratoreDB per poter effettuare
l’operazione di login, così come in entrambi i casi è legata alle eccezioni che possono
essere sollevate in fase di accesso al sistema. Con JSF, Ruolo utilizza la classe Accesso e
le sue derivate per poter gestire il salvataggio delle informazioni di accesso, mentre
con Struts questo compito è delegato alle action. Infine, nell’implementazione in JSF,
la classe Utente accede a tutte quelle classi legate a funzionalità accessibili dall’utente,
tra cui Playlist, SchedaPrepagata, CartaCredito e Mail, mentre con Struts alcune di queste
dipendenze mancano essendo previste nelle action.
E’ da sottolineare che sussistono molte più dipendenze con JSF che non con Struts e
tutto ciò è giustificato dal fatto che nel primo caso, le classi devono gestire tutto in
maniera autonoma interagendo tra loro e con gli oggetti del framework, mentre nel
secondo caso, le action si occupano di alcune di queste interazioni, per cui le classi
della business-logic non fanno altro che eseguire semplici operazioni utilizzando le
classi di accesso alla base di dati.
350
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 72 - JSF : package ruolo
351
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 73 - Struts : package ruolo
352
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda i metodi, la classe Ruolo prevede :
-
login(), logout() : per effettuare le operazioni di login e di logout al sistema;
-
blocca(), sblocca() : per bloccare o sbloccare un ruolo. Essi non hanno corpo in
entrambe le implementazioni ma vengono utilizzate le versioni soggette ad
overriding delle classi Utente ed Amministratore;
Nel caso dell’implementazione con JSF, è da osservare che sono presenti alcuni
metodi privati che invece, nell’implementazione con Struts, si trovano nella
LoginAction.
Il metodo login() opera secondo una modalità di questo tipo :
-
tenta di valutare se al sistema sta accedendo un utente invocando
UtenteDB.login();
-
se lo username non è registrato tra gli utenti, tenta di valutare se sta
accedendo l’amministratore invocando AmministratoreDB.login();
-
nel caso di username inesistente in entrambi i casi viene segnalato un errore,
mentre in caso di esito positivo e di password corretta viene consentito
l’accesso. Se si tratta di un utente, vengono caricate le informazioni di
un’eventuale scheda prepagata e ne viene valutata la scadenza;
-
in tutti gli altri casi, le classi di accesso alla base di dati possono sollevare le
eccezioni relative a password errata, ruolo loggato e ruolo bloccato;
La differenze principali tra le due implementazioni sono le seguenti :
-
con JSF, il parametro di ritorno del metodo sarà comunque una stringa che
rappresenta l’outcome con il quale proseguire la navigazione. Con Struts, viene
restituito un oggetto Ruolo che può puntare ad un’istanza di Utente oppure
Amministratore. Tale oggetto verrà utilizzato dalla LoginAction che invoca
questo metodo;
-
con JSF, le eccezioni sollevate nelle possibili condizioni di errore vengono
catturate e poi ne viene gestita la segnalazione. Con Struts, considerando che
il metodo login() viene invocato dalla LoginAction, le eccezioni vengono
353
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
catturate e poi risollevate a quest’ultima che avrà il compito di salvare i
messaggi di errore nella request;
-
con JSF, la memorizzazione delle informazioni di accesso viene eseguita
all’interno della classe Ruolo attraverso dei metodi privati. Con Struts, gli stessi
metodi sono previsti nella LoginAction;
-
con JSF, nel caso di accesso di un utente, le informazioni di un’eventuale
scheda prepagata vengono caricate all’interno del metodo login() stesso. Con
Struts, tale operazione è delegata alla LoginAction.
Il fatto che alcune elaborazioni siano eseguite nella LoginAction, per quanto riguarda
l’uso di Struts, evidenzia che gli oggetti della business-logic eseguono soltanto le
operazioni che competono loro da un punto di vista concettuale.
Il metodo logout() è completamente diverso, in quanto con JSF, esegue semplicemente
l’invalidazione della sessione mentre altre operazioni specifiche vengono eseguite
dalla versione soggetta ad overriding delle classi Utente ed Amministratore. Con Struts,
tale metodo non ha corpo in quanto vengono utilizzate esclusivamente le sue
versioni sovrascritte che sono invocate all’interno della LogoutAction che si occupa
anche di invalidare la sessione;
La classe Amministratore prevede i seguenti metodi :
-
login(), logout() : versioni sovrascritte delle medesime funzioni di Ruolo. La
login() non fa altro che invocare la versione della superclasse mentre la logout(),
in entrambe le implementazioni, aggiorna le informazioni di uscita dal
sistema;
-
visualizzaDati() : ha il compito di permettere la visualizzazione dei dati
dell’amministratore per un’eventuale modifica. Con JSF, ricava le
informazioni dall’oggetto Amministratore in sessione e restituisce l’outcome per
la navigazione alla pagina di visualizzazione. Con Struts, esegue la lettura dei
dati
dal
database
con
AmministratoreDB.leggi(),
restituendo
l’oggetto
Amministratore;
-
modificaDati() : esegue la modifica dei dati dell’amministratore. Con JSF,
esegue l’aggiornamento invocando AmministratoreDB.aggiorna() oppure segnala
eventuali errori e fa proseguire la navigazione restituendo l’outcome. Con
354
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Struts, effettua l’aggiornamento allo stesso modo ma viene invocato dal
metodo modifica() di AmministratoreAction, che ha il compito di gestire gli errori
e passare alla pagina di visualizzazione;
-
blocca() : è perfettamente uguale in entrambe le implementazioni, bloccando
l’amministratore mediante il metodo AmministratoreDB.blocca();
La classe Utente è sicuramente una delle più complesse, in quanto prevede i seguenti
metodi :
-
login(), logout() : versioni sovrascritte delle medesime funzioni di Ruolo. La
login() non fa altro che invocare la versione della superclasse mentre la logout(),
in entrambe le implementazioni, aggiorna le informazioni di uscita dal
sistema;
-
registrazione() : permette di effettuare la registrazione dell’utente;
-
visualizzaDati() : ha il compito di permettere la visualizzazione dei dati
dell’utente. Con JSF, ricava le informazioni dall’oggetto Utente in sessione e
restituisce un outcome diverso per la navigazione, in base al fatto che la
richiesta sia stata fatta dall’utente, che vorrà modificare i propri dati, oppure
dall’amministratore che potrà soltanto visionarli. Con Struts, esegue la lettura
dei dati dal database con UtenteDB.leggi(), restituendo l’oggetto Utente;
-
modificaDati() : esegue la modifica dei dati dell’utente. Con JSF, esegue
l’aggiornamento invocando UtenteDB.aggiorna() oppure segnala eventuali errori
e fa proseguire la navigazione restituendo l’outcome. Con Struts, effettua
l’aggiornamento allo stesso modo ma viene invocato dal metodo modifica() di
UtenteAction, che ha il compito di gestire gli errori e passare alla pagina di
visualizzazione;
-
blocca(), sblocca() : sono uguali in entrambe le implementazioni ed eseguono le
operazioni di blocco e sblocco di un utente, mediante i corrispondenti metodi
della classi che accedono alla base di dati;
-
sbloccaUtente() : presente soltanto nell’implementazione in JSF, è utile per non
alterare la struttura comune dei metodi precedenti e può essere invocato da
una pagina JSP per sbloccare l’utente e restituire l’outcome per la navigazione;
355
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
visualizzaElencoUtenti() : permette la visualizzazione dell’elenco degli utenti
registrati. Con JSF, invoca UtenteDB.elencoUtenti() e salva la lista in una
variabile di sessione restituendo l’outcome per la navigazione. Con Strust, viene
invocato dal metodo visualizzaUtenti() della UtenteAction al quale restituisce la
lista degli utenti registrati. E’ la action che si occupa di salvare tale lista nella
sessione;
-
elimina(), eliminaUtenti() : permettono di eliminare un singolo utente oppure
più utenti selezionati dall’elenco. In entrambe le implementazioni viene
utilizzato uno o più volte il metodo UtenteDB.elimina(). Con JSF, viene gestito
l’aggiornamento dell’elenco in sessione e restituito l’outcome per la navigazione.
Con Struts, tali operazioni vengono eseguite dai metodi elimina() ed
eliminaUtenti() della UtenteAction che gestisce anche il proseguimento della
navigazione;
-
verificaUsername() : permette di valutare se un certo username risulta essere già
associato ad un utente registrato. Esso viene utilizzato in fase di registrazione
e l’implementazione con JSF, una volta terminata la verifica, restituisce un
outcome per la navigazione. Con Struts, restituisce semplicemente un valore
booleano e viene utilizzato dalla RegistrazioneAction. In entrambi i casi, viene
utilizzato il metodo UtenteDB.esisteUsername();
-
richiediUsernamePassword() : permette all’utente di ricevere una mail contenente
i dati di accesso al sistema. Con JSF, verifica l’esistenza della mail utilizzando
UtenteDB.esisteEmail(), invia i dati mediante la classe Mail oppure segnala
eventuali errori. Con Struts, invia la mail allo stesso modo e restituisce un
semplice valore booleano alla RichiediPasswordAction da cui viene invocato;
Un’osservazione da fare è che i metodi visualizzaElencoUtente() ed eliminaUtenti() sono
dichiarati statici con Struts ma non con JSF. Il fatto di essere statici, ossia non legati
ad una specifica istanza della classe, è plausibile tenendo conto del fatto che non
eseguono operazioni legate ad uno specifico utente ma agli utenti in generale. Con
JSF, non è possibile dichiararli statici in quanto la loro invocazione avviene
direttamente dalle pagine JSP e l’oggetto Utente è istanziato e presente in sessione.
Inoltre, l’utilizzo del method-binding prevede di poter invocare metodi di istanza,
appartenenti ai backing beans dichiarati, ma non metodi statici.
356
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Il metodo registrazione() merita un’analisi a parte, in quanto ha un’implementazione
completamente diversa fra Struts e JSF. Con Struts, non fa altro che invocare
UtenteDB.inserisci() per salvare le informazioni dell’utente nell’archivio. Con JSF, ha
una struttura notevolmente complessa, poichè esegue tutte le operazioni legate alla
registrazione che non prevede soltanto il salvataggio dell’utente in archivio. E’ ovvio
che tali operazioni sono eseguite anche nell’implementazione in Struts ma non
all’interno di questo metodo, bensì nella RegistrazioneAction. La funzionalità di
registrazione, in entrambi i casi, è caratterizzata dalle seguenti fasi :
-
si valuta se l’utente abbia scelto di acquistare una scheda prepagata;
-
se così non fosse, viene semplicemente salvato l’utente in archivio oppure
vengono segnalati eventuali errori dei dati;
-
viceversa, se l’utente vuole usufruire del servizio di acquisto e download dei
brani MP3, vengono ricavate le informazioni della carta di credito e verificata
la copertura, per poi eseguire l’acquisto della scheda prepagata;
-
viene effettuato il login automatico al sistema;
Nel caso dell’implementazione in Struts, tutte le operazioni che riguardano la lettura
dei form con i dati, la verifica della carta di credito, l’acquisto della scheda prepagata,
la segnalazione degli errori e la gestione delle variabili di sessione vengono eseguite
nelle due action RegistrazioneAction ed AcquistoSchedaAction, delegando al metodo
registrazione() il solo compito di salvare l’utente in archivio.
6.4.3 Package brani
Il package brani contiene fondamentalmente le due classi relative alla
gestione dei brani MP3 presenti in archivio : BranoMP3 e FileMP3. Per quanto
riguarda le proprietà che le caratterizzano, esse sono completamente uguali tra le due
implementazioni, in quanto la classe BranoMP3 contiene le informazioni relative ad
un generico brano, mentre FileMP3 ha alcune proprietà che permettono di accedere
al file MP3 associato ad un brano ed altre che rappresentano i tag ID3v1. La
differenza sostanziale, sempre in relazione alle proprietà, è caratterizzata dal fatto che
357
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
l’implementazione in JSF ne prevede delle ulteriori per poter gestire gli elenchi dei
brani. La proprietà elimina permette di valutare se un brano è stato selezionato per
l’eliminazione dall’archivio attraverso una corrispondente checkbox, così come
inserisciInPlaylist ed eliminaDaPlaylist permettono di verificare se un brano è stato
selezionato per essere inserito oppure eliminato da una playlist. Tali proprietà non
sono previste con Struts, in quanto gli elenchi dei brani prevedono l’uso delle
multibox, come visto nella descrizione della View. Un’ulteriore differenza riguarda la
proprietà mp3 della classe FileMP3. Tale proprietà ha il compito di contenere un
riferimento al file MP3 residente in locale, che è stato selezionato dall’amministratore
per l’upload sul server. Facendo riferimento a quanto detto nella descrizione della
View, Struts mette a disposizione il tag per la selezione del file e quindi la classe
corrispondente FormFile, mentre JSF deve affidarsi alle estensioni di MyFaces, ossia al
progetto Tomahawk che prevede la classe UploadedFile. Per questo motivo, la
proprietà mp3 è di tipo diverso considerando le due implementazioni, ma il suo
significato ed il relativo uso sono i medesimi.
Dai diagrammi UML è possibile evidenziare le dipendenze che ci sono tra queste due
classi e le restanti classi del Model, con le quali interagiscono. Per entrambe le
implementazioni, la classe BranoMP3 è legata alle classi Download, BranoMP3DB,
SchedaPrepagata ed Utente, rispettivamente per :
-
tenere traccia del download di un brano;
-
gestire la persistenza delle informazioni del brano all’interno dell’archivio;
-
eseguire l’operazione di acquisto di un brano;
-
garantire il legame con l’utente, in virtù di un acquisto e del download;
358
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 74 - JSF : package brani
359
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 75 - Struts : package brani
La classe FileMP3 utilizza le classi MP3File e ID3v1 della Java MP3 Tag Library per
poter accedere ai tag ID3v1 del file MP3 associato ad un brano e garantirne la
coerenza con le informazioni di quest’ultimo presenti in archivio. Inoltre, essa è
legata alle classi File, InputStream ed OutputStream per stabilire un riferimento alla
directory sul server in cui caricare il file MP3 e gestire la lettura del file in locale con
la corrispondente scrittura in remoto, attraverso due stream di byte.
Le differenze sostanziali tra le due implementazioni riguardano :
-
il legame tra FileMP3 e UploadedFile con JSF ma con FormFile con Struts, in
virtù di quanto detto in precedenza;
360
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
la permanenza delle informazioni di un brano all’interno di una variabile di
sessione. Così come per tutte le altre classi che la prevedono, JSF utilizza la
classe FacesContext mentre con Struts si usano direttamente le classi
HttpServletRequest ed HttpSession. E’ da ricordare e sottolineare che in
quest’ultimo caso, la gestione delle variabili in sessione potrebbe essere
eseguita dalle action che agiscono sui brani e non sono strettamente
necessarie nelle classi della business-logic;
Analizzando in linea generale i metodi della classe BranoMP3, essi svolgono le
seguenti funzionalità :
-
visualizzaInfo() : permette la visualizzazione delle informazioni di un brano
selezionato. Con JSF, il brano è automaticamente presente nella request e
viene spostato in sessione, restituendo un outcome diverso per la navigazione
in base al fatto che la richiesta sia stata fatta dall’amministratore, che potrà
modificare le informazioni del brano, oppure dall’utente che potrà
esclusivamente visionarle. Con Struts, tale metodo viene invocato dal metodo
visualizza() della BranoMP3Action. Il suo compito è quello di ricavare le
informazioni del brano dal database mediante BranoMP3DB.leggi() restituendo
un oggetto BranoMP3 alla action che avrà il compito di salvarla in sessione e
far proseguire la navigazione;
-
modificaInfo() : permette la modifica delle informazioni di un brano,
garantendo la coerenza con i tag ID3v1 del file MP3 associato.
L’implementazione di questo metodo è sostanzialmente diversa nei due casi,
in quanto se con JSF tutte le elaborazioni necessarie sono concentrate nel
metodo, con Struts alcune di esse sono eseguite dal metodo modifica() della
BranoMP3Action. In particolare, con JSF viene individuato il percorso del file
sul server utilizzando la classe FileMP3 e viene effettuato l’aggiornamento dei
tag sulla base delle nuove informazioni immesse dall’amministratore.
Ovviamente, viene invocato il metodo BranoMP3DB.aggiorna() per garantire la
modifica all’interno dell’archivio e viene restituito l’outcome per la navigazione.
Con Struts, il metodo si limita ad aggiornare le informazioni in archivio,
361
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
mentre è compito della action corrispondente effettuare le operazioni di
coerenza con i tag ID3v1 e far proseguire la navigazione;
-
visualizzaElencoBraniMP3(), ricerca() : questi due metodi operano allo stesso
modo, nel senso che permettono la visualizzazione di un elenco di brani sulla
base di un genere selezionato oppure in virtù di criteri di ricerca più raffinati.
Con JSF, utilizzano il metodo BranoMP3DB.ricerca() e caricano la lista ottenuta
all’interno della sessione, restituendo poi l’outcome per la navigazione. Con
Struts,
essi
vengono
visualizzaElencoBraniMP3()
invocati
e
rispettivamente
ricercaBraniMP3()
della
dai
metodi
BranoMP3Action,
restituendo un oggetto contenente la lista dei brani. E’ compito della action
salvare tale elenco in sessione e far proseguire la navigazione;
-
acquista() : permette di effettuare l’acquisto di un brano. La sua
implementazione è più o meno la stessa in entrambi i casi, in quanto vengono
utilizzate le classi SchedaPrepagata e Download, rispettivamente per controllare
l’importo residuo sulla scheda ed effettuare l’acquisto e poi abilitare il
download. La differenza sta nel fatto che con JSF si accede alle informazioni
della scheda direttamente dalla sessione, si segnalano eventuali errori e viene
restituito l’outcome per la navigazione, mentre con Struts le informazioni della
scheda sono passate con un parametro di ingresso e l’accesso alla sessione
viene eseguito dal metodo acquista() della BranoMP3Action;
-
inserisci() : permette l’inserimento di un nuovo brano in archivio ed il
caricamento del file MP3 corrispondente sul server. Opera allo stesso modo
del metodo modifica() ed è implementato in maniera diversa nei due casi. Con
JSF, viene individuato il path sul server in cui caricare il file e l’upload viene
eseguito attraverso il metodo FileMP3.upload(), dopodichè viene valutata la
coerenza tra i tag ID3v1 e le informazioni immesse dall’amministratore. Nel
caso di esito positivo, viene invocato il metodo BranoMP3DB.inserisci() mentre
in caso di esito negativo vengono segnalati gli errori. In entrambi i casi viene
restituito l’outcome per proseguire la navigazione. Con Struts, il metodo esegue
semplicemente l’inserimento delle informazioni del brano in archivio, mentre
è il metodo inserisci() della BranoMP3Action che si occupa delle operazioni di
upload del file, del controllo della coerenza dei tag ID3v1 e del
proseguimento della navigazione;
362
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
elimina(), eliminaBraniMP3() : permettono di eseguire l’eliminazione di un
singolo brano oppure di più brani selezionati da un elenco. Entrambi
utilizzano uno o più volte il metodo BranoMP3DB.elimina(), per cancellare le
informazioni del/i brano/i dall’archivio. Per quanto riguarda l’eliminazione
del/i corrispondente/i file/s MP3 nel file system, con JSF questa operazione
viene eseguita all’interno di questi metodi, invocando FileMP3.elimina(),
mentre con Struts all’interno dei metodi corrispondenti elimina() ed
eliminaBraniMP3() della BranoMP3Action.
Un’osservazione interessante da fare, riguarda la differenza di signature che hanno
alcuni metodi tra l’implementazione con JSF e con Struts. I metodi modificaInfo() ed
inserisci() non prevedono parametri di ingresso con JSF ed al loro interno istanziano
un oggetto della classe FileMP3 per eseguire su di esso le operazioni di
aggiornamento dei tag ID3v1 ed il caricamento del file MP3 sul server. Ciò è
necessario perché da una generica pagina JSP, questi metodi sono invocati attraverso
il method-binding e facendo riferimento ad un backing bean associato alla classe
BranoMP3. Nel caso di Struts, i due metodi prevedono un parametro di ingresso del
tipo FileMP3 che viene passato dai metodi corrispondenti della BranoMP3Action. E’
quest’ultima che istanza l’oggetto FileMP3 gestendo l’aggiornamento dei tag ID3v1
ed il caricamento del file. La distinzione è resa possibile dal fatto che da una pagina
JSP, viene invocata la action e non direttamente i metodi della classe BranoMP3.
Infine, il metodo acquista() non ha parametri di ingresso con JSF, in quanto le
informazioni sull’utente in sessione e della sua scheda prepagata vengono ricavate
direttamente all’interno del metodo. Con Struts, invece, è il metodo acquista() della
BranoMP3Action che si occupa di accedere a queste variabili di sessione passandole al
metodo acquista() della classe BranoMP3. Tutto ciò evidenzia la riusabilità di questa
classe della business-logic in altri contesti, in quanto gli oggetti Utente e
SchedaPrepagata potrebbero essere generati da un meccanismo completamente diverso
dalle action.
363
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda la classe FileMP3, essa presenta i seguenti metodi :
-
upload() : esegue il caricamento del file MP3 sul server. L’implementazione è
praticamente la stessa con JSF e Struts e prevede l’apertuna di uno stream di
ingresso associato al file in locale, l’apertura di uno stream di uscita associato
al file da creare sul server e la scrittura da uno stream all’altro per il
trasferimento;
-
elimina() : permette di eliminare il file MP3 residente sul server. Con JSF,
viene determinato il percorso del file sulla base dei parametri di ingresso,
genere e nomeFileMP3. Con Struts, non è previsto alcun parametro in quanto le
informazioni sul path vengono specificate dal metodo elimina() della
BranoMP3Action, che poi invoca il metodo in questione;
-
aggiornaTag() : esegue l’aggiornamento dei tag ID3v1 del file MP3.
L’implementazione è la stessa in entrambi i casi e prevede l’utilizzo degli
oggetti MP3File ed ID3v1 della Java MP3 Tag Library. Per ciascuna
informazione tra titolo, autore ed album, viene valutato se essa è specificata
tra le informazioni del brano oppure nel corrispondente tag del file. In base al
fatto che uno dei due può essere vuoto, viene eseguito il trasferimento del
valore dall’uno all’altro;
E’ da sottolineare che per quanto riguarda il percorso dei file MP3, esso ha una
struttura standard che dipende ovviamente dal nome del file ed anche dal genere
musicale. Tale struttura è la seguente :
/[dirNomeWebApplication]/mp3/[dirGenere]/nomeFile.mp3
6.4.4 Package playlist
Il package playlist contiene un’unica classe che implementa tutte le
funzionalità che riguardano la gestione delle playlist, la classe Playlist. In entrambe le
implementazioni, le proprietà della classe sono le seguenti :
-
id : identificativo univoco della playlist;
364
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
nome : nome assegnato alla playlist;
-
dataOraCreazione : data ed ora di creazione della playlist;
L’implementazione con JSF prevede una proprietà in più, elimina, che indica se la
playlist è stata selezionata per l’eliminazione da un elenco di playlist attraverso una
checkbox. Con Struts, non è necessaria in quanto sono utilizzate le multibox come
già visto nella descrizione della View.
Per quanto riguarda le dipendenze con altri classi, in entrambe le implementazioni è
prevista un’associazione con ComposizionePlaylistDB, mediante la quale poter gestire le
operazioni di inserimento e cancellazione di un brano nella playlist e quindi la
composizione della stessa. Inoltre, ci sono delle dipendenze con le classi File,
BranoMP3 e PlaylistDB rispettivamente per :
-
creare e cancellare il file M3U con l’elenco dei brani della playlist, necessario
al player MP3 per l’ascolto;
-
le operazioni di inserimento e cancellazione dei brani dalla playlist;
-
la gestione della permanenza delle informazioni associate alla playlist;
La prima differenza tra le due implementazioni riguarda la dipendenza con la classe
Utente, presente con JSF ma non con Struts. Nel primo caso si rende necessaria per
ricavare l’utente a cui è associata la playlist, mentre nel secondo caso tale operazione
viene gestita dalla action PlaylistAction. Infine, la tipica differenza è relativa all’accesso
alle variabili di sessione, che con JSF viene effettuata tramite la classe FacesContext,
mentre in Struts attraverso le classi HttpServletRequest e HttpSession.
365
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 76 - JSF : package playlist
366
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 77 - Struts : package playlist
I metodi previsti dalla classe sono i seguenti :
-
crea() : permette la creazione di una playlist vuota. Con JSF, viene ricavato
dalla session l’identificativo dell’utente che sta creando la playlist e viene
invocato il metodo PlaylistDB.inserisci(), per poi restituire l’outcome per la
navigazione. Con Struts, riceve in ingresso l’identificativo dall’utente che gli
viene passato dal metodo crea() della PlaylistAction da cui viene invocato ed
esegue l’inserimento nel database. E’ compito della action gestire la
navigazione nel caso o meno di errori;
367
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
visualizzaInfo() : permette il caricamento delle informazioni della playlist
selezionata, che restituisce come parametro di uscita. La sua implementazione
è perfettamente uguale in entrambi i casi;
-
visualizzaElencoPlaylist() : permette di visualizzare l’elenco delle playlist relative
ad un certo utente. Con JSF, ricava l’identificativo dell’utente dalla session,
invoca PlaylistDB.elencoPlaylist(), salva la lista nella session e restituisce l’outcome
per
la
navigazione.
Con
Struts,
viene
invocato
dal
metodo
visualizzaElencoPlaylist() della PlaylistAction, dal quale riceve l’identificativo
dell’utente e restituisce la lista delle playlist associate a quest’ultimo. E’
compito della action salvare l’elenco nella session e far proseguire la
navigazione;
-
elimina(), eliminaPlaylists() : metodi che permettono di eliminare una singola
playlist oppure più playlist selezionate da un elenco. In entrambi i casi, invoca
una o più volte PlaylistDB.elimina(). La differenza tra le due implementazioni
sta nel fatto che con JSF, l’aggiornamento della lista in sessione viene fatto
all’interno di questi metodi mente con Struts, viene eseguito dai
corrispondenti metodi elimina() ed eliminaPlaylists() della PlaylistAction;
-
eliminaM3U() : permette di eliminare i file M3U associati alle playlist di uno
specifico utente. Il principio di funzionamento è lo stesso per entrambe le
implementazioni : una volta noto l’identificativo dell’utente, viene ricavato
l’elenco delle playlist associate. Si esegue un ciclo per scorrere tutte le playist e
per ciascuna di esse ne viene cancellato il corrispondente file M3U;
-
visualizzaElencoBraniMP3Playlist() : permette la visualizzazione dell’elenco dei
brani che compongono la playlist corrente. Con JSF, viene invocato il
metodo ComposizionePlaylistDB.composizionePlaylist() e l’elenco dei brani ricavato
viene salvato nella session, per poi restituire l’outcome per la navigazione. Con
Struts, vine invocato dal corrispondente metodo della PlaylistAction al quale
restituisce l’elenco dei brani contenuti nella playlist. E’ poi compito della
action salvare la lista in sessione e far proseguire la navigazione;
-
inserisciBranoMP3(), inserisciBraniMP3() : permettono di inserire un singolo
brano oppure più brani all’interno di una specifica playlist. In entrambe le
implementazioni,
prevedono
l’invocazione
del
metodo
ComposizionePlaylistDB.inserisci() una o più volte. Con JSF, all’interno di questi
368
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
metodi vengono ricavate le informazioni dei brani da inserire e restituito
l’outcome per la navigazione. Con Struts, queste operazioni vengono eseguite
nei metodi inserisciPlaylist() e inserisciBraniMP3Playlist() della BranoMP3Action;
-
eliminaBraniMP3() : effettua l’eliminazione di uno o più brani selezionati
dall’elenco di composizione della playlist. In entrambe le implementazioni
viene eseguito un ciclo sull’elenco dei brani selezionati per invocare il metodo
ComposizionePlaylistDB.elimina().
-
ascolta() : permette l’ascolto di una playlist. La sua implementazione è
fondamentalmente la stessa con JSF e con Struts in quanto prevede il
caricamento
dei
brani
costituenti
la
playlist
con
il
metodo
ComposizionePlaylistDB.composizionePlaylist() e la creazione di un file M3U in cui
scrivere i percorsi dei file MP3 associati ai brani da ascoltare;
E’ da osservare che i metodi visualizzaElencoPlaylist() ed eliminaPlaylists() sono definiti
statici nell’implementazione con Struts ma non con JSF. Da un punto di vista
concettuale ciò è corretto, in quanto le funzionalità sono relative alle playlist in
generale e non ad una specifica playlist. Con Struts, ciò è possibile in quanto dalle
pagine JSP vengono invocati i metodi delle action che a loro volta utilizzano i metodi
della classe Playlist. Con JSF, invece, dalle pagine JSP si invocano direttamente questi
metodi utilizzando il backing bean associato a questa classe, per cui non è possibile
invocare metodi statici ma soltanto metodi di istanza.
E’ da precisare che il file M3U con i percorsi dei brani MP3 contenuti nella playlist, è
necessario per come opera il player MP3 utilizzato. Per rendere tale file univoco, esso
ha un nome caratterizzato dall’identificativo della playlist concatenato con il nome
della stessa. Il percorso in cui sono salvati tali file è il seguente :
/[dirNomeWebApplication]/mp3/playlist/[id+nomePlaylist].m3u
369
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
6.4.5 Package scheda
Il package scheda contiene le classi SchedaPrepagata e Ricarica che mettono a
disposizione le funzionalità per la gestione della scheda prepagata e delle
corrispondenti operazioni di ricarica. La classe SchedaPrepegata prevede le stesse
proprietà per entrambe le implementazioni :
-
id : identificativo della scheda;
-
importoResiduo : importo presente sulla scheda;
-
dataOraAcquisto : data ed ora di acquisto della scheda;
-
dataScadenza : data di scadenza della scheda (ad un anno dall’acquisto oppure
dall’ultima ricarica);
Allo stesso modo, la classe Ricarica prevede le seguenti proprietà :
-
id : identificativo dell’operazione di ricarica;
-
importo : importo della ricarica;
-
dataOra : data ed ora in cui è stata effettuata la ricarica;
Esse sono ovviamente legate fra loro, considerando che un’operazione di ricarica è
sempre associata alla scheda su cui è stata effettuata.
Per quanto riguarda le dipendenze con le altre classi dell’applicazione, la classe
Ricarica è legata soltanto a RicaricaDB per gestire la permanenza delle operazioni di
ricarica. La classe SchedaPrepagata, invece, è associata alla classe SchedaPrepagataDB per
gestire la persistenza delle sue informazioni, alla classe CartaCredito per il pagamento
delle operazioni di acquisto e ricarica ed alla classe Utente, essendo associata ad un
utente registrato. La differenza tra le due implementazioni risiede sempre nell’accesso
alle variabili di sessione, effetuato con FacesContext nel caso di JSF e direttamente con
le classi HttpServletRequest ed HttpSession con Struts.
370
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 78 - JSF : package scheda
371
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 79 - Struts : package scheda
372
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Per quanto riguarda la classe SchedaPrepagata, i suoi metodi sono i seguenti :
-
acquista() : metodo che permette ad un utente l’acquisto di una scheda
prepagata. Con JSF, esso ricava dalla session l’oggetto dell’utente che sta
effettuando l’acquisto e le informazioni della carta di credito e ne verifica la
copertura, calcola la data di scadenza della scheda, la inserisce nell’archivio
mediante il metodo SchedaPrepagataDB.inserisci() ed infine restituisce l’outcome
per la navigazione. Con Struts, viene invocato dal metodo execute() della
AcquistoSchedaAction e riceve da quest’ultima, in ingresso, gli oggetti relativi
all’utente ed alla carta di credito che la action ha ricavato dai form. Opera allo
stesso modo dell’implementazione con JSF ma è compito della action gestire
la navigazione;
-
visualizzaInfo() : è perfettamente identico nelle due implementazioni, poiché
carica
le
informazioni
della
scheda
mediante
il
metodo
SchedaPrepagataDB.leggi() e restituisce l’oggetto SchedaPrepagata corrispondente;
-
ricarica() : permette di effettuare un’operazione di ricarica sulla scheda
corrente. Con JSF, ricava le informazioni della carta di credito dalla session e
quelle della ricarica dalla request, esegue il metodo Ricarica.esegui(), aggiorna
l’importo residuo e la data di scadenza, aggiorna le informazioni nell’archivio
con il metodo SchedaPrepagatDB.aggiorna() ed infine restituisce l’outcome per la
navigazione. Con Struts, viene invocato dal metodo execute() della
RicaricaSchedaAction dalla quale riceve gli oggetti SchedaPrepagata e Ricarica, le
cui informazioni sono prelevate dalla action dai form. Opera allo stesso
modo dell’implementazione con JSF ma è compito della action gestire la
navigazione;
-
controlloImportoResiduo() : viene utilizzato in fase di acquisto di un brano per
valutare se l’importo residuo è sufficiente, in relazione al costo ricevuto come
parametro di ingresso. E’ perfettamente uguale nelle due implementazioni;
-
aggiornaImportoResiduo() : aggiorna l’importo residuo della scheda una volta
effettuato
l’acquisto
SchedaPrepagataDB.aggiorna()
di
un
brano.
Utilizza
il
metodo
ed è perfettamente identico nelle due
implementazioni;
373
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
-
controlloScadenza() : permette di valutare se la scheda sia scaduta o meno. Con
JSF, effettua il confronto della data di scadenza con la data attuale e nel caso
in cui la scheda sia scaduta la elimina dalla base di dati, aggiorna l’utente che
non sarà più abilitato all’acquisto di brani MP3 e restituisce un valore
booleano. Con Struts, effettua semplicemente il confronto tra le date ma le
operazioni di eliminazione della scheda, nel caso in cui sia scaduta, ed
aggiornamento dell’utente vengono eseguite dalla LoginAction in cui il metodo
è invocato;
Così come in altri casi, si osserva che il metodo ricarica() ha una signature diversa nelle
due implementazioni. Con JSF non prevede parametri di ingresso mentre con Struts
prevede l’oggetto CartaCredito e Ricarica, grazie ai quali poter effettuare l’operazione di
ricarica sulla scheda. In questo modo, si evidenzia l’indipendenza della classe della
business-logic dal framework, in quanto gli oggetti ricevuti in ingresso potrebbero
essere generati con meccanismi completamente diversi dalle action.
La classe Ricarica prevede banalmente l’unico metodo esegui() il quale è identico nelle
due implementazioni e non fa altro che salvare la data e l’ora correnti e di inserire
queste informazioni nell’archivio con il metodo RicaricaDB.inserisci().
6.4.6 Package cartacredito
Questo package contiene soltato la classe CartaCredito che contiene le
informazioni della carta di credito utilizzata dall’utente per l’acquisto o la ricarica di
una scheda prepagata. Per entrambe le implementazioni, le proprietà che la
caratterizzano sono le seguenti :
-
tipo : tipologia di carta di credito (VISA, MasterCard, etc…);
-
numero : numero della carta;
-
codiceSegreto : codice segreto associato alla carta;
-
dataScadenza : data di scadenza della carta;
374
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 80 - JSF : package cartacredito
Figura 81 - Struts : package cartacredito
Essa non prevede una corrispondente classe per la gestione della persistenza, in
quanto una volta utilizzata, le relative informazioni vengono eliminate dalla sessione.
375
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
E’ stata realizzata a scopo puramente dimostrativo infatti, il suo unico metodo
verificaCopertura() restituisce sempre il valore true ad indicare che la carta di credito è
coperta per il pagamento. Le uniche dipendenze previste sono con FacesContext in
JSF e le classi HttpServletRequest e HttpSession in Struts per semplificare l’accesso in
sessione.
6.4.7 Package download
Il package download contiene la classe Download attraverso la quale si tiene
traccia dell’acquisto di un brano MP3. La classe prevede l’unica proprietà
dataOraAcquisto che rappresenta la data e l’ora dell’acquisto del brano, nonché è
caratterizzata da un unico metodo, inserisci(), il quale non fa altro che invocare
DownloadDB.inserisci()
per
introdurre
nell’archivio
l’informazione
relativa
all’acquisto/download di un brano da parte di un certo utente. Essa è perfettamente
identica in entrambe le implementazioni.
Figura 82 - JSF e Struts : package download
6.4.8 Package mail
Il package mail contiene solo la classe Mail la quale è perfettamente identica
in entrambe le implementazioni, non ha alcuna proprietà e prevede soltanto il
metodo sendMessage() mediante il quale è possibile inviare una mail. Esso utilizza la
classe Properties per fissare nelle proprietà del sistema l’host che dovrà occuparsi
dell’invio e la classe Session per stabilire una sessione con il mail server. Genera un
messaggio del tipo MimeMessage definendone il mittente, il destinatario, l’oggetto ed il
376
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
corpo che riceve come parametri di ingresso. Infine, invia il messaggio invocando il
metodo Transport.send().
Figura 83 - JSF e Struts : package mail
6.5 I Backing Beans di JavaServer Faces
Nell’implementazione realizzata utilizzando JavaServer Faces, tutte le classi
che costituiscono il Model sono dichiarate all’interno del file di configurazione come
backing beans (managed beans). Questo tipo di approccio garantisce due vantaggi
fondamentali :
-
ciascun componente dell’interfaccia utente può essere associato ad una
proprietà di un backing bean attraverso il value-binding, in modo tale che
quando il form a cui appartiene il componente viene trasmesso, il valore che
assume il componente viene trasferito nella corrispondente proprietà a cui è
legato;
-
utilizzando gli eventi , action e value-change, è possibile invocare
direttamente da un componente un metodo di un backing bean, attraverso il
method-binding, in modo da poter effettuare delle elaborazioni sui dati
contenuti nel backing bean stesso;
377
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
In base a quanto detto, è evidente la netta differenza rispetto al framework Struts, per
quanto riguarda l’acquisizione dei dati dai form e l’esecuzione delle elaborazioni su di
essi. Infatti, Struts utilizza i formbean le cui proprietà sono associate ai campi di un
form in modo che, una volta che quest’ultimo sia stato trasmesso, i valori dei campi
stessi vengano copiati nel formbean corrispondente. Sarà compito della action che
riceve il formbean copiare tali dati nelle corrispondenti proprietà di un oggetto del
Model, per poterne eseguire una qualsiasi elaborazione. JSF evita questa passaggio
intermedio facendo in modo che i valori dei campi dei form vengano copiati
direttamente nelle corrispondenti proprietà di un backing bean.
Per quanto riguarda l’avvio delle elaborazioni da una pagina JSP, Struts prevede il
concetto di action che viene invocata ad esempio alla pressione di un bottone oppure
di un link. La action riceve un formbean con i dati da elaborare, li trasferisce nelle
corrispondenti proprietà di un oggetto del Model e su di esso invoca un metodo per
eseguire l’elaborazione richiesta. JSF permette di avviare direttamente da una pagina
JSP un metodo di un backing bean, ossia di un oggetto del Model, nel quale ci
saranno automaticamente i dati da elaborare. Anche in questo caso, si evita un
passaggio intermedio che riguarda l’utilizzo delle action di Struts.
All’interno del file di configurazione, faces-config.xml, è possibile dichiarare
opportunamente ciascun backing bean specificandone il tipo, ossia la classe che lo
implementa, e l’ambito di visibilità (scope) per indicare se sia accessibile soltanto
nell’ambito di una richiesta (request), di una sessione utente (session) oppure nel
contesto della servlet (application). In maniera del tutto automatica è compito del
framework gestire l’allocazione e la deallocazine dei backing bean quando necessario,
grazie al meccanismo dell’ IoC (Inversion of Control) noto anche come DI (Dependency
Injection).
Un semplice esempio è la seguente dichiarazione del backing bean relativo all’utente,
al quale viene associato un nome, ne viene specificata la classe di appartenenza,
ruolo.Utente, ed infine indicato l’ambito di visibilità, session, in modo che le
informazioni dell’utente siano sempre accessibili durante la sua sessione di utilizzo
dell’applicazione.
378
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
<managed-bean>
<managed-bean-name>utente</managed-bean-name>
<managed-bean-class>ruolo.Utente</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
Per completare il confronto tra JSF e Strus, relativo a questo aspetto, si prenda in
considerazione l’operazione di login. Nel caso di JSF, è stato dichiarato il backing
bean ruolo con un’ambito di visibilità strettamente legato alla richiesta.
<managed-bean>
<managed-bean-name>ruolo</managed-bean-name>
<managed-bean-class>ruolo.Ruolo</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
La pagina JSP, contenente il form per effettuare l’accesso al sistema, prevede due
campi di testo associati alle proprietà userName e password del backing bean suddetto,
così come al bottone di invio è associata l’esecuzione del relativo metodo login().
...
<h:outputText value="#{bundle.menuUsernameLabel}" />
<h:inputText id="userName" value="#{ruolo.userName}"/>
<h:outputText value="#{bundle.menuPasswordLabel}" />
<h:inputSecret id="password" value="#{ruolo.password}"/>
<h:outputText value="" />
<h:commandButton action="#{ruolo.login}"
value="#{bundle.menuButtonLoginLabel}"
styleClass="buttonForm"/>
...
Struts prevede un’implementazione completamente diversa, in cui nel file di
configurazione è dichiarato il formbean loginForm, del tipo LoginForm, associato alla
action LoginAction.
...
<form-bean name="loginForm" type="formbean.LoginForm"/>
...
<action input="/pages/home.jsp" name="loginForm" path="/login"
scope="request" type="defaultactions.LoginAction">
<forward name="failure" path="/pages/home.jsp"/>
</action>
...
379
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
La pagina JSP prevede un form con due campi di testo associati alle proprietà del
formbean ed un bottone che avvia l’esecuzione della action.
<html:form action="/login.do">
...
<tr>
<td class="columsLabelForm">
<fmt:message key="menuUsernameLabel"/>
</td>
<td class="columsInputForm">
<html:text property="userName" />
</td>
</tr>
<tr>
<td class="columsLabelForm">
<fmt:message key="menuPasswordLabel"/>
</td>
<td class="columsInputForm">
<html:password property="password" />
</td>
</tr>
...
<html:submit styleClass="buttonForm">
<fmt:message key="menuButtonLoginLabel"/>
</html:submit>
</html:form>
All’interno della action ci sarà il codice che copia i dati del form dal formbean
all’oggetto corrispondente della business-logic, per poi invocare il metodo login() su
quest’ultimo.
...
// ricavo le informazioni sul ruolo che tenta di accedere
Ruolo ruolo = new Ruolo();
formToRuolo(form,ruolo);
...
...
// invoco il login sul Ruolo
ruolo = ruolo.login();
7. Plug-in di Struts
Il framework Struts prevede un particolare meccanismo per poter estendere
le sue funzionalità legato al concetto di plug-in. Basti pensare al Validator ed allo
stesso Tiles che vengono dichiarati all’interno del file di configurazione appunto
come plug-in. Ovviamente, lo sviluppatore ha la possibilità di realizzarne uno proprio
380
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
mediante una classe che implementi l’interfaccia PlugIn. Il loro uso può risultare utile
quando c’è la necessità di eseguire una certa operazione una sola volta ed all’avvio
dell’applicazione.
Proprio
questa
modalità
di
utilizzo
è
stata
adottata
nell’implmenetazione con Struts, realizzando il plug-in StartupManager che, una volta
avviato, crea le liste di items che verrano usate in tutte le drop-down list
dell’applicazione, ad esempio quella relativa alle province, agli stati e così via.
Figura 84 - Struts : StartupManager
Tale classe prevede i due tipici metodi di un plug-in :
-
initi() : viene eseguito all’avvio dell’applicazione e può contenere tutte le
operazioni necessarie allo startup della Web application;
-
destroy() : viene invocato alla chiusura dell’applicazione per “distruggere” il
plug-in;
Il plug-in realizzato prevede inoltre la proprietà sc che è un’istanza della classe
ServletContext, in quanto è all’interno di quest’ultima che verranno salvate le liste
generate. Infatti, ogni oggetto salvato all’interno del contesto della servlet ha un
ambito di visibilità di tipo application ed è quindi accessibile in un qualsiasi punto
dell’applicazione ed è comune a tutti gli utenti.
381
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
La generazione delle liste viene eseguita nel metodo init(), cos’ come il salvataggio nel
contesto della servlet, invocando il metodo setAttribute() sulla proprietà sc. Infine, il
plug-in è stato dichiarato nell’opportuna sezione all’interno del file di configurazione.
<plug-in className="plugin.StartupManager"/>
Nell’implementazione con JSF, non essendo disponibile uno strumento come i plugin di Struts, è stato realizzata la classe ItemsBean per la quale ne è stato dichiarato un
backing bean nell’ambito di visibilità application.
Figura 85 - JSF : ItemsBean
Si osservi che le proprietà della classe corrispondono esattamente alle liste necessarie
all’interno dell’applicazione. La generazione delle liste viene eseguita all’interno del
costruttore e quindi nel momento in cui il framework istanzia questo backing bean.
8. Navigazione
La navigazione all’interno dell’applicazione è certamente uno degli aspetti
che differenzia maggiormente i due framework, in quanto essi sfruttano due
meccanismi diversi che comunque possono essere paragonati l’uno all’altro.
JavaServer Faces si basa sul concetto delle navigation-rules, all’interno di ciascuna delle
quali va definita la pagina di partenza della specifica “regola” e vanno definiti uno o
più
navigation-case che specificano, sulla base dell’outcome rinvenuto dal
NavigationHandler, quale sia la pagina verso la quale proseguire la navigazione.
382
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
In base a quanto detto, ogni regola prevede :
-
la pagina che rappresenta il punto di partenza di riferimento;
-
uno o più pagine destinazione che è possibile raggiungere dalla suddetta
pagina, ciascuna delle quali è distinta da un differente outcome;
Ciò vuol dire che, nel momento in cui viene invocato un metodo di un backing bean
da una certa pagina JSP, quest’ultimo dovrà restituire come parametro di uscita una
stringa che rappresenti l’outcome di navigazione. Sulla base di quest’ultimo, il
NavigationHandler esegue una ricerca nel file di configurazione e determina verso
quale pagina deve proseguire la navigazione. Nel caso della Web application
implementata si è evidenziata la non perfetta integrazione tra JSF e Tiles. Infatti, se si
utilizza questo framework per la definizione del layout, non è possibile utilizzare le
regole di navigazione come spiegato in precedenza, ma è necessario definire un’unica
regola, senza alcuna pagina associata, all’interno della quale ci sono tutti i navigationcase.
<navigation-rule>
<navigation-case>
<from-outcome>registrazione</from-outcome>
<to-view-id>/pages/registrazione.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>home</from-outcome>
<to-view-id>/pages/home.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>acquistoRicaricaScheda</from-outcome>
<to-view-id>/pages/acquistoRicaricaScheda.jsp</to-view-id>
</navigation-case>
...
</navigation-rule>
Il motivo di questo limite è dato dal fatto che nel Deployment Descriptor web.xml
dell’applicazione realizzata con JSF, l’utilizzo di Tiles è specificato attraverso la
dichiarazione di un’ulteriore servlet, TilesServlet, che viene avviata immediatamente
dopo la FacesServlet e che intercetta per prima le richieste verso le pagine, interferendo
con il NavigationHandler.
Se in JSF la definizione della navigazione viene dichiarata in termini generali, con
Struts è descritta in maniera più specifica e localizzata, all’interno delle action
383
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
mediante il concetto di forward. Infatti, ciascuna action prevista dall’applicazione può
avere un unico metodo execute() oppure più metodi, nel caso di una DispatchAction,
che comunque restituiscono un oggetto del tipo ActionForward. Ciascun forward
specifica la pagina verso la quale proseguire la navigazione ed è dichiarato all’interno
del file di configurazione, secondo due modalità :
-
locale : è relativo ad una specifica action che è l’unica che permette la
navigazione verso la pagina ad esso associata;
-
globale : è comune a tutte le action, in modo tale che ciascuna di esse possa
redirezionare il flusso dell’applicazione verso la pagina ad esso associata;
<action input="/pages/registrazione.jsp" name="registrazioneForm"
path="/registrazione" scope="session"
type="defaultactions.RegistrazioneAction" validate="true">
<forward name="login" path="/login.do"/>
<forward name="acquistoScheda" path="/pages/acquistoScheda.jsp"/>
<forward name="failure" path="/pages/registrazione.jsp"/>
</action>
In un certo senso, il nome del forward restituito può essere paragonato all’outcome di
JSF e ciascun forward può essere equiparato ad un navigation-case così come la
dichiarazione della action ad una navigation-rule.
9. Eccezioni
La gestione delle eccezioni dichiarative è una potenzialità messa a
disposizione solo ed esclusivamente da Struts ma non da JSF. Infatti, con Struts, è
possibile dichiarare un’eccezione nel file di configurazione in modo tale che, nel caso
in cui venga sollevata all’interno del codice, entri in gioco in maniera automatica
l’ExceptionHandler che si fa carico di gestirla. Inoltre, all’eccezione stessa è possibile
associare una pagina verso la quale redirezionare il flusso dell’applicazione.
<global-exceptions>
<exception bundle="ApplicationResources" key="errorDatabase"
path="/pages/error.jsp"
type="org.apache.struts.util.ModuleException"/>
</global-exceptions>
384
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Nel caso di studio in esame, è stato previsto l’utilizzo delle eccezioni dichiarative per
poter visualizzare all’utente una pagina di errore, qual’ora si verificasse qualche
problema di accesso alla base di dati. Moltissime applicazioni, in questi casi,
prevedono semplicemente la visualizzazione di errori di accesso assolutamente
incomprensibili all’utente. Per evitare una situazione di questo tipo, si è fatto in modo
che, se durante l’accesso al database si verifica un errore, viene sollevata una
ModuleException la quale è intercettata dall’ExceptionHandler che la ricerca nel file di
configurazione e fa in modo che all’utente venga visualizzata la pagina ad essa
associata.
...
} catch (SQLException e) {
ModuleException me = new ModuleException("errorDatabase");
throw me;
} finally {
...
JavaServer Faces non fornisce questa potenzialità per cui in questo caso si è ricorso
alla semplice funzionalità di navigazione. Più precisamente, nel caso in cui si verifichi
un errore di accesso alla base di dati, viene sollevata un’eccezione che, intercettata
all’interno del codice stesso, fa in modo che il metodo del backing bean in questione
restituisca l’outcome verso la pagina di errore.
10. Sicurezza
La Web application realizzata prevede una funzionalità particolare,
nell’ambito della quale sono trasmessi dei dati fortemente sensibili, quali il numero ed
il codice della carta di credito, per l’acquisto e la ricarica di una scheda prepagata. In
una situazione di questo tipo, si rende necessario l’utilizzo di un meccanismo di
sicurezza mediante il quale sia possibile crittografare i dati inviati attraverso la rete, in
modo da renderli incomprensibili a chiunque riesca ad intercettarli in maniera
fraudolenta.
385
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Gli elementi principali che permettono un approccio di questo tipo sono
fondamentalmente due :
-
l’acquisizione di un certificato digitale;
-
uso del protocollo HTTPS, ossia HTTP basato su SSL (Secure Socket Layer);
Attraverso un certificato digitale, rilasciato dalla CA (Certification Authority), è
sempre possibile essere a conoscenza dell’identità dell’interlocutore e decidere se
accettare o meno di stabilire una comunicazione con qeust’ultimo. Uno strumento di
questo tipo risulta notevolmente utile, in virtù del fatto che ci si potrebbe ritrovare a
scambiare informazioni con un’entità sulla rete che non è quella da noi attesa, ma che
ne abbia preso il posto in maniera fraudolenta. Chiunque sia in possesso di un
certificato digitale è stato rinosciuto da terze parti e quindi si ha la certezza che i dati
trasmessi verranno acquisiti dal destinatario corretto. Una delle funzionalità che è
possibile sfruttare mediante i certificati digitali è la crittografia, mediante la quale è
possibile cifrare i dati trasmessi e renderli illeggibili durante il loro invio. Soltanto il
destinatario, riconosciuto sulla base di un certificato digitale, avrà la possibilità di
decrittografarli attraverso l’utilizzo di una chiave. La comunicazione avviene
attraverso il protocollo HTTPS, ossia il tipico HTTP basato su SSL (Secure Socket
Layer), che garantisce una cifratura con chiave a 128 bit.
Nel caso di studio in esame, per garantire la sicurezza, si sono rese necessarie le
seguenti operazioni :
-
creazione di un certificato digitale di esempio;
-
abilitazione del Connector SSL nel Web Container Apache Tomcat;
-
configurazione
della
pagine
protette
nel
Deployment
Descriptor
dell’applicazione;
La creazione del certificato digitale è stata effettuta facendo uso di uno degli
strumenti messi a disposizione dall’SDK di Java2, ossia keytool, che produce un
cosiddetto keystore. Quest’ultimo permette inoltre di specificare il tipo di algoritmo da
utilizzare per la crittografia, che nel caso specifico è l’RSA.
386
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
keytool -genkey -alias tomcat -keyalg RSA
Una volta creato il certificato, bisogna abilitare il Connector SSL del Web Container
Tomcat, mediante il quale è possible redirezionare tutte le comunicazioni protette,
verso una porta specificata e tramite protocollo HTTP. Per fare questo è necessario
apportare una modifica al file di configurazione server.xml, all’interno del quale va
specificato il keystore da utilizzare e la relativa password.
<Connector
port="8443" maxThreads="150" minSpareThreads="25"
maxSpareThreads="75" enableLookups="false"
disableUploadTimeout="true" acceptCount="100" debug="0"
scheme="https" secure="true" clientAuth="false"
sslProtocol="TLS" keystorePass="changeit"
keystoreFile="C:\Documents and Settings\Paolo\.keystore"/>
Per quanto riguarda la modifica da applicare alla Web application, essa è del tutto
analoga in entrambe le implementazioni, tenendo conto del fatto che JSF e Struts
demandano la gestione della sicurezza al Web Container sottostante e non
forniscono un proprio particolare strumento. All’interno del Deployment Descriptor
web.xml è possibile specificare le pagine, la cui trasmissione deve essere effettuata su
protocollo HTTPS. In questo caso si è deciso di rendere tutta l’applicazione sicura,
garantendo la trasmissione tramite SSL per tutte le pagine a partire dalla pagina di
ben venuto index.jsp.
<security-constraint>
<display-name>SSL Constraint</display-name>
<web-resource-collection>
<web-resource-name>
Automatic SLL Forwarding
</web-resource-name>
<url-pattern>/index.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
387
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
In questo modo, alla richiesta dell’URL iniziale viene segnalata la redirezione verso
una connessione sicura garantita da un certificato digitale. La trasmissione dei dati tra
client e server avverrà tramite il protocollo SSL in modalità crittografata.
Nella figura seguente, è visibile il messaggio del browser Web che segnala il passaggio
ad una modalità di comunicazione protetta mediante protocollo SSL. E’ possibile
visionare le informazioni relative al certificato digitale, in modo da essere a
conoscenza dell’interlocutore e decidere se accettare o meno la trasmissione dei dati.
Figura 86 - Segnalazione del certificato digitale
Una volta accettato il passaggio al protocollo HTTPS, la navigazione all’interno della
Web application prosegue normalmente, ma è visibile nella parte bassa del browser
(es. Internet Explorer 6) un lucchetto che indica la garanzia di una comunicazione
protetta e cifrata.
388
Capitolo VI – Case Study : Implementazioni a confronto
_________________________________________________________________
Figura 87 - Indicazione modalità protetta con SSL
389
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
Appendice A – SRS Web Application MP3-Web
1. Introduzione
1.1 Propositi
Questo documento ha lo scopo di definire i requisiti e le specifiche del prodotto
software “MP3 - Web”, al fine di facilitarne la realizzazione e la validazione.
E’ destinato sia al committente del prodotto software che allo sviluppatore, al fine di
definire una base di riferimento per la validazione del prodotto e creare le premesse
per la produzione di un software di alta qualità.
1.2 Obiettivi
Il prodotto software “MP3 - Web” ha come obiettivo la realizzazione di una Web
application che permetta agli utilizzatori di usufruire di contenuti audio, quali brani
musicali in formato MP3 (MPEG Layer 3). Il sistema permette l’automatizzazione
delle seguenti operazioni, per quanto riguarda l’interazione con l’Utente :
1. Registrazione nelle versioni “base” ed “estesa”;
2. Identificazione dell’Utente tramite lo Username e la Password;
3. Accesso all’archivio dei brani MP3;
4. Ricerche avanzate nell’archivio dei brani MP3;
5. Ascolto di un singolo brano MP3;
6. Gestione ed ascolto di playlist personalizzate contenenti brani MP3;
7. Acquisto e ricarica di una scheda prepagata per effettuare il download dei
brani MP3;
8. Acquisto e Download dei brani MP3;
9. Gestione dei propri dati personali;
10. Richiesta dei propri dati di accesso via mail;
11. Uscita dal sistema;
390
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
L’Amministratore disporrà di funzionalità avanzate, mediante le quali saranno
consentite le seguenti operazioni :
1. Identificazione dell’Amministratore tramite lo Username e la Password;
2. Gestione dell’archivio dei brani MP3 per l’accesso, la ricerca, l’inserimento, la
modifica e l’ascolto;
3. Gestione degli utenti registrati;
4. Gestione dei propri dati di accesso;
5. Uscita dal sistema;
1.3 Definizioni, Acronimi ed Abbreviazioni
Utente :
persona che ha effettuato la registrazione (“base” oppure “estesa”) e che risulta
abilitata all’utilizzo dei servizi resi disponibili dalla scelta effettuata;
Amministratore :
persona addetta alla gestione degli archivi degli utenti e alla gestione dei servizi offerti
dal sistema;
Utilizzatore – Ruolo :
persona non ancora identificata tra Utente ed Amministratore, che non ha effettuato
l’accesso al sistema;
Servizio :
ciascuna delle attività accessibili e consentite ad un qualunque tipo di utente o
all’amministratore;
Registrazione :
contratto stipulato dall’Utente, necessario per poter usufruire dei servizi offerti dal
sistema. Può essere di due tipologie :
-
base : permette di accedere a tutti i servizi a meno del download di brani MP3;
391
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
-
esteso : offre i medesimi servizi della registrazione “base” ed in più permette
l’acquisto ed il download di brani MP3, previo l’acquisto di una scheda
prepagata;
Username :
identificativo univoco dell’Utente oppure dell’Amministratore;
Password :
password di accesso al sistema dell’Utente oppure dell’Amministratore;
Playlist :
sequenza di ascolto dei brani musicali definita dall’Utente;
1.4 Riferimenti
Standard IEEE 830-1993.
1.5 Generalità
L’intento di questo documento è quello di descrivere le funzionalità che il software
deve soddisfare, le quali saranno specificate nel capitolo successivo in modo chiaro e
conciso.
Il resto del documento contiene l’elenco delle funzioni che il prodotto software deve
avere insieme ai vincoli che deve soddisfare. Più avanti nel testo sono presentate
l’interfaccia (sia verso l’Utente sia verso l’Amministratore) dei servizi messi a
disposizione dal prodotto e l’interfaccia verso l’hardware. Al presente documento ne
sono allegati altri contenenti i diagrammi realizzati secondo lo standard UML,
necessari per la miglior comprensione del dominio applicativo.
392
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
2. Descrizione Generale
2.1 Prospettive del prodotto
Questo prodotto non si integra con nessun altro sistema software ed è indipendente
ed autonomo per quanto riguarda l’elaborazione(stand-alone).
2.2 Funzionalità
Il prodotto software “MP3 - Web” dovrà :
nei confronti dell’Amministratore fornire le seguenti funzionalità :
-
accesso al sistema;
-
registrazione dell’accesso;
-
modifica della propria Password di accesso;
-
gestione dell’archivio di brani MP3, che prevede :
-
-
visualizzazione dei brani sulla base di un genere musicale;
-
visualizzazione dei brani sulla base di criteri di ricerca specifici;
-
inserimento di un nuovo brano in archivio;
-
modifica delle informazioni di un brano;
-
eliminazione di uno o più brani dall’archivio;
-
ascolto di un brano;
gestione degli utenti registrati, che prevede :
-
eliminazione di un utente;
-
sblocco di un utente bloccato;
-
uscita dal sistema;
-
registrazione dell’uscita;
nei confronti dell’Utente fornire le seguenti funzionalità :
-
registrazione;
-
richiesta via mail dei dati di accesso;
-
accesso al sistema;
-
registrazione dell’accesso;
393
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
-
modifica dei propri dati personali;
-
accesso all’archivio dei brani, che prevede :
-
-
-
visualizzazione dei brani sulla base di un genere musicale;
-
visualizzazione dei brani sulla base di criteri di ricerca specifici;
-
ascolto di un brano;
-
acquisto e download di un brano;
gestione di playlist personalizzate, che prevede :
-
visualizzazione delle playlist già create in precedenza;
-
creazione di una nuova playlist;
-
eliminazione di una o più playlist;
-
inserimento ed eliminazione di brani da una playlist;
-
ascolto di una playlist;
-
acquisto e download di un brano presente in una playlist
gestione di una propria scheda prepagata, che prevede :
-
acquisto di una scheda prepagata;
-
ricarica della propria scheda prepagata;
-
uscita dal sistema;
-
registrazione dell’uscita;
2.3 Caratteristiche Utente
Il prodotto software è destinato ad utenti che abbiano una conoscenza di base
nell’utilizzo di Personal Computer e relativi software per la produttività personale;
mentre gli amministratori, che usano il software di gestione, hanno bisogno di una
conoscenza informatica di base.
394
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
2.4 Vincoli Generali
I vincoli generali sono i seguenti :
-
L’Utente che richiede l’accesso ai servizi del sistema deve digitare
esclusivamente il proprio Username e la relativa Password;
-
L’Utente non può inserire più di 2 volte una Password errata;
-
All’Utente non è permesso l’acquisto oppure la ricarica di una scheda
prepagata, se il credito su conto corrente, cui fa riferimento la carta di
credito per il pagamento, è insufficiente.
-
L’Utente non può acquistare ed effettuare il relativo download di un
brano MP3 se non è in possesso di una scheda prepagata oppure se il
credito residuo sulla scheda prepagata è insufficiente;
-
L’Amministratore non può inserire più di 2 volte una Password errata;
-
L’Amministratore che richiede l’accesso ai servizi del sistema deve
digitare esclusivamente il proprio Username e la relativa Password;
-
La Password di accesso dell’Utente o dell’Amministratore può essere
composta da almeno 5 caratteri alfanumerici;
2.5 Assunzioni e Dipendenze
Il Sistema software dovrà essere utilizzato su una macchina dotata di sistema
operativo Windows 95/98/Me/2000/Xp oppure di una distribuzione Linux, con
128 Mb di memoria RAM, Hard Disk da 10 GB ed una connessione Internet
consigliata ADSL.
395
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3. Requisiti Specifici
3.1 Requisiti di interfaccia esterna
3.1.1 Interfaccia Utente
E’ richiesta un’interfaccia utente visuale, con finestre, bottoni e form di immissione
dati.
3.1.2 Interfaccia Hardware
Il sistema software non si interfaccia con alcun particolare sistema hardware.
3.1.3 Interfaccia Software
Il sistema software non si integra e non comunica con nessun altro sistema software.
3.1.4 Interfaccia di Comunicazione
La comunicazione fra il sistema software “lato client” e quello “lato server”, si svolge
utilizzando la rete Internet e si basa fondamentalmente sull’accesso di un database
condiviso localizzato sul server stesso.
396
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2 Requisiti Funzionali
Classe Amministratore
3.2.1 Login
3.2.1.1 Introduzione
Questa funzionalità permette all’Amministratore di accedere al sistema.
3.2.1.2 Input
•
Username (obbligatorio)
•
Password (obbligatorio)
3.2.1.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che la Username e la Password siano corrette e cioè
corrispondano a quelle memorizzate nell’archivio. Se il controllo
va a buon fine, viene permesso l’accesso, altrimenti viene
concesso un altro tentativo ed in caso di un ulteriore errore, viene
registrato l’accaduto e bloccato l’accesso al sistema;
•
Controlla che l’Amministratore non sia già loggato;
•
Registrazione dei dati relativi all’accesso;
•
Verifica dei diritti di accesso;
•
Visualizzazione del menù per accedere alle aree di gestione;
3.2.1.4 Output
Menu di accesso alle aree di gestione.
Dati relativi all’accesso registrati in archivio :
•
Data ed Ora di login
•
Indirizzo IP
•
Validità login
•
Tentativo
397
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
Messaggi :
“Username e/o Password errati”
“Tentativi di accesso esauriti : sistema bloccato”
“Già loggato”
3.2.2 Modifica Password Amministratore
3.2.2.1 Introduzione
Questa funzionalità permette all’Amministratore di modificare i propri
dati di accesso al sistema, nella fattispecie soltanto la password. E’
ovviamente previsto che l’Amministratore abbia già eseguito il login,
altrimenti la funzionalità non è disponibile.
3.2.2.2 Input
•
Identificativo Amministratore (obbligatorio)
•
Password nuova (obbligatorio)
•
Conferma Password nuova (obbligatorio)
3.2.2.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che la Password nuova e Conferma Password siano
almeno di 5 caratteri e visualizza eventualmente un messaggio di
errore;
•
Controlla che la Password nuova e la Conferma Password
coincidano, altrimenti visualizza un messaggio di errore;
•
Registrazione dei nuovi dati inseriti;
3.2.2.4 Output
Parte dei dati letti in input che vengono registrati in archivio :
•
Password nuova;
Messaggi :
“La Password nuova e la sua Conferma non coincidono”
398
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
“La Password deve avere una lunghezza di almeno 5 caratteri”
“La Conferma Password deve avere una lunghezza di almeno 5
caratteri”
“Aggiornamento effettuato con successo”
3.2.3 Visualizzazione elenco brani MP3 per genere musicale
3.2.3.1 Introduzione
Questa funzionalità permette all’Amministratore di visualizzare l’elenco
dei brani MP3 presenti in archivio, relativamente ad un determinato
genere musicale
3.2.3.2 Input
•
Genere Musicale (obbligatorio)
3.2.3.3 Elaborazione
Visualizzazione di un form con l’elenco dei generi musicali disponibili,
sulla base del quale, effettuando una scelta, il sistema effettua le seguenti
operazioni :
•
Controlla che sia stato selezionato un Genere Musicale;
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco dei brani MP3 sulla base del genere
musicale scelto;
3.2.3.4 Output
Elenco dei brani musicali relativi al genere scelto
Messaggi :
“Nessun genere musicale selezionato”
“Nessun brano disponibile in archivio per questo genere”
399
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.4 Ricerca di un brano MP3 secondo uno o più criteri
3.2.4.1 Introduzione
Questa funzionalità permette all’Amministratore di cercare uno o più
brani MP3 all’interno dell’archivio, sulla base di propri criteri, per poter
effettuare su di essi delle eventuali operazioni.
3.2.4.2 Input
•
Titolo
•
Autore
•
Genere Musicale
•
Album
3.2.4.3 Elaborazione
Visualizzazione di un form che permette all’Amministratore di stabilire i
propri criteri di ricerca dei brani MP3. Inoltre, il sistema effettua le
seguenti operazioni :
•
Controlla che almeno uno fra i campi Titolo, Autore, Genere
Musicale e Album non sia vuoto;
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco dei brani MP3;
3.2.4.4 Output
Elenco dei brani musicali che corrispondono ai criteri impostati.
Messaggi :
“Nessun brano corrisponde ai criteri impostati”
“Non è stato impostato alcun criterio di ricerca”
400
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.5 Inserimento di un brano MP3
3.2.5.1 Introduzione
Questa funzionalità permette all’Amministratore di inserire un nuovo
brano MP3 in archivio. Le informazioni relative al brano possono essere
specificate dall’Amministratore oppure vengono lette dal sistema
direttamente dal file MP3 caricato sul server, tramite i tag MP3.
3.2.5.2 Input
•
Titolo
•
Autore
•
Genere Musicale (obbligatorio)
•
Album
•
Durata
•
Costo (obbligatorio)
•
File MP3 del brano (obbligatorio)
3.2.5.3 Elaborazione
Visualizzazione di un form per l’input dei dati sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che sia stato selezionato un File MP3 da caricare nel
sistema;
•
Nel caso in cui l’Amministratore non abbia specificato le
informazioni del brano, queste vengono estratte direttamente dal
File MP3 caricato, tramite i tag MP3 e si controlla comunque che
alcuni tag MP3 non siano specificati;
•
Verifica che ci sia coerenza tra le informazioni immesse
dall’Amministratore ed i tag MP3;
•
Registrazione dei dati di input in archivio;
3.2.5.4 Output
Tutti i dati letti in input registrati in archivio.
Altri dati registrati in archivio :
•
Dimensione (in byte)
401
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
Messaggi :
“Inserimento brano effettuato con successo”
“Il tag relativo al titolo è vuoto”
“Il tag relativo al genere musicale è vuoto”
“Il tag relativo all’autore è vuoto”
3.2.6 Visualizzazione informazioni di un brano MP3
3.2.6.1 Introduzione
Questa funzionalità permette all’Amministratore di visualizzare le
informazioni dettagliate di un brano MP3 presente in archivio.
3.2.6.2 Input
•
Identificativo brano MP3 (obbligatorio)
Dati caricati dal sistema provenienti dall’archivio.
3.2.6.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione delle informazioni dettagliate del brano selezionato;
3.2.6.4 Output
Informazioni dettagliate del brano selezionato.
3.2.7 Modifica informazioni di un brano MP3
3.2.7.1 Introduzione
Questa funzionalità permette all’Amministratore di modificare le
informazioni di un brano MP3 presente in archivio, garantendo la
coerenza con i tag MP3 del brano stesso.
3.2.7.2 Input
•
Titolo
•
Autore
•
Genere Musicale (obbligatorio)
402
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Album
•
Durata
•
Costo (obbligatorio)
3.2.7.3 Elaborazione
Visualizzazione di un form, contenente i dati attuali relativi al brano MP3,
caricati dall’archivio, per l’input dei nuovi dati sui quali il sistema esegue
le seguenti operazioni:
•
Controlla che i campi relativi a Genere Musicale e Costo non
siano vuoti;
•
Aggiornamento dei tag MP3 del brano per garantire la coerenza
con le informazioni in archivio;
•
Registrazione dei dati di input in archivio;
3.2.7.4 Output
Tutti i dati letti in input registrati in archivio.
Messaggi :
“Aggiornamento effettuato con successo”
“Non è stato selezionato alcun genere musicale”
3.2.8 Cancellazione di un brano MP3
3.2.8.1 Introduzione
Questa funzionalità permette all’Amministratore di cancellare uno o più
brani MP3 presenti in archivio.
3.2.8.2 Input
•
Identificativo brano MP3 (obbligatorio)
3.2.8.3 Elaborazione
Visualizzazione di un form, contenente l’elenco dei brani MP3 per genere
musicale oppure sulla base di una specifica ricerca, con possibilità di
selezionare i brani da cancellare. E’ possibile cancellare un brano anche
403
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
dalla funzionalità di visualizzazione delle sue informazioni dettagliate.
Inoltre, il sistema effettua le seguenti operazioni :
•
Controlla che sia stato selezionato almeno un brano MP3;
•
Eliminazione dei dati presenti in archivio relativi al/i brano
selezionato/i;
•
Visualizzazione dell’elenco dei brani;
3.2.8.4 Output
Elenco dei brani.
Messaggi :
“Eliminazione effettuata con successo”
“Non è stato selezionato alcun brano”
3.2.9 Ascolto di un brano MP3
3.2.9.1 Introduzione
Questa funzionalità permette all’Amministratore di ascoltare in streaming
un brano MP3.
3.2.9.2 Input
•
Identificativo brano MP3 (obbligatorio)
3.2.9.3 Elaborazione
Visualizzazione di un form per l’avvio della riproduzione del brano MP3
selezionato. Inoltre, il sistema effettua le seguenti operazioni :
•
Controlla che sia stato selezionato un brano MP3 da ascoltare;
•
Caricamento del player MP3 per la ricezione in streaming e la
riproduzione del brano;
3.2.9.4 Output
Messaggi :
“Non è stata selezionata alcun brano da ascoltare”
404
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.10 Visualizzazione elenco utenti
3.2.10.1 Introduzione
Questa funzionalità permette all’Amministratore di visualizzare l’elenco
degli utenti iscritti.
3.2.10.2 Input
Dati caricati dal sistema provenienti dall’archivio.
3.2.10.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco degli utenti;
3.2.10.4 Output
Elenco degli utenti.
Messaggi :
“Nessun utente registrato”
3.2.11 Cancellazione di un utente
3.2.11.1 Introduzione
Questa funzionalità permette all’Amministratore di cancellare uno o più
utenti presenti in archivio.
3.2.11.2 Input
•
Identificativo Utente (obbligatorio)
3.2.11.3 Elaborazione
Visualizzazione di un form, contenente l’elenco degli utenti, con
possibilità di selezionare gli utenti da cancellare. E’ possibile cancellare un
utente anche dalla funzionalità di visualizzazione dei suoi dati anagrafici.
Inoltre, il sistema effettua le seguenti operazioni :
•
Controlla che sia stato selezionato almeno un utente;
•
Eliminazione dei dati presenti in archivio relativi all/gli utente/i
selezionato/i;
405
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Visualizzazione dell’elenco degli utenti;
3.2.11.4 Output
Elenco degli utenti.
Messaggi :
“Eliminazione effettuata con successo”
“Nessun utente è stato selezionato”
3.2.12 Visualizzazione dati anagrafici utente
3.2.12.1 Introduzione
Questa funzionalità permette all’Amministratore di visualizzare i dati
anagrafici di un utente presente in archivio.
3.2.12.2 Input
•
Identificativo Utente (obbligatorio)
Dati caricati dal sistema provenienti dall’archivio.
3.2.12.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dei dati anagrafici dell’utente selezionato;
3.2.12.4 Output
Dati anagrafici dell’utente selezionato.
3.2.13 Sblocco di un utente
3.2.13.1 Introduzione
Questa funzionalità permette all’Amministratore di sbloccare un Utente
che ne abbia fatto richiesta ufficiale via telefono o via mail.
3.2.13.2 Input
•
Identificativo Utente (obbligatorio)
3.2.13.3 Elaborazione
•
Registrazione dei dati in archivio, ossia del sblocco dell’Utente.
406
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.13.4 Output
Sblocco Utente.
3.2.14 Logout
3.2.14.1 Introduzione
Questa funzionalità permette all’Amministratore di eseguire il logout dal
sistema.
3.2.14.2 Input
•
Identificativo Amministratore (obbligatorio)
3.2.14.3 Elaborazione
•
Registrazione dei dati in archivio che tengono traccia del logout;
3.2.14.4 Output
Dati relativi all’uscita dal sistema registrati in archivio :
•
Data ed Ora di logout
Classe Utente
3.2.15 Login
3.2.15.1 Introduzione
Questa funzionalità permette all’Utente di accedere al sistema.
3.2.15.2 Input
•
Username (obbligatorio)
•
Password (obbligatorio)
3.2.15.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che la Username e la Password siano corrette e cioè
corrispondano a quelle memorizzate nell’archivio. Se il controllo
va a buon fine, viene permesso l’accesso, altrimenti viene
407
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
concesso un altro tentativo ed in caso di un ulteriore errore, viene
registrato l’accaduto e bloccato l’accesso al sistema;
•
Controlla che l’Utente non sia già loggato;
•
Registrazione dei dati relativi all’accesso;
•
Verifica dei diritti di accesso;
•
Visualizzazione del menù per l’accesso alle aree di utente;
3.2.15.4 Output
Menù di accesso alle aree di utente.
Dati relativi all’accesso registrati in archivio :
•
Data ed Ora di login
•
Indirizzo IP
•
Validità login
•
Tentativo
Messaggi :
“Username e/o Password errati”
“Tentativi di accesso esauriti : impedito l’accesso”
“Già loggato”
3.2.16 Registrazione
3.2.16.1 Introduzione
Questa funzionalità permette all’Utente di effettuare la registrazione, per
usufruire dei servizi offerti dalla web application.
3.2.16.2 Input
Dati dell’Utente :
•
Email (obbligatorio)
•
Username (obbligatorio)
•
Password (obbligatorio)
•
Acquisto MP3 (si/no)
408
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.16.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che i campi relativi all’Email, Username, Password e
non siano vuoti o non validi, in particolare l’Email abbia una
struttura corretta e la Password abbia una lunghezza di almeno 5
caratteri;
•
Controlla che lo Username non sia già presente in archivio;
•
Registrazione dei dati di input in archivio;
•
Passaggio alla funzionalità di acquisto scheda prepagata qualora
l’Utente voglia usufruire della funzionalità di download;
3.2.16.4 Output
Tutti i dati letti in input registrati in archivio.
Menù di accesso alle aree di utente.
Altri dati registrati :
•
Data/Ora registrazione
Messaggi :
“Registrazione effettuata con successo”
“Email non valida”
“Il campo relativo all’email non può essere vuoto”
“Il campo relativo alla Username non può essere vuoto”
“Il campo relativo alla Password non può essere vuoto”
“La Password deve essere almeno di 5 caratteri”
3.2.17 Acquisto scheda prepagata per il download di brani MP3
3.2.17.1 Introduzione
Questa funzionalità permette all’Utente di acquistare una scheda
prepagata “virtuale”, mediante la quale può eseguire l’acquisto e quindi il
download degli MP3.
409
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.17.2 Input
•
Nome (obbligatorio)
•
Cognome (obbligatorio)
•
Indirizzo (obbligatorio)
•
Città (obbligatorio)
•
Provincia
•
CAP
•
Stato (obbligatorio)
•
Telefono
•
Data di Nascita
•
Sesso
•
Tipo Carta di Credito (obbligatorio)
•
Numero Carta di Credito (obbligatorio)
•
Data scadenza Carta di Credito (obbligatorio)
•
Codice Segreto (obbligatorio)
•
Importo (obbligatorio)
3.2.17.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che i campi relativi al Nome, Cognome, Indirizzo, Città
e Stato non siano vuoti;
•
Controlla che sia stato selezionato un Tipo di Carta di Credito;
•
Controlla che il campo relativo al Numero Carta di Credito non
siano vuoto o non valido;
•
Controlla che sia stata specificata la Data di Scadenza;
•
Controlla che il campo relativo al Codice Segreto della carta non
sia vuoto;
•
Controlla che sia stato selezionato un Importo;
•
Controllo dei dati attraverso il sistema bancario;
410
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Registrazione dati relativi all’importo della scheda prepagata,
registrati in archivio;
3.2.17.4 Output
Alcuni dei dati di input registrati in archivio :
•
Importo
Altri dati registrati in archivio
•
Data/Ora acquisto scheda prepagata
•
Data scadenza scheda prepagata
Messaggi :
“Il Controllo sul circuito bancario non ha avuto successo”
“Scheda prepagata acquistata con successo”
“Non è stata selezionata alcuna carta di credito”
“Il campo relativo al numero carta di credito non può essere vuoto”
“Il campo relativo al numero carta di credito ha un formato non
valido”
“Non è stata specificata la data di scandenza”
“Il campo relativo al codice segreto non può essere vuoto”
“Non è stato selezionato alcun importo per la scheda prepagata”
“Il campo relativo al nome non può essere vuoto”
“Il campo relativo al cognome non può essere vuoto”
“Il campo relativo all’indirizzo non può essere vuoto”
“Il campo relativo alla città non può essere vuoto”
“Il campo relativo allo stato non può essere vuoto”
3.2.18 Ricarica scheda prepagata per il download di brani MP3
3.2.18.1 Introduzione
Questa funzionalità permette all’Utente di ricaricare la scheda prepagata
“virtuale”, mediante la quale può eseguire l’acquisto e quindi il download
degli MP3.
411
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.18.2 Input
•
Identificativo utente (obbligatorio)
•
Tipo Carta di Credito (obbligatorio)
•
Numero Carta di Credito (obbligatorio)
•
Data scadenza Carta di Credito (obbligatorio)
•
Codice Segreto (obbligatorio)
•
Importo Ricarica (obbligatorio)
3.2.18.3 Elaborazione
Visualizzazione di un form per l’input dei dati, sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che sia stato selezionato un Tipo di Carta di Credito;
•
Controlla che il campo relativo al Numero Carta di Credito non
siano vuoto o non valido;
•
Controlla che sia stata specificata la Data di Scadenza;
•
Controlla che il campo relativo al Codice Segreto della carta non
sia vuoto;
•
Controlla che sia stato selezionato un Importo di Ricarica;
•
Controllo dei dati attraverso il sistema bancario;
•
Registrazione dati relativi all’importo della ricarica, registrati in
archivio;
3.2.18.4 Output
Alcuni dei dati di input registrati in archivio :
•
Importo Ricarica
Altri dati registrati in archivio
•
Data/Ora ricarica
Messaggi :
“Il Controllo sul circuito bancario non ha avuto successo”
“Ricarica eseguita con successo”
“Non è stata selezionata alcuna carta di credito”
“Il campo relativo al numero carta di credito non può essere vuoto”
412
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
“Il campo relativo al numero carta di credito ha un formato non
valido”
“Non è stata specificata la data di scandenza”
“Il campo relativo al codice segreto non può essere vuoto”
“Non è stato selezionato alcun importo per la ricarica”
3.2.19 Visualizzazione importo residuo e scadenza scheda prepagata
3.2.19.1 Introduzione
Questa funzionalità permette all’Utente di visualizzare l’importo residuo e
la data di scadenza della scheda prepagata “virtuale”, mediante la quale
può eseguire l’acquisto e quindi il download degli MP3.
3.2.19.2 Input
•
Identificativo Utente (obbligatorio)
3.2.19.3 Elaborazione
•
Controlla che la scheda non sia scaduta;
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’importo residuo e della data di scadenza;
3.2.19.4 Output
Importo residuo e data di scadenza della scheda prepagata.
Messaggi :
“Attenzione ! La scheda è scaduta”
3.2.20 Modifica dati personali
3.2.20.1 Introduzione
Questa funzionalità permette all’Utente di modificare i propri dati
personali.
3.2.20.2 Input
Dati dell’Utente :
•
Nome (obbligatorio)
413
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Cognome (obbligatorio)
•
Indirizzo (obbligatorio)
•
CAP
•
Stato (obbligatorio)
•
Provincia
•
Città (obbligatorio)
•
Telefono
•
Data di Nascita
•
Sesso
•
Email (obbligatorio)
•
Username (obbligatorio)
•
Password nuova (obbligatorio)
•
Conferma Password nuova (obbligatorio)
3.2.20.3 Elaborazione
Visualizzazione di un form, contenente i dati attuali relativi all’Utente
caricati dall’archivio, per l’input dei nuovi dati sui quali il sistema esegue
le seguenti operazioni
•
Controlla che i campi relativi all’Email, Username, Password
vecchia e nuova e Conferma Password non siano vuoti o non
validi, in particolare l’Email abbia una struttura corretta e la
Password abbia una lunghezza di almeno 5 caratteri;
•
Controlla che i campi relativi al Nome, Cognome, Indirizzo, Città
e Stato non siano vuoti;
•
Controlla che la Password nuova e la Conferma Password
coincidano, altrimenti visualizza un messaggio di errore;
•
Registrazione dei dati di input in archivio;
3.2.20.4 Output
Tutti i dati letti in input registrati in archivio.
Menù di accesso alle aree di utente.
414
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
Messaggi :
“Aggiornamento effettuato con successo”
“Email non valido”
“Il campo relativo all’email non può essere vuoto”
“Il campo relativo alla Username non può essere vuoto”
“Il campo relativo alla Password nuova non può essere vuoto”
“Il campo relativo alla Conferma Password non può essere vuoto”
“La Password deve essere di almeno 5 caratteri”
“la Password ed il relativo campo di Conferma non coincidono”
“Il campo relativo al nome non può essere vuoto”
“Il campo relativo al cognome non può essere vuoto”
“Il campo relativo all’indirizzo non può essere vuoto”
“Il campo relativo alla città non può essere vuoto”
“Il campo relativo allo stato non può essere vuoto”
3.2.21 Visualizzazione elenco playlist
3.2.21.1 Introduzione
Questa funzionalità permette all’Utente di visualizzare l’elenco delle
playlist create in precedenza per poterle ascoltare.
3.2.21.2 Input
Dati caricati dal sistema provenienti dall’archivio.
3.2.21.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco delle playlist;
3.2.21.4 Output
Elenco delle playlist.
Messaggi :
“Nessuna playlist creata in precedenza”
415
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.22 Creazione di una playlist
3.2.22.1 Introduzione
Questa funzionalità permette all’Utente di creare una nuova playlist.
3.2.22.2 Input
•
Nome Playlist (obbligatorio)
3.2.22.3 Elaborazione
Visualizzazione di un form, per l’input dei dati sui quali il sistema esegue
le seguenti operazioni
•
Controlla che il campo relativo al Nome Playlist non sia vuoto;
•
Registrazione dei dati di input in archivio;
3.2.22.4 Output
Elenco delle playlist.
Altri dati registrati in archivio :
•
Data/Ora creazione
Messaggi :
“Playlist creata con successo”
“Il campo relativo al nome della playlist non può essere vuoto”
3.2.23 Cancellazione di una playlist
3.2.23.1 Introduzione
Questa funzionalità permette all’Utente di cancellare uno o più playlist
create in precedenza.
3.2.23.2 Input
•
Identificativo Playlist (obbligatorio)
3.2.23.3 Elaborazione
Visualizzazione di un form, contenente l’elenco delle playlist, con
possibilità di selezionare quali cancellare. Inoltre, il sistema effettua le
seguenti operazioni :
416
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Controlla che sia stato selezionata almeno una playlist;
•
Eliminazione dei dati presenti in archivio relativi alla/e playlist
selezionata/e;
•
Visualizzazione dell’elenco delle playlist;
3.2.23.4 Output
Elenco delle playlist.
Messaggi :
“Eliminazione effettuata con successo”
“Non è stata selezionata alcuna playlist”
3.2.24 Visualizzazione brani presenti nella playlist
3.2.24.1 Introduzione
Questa funzionalità permette all’Utente di visualizzare l’elenco dei brani
MP3 che compongono una particolare playlist.
3.2.24.2 Input
•
Identificativo Playlist (obbligatorio)
Dati caricati dal sistema provenienti dall’archivio.
3.2.24.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco dei brani;
3.2.24.4 Output
Elenco dei brani MP3 presenti all’interno della playlist.
Messaggi :
“La playlist è vuota
417
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.25 Ascolto della playlist
3.2.25.1 Introduzione
Questa funzionalità permette all’Utente di ascoltare in streaming i brani
MP3 che costituiscono una playlist.
3.2.25.2 Input
•
Identificativo Playlist (obbligatorio)
3.2.25.3 Elaborazione
Visualizzazione di un form per l’avvio della riproduzione dei brani
contenuti nella playlist. Inoltre, il sistema effettua le seguenti operazioni :
•
Controlla sia stata selezionata una playlist da ascoltare;
•
Caricamento del player MP3 per la ricezione in streaming e la
riproduzione della playlist;
3.2.25.4 Output
Messaggi :
“Non è stata selezionata alcuna playlist da ascoltare”
3.2.26 Visualizzazione elenco brani MP3 per genere musicale
3.2.26.1 Introduzione
Questa funzionalità permette all’Utente di visualizzare l’elenco dei brani
MP3 presenti in archivio, relativamente ad un determinato genere
musicale
3.2.26.2 Input
•
Genere Musicale (obbligatorio)
3.2.26.3 Elaborazione
Visualizzazione di un form con l’elenco dei generi musicali disponibili,
sulla base del quale, effettuando una scelta, il sistema effettua le seguenti
operazioni :
•
Controlla che sia stato selezionato un Genere Musicale;
418
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco dei brani MP3 sulla base del genere
musicale scelto;
3.2.26.4 Output
Elenco dei brani musicali relativi al genere scelto
Messaggi :
“Nessun genere musicale selezionato”
“Nessun brano disponibile in archivio per questo genere”
3.2.27 Ricerca di un brano MP3 secondo uno o più criteri
3.2.27.1 Introduzione
Questa funzionalità permette all’Utente di cercare uno o più brani MP3
all’interno dell’archivio, sulla base di propri criteri, per poter effettuare su
di essi delle eventuali operazioni, tra cui l’ascolto, il download e
l’inserimento in una playlist.
3.2.27.2 Input
•
Titolo
•
Autore
•
Genere Musicale
•
Album
3.2.27.3 Elaborazione
Visualizzazione di un form che permette all’Utente di stabilire i propri
criteri di ricerca dei brani MP3. Inoltre, il sistema effettua le seguenti
operazioni :
•
Controlla che almeno uno fra i campi Titolo, Autore, Genere
Musicale e Album non sia vuoto;
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione dell’elenco dei brani musicali;
419
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.27.4 Output
Elenco dei brani musicali che corrispondono ai criteri impostati.
Messaggi :
“Nessun brano corrisponde ai criteri impostati”
“Non è stato impostato alcun criterio di ricerca”
3.2.28 Visualizzazione informazioni di un brano MP3
3.2.28.1 Introduzione
Questa funzionalità permette all’Utente di visualizzare le informazioni
dettagliate di un brano MP3 presente in archivio.
3.2.28.2 Input
•
Identificativo brano MP3 (obbligatorio)
Dati caricati dal sistema provenienti dall’archivio.
3.2.28.3 Elaborazione
•
Caricamento dei dati presenti in archivio;
•
Visualizzazione delle informazioni dettagliate del brano selezionato;
3.2.28.4 Output
Informazioni dettagliate del brano selezionato.
3.2.29 Ascolto di un brano MP3
3.2.29.1 Introduzione
Questa funzionalità permette all’Utente di ascoltare in streaming un
brano MP3.
3.2.29.2 Input
•
Identificativo brano MP3 (obbligatorio)
3.2.29.3 Elaborazione
Visualizzazione di un form per l’avvio della riproduzione del brano MP3
selezionato. Inoltre, il sistema effettua le seguenti operazioni :
420
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Controlla che sia stato selezionato un brano MP3 da ascoltare;
•
Caricamento del player MP3 per la ricezione in streaming e la
riproduzione dle brano;
3.2.29.4 Output
Messaggi :
“Non è stata selezionata alcun brano da ascoltare”
3.2.30 Inserimento di un brano MP3 all’interno di una playlist
3.2.30.1 Introduzione
Questa funzionalità permette all’Utente di inserire un brano MP3
all’interno di una playlist.
3.2.30.2 Input
•
Identificativo brano MP3 (obbligatorio);
•
Nome Playlist (obbligatorio);
3.2.30.3 Elaborazione
Visualizzazione di un form per l’input dei dati sui quali il sistema esegue
le seguenti operazioni :
•
Controlla che sia stato selezionato un brano MP3 da aggiungere
ad una playlist;
•
Controlla che sia stata selezionata la Playlist di destinazione nella
quale inserire il brano;
•
Registrazione dei dati di input in archivio;
3.2.30.4 Output
Tutti i dati letti in input registrati in archivio.
Messaggi :
“Inserimento brano effettuato con successo”
“Non è stato selezionato alcun brano”
“Non è stata selezionata la playlist di destinazione”
421
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.31 Cancellazione di un brano MP3 da una playlist
3.2.31.1 Introduzione
Questa funzionalità permette all’Utente di cancellare uno o più brani
MP3 dalla playlist selezionata.
3.2.31.2 Input
•
Identificativo brano MP3 (obbligatorio);
•
Identificativo playlist (obbligatorio);
3.2.31.3 Elaborazione
Visualizzazione di un form per la selezione del/i brani da rimuovere. Il
sistema, inoltre, effettua le seguenti operazioni :
•
Controlla che sia stato selezionato almeno un brano;
•
Eliminazione dei dati presenti in archivio relativi al/i brani
selezionati;
3.2.31.4 Output
Elenco dei brani presenti nella playlist.
Messaggi :
“Eliminazione effettuata con successo”
“Non è stato selezionato alcun brano”
3.2.32 Acquisto/Download di un brano MP3
3.2.32.1 Introduzione
Questa funzionalità permette all’Utente di acquistare ed effettuare il
download di un brano MP3 presente in archivio.
3.2.32.2 Input
•
Identificativo brano MP3 (obbligatorio)
422
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.2.32.3 Elaborazione
•
Il sistema controlla che l’importo residuo sia sufficiente all’acquisto
del brano MP3. In caso negativo, avvia la funzionalità di acquisto di
una scheda prepagata oppure di ricarica.
•
Caricamento dei dati dall’archivio relativi al brano selezionato;
•
Riduzione dell’importo residuo nella scheda prepagata in base al
costo del brano;
•
Abilitazione al download;
•
Registrazione dei dati in archivio;
3.2.32.4 Output
Tutti i dati letti in input registrati in archivio
Altri dati registrati in archivio :
•
Data acquisto
Messaggi :
“Acquisto del brano eseguito con successo”
“Importo insufficiente sulla scheda prepagata, prego ricaricare”
“Nessuna carta prepagata a disposizione, effettuarne l’acquisto”
3.2.33 Richiesta username/password
3.2.33.1 Introduzione
Questa funzionalità permette all’Utente di chiedere l’invio di una mail
contenente la username e la password, qualora se ne fosse dimenticato.
3.2.33.2 Input
•
Email (obbligatorio)
3.2.33.3 Elaborazione
Visualizzazione di un form per l’inserimento dei dati, sui quali il sistema
effettua le seguenti operazioni :
•
Controlla che il campo relativo alla Email non sia vuoto e sia
valido;
423
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
•
Caricamento dei dati presenti in archivio;
•
Invio della mail contenente username e password;
3.2.33.4 Output
Messaggi :
“Mail inviata con successo”
“Il campo relativo alla Email non può essere vuoto”
“L’Email ha un formato non valido”
“Email non registrata in archivio”
3.2.34 Logout
3.2.34.1 Introduzione
Questa funzionalità permette all’Utente di eseguire il logout dal sistema.
3.2.34.2 Input
•
Identificativo utente (obbligatorio)
3.2.34.3 Elaborazione
•
Registrazione dei dati in archivio che tengono traccia del logout;
3.2.34.4 Output
Dati relativi all’uscita dal sistema registrati in archivio :
•
Data ed Ora di uscita
3.3 Requisiti di prestazioni
Nessuno.
3.4 Vincoli di progetto
Nessuno.
424
Appendice A – SRS Web Application MP3-Web
_________________________________________________________________
3.5 Attributi
3.5.1 Sicurezza
Come strumento di protezione è previsto l’utilizzo di una Password al fine di evitare
accessi al sistema da parte di persone non autorizzate.
3.6 Altri requisiti
3.6.1 Database
Il sistema software prevede l’utilizzo di un database relazionale per l’archiviazione dei
dati.
425
Riferimenti Bibliografici
_________________________________________________________________
Riferimenti Bibliografici
Capitolo I
N. Ford - “Art of Java Web Development” - Ed. Manning
K. D. Mann - “JavaServer Faces in Action” - Ed. Manning
C. Cavaness - “Programming Jakarta Struts 2nd Edition” - Ed. O’Reilly
M. Pianciamore - “Principi di Ingegneria del Software – Design Pattern” - CEFRIEL
G. Mecca - “Applicazioni Web J2EE : Java Servlet”, corso di Tecnologie di sviluppo
per il Web - Università della Basilicata
J. Falkner, K. Jones - “Servlets and JavaServer Pages : The J2EE technology Web tier” - Ed.
Addison Wesley
Capitolo II
E. Armstrong, J. Ball, S. Bodoff, D.B. Carson, I. Evans, D. Green, K. Haase, E.
Jendrock - “The J2EE 1.4 Tutorial” (cap. 17,18,19,20,21) - Sun Microsystems
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
426
Riferimenti Bibliografici
_________________________________________________________________
S. Shin - “J2EE Advanced” (www.javapassion.com) - 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
Capitolo III
Apache Software Foundation - “Official Struts documentation”
Apache Software Foundation, C. Dumoulin - “Official Struts Tiles documentation”
C. Cavaness - “Programming Jakarta Struts 2nd Edition” - Ed. O’Reilly
J. Holmes - “Struts : The Complete Reference” - Ed. McGraw/Hill
S. Spielman - “The Struts framework : Practical guide for Java programmers” - Ed. Morgan
Kaufmann
T. Husted, C. Dumoulin, G. Franciscus, D. Winterfeldt - “Struts in action : building
Web applications with the leading Java framework” - Ed. Manning
S. Shenoy - “Struts survival guide : basics to best practices” – Ed. ObjectSource
M. Robinson, E. Finkelstein - “Jakarta Struts for dummies” - Ed. Wiley Publishing
R. W. Barnes - “Introduction to Struts” - Project Refinery
S. Shenoy - “Struts for J2EE Developers” (www.objectsource.com)
427
Riferimenti Bibliografici
_________________________________________________________________
C. Cavaness - “Jakarta Struts 1.1 : ready for prime time”, Atlanta Java Users Group
(AJUG) 2002
D. Lucek - “Basic Struts Web development” (www.lucek.com)
Capitolo IV
E. Burns - “About Faces : The JavaServer Faces API and how it relates to Struts” - Sun
Microsystems
C. McClanahan – “The Best of Both Worlds: Integrating JSF with Struts in Your J2EE
Applications” (www.oracle.com)
R. Barcia - “JavaServer Faces vs Struts : A brief comparison” (websphere.sys-con.com)
C. McClanahan - “JavaServer Faces and Struts : Competition or Coexistence ?”
SAML Security – “JavaServer Faces : A comparative study” (www.oneinfoplace.com)
K.D. Mann – “Migrating from Struts to JavaServer Faces” - Virtua
K. D. Mann - “From Struts to JavaServer Faces , Evolving your Web applications to support
the new standard” (www.jsfcentral.com)
C. McClanahan - “The evolution of Web application architectures”, O’Reilly Open Source
Convention 2005
D. Geary - “JavaServer Faces : Finally, a component model for enterprise Java!”, Denver Java
User’s Group 2003
428
Riferimenti Bibliografici
_________________________________________________________________
Capitolo V
R.S. Pressman - “Principi di Ingegneria del Software” - Ed. McGraw/Hill
P. Atzeni, S. Ceri, S. Paraboschi, R. Torlone - “Basi di dati”, seconda edizione Ed. McGraw/Hill
G. A. Di Lucca - “Corso di Ingegneria del Software”, slide a.a. 2003-2004 - Università
degli Studi del Sannio
Sybase - “Sybase Power Designer : Conceptual Data Model , User’s Guide”
Sybase - “Sybase Power Designer : Object Oriented Model , User’s Guide”
Sybase - “Sybase Power Designer : Physical Data Model , User’s Guide”
Capitolo VI
A. Cioroianu - “Upload Files with JSF and MyFaces” (www.onjava.com)
B. Dudney - “Creating JSF Custom Components” (www.java.net)
R. Hightower - “JSF for nonbelievers : JSF component development” (www.ibm.com)
Apache Software Foundation - “Apache Jakarta Tomcat 5 official documentation : SSL
Configuration How-to”
S. Smirnov - “How to use Tiles with JSF” – Exadel
Appendice A – SRS Web Application MP3-Web
Software Engineering Standards Committee of the IEEE Computer Society –
“IEEE Recommended Practice for Software Requirements Specifications”, IEEE Std 830-1993
429