Reti di Calcolatori L-S A.A. 2007/2008. Sviluppo e collaudo di un'applicazione web mediante IoC e AOP. di Franchi Alessandro matr.



Documenti analoghi
Programmazione Java Avanzata Spring - JDBC

Breve introduzione curata da Alessandro Benedetti. Struts2-Introduzione e breve guida

SWIM v2 Design Document

L architettura MVC (Model- View-Controller) Introduzione

Implementazione di MVC. Gabriele Pellegrinetti

Al giorno d oggi, i sistemi per la gestione di database

Architettura MVC-2 A L B E R T O B E L U S S I A N N O A C C A D E M I C O /

PROGETTAZIONE E SVILUPPO DI UN. Relatore: Studente: Paolo Merialdo Valerio Barbagallo

SITI-Reports. Progetto SITI. Manuale Utente. SITI-Reports. ABACO S.r.l.

Il Pattern MVC nei Framework di sviluppo per applicazioni Web. Analisi e comparazione di SPRING MVC Framework e ASP.NET MVC Framework.

EXPLOit Content Management Data Base per documenti SGML/XML

SERVICE BROWSER. Versione 1.0

CORSO DI PROGRAMMAZIONE JAVA

Mac Application Manager 1.3 (SOLO PER TIGER)

Sviluppata da: Lo Russo - Porcelli Pag. 1 di 6 6FRSR utilizzare il DBMS Postgresql per imparare il linguaggio SQL.

Airone Gestione Rifiuti Funzioni di Esportazione e Importazione

Università degli Studi di Bologna Facoltà di Ingegneria. Tecnologie Web L-A A.A Esercitazione 08 DAO e Hibernate

Client - Server. Client Web: il BROWSER

LA GESTIONE DELLE VISITE CLIENTI VIA WEB

Laboratorio di Basi di Dati

PSNET UC RUPAR PIEMONTE MANUALE OPERATIVO

Organizzazione degli archivi

Database e reti. Piero Gallo Pasquale Sirsi

Manuale Utente Amministrazione Trasparente GA

Corso di Amministrazione di Reti A.A. 2002/2003

Capitolo 4 Pianificazione e Sviluppo di Web Part

Manuale d uso Software di parcellazione per commercialisti Ver [05/01/2015]

DATABASE IN RETE E PROGRAMMAZIONE LATO SERVER

Progetto di Ingegneria del Software 2. SWIMv2

CONTENT MANAGEMENT SYSTEM

J2EE (o JEE): Framework Java per lo sviluppo di applicazioni WEB Enterprise, che vivono in rete e che siano accessibili attraverso browser.

Progettazione della componente applicativa

Introduzione Ai Data Bases. Prof. Francesco Accarino IIS Altiero Spinelli Via Leopardi 132 Sesto San giovanni

Introduzione alle basi di dati. Gestione delle informazioni. Gestione delle informazioni. Sistema informatico

Manuale Amministratore Legalmail Enterprise. Manuale ad uso degli Amministratori del Servizio Legalmail Enterprise

SCI Sistema di gestione delle Comunicazioni Interne > MANUALE D USO

Come funziona il WWW. Architettura client-server. Web: client-server. Il protocollo

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

MODELLO CLIENT/SERVER. Gianluca Daino Dipartimento di Ingegneria dell Informazione Università degli Studi di Siena

Riccardo Dutto, Paolo Garza Politecnico di Torino. Riccardo Dutto, Paolo Garza Politecnico di Torino

Progettazione: Tecnologie e ambienti di sviluppo

Generazione Automatica di Asserzioni da Modelli di Specifica

Creare un sito Multilingua con Joomla 1.6

Introduzione. Coordinazione Distribuita. Ordinamento degli eventi. Realizzazione di. Mutua Esclusione Distribuita (DME)

Regione Piemonte Portale Rilevazioni Crediti EELL Manuale Utente

Esercizi di JavaScript

MANUALE D USO DELLA PIATTAFORMA ITCMS

NOVITÀ SITI COMMERCIALISTA

BDCC : Guida rapida all utilizzo

3. Introduzione all'internetworking

Direzione Programmazione Sanitaria. Scarico Dati Sanità. Manuale Utente. Versione 1.0.0

Portale tirocini. Manuale utente Per la gestione del Progetto Formativo

Introduzione al mondo della persistenza. Dott. Doria Mauro

Access. P a r t e p r i m a

19. LA PROGRAMMAZIONE LATO SERVER

Architettura MVC-2: i JavaBeans

Guida Compilazione Piani di Studio on-line

SERVIZIO DI MESSAGGISTICA ALL UTENTE. Manuale per l operatore

filrbox Guida all uso dell interfaccia WEB Pag. 1 di 44

Indice generale. Capitolo 3 Introduzione a PHP...43 Sintassi e istruzioni di base Variabili, operatori e commenti Array...

I MODULI Q.A.T. PANORAMICA. La soluzione modulare di gestione del Sistema Qualità Aziendale

MANUALE D'USO DEL PROGRAMMA IMMOBIPHONE

Reti di Telecomunicazione Lezione 6

RIFERIMENTI ATTORI GLOSSARIO. ERRORI COMUNI REV. REQUISITI INGEGNERIA DEL SOFTWARE Università degli Studi di Padova

SOSEBI PAPERMAP2 MODULO WEB MANUALE DELL UTENTE

Manuale Utente Albo Pretorio GA

MANUALE DI UTILIZZO: INTRANET PROVINCIA DI POTENZA

FPf per Windows 3.1. Guida all uso

Application Server per sviluppare applicazioni Java Enterprise

Manuale Gestore. STWS Web Energy Control - Servizio di telelettura sul WEB

Excel. A cura di Luigi Labonia. luigi.lab@libero.it

Finalità della soluzione Schema generale e modalità d integrazione Gestione centralizzata in TeamPortal... 6

Approccio stratificato

Guida Rapida di Syncronize Backup

I casi d uso corrispondono ai compiti che l attore (che può essere una persona fisica e non) può svolgere.

Coordinazione Distribuita

. A primi passi con microsoft a.ccepss SommarIo: i S 1. aprire e chiudere microsoft access Start (o avvio) l i b tutti i pro- grammi

Collegamento remoto vending machines by do-dots

BASE DI DATI: introduzione. Informatica 5BSA Febbraio 2015

Protocolli e architetture per WIS

Siti interattivi e dinamici. in poche pagine

Lezione 1 Introduzione

Gestione dei servizi all utenza. 3. Autorizzazioni

WG-TRANSLATE Manuale Utente WG TRANSLATE. Pagina 1 di 15

GenLApp Generazione Lista di Applicazioni. Design Patterns. Classi Essenziali. Modellazione Dati. Progettazione della Linea di Prodotti

Obiettivi d esame PHP Developer Fundamentals on MySQL Environment

Guida alla registrazione on-line di un NovaSun Log

Università degli Studi di Messina

Progetto ittorario Anno scol

PROGRAMMA CORSO Analista Programmatore JAVA - ORACLE

MANUALE MOODLE STUDENTI. Accesso al Materiale Didattico

UNIVERSITÀ DEGLI STUDI DI FIRENZE FACOLTA DI INGEGNERIA DIPARTIMENTO DI SISTEMI E INFORMATICA. Elaborato di Tecnologie del Software per Internet

Mon Ami 3000 Varianti articolo Gestione di varianti articoli

Scaletta. Estensioni UML per il Web. Applicazioni web - 2. Applicazioni web. WAE: Web Application Extension for UML. «Client page»

Con il termine Sistema operativo si fa riferimento all insieme dei moduli software di un sistema di elaborazione dati dedicati alla sua gestione.

Corso di Reti di Calcolatori T

Web Programming Specifiche dei progetti

B.P.S. Business Process Server ALLEGATO C10

Legge e apprende nozioni in qualsiasi lingua, le contestualizza ed è in grado di elaborarle e riutilizzarle quando serve

Guida alla registrazione on-line di un DataLogger

Transcript:

Reti di Calcolatori L-S A.A. 2007/2008 Sviluppo e collaudo di un'applicazione web mediante IoC e AOP di Franchi Alessandro matr. 0000219521

Introduzione Le specifiche J2EE definiscono una piattaforma per la realizzazione di applicazioni Java di classe Enterprise. I punti cardine sono: uno strato Web, composto da JSP e Servlet, per la parte di presentazione e uno strato EJB, che contiene la business logic Tuttavia gli EJB si rivelano troppo spesso complicati da usare e portano alla stesura di codice poco riutilizzabile e difficile da testare al di fuori dell'ambiente di esecuzione. Nuovi pattern di programmazione come Inversion of Control[1][2] (IoC) e Aspect Oriented Programming[2] (AOP), consentono ora di sviluppare componenti loosely coupled, riutilizzabili, facilmente testabili e indipendenti dal container in cui sono utilizzati. Questo progetto si propone di utilizzare le funzionalità di Spring[2][3], uno dei principali framework che ha adottato queste metodologie di programmazione, per realizzare un applicazione web per la gestione di uno shop on-line di libri. In particolare si vuole realizzare un componente software per l acquisto di uno o più libri mediante carrello della spesa. Dopo una breve descrizione di IoC e AOP, illustriamo le principali caratteristiche di Spring e dei suoi moduli. Nel capitolo 3 invece viene discussa l applicazione web, mentre nel capitolo successivo è mostrato il supporto di Spring al testing. Dettagli tecnici sono discussi nelle Appendici perché esulano dallo scopo di questa relazione. 1 Nuove tecniche per lo sviluppo di applicazioni Enterprise Il framework EJB fallisce nel mantenere la semplicità dei JavaBeans originali, è difficile da capire e imparare, l implementazione è complessa ed è molto invasivo. Oggi lo sviluppo di componenti Java è supportato da nuove tecniche come Aspect-Oriented Programming (AOP) e Inversion of Control (IoC) che consentono di realizzare con JavaBeans e Plain Old Java Objects (POJO) (semplici oggetti Java liberi da qualsiasi contratto), applicazioni prima possibili solo utilizzando EJB. 1.1 Inversion of Control (IoC) e Dependency Injection (DI) L Inversione del Controllo (IoC) è un principio base per cui il flusso del controllo di un sistema è invertito rispetto alla tradizionale architettura delle librerie software. La Dependency Injection (DI) è un pattern di programmazione che applica il principio dell IoC. Generalmente quando due o più oggetti devono collaborare per eseguire qualche logica di business, ciascuno di essi è responsabile del reperimento dei propri riferimenti agli oggetti con cui deve dialogare. Questo comporta un codice highly coupled, difficile da testare, da capire e da riutilizzare. Una tecnica comune utilizzata per ridurre l accoppiamento è quella di nascondere i dettagli dell implementazione dietro le interfacce; tuttavia non è sufficiente perché è ancora il componente a dover instanziare o recuperare le proprie dipendenze. Occorre trasferire la responsabilità di coordinare la collaborazione tra oggetti dipendenti al di fuori degli oggetti stessi e questo è possibile grazie alla Dependency Injection. Con la DI infatti è il container che assembla i componenti e imposta ( inietta ) le loro dipendenze a runtime. In questo modo la configurazione e la specifica delle dipendenze è disaccoppiata dalla logica del programma: ciascun componente si occupa solo delle proprie funzionalità, confidando che i suoi riferimenti e i suoi parametri saranno valorizzati quando necessario.

1.2 Aspect Oriented Programming Un sistema software è composto da vari componenti, ciascuno responsabile di una certa funzionalità relativa alla business logic; un applicazione enterprise però ha bisogno anche di servizi come logging, gestione delle transazioni, sicurezza ecc; questi servizi sono noti cross-cutting concerns. Anche se concettualmente separati dalla business logic, purtroppo spesso il codice relativo a crosscutting concerns è inglobato all interno della business logic stessa, aumentandone la complessità. Aspect-Oriented Programming (AOP) è una tecnica di programmazione che promuove la separazione delle responsabilità all interno di un sistema software. Permette di separare funzionalità ortogonali alla business logic, catturandoli in moduli riutilizzabili, che possono essere applicati dichiarativamente ai componenti dell applicazione senza modificarne il codice. 2 Spring Framework Spring è un framework per il supporto alla programmazione a componenti software in ambiente Java, nato per affrontare la complessità dello sviluppo di applicazioni enterprise. È un framework nel senso che consente di configurare e comporre applicazioni complesse a partire da componenti semplici. Ma è anche un container perché contiene e gestisce il lifecycle e la configurazione dei componenti. È leggero, sia in termini di overhead che di dimensioni, soprattutto rispetto ad EJB. È anche poco invasivo cioè il codice che scriviamo è disaccoppiato da Spring; infatti tutte le classi che implementiamo sono semplici POJO che non hanno riferimenti alle API di Spring. Promuove una programmazione ad interfacce e utilizza la Dependency Injection per ottenere loose coupling. Tutto questo rende il codice semplice da leggere, facilmente testabile e riutilizzabile. Spring è organizzato in 5 moduli costruiti al di sopra del core module. Il core module contiene le funzionalità di base di Spring e definisce il container ApplicationContext. Questo container è una Factory in grado creare istanze di oggetti di qualsiasi classe; oltre a gestire e configurare i componenti, offre funzionalità specifiche per applicazioni enterprise come event propagation, supporto ad AOP ecc. Ciascun modulo offre funzionalità aggiuntive: Spring AOP: fornisce un implementazione di Aspect-Oriented Programming conforme alle specifiche dell AOP Alliance (progetto che mira a standardizzare l utilizzo dell AOP e garantire l interoperabilità delle diverse implementazioni). Spring Web: modulo di supporto allo sviluppo del layer di presentazione; include Spring MVC, un web framework, costruito sui principi di Spring, che consente di affrontare in modo semplice i problemi legati alla realizzazione del Presentation Layer, come la gestione dello stato, vista la natura stateless del protocollo HTTP, oppure la validazione dell input dell utente ecc. Fornisce un implementazione del pattern Model-View-Controller per gestire web request.

Spring DAO e Spring JDBC: sono dedicati all integrazione con i principali framework di accesso a database e al supporto alle transazioni. Sollevano lo sviluppatore dai processi comuni e ridondanti legati alla persistenza (gestione delle connessioni, gestione delle query e dei risultati, ecc), permettendo di concentrarsi sulla logica di accesso. Offrono una gerarchia di eccezioni non associata ad uno specifico framework di persistenza, semplificando la migrazione verso altre soluzioni. Utilizzando il pattern Template Method, Spring divide il processo di accesso in due classi separate: template e callback. Le classi template gestiscono le parti fisse dell accesso (transazioni, eccezioni...) mentre implementando la classe callback possiamo gestire in modo personalizzato la parte variabile (creazione degli statement, parametri di binding ). Spring JEE: integrazione con i servizi J2EE (JMS, JNDI ) 2.1 Spring Web Flow Nelle applicazioni web possiamo individuare due tipi di interazione con l utente. Molti siti sono basati su una navigazione libera da flussi cioè all'utente è dato un array di collegamenti e bottoni con cui ha il completo controllo del flusso dell'applicazione. Ci sono invece applicazioni che guidano l'utente da una pagina all'altra, come fosse una conversazione, ma l'applicazione segue comunque un flusso predefinito. Framework come Spring MVC, forzano lo sviluppatore a suddividere il flusso in controller e view individuali. In questo modo però la logica del flusso dell'applicazione è distribuito all'interno delle pagine JSP (in particolare nei link) e dei Controller (nel ModelAndView) e quindi è difficile da seguire. Inoltre è un approccio poco flessibile: cambiare il flusso significherebbe modificare più file sorgenti e in più non è riutilizzabile facilmente. Spring Web Flow elimina questo accoppiamento stretto tra il codice e il flusso dell'applicazione definendo il flusso in un file di configurazione separato e autonomo: in questo modo è facile da individuare ed è self-contained, cioè possiamo considerarlo come un modulo dell applicazione web e riutilizzarlo in situazioni diverse. Inoltre Spring Web Flow gestisce tutto il controllo della navigazione, accertandosi che l applicazione web funzioni correttamente, anche quando l utente utilizza i famigerati bottoni di refresh e back del browser. 2.2 Hibernate Un altro problema da affrontare nello sviluppo di applicazioni enterprise è quello della discordanza tra la rappresentazione dei dati negli oggetti e quella nei database relazionali. Hibernate[4] è un framework di Object-Relational Mapping (ORM): esegue un mapping tra la rappresentazione dei dati negli oggetti e quella nelle tabelle; in questo modo possiamo continuare ad utilizzare classi invece di result set e la nostra applicazione continua ad essere object-oriented.

3 Struttura e funzionamento dell applicazione Seguendo la logica di un architettura Enterprise three-tiered, l applicazione è strutturata in 3 layer: Presentation Layer: interfaccia utente Application Layer: business logic Persistence Layer: accesso a database Un Security Layer wrappa l applicazione web: la sicurezza è gestita attraverso un request filter che intercetta ogni richiesta prima che arrivi al Presentation Layer. Poiché la gestione della sicurezza non è nello scopo di questo progetto, i dettagli sono stati inclusi in appendice. Analizziamo più in dettaglio cosa fanno i componenti dei singoli layer. Web Browser Security Layer Presentation Layer Application Layer Persistence Layer 3.1 Presentation Layer (Client-side logic) Database (mysql, HSQLDB ) Questo layer realizza la parte di presentazione e di interazione con l utente. L interfaccia utente è costituita da poche pagine: inizialmente viene visualizzata la pagina di benvenuto da cui l utente può cercare prodotti su database oppure effettuare il login. A seconda delle credenziali inserite nella pagina di login, vengono visualizzati nuovi collegamenti: se l utente è amministratore, può aggiungere nuovi libri al database, se invece è un cliente dello shop-online, può accedere alla pagina di acquisto (vedi Appendice F - Sicurezza) Utilizza la DispatcherServlet di Spring MVC come Front Controller per gestire tutte le richieste inoltrate dall utente attraverso il browser. Le singole pagine web sono gestite da controller MVC, noti anche come Page Controller. L applicazione ha più controller MVC; il compito della DispatcherServlet è quello di mappare le richieste ai controller MVC di competenza. Per fare questo la servlet utilizza uno o più HandlerMapping, i quali definiscono un mapping tra l URL della richiesta e il controller MVC corrispondente. Quando la richiesta arriva al controller, viene estratto il payload per essere elaborato; il controller non contiene nessuna business logic, ma si appoggia al Service Layer per processare il payload. Handler Mapping Page Controllers Request: login.htm 1 2 FRONT CONTROLLER Dispatcher Servlet 3 ModelAndView 5 4 HomeController LoginController FlowController Service Layer FlowExecutor 6 Views View Resolver FlowRegistry hello.jsp login.jsp Percorso di una HTTP request per essere completamente elaborata

Il risultato dell elaborazione in genere deve essere restituito all utente; l insieme delle informazioni da restituire è chiamato model. Queste informazioni devono essere anche formattate in un formato userfriendly, generalmente in HTML, e per fare questo il model viene affidato ad una view, ad esempio una pagina JSP. Il controller non fa altro che restituire alla DispatcherServlet un oggetto chiamato ModelAndView che contiene il model e il nome logico della view. A questo punto la DispatcherServlet chiede ad un ViewResolver di eseguire il lookup della pagina JSP a partire dal nome della view. Una volta identificata la view corretta, la servlet passa la richiesta alla pagina JSP, la quale estrae il model dalla request e genera la pagina HTML che viene inserita nella risposta HTTP da restituire al browser. search flow search results searc buybooks flow start buy checkou cancel checkout continue update Database continue thankyou end addtocar book Added bookremoved remove FromCart continue exceptio n warn NotInStoc addtocart flow removefromcart flow addtocart bookadde addtocar bookremove Diagramma degli stati del flow di acquisto L acquisto con carrello della spesa virtuale è realizzato come flow perchè richiede una conversazione complessa tra applicazione e utente: l utente può cercare libri nel database, aggiungere e rimuovere libri nel carrello, eseguire il checkout ecc. La ricerca, l aggiunta e la rimozioni di libri dal carrello sono azioni che devono essere ripetute più volte durante la conversazione, quindi sono stati modellate come flow separati e utilizzati come subflow all interno del flow generale di acquisto. Spring Web Flow si integra con Spring MVC attraverso un controller MVC chiamato FlowController che agisce come Front Controller per tutte le richieste relative ai flow. Quando il FlowController viene invocato dalla DispatcherServlet per gestire una richiesta, vengono esaminati i parametri della HTTP request per determinare se deve iniziare una nuova esecuzione di un flow o se riprendere l esecuzione di un flow esistente. L attuale esecutore è FlowExecutor il quale determina, sulla base dei parametri contenuti nella request, quale flow è coinvolto e quale transizione di stato eseguire. FlowExecutor utilizza un FlowRegistry per ottenere le definizioni di un dato flow; FlowRegistry è un registro che mappa il file di definizione del flow in un nome logico.

3.2 Application Layer (business logic) L Application Layer è lo strato dedicato alla business logic e alla gestione dei domain object. Nel nostro sistema di shop online il domain model è costituito dagli oggetti Libro e Carrello della Spesa. In figura sono mostrati i servizi che implementano la business logic. Per disaccoppiare il Service Layer dal sovrastante Presentation Layer per ciascun servizio è definita un interfaccia. I servizi sono noti e predefiniti, quindi non è previsto un servizio di naming. ShoppingCartService consente di modificare il contenuto del carrello e di eseguire il checkout finale (aggiornamento del database e svuotamento del carrello). BookService è l interfaccia del servizio responsabile della gestione dei libri; consente al Presentation Layer di ottenere, aggiornare e salvare libri. L applicazione deve eseguire in un contesto di esecuzione multiutente con numero utenti non predefinito. Ciascun utente ovviamente ha bisogno di un proprio carrello della spesa. Questo componente (ShoppingCart) deve sopravvivere tra una richiesta e l altra per questo è definito in uno scope session, cioè viene creato un carrello per ogni HTTP Session ed è valido durante tutta la sessione dell utente. Tutti gli altri bean sono definiti con scope singleton; significa che viene creata una sola istanza per container. Il problema è che i bean con scope singleton vengono configurati una sola volta al momento della creazione: il risultato è che ShoppingCartService opererà sempre sullo stesso ShoppingCart. Per risolvere il problema abbiamo wrappato il componente ShoppingCart in un proxy che espone la stessa interfaccia e lo abbiamo iniettato in ShoppingCartService al posto del vero ShoppingCart. Quando il servizio richiama un metodo di ShoppingCart, il proxy object recupera il vero target object dalla sessione HTTP e delega la chiamata ad esso. 3.3 Persistence Layer Il compito di questo layer è quello della gestione della persistenza su database. Vogliamo che la soluzione sia portabile verso diverse piattaforme. L accesso al database è incapsulato in un Data Access Object (DAO): attraverso l interfaccia BookDao, il Persistence Layer espone le proprie funzionalità alla business logic. L utilizzo dell interfaccia facilita il test del codice della business logic: gli unit test sono più veloci (possiamo usare implementazioni mock del DAO quindi non ci connettiamo al database) e evitiamo fallimenti dovuti all inconsistenza dei dati.

Inoltre l interfaccia espone solo i metodi di accesso ai dati: la scelta del meccanismo di persistenza rimane confinato al DAO, quindi possiamo in un secondo momento cambiare il framework di persistenza senza modificare la business logic. L attuale implementazione dell interfaccia utilizza il framework Hibernate per la gestione della persistenza. Estende la classe HibernateDaoSupport di Spring: in questo modo possiamo utilizzare il metodo gethibernatetemplate per ottenere un HibernateTemplate già configurato con cui eseguire le operazioni di persistenza senza preoccuparsi di gestire le sessioni e le eccezioni proprietarie di Hibernate. Per quanto riguarda la gestione degli errori di database a runtime, molte delle eccezioni sono causate da condizioni fatali cioè tali per cui, anche se le catturiamo in un blocco catch, non possiamo fare niente per risolvere il problema, risultando in un codice poco leggibile pieno di blocchi catch vuoti. La gerarchia di eccezioni di Spring ha radice in DataAccessException; la particolarità di questa eccezione è di essere unchecked cioè non siamo più obbligati a catturarla inutilmente. La data source è definita attraverso un driver JDBC perché semplice da configurare e utile in fase di sviluppo. Per un utilizzo reale, è meglio utilizzare una data source, recuperata attraverso JNDI, che ottiene le sue connessioni da un pool di connessioni. 3.3.1 Gestione transazioni Le transazioni sono definite in modo dichiarativo utilizzando Spring AOP. Mediante la programmazione ad aspetti possiamo disaccoppiare un operazione dalle politiche transazionali che la coinvolgono (per dettagli sulla configurazione, vedi appendice) Quando l utente conferma un ordine, il database deve essere aggiornato, sottraendo al numero delle copie presenti in magazzino la quantità di copie acquistate. L operazione è wrappata in una transazione perché se uno dei libri acquistati non è disponibile, l ordine viene annullato eseguendo il rollback degli aggiornamenti già effettuati e mostrando al cliente un messaggio di avvertimento. Per questo motivo l attributo propagation behavior della transazione è definito come PROPAGATION_REQUIRED: significa che il metodo deve essere eseguito in una transazione e se una transazione non è in corso, ne deve essere creata una nuova. L operazione di ricerca invece non comporta la modifica del database quindi è di tipo read-only e con propagazione PROPAGATION_SUPPORTS, cioè esegue in una transazione se ce n è una in corso, ma non deve necessariamente essere eseguita all interno di una transazione. Essendo in un contesto di esecuzione multiutente, occorre anche gestire accessi concorrenti. Nel caso di acquisti multipli, abbiamo più transazioni concorrenti che possono causare problemi di dirty reads; non abbiamo problemi di non-repeatable reads o phantom reads perché la transazione di acquisto non prevede letture consecutive delle stesse righe. Di conseguenza il livello di isolamento è configurato su ISOLATION_READ_COMMITTED, che permette letture tra transazioni concorrenti che sono state committed. Il livello di isolamento è tale da non limitare troppo la concorrenza. L operazione di ricerca invece è di sola lettura quindi possono essere eseguite più ricerche contemporaneamente senza causare modifiche inconsistenti al database. Il livello di isolamento è ISOLATION_READ_UNCOMMITTED.

4 Test con Spring Spring generalmente non è direttamente coinvolto nella fase di test perché le applicazioni che sfruttano la Dependency Injection di Spring, sono costituite da oggetti loosely coupled, che sono per loro natura più semplici da testare. Tuttavia ci sono punti in cui Spring partecipa attivamente nei test. Unit Testing di Spring MVC Controllers: un controller MVC in realtà non ha molto a che fare con il Web; infatti semplicemente prende un input (sottoforma di HttpServletRequest) e produce un output (sottoforma di un ModelAndView), ma non ha il compito di creare la pagina HTML. Per testare queste classi utilizziamo le implementazioni mock fornite da Spring di Request e Response (MockHttpServletRequest e MockHttpServletResponse). Inoltre, poiché non c è l ApplicationContext di Spring, gli eventuali riferimenti a servizi sono risolti utilizzando implementazioni mock create con EasyMock: con questo tool possiamo generare implementazioni mock delle interfacce on the fly e addestrarle a restituire un certo oggetto a seguito di una chiamata ad un certo metodo. Testing di flow definiti con Spring Web Flow: per testare l esecuzione di un flow, utilizziamo la classe AbstractXmlFlowExecutionTests di Spring Web Flow, un estensione di TestCase con assert specifici per verificare lo stato corrente di un flusso e per verificare la presenza e i valori di oggetti contenuti in uno degli scope del flow. Lo scopo di questi test è quello di verificare tutti i percorsi possibili del flow: in ogni test definiamo lo stato corrente del flow e utilizziamo la classe MockExternalContext per definire il contesto attuale di esecuzione, ad esempio per simulare la notifica di un evento, in modo da poter testare tutte le transazioni possibile di ogni stato. Per i necessari service object sono state definite implementazioni mock con EasyMock. Integration Testing di applicazioni Spring: La classe AbstractDependencyInjectionSpringContextTests è la classe base per fare test d integrazione dei componenti dell applicazione. Permette di caricare l ApplicationContext una volta sola per tutti i test definiti in quel testcase. Transactional Testing: per i test transazionali utilizziamo le classi: o AbstractTransactionalSpringContextTests o AbstractTransactionalDataSourceSpringContextTests Entrambe caricano il context di Spring per eseguire il wiring dei bean. In più hanno l'interessante caratteristica di eseguire il rollback di ogni operazione su database fatta nei test; in questo modo al termine dei test il database torna ad uno stato noto, pronto per il test successivo. L'unica differenza è che il secondo consente di interagire direttamente con il database tramite un JdbcTemplate. Conclusioni Il framework Spring consente di realizzare applicazioni enterprise modulari separando i vari layer di funzionalità. Grazie all uso di interfacce e al supporto alla Dependency Injection i componenti che abbiamo sviluppato sono loosely coupled, facilmente testabili e scalabili; inoltre tutti i componenti realizzati con Spring sono facilmente riutilizzabili perché sono semplici POJO in cui non abbiamo nessun riferimento alle API di Spring. Il supporto ad Aspect Oriented Programming consente di applicare servizi ortogonali all applicazione come transazioni e sicurezza in modo trasparente alla business logic.

Tuttavia queste sono solo alcune delle caratteristiche del framework. Spring ha molte altre funzionalità per affrontare e semplificare lo sviluppo di applicazioni enterprise: ad esempio supporta anche l accesso e la creazione di servizi remoti con le principali tecnologie di remoting (RMI, SOAP Web Services ) offrendo un sistema di fault-recovery, semplifica l utilizzo di Java Message System (JMS) per le comunicazioni asincrone tramite messaggi, supporta il lookup di oggetti da directory JNDI. Bibliografia [1] Understanding Inversion of Control e Dependency Injection (http://martinfowler.com/bliki/inversionofcontrol.html, http://martinfowler.com/articles/injection.html) [2] C. Walls, R. Breidenbach, Spring in Action,2 nd Edition, Manning, 2008 [3] Spring Framework (http://www.springsource.com) [4] Hibernate (www.hibernate.org)

Appendice A Spring AOP I cross-cutting concerns sono modularizzati in speciali oggetti chiamati aspect. Un aspect è definito in termini di: advice: definisce il cosa (cioè il compito) e il quando (cioè quando applicare, ad es. prima o dopo un metodo) di un aspect joinpoint: è un punto nel flusso di esecuzione dell applicazione in cui un aspect può essere applicato (ad es. il lancio di un eccezione, l invocazione di un metodo ). pointcut: definisce il dove cioè in quali joinpoint applicare l aspect L AOP di Spring è proxy-based cioè gli aspect vengono applicati a runtime, wrappando il target bean in una classe proxy. Gli oggetti che dipendono dal target object non notano nessuna differenza tra l oggetto originale (pre-aop) e il proxy (post-aop) quindi non devono essere modificati per supportare il proxy. La classe proxy intercetta le invocazioni dei metodi definiti nei pointcut, esegue la logica dell aspect (che è definita nell advice) e poi inoltra le chiamate al target object. Poiché è basato su proxy dinamici, il supporto all AOP di Spring è limitato all intercettazione dell invocazione di metodi (method joinpoint), mentre non sono esposti joinpoint a livello di costruttori o di proprietà (constructor e field joinpoint) come avviene con altri framework come JBoss AOP e AspectJ. In ogni caso, qualora l intercettazione dei soli metodi non sia sufficiente, Spring AOP consente di utilizzare AspectJ, avvantaggiandosi del suo supporto a constructor joinpoint e classload time weaving. Il modo più semplice di definire advice e pointcut è utilizzare i nuovi elementi di configurazione di Spring AOP: attraverso questi elementi possiamo trasformare un semplice POJO in un aspect dichiarativamente nell ApplicationContext di Spring, ma la classe rimane comunque un POJO, non c è niente che indichi che debba essere utilizzato come aspect. Spring permette di utilizzare anche annotazioni @AspectJ, ma l utilizzo degli elementi di configurazione ha il vantaggio di non richiedere il codice sorgente della classe e di raccogliere tutte le informazioni sugli aspect in un unico file di configurazione. L elemento radice è <aop:config> che può contenere uno o più elementi <aop:advisor>, <aop:aspect> e <aop:pointcut>. Esempio: <bean id= logger class= it.loggerimpl > <bean id= securitychecker class= it.securitycheckerimpl > <aop:config> <aop:aspect ref= logger > <aop:after-returning method= log pointcut= execution(* *.getbooks(..)) /> </aop:aspect> <aop:aspect ref= securitychecker > <aop:before method= checkcredentials pointcut= execution(* *.savebooks(..)) /> </aop:aspect> </aop:config>

All interno dell elemento <aop:aspect> indichiamo il riferimento al POJO bean che deve essere trattato come aspect e definiamo gli advice, che sono di 5 tipi a seconda di quando vogliamo che il metodo sia invocato: <aop:before>: applica l advice prima dell esecuzione di un metodo <aop:after>: applica l advice quando il metodo termina, con successo o meno <aop:after-returning>: applica l advice quando il metodo ritorna <aop:after-throwing>: applica l advice a seguito di un eccezione <aop:around>: include il comportamento di tutti i precedenti advice L elemento <aop:pointcut> è usato per definire un pointcut che può essere riferito in più elementi advice, anche di aspect diversi: è utile per evitare codice duplicato quando più metodi devono essere invocati sullo stesso pointcut. Appendice B Spring MVC Tutte le pagine JSP sono contenute nella directory WEB-INF/jsp. Questo assicura che le view siano accedibili solo attraverso i controller, visto che non è possibile accedere a queste pagine attraverso un URL. Inoltre per disaccoppiare la view dal controller, si utilizzano dei nomi logici invece del percorso completo alla pagina JSP: basta configurare il ViewResolver con un prefisso (percorso alla cartella contenente tutte le JSP) ed un suffisso (l estensione). In questo modo, per riferirci ad esempio alla homepage, utilizziamo il nome logico home, invece del percorso completo /WEB- INF/jsp/home.jsp. Spring MVC rende disponibili varie implementazioni di controller, a seconda delle funzionalità di cui abbiamo bisogno. I più semplici sono i controller di tipo view che possono solo visualizzare una view statica (ParameterizableViewController, UrlFilenameViewController). AbstractController invece permette di inserire dati nel model ed è quindi adatto a casi in cui si vuole solo visualizzare dei dati recuperati da un database. Generalmente però una HTTP request contiene dei parametri che devono essere usati per determinare i risultati; tali parametri devono essere validati e legati ad un oggetto chiamato Command Object o Form Backing Object. Un Command Object è un bean destinato a contenere i parametri della richiesta per un accesso più semplice. I precedenti controller possono essere estesi per includere tali funzionalità, ma un controller non dovrebbe contenere la logica di binding e di validazione. Spring ci viene incontro con AbstractCommandController: questo tipo di controller esegue automaticamente il binding tra i parametri della richiesta e il Command Object, e può essere configurato per eseguire anche la validazione. Nel costruttore del controller dobbiamo definire la classe del Command Object che deve gestire; prima di chiamare il controller, Spring tenterà di eseguire un match tra i parametri della richiesta e le proprietà del Command Object (es. i campi author o title di un oggetto Search che memorizza le chiavi di ricerca di una form per cercare libri in un database). Quando l utente esegue il submit di una form, i dati inseriti vengono inviati al server per essere elaborati; al termine viene visualizzata la pagina di successo oppure la form stessa con gli errori da correggere. Potremmo pensare di usare un AbstractCommandController per elaborare input da form, ma dovremmo usare anche un AbstractController per visualizzare la form. Spring MVC fornisce un altra implementazione di controller che ingloba questo comportamento, chiamata SimpleFormController. Un form controller può sia visualizzare la form a seguito di una

HTTP GET request che elaborare la form quando riceve una HTTP POST request. Inoltre, in caso di valori non validi, il controller sa che deve visualizzare nuovamente la form per permettere la correzione. Una differenza rispetto agli altri controller è che il form controller è progettato per mantenere i dettagli delle view (quella della form e quella di successo) e dei validatori al di fuori del controller stesso. Il controller infatti viene configurato direttamente nell application context di Spring. Per quanto riguarda la validazione, Spring mette a disposizione un interfaccia Validator che richiede di implementare il metodo validate(); al momento del submit della form, il framework esegue il binding dei campi della form con il Command Object definito nel form controller e poi chiama il metodo validate() passando come parametro il Command Object stesso e un oggetto Errors per contenere eventuali errori. Il metodo deve validare tutte le proprietà dell oggetto e rifiutare i valori invalidi. Questo tipo di validazione è utile in casi complessi in cui occorre una logica specifica per gestirla, ma in casi semplici potrebbe essere meglio validare i Command Object dichiarativamente attraverso delle regole poste in un file XML (come avviene con Jakarta Struts). Spring non prevede questo tipo di validatori, ma esiste il progetto Spring Modules che estende le funzionalità di Spring, aggiungendo anche un modulo di validazione che utilizza Jakarta Commons Validator, proprio come Struts (quindi i file XML di configurazione sono identici). Nel caso in cui la form è strutturata in sottosezioni e si sviluppa in più pagine (es. registrazione di un nuovo utente), possiamo usare un AbstractWizardFormController. Anche questo form controller deve essere configurato nell application context di Spring, indicando i nomi logici delle view che compongono la form. L ordine viene stabilito inserendo un parametro nella request chiamato _target# (dove # è il numero della view nella lista): il metodo gettargetpage() del controller rimuove il prefisso _target e ottiene così l indice nella lista della pagina successiva. Quando l ultima pagina della form viene completata dall utente, basta inserire un parametro di nome _finish nella request per avvertire il controller di finalizzare la form. Invece per annullare la compilazione, si deve inserire nella request un parametro di nome _cancel. Anche in questo caso è possibile validare i campi della form, l unica differenza è che viene validata una pagina alla volta, quindi il controller non può chiamare il metodo validate(). Il wizard controller invece offre il metodo validatepage(#) (# è il numero della pagina) che specifica l indice dalla pagina corrente da validare. A questo punto possiamo scegliere se validare direttamente nel controller o se delegare comunque ad un implementazione di Validator (preferibile se la validazione è complessa). Appendice C Spring Web Flow Un flow incapsula una sequenza riutilizzabile di passi che può essere eseguita in contesti diversi. Gli stati sono punti del flow dove ha luogo qualche azione, sia da parte dell'applicazione (Action State), sia da parte dell'utente (View State). L ingresso in un View State, comporta la visualizzazione di una view all utente. Interagendo con la view, l utente genera degli eventi che vengono gestiti dallo stato corrente del flow; tali eventi possono innescare delle transizioni verso altri stati, risultando nella navigazione tra pagine web diverse. Ci sono vari tipi di stato: Action State: stati dove è eseguita la logica del flow (es. elaborazione dei dati inseriti dall utente, interazione con il Service Layer) Decision State: permettono di selezionare cammini diversi all interno di un flow End State: stato finale di un flow; possono essere definiti end state multipli, ciascuno rappresentante una diversa situazione finale (successo, errore )

Subflow State: inizia un subflow all'interno del contesto del flow in esecuzione; consente il riutilizzo di flow (es. subflow per aggiungere un oggetto al carrello ) View State: punti del flow in cui viene visualizzata una view ed è richiesta l interazione dell utente Un flusso è composto principalmente di View State e Action State che rappresentano i due lati della conversazione tra utente e applicazione. FlowRegistry assegna ad ogni flow un identificatore uguale al nome del file troncato dell'estensione; questo è l identificatore che dobbiamo usare per richiamare un flow attraverso un URL. Quando un flow viene iniziato, viene inserita una Flow Execution Key nei parametri della request; questa chiave è indicata con il parametro execution=e#s#, dove e# è l executionid e s# è lo snapshotid (ad ogni transizione in un View State, viene preso uno snapshot dello stato di esecuzione per supportare backtracking). Quindi se la request contiene questo parametro, significa che un flow è già stato iniziato e il FlowHandler ne riprende l esecuzione. I flow sono identificati attraverso un parametro _flowid; generalmente è derivato dalla proprietà PathInfo della HTTP request (es. https://localhost:8443/bookshop/buybooks.htm risulta nel flow id buybooks, a patto ovviamente che buybook.htm sia mappato sul FlowController) ma può essere anche indicato come parametro della request. Quando un flow entra in un View State, redireziona l utente al relativo execution URL e attende un evento scatenato dall utente per riprendere l esecuzione. Gli eventi generalmente sono generati attivando bottoni o link; l utente, cliccando su comandi dell interfaccia, invia una HTTP request al server contenente un parametro _eventid che indica il nome dell evento scatenato. Spring Web Flow estrae _eventid ed esegue la transizione corrispondente definita nello stato corrente. Tutte le eccezioni non gestite vengono propagate fino alla DispatcherServlet, a meno che l eccezione non sia una NoSuchFlowExecutionException, nel qual caso l handler cerca di recuperare dall eccezione eseguendo nuovamente il flow Il framework Spring permette di definire anche lo scope di un bean; lo scope determina la disponibilità di un istanza del bean (ad es. scope singleton significa che Spring crea una sola istanza del bean nell Application Context, invece scope session significa che un bean è valido per tutto il ciclo di vita di una HTTP Session) Spring Web Flow definisce 5 scope aggiuntivi per memorizzare dati relativi alla conversazione: Flow Scope: allocato all avvio del flow e distrutto al suo termine View Scope: allocato quando si entra in un View State e distrutto all uscita da questo stato Request Scope: allocato quando il flow è chiamato e distrutto quando il flow ritorna Flash Scope: allocato all avvio del flow, re-inizializzato ad ogni View State e distrutto al termine del flow Conversation Scope: allocato all avvio del flow e distrutto al suo termine, condiviso con tutti i subflow Possiamo dichiarare un Command Object per una view attraverso l attributo model del View State; al momento del submit della form, l engine di Spring Web Flow esegue automaticamente il binding e la validazione delle proprietà dell oggetto. Il model può essere un oggetto presente in un qualsiasi scope accessibile (es. Flow Scope, View Scope ).

Il binding deve avere successo affinché la transizione associata all evento sia eseguita; se il binding fallisce, la view viene nuovamente visualizzata evidenziando gli errori per permettere all utente di correggerli. Per eseguire la validazione automaticamente, basta definire un bean nell Application Context il cui nome rispetta il pattern ${model}validator e che implementi i metodi validate${state}, dove ${state} indica l id del View State che vogliamo validare. E possibile definire transizioni globali cioè valide per tutti i View State del flow, utile ad esempio per collegamenti presenti in tutte le view come login o logout. L ereditarietà tra flow permette di ereditare la configurazione di un altro flow; è utile ad esempio per definire transizioni globali e gestori delle eccezioni che coinvolgono tutti i flow. E simile all ereditarietà di Java nel senso che gli elementi definiti nel flow padre sono disponibili anche ai flow figli, ma in questo caso non è permesso l override degli elementi del padre ed inoltre è ammessa l ereditarietà multipla. Spring Web Flow dispone di una sintassi concisa per invocare azioni all interno dei flow utilizzando un Expression Language (EL), con supporto sia a OGNL che Unified EL; si può accedere a dati inviati dal client (es. parametri della request), accedere alle strutture interne (es. flowscope), oppure invocare metodi sui bean definiti nel context di Spring. Le strutture dati di un flow possono essere accedute anche all interno delle view, sempre utilizzando EL (ad esempio per visualizzare i risultati di una query). Appendice D Spring DAO e Spring ORM Spring fornisce diversi template per supportare piattaforme diverse di persistenza; in più offre un insieme di classi DAO di supporto che possono gestire il template per noi; basta estendere queste classi per avere subito accesso al template, senza bisogno di configurazioni aggiuntive. La classe HibernateTemplate di Spring costituisce un astrazione dell interfaccia Session di Hibernate; il suo compito è quello di semplificare l apertura e la chiusura delle sessioni e di convertire le eccezioni specifiche di Hibernate nelle eccezioni di Spring. LocalSessionFactoryBean è una factory che produce istanze di SessionFactory; ha una proprietà mappingresources che prende una lista di uno o più percorsi a file XML di mapping. La proprietà hibernateproperties invece consente di configurare le sessioni: dobbiamo almeno specificare, in base al database che utilizziamo, la Hibernate dialect che indica a Hibernate come costruire le query SQL. Possiamo lasciare la dialect come una variabile placeholder in modo da poterla configurare attraverso un file di proprietà. Spring offre anche una classe DAO di supporto, HibernateDaoSupport, che fornisce un template già configurato. Il problema nell usare il template è che la classe DAO risulta legata alle API di Spring. Hibernate 3 ha introdotto le Contextual Sessions dove il framework stesso si occupa di gestire una Session per ogni transazione. Invece di definire un HibernateTemplate, possiamo allora definire un riferimento ad una SessionFactory; per eseguire le operazioni, chiediamo alla SessionFactory di restituirci la sessione corrente. In questo modo il DAO non dipende più da Spring poiché SessionFactory fa parte delle API di Hibernate. Tuttavia lo svantaggio è che le contextual sessions lanciano le eccezioni proprietarie di Hibernate.

5 Appendice E Configurazione delle transazioni Spring fornisce nuovi elementi di configurazione specifici per dichiarare transazioni. Il principale elemento è <tx:advice> che permette di definire le politiche transazionali per uno o più metodi. Il pointcut è definito come advisor usando l elemento <aop:config>. La nostra applicazione ha la seguente configurazione: <aop:config> <aop:advisor pointcut="execution(* *..BookDao.*(..))" advice-ref="txadvice" /> </aop:config> <tx:advice id="txadvice"> <tx:attributes> <tx:method name="save*" propagation="required" isolation= READ_COMMITTED /> <tx:method name="update*" propagation="required" isolation= READ_COMMITTED /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> Il pointcut definisce che tutti i metodi dell interfaccia BookDao sono considerati joinpoint; nell advice poi si divide i metodi in 3 gruppi: quelli che iniziano con save (savebook, savebooks), quelli che iniziano con update e tutti gli altri metodi. I primi due gruppi sono definiti con PROPAGATION_REQUIRED e ISOLATION_READ_COMMITTED. Gli altri metodi sono di sola lettura e hanno PROPAGATION_SUPPORTS, cioè possono essere eseguiti in una transazione ma non lo richiedono. Per abilitare il supporto alle transazioni in Spring è necessario definire un Transaction Manager; poiché utilizziamo Hibernate con framework di persistenza, dobbiamo dichiarare un bean HibernateTransactionManager nell ApplicationContext. Questo bean delega la responsabilità della gestione delle transazioni ad un oggetto org.hibernate.transaction recuperato dalla sessione Hibernate. Quando una transazione è completata con successo, HibernateTransactionManager chiama il metodo commit() di Transaction, quando fallisce invece invoca il metodo rollback(). Per convenzione il bean deve avere id transactionmanager. Appendice F Gestione della Sicurezza La sicurezza è gestita dal modulo Acegi Security. Acegi funziona come un request filter che intercetta ogni richiesta prima che arrivi alla DispatcherServlet. Il supporto di Acegi Security alla sicurezza web è basato su "servlet filters". I principali filtri utilizzati da questa applicazione sono: 1. HttpSessionContextIntegrationFilter: ha il compito di ricordare un utente autenticato attraverso più richieste, verificando la presenza di informazioni di autenticazione nella Sessione 2. AuthenticationProcessingFilter: definisce un entry point in cui l utente può fornire le sue credenziali (la pagina di login); inoltre verifica le credenziali con quelle memorizzate su un database. Se l autenticazione ha successo, memorizza nella HTTP Session un oggetto di autenticazione e redireziona l utente verso la pagina richiesta. 3. AnonymousProcessingFilter: permette di accedere ad alcune pagine anche se non si è autenticati (ad es. la pagina di login deve essere accedibile da chiunque)

4. ExceptionTranslationFilter: cattura le eccezioni lanciate da FilterSecurityInterceptor. In caso di AuthenticationException (le credenziali fornite sono errate) il questo filtro redireziona l utente verso l entry point; invece in caso di AccessDeniedException (privilegi insufficienti per accedere alla risorsa richiesta) mostra una pagina di errore. 5. FilterSecurityInterceptor: gestisce l intercettazione delle richieste, definisce quali risorse devono essere protette e quali privilegi sono richiesti per accedervi e lancia eventuali eccezioni in caso di errore L'ordine dei filtri è importante: alcuni filtri assumono che certi processi di sicurezza siano stati eseguiti prima di loro; se sono configurati fuori ordine, si generano conflitti tra filtri. Allo scopo di utilizzare questi filtri, è necessario definire nel file di configurazione il bean FilterToBeanProxy; questo bean è una speciale servlet che delega il proprio lavoro a uno dei filtri elencati sopra. Tuttavia in questo modo si deve aggiungere un FilterToBeanProxy per ogni filtro; invece possiamo utilizzare FilterChainProxy che è un'implementazione di javax.servlet.filter che può essere configurato per concatenare più filtri alla volta; FilterToBeanProxy intercetta la richiesta dal cliente e la invia a FilterChainProxy il quale a sua volta passa la richiesta in ordine ai filtri configurati nell'applicationcontext. Acegi Security mette a disposizione una tag library che consente di gestire la sicurezza al livello di view. Per utilizzare questi tag in una pagina JSP, occorre importare la libreria usando la direttiva taglib: <%@ taglib prefix="authz" uri="http://acegisecurity.org/authz" %> Il principale tag è <authz:authorize> che condiziona il rendering del contenuto di questo tag ai privilegi dell utente. Ad esempio, nella nostra applicazione, il collegamento alla pagina di acquisto viene mostrato solo se l utente autenticato ha ruolo ROLE_USER: <authz:authorize ifanygranted="role_user"> <a href="<c:url value="/buybooks.htm"/>"><fmt:message key="buy" /></a> </authz:authorize> Invece il collegamento alla pagina di login è mostrato solo se l utente non si è autenticato con almeno uno dei ruoli previsti; allo stesso modo il link di logoff è attivo solo se l utente si è già autenticato: <authz:authorize ifnotgranted="role_user,role_admin"> <a href="<c:url value="/login.htm"/>">login</a> ] </authz:authorize> <authz:authorize ifanygranted="role_user,role_admin"> <a href="j_acegi_logout">logoff</a> ] </authz:authorize> Un altro utile tag è <authz:authentication> che permette di visualizzare informazioni sull utente. Il tag visualizza proprietà dell oggetto ottenuto attraverso Autherntication.getPrincipal(): <authz:authorize ifanygranted="role_user,role_admin"> <authz:authentication operation="username"/> </authz:authorize> L attributo operation definisce il metodo getter che deve essere invocato; in questo caso visualizziamo lo username dell utente.