JSF Basics: il Lifecycle

Le attuali web application vengono spesso progettate basandosi sul pattern architetturale MVC (Model-View-Controller), grazie al quale è stato introdotto il concetto di disaccoppiamento fra i livelli seguenti:

  • interfaccia utente, detta anche vista o livello di presentation, comprendente anche uno strato che funziona da middleware fra la pagina e lo strato successivo;
  • business logic, cioè la parte in cui si implementano le funzionalità più interne dell’applicativo, come logiche di calcolo, richiesta/salvataggio dati;
  • strato di persistenza, cioè quello con cui si interfaccia la business logic e che gestisce le interazioni, dirette o meno, con il DB.

Limitando il nostro interesse all’implementazione della view e “javologicamente” parlando, negli ultimi anni siamo passati dall’utilizzo delle JavaServer Pages (in cui potevamo anche trovare mescolati HTML e implementazione del codice) a quello delle JavaServer Faces: queste ultime garantiscono una netta distinzione fra presentation e quella logica Java che definisce il comportamento “superficiale” dell’applicazione a seguito di un’interazione da parte dell’utente; il benificio primario che si ottiene è uno sviluppo più easy e modulare.

Cerchiamo ora di capire in maniera quantomeno basilare come il framework JSF interpreti ed esegua le azioni richieste dall’utente. La novità fondamentale è l’introduzione del concetto di ciclo di vita (o lifecycle, che fa molto più cool), la cui comprensione è più che una mera disquisizione teorica: avere ben presenti le varie fasi ci aiuterà molto nello sviluppo sia del codice Java che della view, come vedremo nei futuri post al riguardo.
In sostanza, il “percorso” request – response viene diviso in più step, come è possibile vedere nella figura sottostante (l’attributo “immediate” che vedete citato nell’immagine sarà oggetto di un post a parte, in quanto paragonabile, almeno inizialmente, ad uno dei misteri di Lourdes!).

Analizziamo ora le varie fasi:

  • Restore View: consiste nella costruzione di un “albero di componenti” che rappresenta l’alter-ego Java dei tag che utilizzeremo nella nostra pagina (siano essi campi di input, di output o altro); ogni volta che viene eseguita una richiesta iniziale (cioè l’ingresso iniziale in una pagina, senza inserimento di dati) o una richiesta postback (cioè la submit di una form, con l’invio di dati al server), il framework JSF si costruisce la propria struttura in memoria.
    La differenza fra le due richieste è che, in quella iniziale, si passa direttamente all’ultima fase in quanto nessun dato è stato inviato ancora al server, mentre nel secondo caso vengono eseguite (ma non necessariamente) tutte le fasi;

  • Apply Request Values: in questa fase, i valori inseriti dall’utente nei campi della form vengono inclusi all’interno dell’albero JSF a cui accennavamo prima. I dati sono ancora da considerare submitted values, cioè inviati al server sotto forma di semplici stringhe,ma non memorizzati all’interno degli attributi del backing bean (che potrebbero avere un tipo diverso da String e quindi necessitano di una “trasformazione”)

  • Process Validation: I submitted values sono ora sottoposti alla cosiddetta conversione: le stringhe contenute all’interno dei componenti JSF sono trasformate nei tipi caratterizzanti i campi del backing bean che sono legati agli input JSF.
    Per esempio, se abbiamo un input che è legato ad un field Integer sul backing bean, la conversione cercherà di trasformare quel che abbiamo inserito nel campo in un numero; chiaramente, se abbiamo inserito una parola, essa non potrà essere convertita correttamente e verrà sollevata una ConverterException, causando un salto diretto all’ultima fase. La conversione viene effettuata per ogni componente che sia dotato di un converter: è quindi possibile che siano mostrati contemporaneamente più errori (uno per ogni campo che non ha superato la conversione).
    I dati convertiti vengono quindi sottoposti alla validazione, cioè viene controllato che rispettino le regole che sono state imposte sui campi (tramite l’uso di validatori già presenti nel framework oppure tramite quelli custom implementati dallo sviluppatore… ma questo sarà argomento di un altro post!); un esempio di validazione è controllare se il numero di caratteri è maggiore o minore di X oppure se rispetta condizioni particolari rispetto agli altri campi (cross-validation).
    Anche in questa caso è possibile che vengano sollevate eccezioni (di tipo ValidatorException), la cui notifica, come nel caso della conversione, viene riportata in vista tramite il passaggio diretto all’ultima fase;

  • Update Model Values: ora i dati vengono realmente scritti all’interno dei campi della classe Java che svolge il ruolo di backing bean, in quanto hanno superato tutti i controlli, siano essi customizzati o no;

  • Invoke Application: vengono eseguite tutti gli ActionListener o Action associati ai vari componenti; infatti la submit può essere caratterizzata dall’esecuzione di questi metodi che possono operare sui valori salvati nel backing bean. Essi possono restituire una stringa utilizzabile per la navigazione ad un’altra pagina oppure il valore null o anche non restituire niente (cioè hanno void come “tipo” restituito), così da far rimanere l’utente nella pagina corrente. Da ricordare fin da ora che è possibile associare ad un componente più di un ActionListener: è garantito che essi vengano eseguiti prima della Action specificata, ma NON è garantito l’ordine di esecuzione fra di loro (in poche parole, non ci illudiamo che vengano eseguiti nell’ordine in cui li abbiamo inclusi all’interno del tag del componente!)

  • Render Response: viene eseguito il refresh della vista, con l’aggiornamento dei valori contenuti nell’albero JSF sulla base dei field del backing bean.

Le implementazioni di JSF (come Mojarra o MyFaces, infatti è bene ricordare che JSF è una specifica) possono essere integrate anche da altri framework come Richfaces, che apportano anche l’utilizzo di funzionalità AJAX (Asynchronous JavaScript And XML) per l’update di alcune parti della pagina (anche se le nuove JSF 2.0 prevedono già l’importazione di tali caratteristiche)… ma questa è un’altra storia di cui parleremo!

Gabriele Biagiotti

Sviluppo da circa tre anni in Java e da quasi due anni presso OmniaGroup (di cui sono Senior Developer) focalizzando il mio operato su progetti mission critical di applicazioni J2EE per CoopItalia. Grazie a questo, ho potuto affinare le mie conoscenze relativamente a IBM WebSphere AS 6.1/7.0,JSF, RichFaces, JPA (precisamente l'implementazione EclipseLink), EJB 2.1/3.0, JavaScript e CSS. Il mio IDE di riferimento è attualmente IBM Rational Application Developer, ma ho utilizzato anche NetBeans e Eclipse