MokaByte 77 - 7mbre 2003 
Portlet Java
III Parte
di
Massimiliano Dessė
Diamo un primo sguardo sulle specifiche ufficiali che renderanno portabili le
portlet sui vari Portlet Container open-source e commerciali,
estendendo il concetto di web-application.

Introduzione
Dopo i precedenti due articoli dove veniva illustrato cosa è possibile fare con le portlet e come scrivere una semplice portlet Mvc, daremo uno sguardo a cosa il jcp ha prodotto e rilasciato sulle portlet, per espressa dichiarazione si è riusato il lavoro prodotto dalle specifiche delle Servlet2.3, infatti molti metodi sono identici.
Su queste specifiche viene costruito in questi mesi Jetspeed 2 che grazie alle portlet standard (che soddisfano i requisiti J2EE) diventerà un EIS (Enterprise information Portal) J2EE in quanto adotterà molto strettamente le tecnologie e gli standard J2EE .
Con il termine portlet application costruita usando le portlet viene ora indicata una estensione della web-application.

 

Portlet Container e Portal server
Una distinzione resasi ora necessaria è la distinzione tra la parte di aggregazione delle portlet e la gestione del loro funzionamento.
Abbiamo visto nel precedente articolo come deployare una portlet e visualizzarla, però non era presente una netta separazione tra chi doveva istanziare la portlet e chi la doveva visualizzare nelle pagine.
Nelle specifiche questa separazione a livello logico funzionale viene fatta, ma a livello pratico il container delle portlet e chi le aggrega potrebbe essere lo stesso framework, oppure due ben distinti.
Il Portlet Container fornisce alle portlet il necessario ambiente di esecuzione, gestisce il loro ciclo di vita e il comportamento in base al file di deploy con estensione xml (in jetspeed1.x con estensione xreg).
Il Container istanzia le portlet prima che vengano richieste, lancia le eccezioni se qualcosa va male.
Esso è una estensione di un Servlet Container e può essere costruito sopra di esso.
Il suo nome in codice è Pluto e verrà fornito dalla IBM.
Il Portal server invece è il responsabile della aggregazione delle portlet fornite dal Portlet Container.

 

Preferences object al servizio delle portlet.
I file di deploy che caratterizzano il funzionamento della portlet e i parametri necessari al suo funzionamento vengono associati a ciascuna portlet mediante un oggetto chiamato preferences object, l'associazione portlet-preferences-object è gestita dal container, questa loro occorrenza è chiamata portlet window (o più brevemente window).


Figura 1- Portlet window


Il client chiama chi risponde ?
Una volta che il container ha istanziato correttamente le portlet , esse possono essere invocate.
L' interfaccia Portlet definisce due metodi per gestire le richieste , il processAction e il render .
Il metodo processAction esegue una richiesta di elaborazione, il metodo render esegue la visualizzazione delle portlet.
Una volta che il client ha effettuato la sua richiesta , il container esegue il metodo processAction (di una sola portlet) e solo dopo che questa azione è finita vengono chiamati i metodi render delle altre portlet presenti nella pagina (in qualsiasi ordine, anche in parallelo se possibile).


Figura 2


ProcessAction : dietro le quinte
Il metodo processAction riceve due parametri, la ActionRequest (che estende la PortletRequest) e la ActionResponse (che estende la PortletResponse).
L' ActionRequest fornisce i parametri della request , e le informazioni sulla portlet, sulle preferenze e sulla sessione, in questa punto si può anche eseguire una ridirezione se necessaria alla portlet.
Nella ActionResponse invece si può cambiare la modalità di funzionamento della portlet o il suo stato che diverrà effettivo nella successiva fase di render.

Render Request :mostrami il tuo viso
In questa operazione viene generato il contenuto, anche qui vengono passati due parametri
RenderRequest e la RenderResponse, il comportamento è il medesimo della processAction solamente che ora vengono passati parametri per la visualizzazione

 

GenericPortlet
Essa è una classe astratta e fornisce le funzionalità basilari e i metodi per modificare la render request.
Il metodo render della generic portlet setta il titolo usando quello presente nel deployment descriptor della portlet e invoca il metodo doDispatch.
Il metodo doDispatch viene usato a seconda dello stato corrente della portlet per il reindirizzamento ad altri metodi che sono, il doView per la view request, il doEdit per l' edit request e il doHelp per l' help request.
Il getPortletConfig restituisce l'oggetto che contiene le informazioni presenti nel deployment descriptor
Il getPortletContext che funziona allo stesso modo delle Servlet.
I metodi getPortletName, getPortletTitle che non hanno bisogno di spiegazioni in quanto il loro nome chiarisce la loro funzione , il getResourceBundle che serve per la localizzazione nelle varie lingue.
Sono inoltre presenti altri metodi di utilità.

 

Container e multithread delle portlet
Il Container gestisce le richieste concorrenti che arrivano alla portlet (la stessa portlet può essere visualizzata in vari punti in più pagine) da esecuzioni concorrenti di gestione richiesta su differenti thread.
Lo sviluppatore deve scrivere le portlet per gestire l'esecuzione concorrente del processAction e del render

 

Eccezioni
Durante la richiesta può essere lanciata una eccezione di tipo:

  • PortletException , quando si è verificato un errore e il container deve pulire la request , ma se si verifica nella processAction il container mostra le altre portlet visibili nella pagina ignorando tutte le operazioni nella actionResponse della portlet che ha lanciato l' eccezione.Vengono trattate come eccezioni di questo tipo anche le RuntimeException
  • PortletSecurityException , quando l' utente non ha sufficienti diritti per eseguire una operazione e il container gestirà questa evenienza nella maniera più appropriata (magari ridirezionando ad una pagina di servizio)
  • UnavailableException quando la portlet è temporaneamente o permanentemente non disponibile, se è il secondo caso, il container rimuove il servizio della portlet chiamando il metodo destroy.


Fine del servizio di una portlet: metodo destroy

Quando per un qualsiasi motivo valido il container debba interrompere il servizio di una portlet chiama il metodo destroy presente nella interfaccia Portlet , la portlet rilascerà le risorse che usava e salverà in maniera persistente i dati che ne avessero bisogno.

 

Configurazione : PortletConfig object
Attraverso il PortletConfig la portlet accede al suo deployment descriptor che contiene tutti i dati che le sono necessari durante il funzionamento, anche parti del resource bundle se necessario (viene usato dal metodo render della GenericPortlet)

 

Come ti chiamo direttamente la portlet : PortletUrl
Se fosse necessario chiamare una portlet direttamente e dirgli in quale stato di visualizzazione si deve porre, lo si può fare attraverso l'oggetto PortletUrl, lo si crea chiamando il createActionURL e il createRenderURL della interfaccia RenderResponse (è una specializzazione della action url).
Va tenuto presente che questi url delle portlet non vanno usati con l' http get che è usato dal portale per codificare stati interni di funzionamento , e va fatta attenzione che i parametri aggiuntivi eventuali (aggiunti con addParameter) della portlet non abbiano nomi uguali ad altri già presenti.

 

Conversiamo con le Servlet e condividiamo informazioni :PortletContext
Per ciascuna portlet esiste una istanza della interfaccia (che sarà naturalmente implementata) PortletContext associata a ciascuna portlet application deployata nel container.
Nel caso il container non sia solo uno ma la computazione sia distribuita, l'istanza del PortletContext sarà una per virtual machine.
Attraverso il PortletContext è possibile accedere ai parametri di inizializzazione della portlet application , immagazzinare dati , ottenere risorse statiche e ottenere il request dispatcher per includere Servlet e Jsp.
Poichè gli attributi settati nel PortletContext devono essere messi nel ServletContext una diretta conseguenza di questo è che il ServletContext delle Servlet e delle Jsp è accessibile alle portlet e il PortletContext è accessibile dalle Servlet e dalle Jsp.

 

Sessioni, visibilità e attributi e relazioni con la Web-App e la sessione HTTP
Il container deve assicurare che ciascuna richiesta alle portlet generata come richieste dal portale in seguito ad una richiesta di un client , abbiano tutte la stessa sessione.
Se con queste richieste alle portlet , più di una portlet creasse una sessione, l'oggetto sessione deve essere lo stesso per tutte le portlet della stessa portlet application.
La visibilità della sessione è a livello di contesto della portlet application.
Naturalmente poichè una portlet è usata da più utenti in più modi, ciascuna portlet ha il suo unico oggetto PortletSession per identificare la sessione di ciascun utente.
Il container ha la responsabilità di non condividere il PortletSession tra portlet application o tra diversi utenti
Una portlet può mascherare attributi nella PortletSession.
Questi attributi possono avere visibilità a livello di applicazione APPLICATION_SCOPE ( visibile a tutte le portlet che fanno parte della portlet application)o a livello di portlet PORTLET_SCOPE, ma in quest' ultimo caso non è protetto dagli altri componenti web, perciò bisogna prestare attenzione ai nomi che si danno.
Per conoscere la visibilità di una variabile nella sessione http (usata dalla PortletSession) va usata la PortletSessionUtil.
Essendo una portlet application una estensione di una web - application , essa può contenere Servlet e Jsp oltre alle portlet.
La PortletSession immagazzina gli attributi nella sessione HTTP perciò i dati messi nella http-session dalle Servlet e dalle Jsp sono accessibili alle portlet attraverso la PortletSession, e viceversa, quelli messi dalle portlet nella PortletSession sono accessibili alle Servlet e Jsp attraverso la HttpSession.
Se la sessione http deve essere invalidata, il container invalida anche la PortletSession associata e viceversa.
I metodi per agire sulla sessione e sui suoi parametri hanno gli stessi nomi e le stesse funzioni di quelli usati con le Servlet.

 

PortletRequestDispatcher
Una portlet può delegare la creazione del contenuto a una Servlet o a una Jsp, per farlo viene usato il PortletRequestDispatcher.
La portlet lo ottiene dal PortletContext, ma può usarlo solo durante l' esecuzione del metodo render.
Una volta chiamata la Servlet o la Jsp con i parametri eventuali, viene chiamato l' include sul PortletRequestDispatcher e vengono passati anche la renderRequest e la renderResponse, è compito del container assicurare che le Servlet o le Jsp chiamate dall' include del PortletRequestDispatcher, vengano chiamate nello stesso thread di questo.
Se una risorsa invocata con l'include dovesse lanciare una eccezione , questa deve essere incapsulata in una PortletException, in questo modo è il chiamante che gestisce i malfunzionamenti.

 

Caching
Viene definito un meccanismo di caching per portlet per singolo utente, nel deployment descriptor della portlet viene dichiarato per quanto tempo deve essere tenuto in cache il contenuto della portlet.
In questo modo tutte le portlet che compongono una pagina ma che non vengono modificate da elaborazioni non devono essere rigenerate, naturalmente la portlet può sempre agire anche settando l' expiration-cache nell' oggetto RenderResponse, però deve essere necessariamente scritto nel deployment descriptor che la portlet richiede il caching altrimenti il container non esegue il caching.
Non è richiesto ai container che abbiano un sistema di caching, ma se viene implementato può anche essere disabilitato parzialmente o totalmente in qualsiasi momento ci sia bisogno di liberare memoria.

 

Sicurezza
Una portlet application contiene risorse che saranno accedute da diversi utenti, è perciò necessario che gli utenti abbiano diversi gradi di permessi.
I ruoli definiti sono gli stessi definiti nelle specifiche 2.3 delle Servlet, per conoscere l' utente l' interfaccia Request espone tre metodi

  • getRemoteUser
  • isUserInRole
  • getUserPrincipal

Il getRemoteUser restituisce il nome usato dal client per l' autenticazione. Il isUserInRole se l' utente ha uno specifico ruolo di sicurezza e il getUserPrincipal determina il principal name dell' utente corrente e restituisce un oggetto java.security.Principal
Usando questi tre metodi nel codice è possibile capire se l' utente è autorizzato ad eseguire determinate operazioni.
I permessi di ciò che l' utente può fare sono scritti nel deployment descriptor della portlet, se il container ne avesse bisogno e non trova i permessi dichiarati in questo file , li cerca nel web.xml della portlet application.
Ci sono anche degli specifici vincoli di sicurezza che possono essere assegnati a:

  • portlet collection
  • user data constraint

La prima è una collezione con i nomi delle portlet che descrivono la lista delle risorse da proteggere, in questo modo le richieste che arrivano a una portlet della collezione sono soggette a questi vincoli.
Invece lo user data constraint sono i requisiti per lo strato di trasporto delle portlet collection, questi requisiti possono essere sulla integrità del contenuto o per evitare che possano essere letti durante il trasporto (Confidential), in questo caso il container deve usare SSL se per rispondere alla request se le risorse nel deployment descriptor della portlet sono segnate con livello di trasporto CONFIDENTIAL.

 

Propagazione della sicurezza a un EJB container
Quando una portlet esegue chiamate a degli EJB il Portlet container propaga l' identita dell' utente all' EJB container.
Poichè i Portlet Container sono parte della piattaforma J2EE è richiesto che utenti non conosciuti dal Portlet container possano fare chiamate all EJB container, in questo caso, la Portlet application può specificare l' elemento run-as nel web.xml.
In questo caso, l' identità dichiarata come run-as viene propagata allo strato EJB con uno dei ruoli definiti nel web.xml.
Se questo non dovesse avvenire la Portlet-application è la sola che si deve occupare della autenticazione nel container EJB.

 

PortletTagLibrary
Attraverso le tag library le Jsp possono accedere alla RenderRequest e alla RenderResponse e al PortletConfig delle portlet, che forniscono i tag actionURL e renderURL.

 

TCK Test Compatibility KIT
Per assicurare la compatibilità e l' aderenza allo standard dei portlet Container, l' implementazione di quest' ultimo deve soddisfare i requisiti del TCK.
Il TCK è composto da dei test case e da 165 asserzioni che devono essere verificate affinchè il container sia certificato come aderente allo standard.

 

Conclusioni
Con l' ufficializzazione dello standard sarà possibile portare le portlet da un Portlet container ad un altro, altresì, si apre ufficialmente anche il mercato dei portlet container commerciali (Sun, IBM e Oracle) e quello open source con Jetspeed 2 che aderirà in maniera molto stretta alle specifiche J2EE.
Insieme alle portlet vi è un altro importante sviluppo che cammina parallelo ma che non è ancora ufficiale, quello dei WSRP cioè i web-services for remote portlet di cui l' Apache Software Foundation insieme all' OASIS con altre società stanno definendo lo standard.
Jetspeed2 e i WSRP saranno argomento dei prossimi articoli.

 

Bibliografia e riferimenti
jsr168: <http://www.jcp.org/en/jsr/detail?id=168>
Documentazione ufficiale completa:http://jcp.org/aboutJava/communityprocess/review/jsr168/
Esempi portlet SUN: http://developers.sun.com/prodtech/portalserver/reference/techart/jsr168/index.html


Massimiliano Dessì è raggiungibile a desmax74@yahoo.it oppure massimiliano.dessi@gruppoatlantis.com (oltre a mdessi@mokabyte.it). Ha iniziato a lavorare presso la Sistemi Informativi S.p.A (IBM come programmatore Java.
Da due anni lavora presso Atlantis S.p.A.dove utilizzando metodologie agili quali l'eXtreme programming (Xp), sviluppa applicazioni enterprise Web-based con tecnologia J2EE quali portali e content management system per la promozione del territorio. Nel tempo libero contribuisce al progetto open-source jakarta -Jetspeed, di cui ha realizzato il servizio di localizzazione e la portlet per la localizzazione nelle varie lingue, cura la versione italiana
di Jetspeed.
Laureando in Ingegneria Elettronica presso l'Università di Cagliari.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it