JSF non è né il primo né l‘unico web framework Java EE. Può quindi sorgere la necessità di integrare JSF in applicazioni esistenti e magari sviluppate con altri framework. In questo articolo affrontiamo alcuni aspetti di questa integrazione.
Introduzione
Nei precedenti articoli abbiamo esaminato molti degli aspetti principali di JSF: la sua architettura a componenti ed eventi, i convertitori e i validatori, il ciclo di vita delle richieste… insomma tutto quello che fa di JSF un’ottima scelta come framework per lo sviluppo di applicazioni web J2EE. Per un progetto che nasce oggi, sicuramente JSF è la scelta consigliata per la parte di interfaccia grafica e di controllo di flusso dell’applicazione, nche perch� è una specifica entrata a far parte dello standard Java EE.
Ma il mondo ovviamente non è nato con JSF… Prima di JSF sono stati sviluppati numerosi altri framework utilizzati per lo sviluppo. Basti ricordare Jakarta Struts, leader indiscusso tra i framework MVC.
Nel caso in cui si vogliano sviluppare nuove funzionalità di un’applicazione esistente o utilizzare in essa alcune delle caratteristiche di JSF, ci si trova di fronte al problema di come integrare JSF con la propria applicazione.
Passare a JSF è senz’altro una scelta appropriata per una applicazione da sviluppare da zero, ma può essere anche utile ad esempio utilizzare i componenti UI di JSF in un’applicazione esistente.
L’integrazione di JSF non si limita al solo layer di presentation ma può sorgere la necessità di far interagire JSF con framework che indirizzano lo sviluppo di altri layer applicativi.
Le possibilità di integrazione di JSF con altre applicazioni e con altri framework è piuttosto variegata e complessa visto che gli scenari possibili sono numerosi. Cercheremo quindi di fornire qualche spunto che possa facilitare l’approccio al problema.
Richieste e risposte Faces e Non Faces
Per affrontare nell’ottica corretta il problema dell’integrazione di JSF bisogna partire da un assunto fondamentale che per certi limiti è ovvio ma può forse sfuggire a chi non ha esperienza nello sviluppo web Java EE. JSF non è altro che un’applicazione web strutturata secondo il pattern MVC e che ha una servlet fondamentale di controllo, la FacesServlet. Come è noto, in un’applicazione web possono coesistere quante servlet vogliamo, quindi se vediamo JSF semplicemente come una nuova servlet della nostra applicazione capiamo che l’integrazione non è poi così complicata.
Ovviamente questa osservazione è molto semplicistica ma ci fa capire che seppure noi vediamo JSF sotto forma di componenti di interfaccia, managed-beans e custom-tags, in realtà il tutto è una comune applicazione web J2EE in cui il livello di astrazione è stato spinto più in alto rispetto ad altri framework, quali ad esempio Struts, così da mascherare allo sviluppatore il meccanismo richiesta risposta che è comunque gestito dalla servlet di controllo di JSF.
In linea teorica, quindi, si può affermare che un gestore di eventi di JSF può accedere a un qualsiasi oggetto della propria applicazione messo in uno scope opportuno così come un managed-bean può essere reperito dalle servlet e dalle JSP della propria applicazione.
Questo per dire quindi che JSF non è un qualcosa che ha vita a se stante e che non può essere inserito in una applicazione web esistente.
Se in un’applicazione web esistente, sviluppata in qualsiasi modo, si vuole aggiungere una nuova funzionalità e questa la si vuole sviluppare con JSF, non c’è alcun problema. Si aggiunge la definizione della servlet di JSF nel web.xml, si aggiungono le librerie di JSF nella /WEB-INF/lib e il gioco è fatto. In base a quanto detto prima, è possibile rendere visibili a questa nuova funzione oggetti dell’applicazione esistente in quanto JSF può accedere ai contesti standard di una applicazione web, e la stessa applicazione può avere visibilità degli oggetti gestiti da JSF.
Per comprendere però le interazioni che possono avvenire tra un’applicazione JSF e una non JSF bisogna sempre tenere a mente il ciclo di vita delle richieste JSF che costituisce il riferimento essenziale per comprendere come il framework gestisca una richiesta HTTP. L’argomento è stato trattato in [7] e quindi non ci torneremo sopra, però è interessante capire cosa accade quando una richiesta proviene da un’applicazione non JSF oppure cosa accade quando il controller di JSF invia una risposta non di tipo JSF.
A tale scopo si definiscono quattro tipi di richiesta e risposta come segue:
- Faces Response. Una servlet-response generata dalla fase Render Response del ciclo di vita di elaborazione delle richieste di JSF.
- Non-Faces Response. Una servlet-response non generata dalla fase Render Response del ciclo di vita di elaborazione delle richieste di JSF. Ad esempio una risposta generata da una comune Servlet o da un JSP che non contiene componenti JSF.
- Faces Request. Una servlet-request inviata da una Faces Response generata in precedenza. Ad esempio un submit di un form generato da un componente in una pagina JSF.
- Non-Faces Request. Una servlet-request inviata non al controller di JSF ma a un componente qualsiasi di un’applicazione quale una servlet o un pagina JSP.
Chiarite queste definizioni, occorre esaminare cosa accade quando si verificano le combinazioni di queste quattro tipologie di richiesta e risposta; ne consegue un diverso comportamento per quel che riguarda le fasi del ciclo di elaborazione delle richieste di JSF.
Su due delle casistiche possibili c’è ben poco da dire . Nel caso in cui vi sia una Faces Request che genera un Faces Response, vale quanto è stato detto nella discussione sul ciclo di vita delle richieste [7] poich� siamo nel caso di una applicazione JSF non integrata con altre applicazioni.
Nel caso invece di una Non Faces Request che genera una Non Faces Response c’è ancora meno da dire poich� è il caso in cui JSF non c’entra proprio nulla. Si tratta di un’applicazione in cui JSF semplicemente non esiste.
I casi di interazione tra applicazioni JSF e applicazioni non JSF ricadono invece nelle due casistiche seguenti.
Un caso molto comune è quello in cui una Non Faces Request genera una Faces Response. È il caso ad esempio in cui con un link da una pagina JSP della nostra applicazione non sviluppata con JSF invochiamo una risorsa sotto il controllo della servlet di controllo di JSF. Ad esempio da una comune pagina JSP potremmo fare un link a un’altra pagina che contiene componenti JSF.
È evidente che in questo caso la richiesta che arriva alla FacesServlet provoca l’esecuzione della fase di Restore View in quanto il framework deve costruire l’albero di componenti contenuti nella vista che deve essere presentata all’utente. Essendo la prima richiesta a questa pagina il ciclo passa poi alla fase di Render Response in cui la vista viene renderizzata e inviata all’utente.
Come si vede questo scenario non presenta particolari criticità nè difficoltà di comprensione. Se da una risorsa non JSF invoco una risorsa JSF, la servlet di controllo di JSF gestisce questa richiesta allo stesso modo in cui farebbe se la risorsa fosse invocata la prima volta in una normale applicazione JSF.
L’altra casistica è quella in cui una Faces Request genera una Non Faces Response. In questa casistica rientrano i casi in cui si vuole redirigere il flusso applicativo verso una risorsa non gestita da faces oppure quando si vuole ad esempio inviare uno stream di byte al client, ad esempio nel caso di un download di un documento. Anche questo caso è concettualmente molto semplice. Il ciclo di vita della richiesta è completo tranne per il fatto che la fase di Render Response viene saltata. Un’ottima discussione delle varie casistiche è reperibile in [2].
La discussione fatta ci fa comprendere come in realtà JSF si possa inserire in applicazioni esistenti senza particolari problemi purch� si tenga sempre ben a mente come viene elaborata una richiesta sotto il controllo della Faces Servlet [7].
Posso quindi avere un’applicazione sviluppata ad esempio interamente con Struts alla quale oggi voglio aggiungere una funzionalità sviluppata con JSF. Nulla di più semplice, avrò due controller, uno per la parte realizzata con Struts e uno per la parte realizzata con JSF.
Questo vale se le funzionalità sono distinte e separate ed hanno interazioni limitate a link nelle pagine che chiamano reciprocamente le funzioni sotto il controllo dell’uno o dell’altro controller.
Diverso è l’approccio se invece di aggiungere funzionalità voglio modificare in qualche modo quelle esistenti per sfruttare alcune delle caratteristiche di JSF. Qui la scelta è più complessa anche se abbiamo qualche strumento che ci viene in aiuto.
Struts, JSF o tutti e due?
Come abbiamo già accennato, prima che venisse alla luce JSF, le applicazioni web esistevano già da molti anni e funzionavano bene lo stesso! A farla da padrone incontrastato nel mondo dei web fameworks MVC era, e forse lo è ancora oggi, Jakarta Struts. Di Jakarta Struts abbiamo già svelato molti dei segreti nella serie iniziata in [6], ma vale la pena ricordare che la sua maturità, la sua vasta adozione e l’innumerevole documentazione esistente ne hanno fatto per lungo tempo la scelta preferita di milioni di sviluppatori. JSF, come ben sappiamo, si sovrappone a Struts per alcune funzionalità migliorandone alcune ma lasciandole meno complete delle altre.
La domanda di fondo potrebbe quindi essere: continuo a sviluppare le mie applicazioni con Struts o passo completamente a JSF? La risposta richiederebbe una discussione molto approfondita per poter fare un confronto serio tra i due framework.
Come dicevo per applicazioni nuove di zecca il mio consiglio è passare a JSF, non perch� il buon vecchio Struts non sia una buona scelta, ma per una serie di motivi tra i quali uno non trascurabile è che JSF è ora uno standard Java EE; sarà quindi mantenuto e sviluppato nel futuro e, cosa molto importante, ha un modello vincente dal punto di vista della rapidità di sviluppo, aspetto decisivo nella realizzazione di progetti e reali e da sempre nota dolente nel mondo Java EE.
La domanda invece da farsi è se è lecito riscrivere le proprie applicazioni esistenti e pensare a una migrazione verso JSF.
È a mio parere una scelta folle mettersi a riscrivere applicazioni stabili, ben fatte e funzionanti in produzione per il solo desiderio di un aggiornamento tecnologico fine a se stesso. La risposta è quindi sicuramente no. In particolari situazioni si può però pensare di voler utilizzare alcune delle caratteristiche di JSF in un’applicazione Struts senza però doverla riscrivere pesantemente e soprattutto lasciando inalterato tutto il layer di business logic che è il vero valore aggiunto dell’applicazione.
Questa operazione è possibile grazie a una libreria denominata Struts-faces che è nata proprio allo scopo di rendere possibile l’utilizzo dei componenti di interfaccia di JSF in un’applicazione Struts.
La libreria è nata con l’obiettivo di rendere possibile l’uso dei componenti JSF in una applicazione Struts 1, ed è stata testata con la versione 1.1 di JSF, quindi è un po’ vecchiotta. Consiste in una serie di custom-tag e in un Request Processor modificato opportunamente per consentire l’utilizzo dei componenti di interfaccia di JSF in una applicazione Struts senza modificarne minimamente i livelli di controller e di model.
Non è lo scopo di questo articolo entrare nei dettagli di come utilizzare la libreria, tra l’altro attività veramente semplice, ma si possono trovare tutti i riferimenti in [3].
Era comunque doveroso rendere nota questa opportunità, dall’uso a parer mio piuttosto limitato ai casi nei quali si voglia rivedere l’interfaccia di una applicazione Struts esistente per sfruttare le caratteristiche di qualche componente UI di JSF.
È una strada secondo me di poca utilità, ma è bene sapere che esiste.
JSF e Spring
Fino ad ora abbiamo esaminato le interazioni di JSF con applicazioni web esistenti limitandoci sempre al layer di presentation e controllo.
Ormai dovremmo essere ben consapevoli del fatto che è in questi layer applicativi che JSF entra in gioco, così come dovremmo ben sapere che un’applicazione è fatta anche di altri layer nei quali JSF a ben poco a che fare.
Una applicazione JSF si deve quindi interfacciare in qualche modo con il layer di business così come un qualsiasi altro framework che ricopre il ruolo di controller di un’applicazione.
Sia chiaro che, così come Struts, neanche JSF impone vincoli o scelte particolari su come realizzare il layer di business di un’applicazione. Restano valide tutte le best-practises e i design pattern già noti ed utilizzati.
Sarà compito di una futura serie andare ad approfondire come costruire layer per layer un’applicazione e quali tecnologie usare in ogni singolo layer.
A scopo di suggerimento però è bene citare una di queste possibili integrazioni che a parer mio è quella che meglio si adatta alla architettura di JSF: l’integrazione con Spring.
Per chi non conosce Spring è possibile fare riferimento agli articoli della serie pubblicata su MokaByte [8] o alla documentazione ufficiale [9]. Detto in estrema sintesi, Spring è un framework Java EE full-stack, ovvero che indirizza tutti i layer di un’applicazione, fondato sul pattern IoC, Inversion Of Control [10].
Spring grazie alle sue caratteristiche di semplicità ed efficienza sta diventando sempre più la scelta preferita dagli sviluppatori per la realizzazione del layer di business delle applicazioni. Il fatto che, come JSF, anche Spring sia fondato sui comuni JavaBeans, i cosidetti POJO, dei quali gestisce la creazione e le dipendenze, fa si che esso si integri quasi naturalmente con JSF.
Sia JSF che Spring definiscono e gestiscono bean; anche se con modalità differenti concettualmente la definizione di un managed bean è la stessa cosa della definizione di un bean da parte del container IoC di Spring. Integrare JSF con Spring significa quindi semplicemente consentire a JSF di utilizzare in un managed bean un bean definito da Spring.
Questo lo si fa molto semplicemente aggiungendo nel faces-context.xml la definizione di una particolare classe che assolve proprio a questo compito, un variable-resolver:
org.springframework.web.jsf.DelegatingVariableResolver
Una volta definito il variable-resolver se nel file di configurazione di Spring definisco un bean così fatto
class="it.mokabyte.jsf.MioServiceImpl">
lo posso poi referenziare nella definizione di un managed-bean JSF semplicemente inserendo un suo riferimento nel faces-context.xml come segue:
mioBean
it.mokabyte.jsf.MioManagedBean
session
service
#{mioService}
A questo punto nel mio managed-bean posso definire un attributo come segue
public class MioManagedBean
{
private MioService service;
.
.
}
dove it.mokabyte.jsf.MioService è l’interfaccia implementata dalla classe it.mokabyte.jsf.MioServiceImpl.
Cosa ho ottenuto con tutto ciò? MioServiceImpl è la classe che implementa i metodi di business esposti dal layer di business mediante l’interfaccia MioService al livello di controller. Il managed-bean di JSF acquisirà il riferimento alla classe service mediante la quale invocherà i metodi del layer di business. Tutto ciò grazie alle definizioni viste e senza dover effettuare alcuna operazione di lookup o istanziamento nel managed bean. A questo ci pensano Spring e JSF!
Abbiamo quindi ottenuto lo scopo; il layer di controller vede il layer di business mediante un interfaccia standard la cui implementazione gli è sconosciuta e che può essere modificata semplicemente agendo su di un file di configurazione. Ed il tutto senza che nel managed-bean JSF sia necessario scrivere una sola riga di codice.
Questo fa capire la potenzialità dell’integrazione JSF-Spring e la fa scegliere oggi come una delle migliori soluzioni per lo sviluppo delle applicazioni web.
Conclusioni
Nell’articolo si è affrontato il problema dell’integrazione di JSF con applicazioni esistenti e con altri framework. Come detto gli scenari sono molteplici; lo scopo era di fornire le basi concettuali per affrontare in casi reali questo problema e di dare qualche suggerimento su alcune modalità di integrazione possibile. Quello che in conclusione deve essere assodato è che JSF non è un monolite che implica una scelta del tipo “o con me, o contro di me”, ma è un framework aperto e integrabile in molti modi.
Riferimenti
[1] David Geary – Cay Horstmann, “Core Java Server Faces”, Sun Microsystems Press, 2004
[2] Bill Dudney – Jonathan Lehr – Bill Willis – LeRoy Mattingly, “Mastering Java Server Faces”, Wiley Publishing Inc., 2004
[3] Kito D. Mann, “Java Server Faces In Action”, Manning Publications Co., 2005
[4] Autori Vari, “The Java EE 5 Tutorial”, Sun Microsystems, Febbraio 2007
[5] The API Javadocs for the JavaServer TM Faces Specification
http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html
[6] Alfredo Larotonda, “Sviluppare applicazioni con Jakarta Struts. I Parte”, MokaByte 81, Gennaio 2004
[7] Alfredo Larotonda, “JSF: Il nuovo volto dello sviluppo web. II Parte”, MokaByte 118, Maggio 2007
[8] Mario Casari, “Spring. I parte: introduzione al framework”, MokaByte 111, Ottobre 2006
[9] Autori Vari, “Spring Framework Documentation”
http://www.springframework.org/documentation
[10] Mario Casari, “Spring. II parte: il core”, MokaByte 112, Novembre 2006