La gestione dello stato conversazionale è uno degli aspetti più importanti di una applicazione web. Analizziamo le tecniche a disposizione dello sviluppatore per risolvere questo importante problema.
Introduzione
Le applicazioni web sono costruite come è noto su un meccanismo di tipo richiesta-risposta. Un client effettua una richiesta a un server che restituisce al client una determinata risposta. Il tutto avviene sfruttando il protocollo HTTP. Una caratteristica fondamentale di questo protocollo è quella di essere stateless; ossia un web server non ha in sà© alcun meccanismo per mantenere lo stato conversazionale dell‘applicazione cioè per legare richieste provenienti da uno stesso client. Ogni richiesta che arriva a un web server è assolutamente indipendente dall‘altra anche se proviene dal medesimo client. Questo non è un problema nel caso di siti statici anzi è un vantaggio in termini di prestazioni e di carico del server, ma lo è invece nel caso di applicazioni nelle quali quasi sempre si ha la necessità di legare logicamente richieste successive di uno stesso client.
L‘esempio classico è quello del carrello della spesa tipico dei siti di e-commerce nei quali un utente seleziona diversi prodotti da acquistare e alla fine procede all‘acquisto della merce. Il tutto non potrebbe funzionare se non ci fosse il modo di associare le varie richieste provenienti dal client dell‘utente a una stessa sessione utente. La gestione della sessione utente è quindi uno degli aspetti peculiari delle applicazioni web che le distingue dai siti web statici.
Il session tracking nella Servlet API
La Servlet API mette a disposizione tutto ciò che necessita allo sviluppatore per gestire in maniera semplice ed efficace la sessione. La gestione è fatta utilizzando un oggetto del container che implementa l‘interfaccia javax.servlet.HttpSession. L‘oggetto HttpSession consente di mantenere lo stato conversazionale tra n richieste provenienti da uno stesso client, fornendo il meccanismo per associare queste richieste l‘una all‘altra. Nella Figura 1 è rappresentato il ciclo di vita di una sessione in una applicazione web Java EE.
Il client effettua una prima richiesta al server; il server, opportunamente istruito dall‘applicazione, genera un identificativo univoco e lo restituisce al client insieme alla risposta. Da questo momento in poi il client invia ad ogni richiesta seguente questo identificativo consentendo così al server di associare questa richiesta a quelle precedenti, quindi alla sessione esistente. Il funzionamento è concettualmente molto semplice ma è assolutamente efficace e di semplice utilizzo. Per comunicare questo identificativo univoco al client il server fa uso di un cookie. Un cookie non è altro che un‘informazione aggiunta all‘header della risposta HTTP e può essere usato per inviare al client una certa informazione di tipo testuale che il browser memorizzerà in locale e che potrà essere utilizzata nelle successive richieste. In questo caso il cookie inviato nella risposta dal server è denominato JSESSIONID e il suo valore è l‘identificativo univoco associato alla sessione creata dal server per l‘utente in questione.
Lato server, una sessione non è altro che uno spazio di memoria dedicato all‘utente che sta effettuando la navigazione e nel quale è possibile memorizzare oggetti di qualsiasi tipo. Anche i cookie stessi venivano utilizzati per il session tracking, quindi per memorizzare durante la navigazione informazioni associate a uno stesso utente; uno dei principali difetti dei cookie risiede però nel fatto che sono in grado di memorizzare solo una informazione di tipo testuale nella forma chiave-valore, e inoltre che sono un meccanismo lato client. Nessuno quindi garantisce che l‘utente stesso non cancelli il cookie provocando la perdita dell‘informazione stessa. Una HttpSession invece è un oggetto che esiste sul server nel quale possono essere memorizzati altri oggetti di qualsiasi tipo. È come un contenitore di oggetti sul server messo a disposizione di un singolo utente.
La tecnica dei cookie è comunque utilizzata nell‘ambito della gestione della sessione effettuata con l‘HttpSession per la memorizzazione in locale da parte del browser dell‘identificativo della sessione.
Figura 1 – Il session id
L‘interfaccia HttpSession
Il procedimento visto mediante il quale il server genera un identificativo univoco e lo comunica al client che a sua volta lo restituisce al server ad ogni successiva richiesta è completamente trasparente allo sviluppatore che vuole gestire la sessione nella propria applicazione. Non è necessario fare altro se non creare un oggetto sessione ed utilizzarlo.
La creazione dell‘oggetto sessione avviene mediante il metodo public HttpSession getSession() dell‘interfaccia javax.servlet.HttpServletRequest, proprio perché l‘informazione della sessione è contenuta nella richiesta HTTP del client. Il metodo getSession() restuisce un oggetto che implementa l‘interfaccia javax.servlet.HttpSession. Se esiste, restituisce la sessione associata alla richiesta rappresentata dall‘oggetto request, altrimenti crea una nuova sessione e la restituisce. Il metodo public HttpSession getSession(boolean create) accetta invece come parametro una variabile booleana. In questo caso se il valore passato in input al metodo è true il comportamento è identico a quello visto per il metodo getSession() senza parametri. Se invece viene passato false, il metodo restituisce la sessione se ne esiste una associata alla richiesta altrimenti restituisce il valore null.
Una volta creato l‘oggetto sessione, è possibile memorizzare in esso oggetti che saranno quindi disponibili all‘utente per tutta la vita della sessione stessa. Il metodo che consente questa operazione è il
public void setAttribute(String name, Object value)
che consente di memorizzare nella sessione un oggetto associandogli una label identificativa. All‘opposto per rimuovere dalla sessione un oggetto è possibile utilizzare il metodo
public void removeAttribute(String name)
Abbiamo detto che gli oggetti memorizzati nella sessione sono disponibili all‘utente finchà© la sessione è attiva. Dal momento che creare una sessione significa allocare sul server uno spazio di memoria per un utente, e considerando che gli utenti di una applicazione web possono essere molto numerosi, è evidente che una sessione non può avere una durata infinita. La sessione ha infatti un time-out di scadenza dopo il quale il server provvede alla sua rimozione. Questo perché ovviamente un server web non ha alcuna informazione sull‘attività del client, tranne accorgersi della sua esistenza quando riceve da esso una richiesta. L‘utente potrebbe anche chiudere il suo browser senza che il server sia a conoscenza della cosa. Quindi se tra due richieste di uno stesso client intercorre un tempo superiore al time-out fissato per la sessione, quest‘ultima viene invalidata dal server. Il time-out può essere impostato da codice con il metodo
public void setMaxInactiveInterval(int interval)
o meglio può essere settato a livello di web application con un opportuna sezione del web.xml.
È possibile però invalidare la sessione anche prima che sia scaduto il time-out. Se ad esempio la nostra applicazione prevede una funzione di logout, è buona norma per liberare spazio in memoria invalidare la sessione dell‘utente che sta effettuando esplicitamente la disconnessione dal sistema. A tale scopo si può utilizzare il metodo
public void invalidate()
così come è possibile invalidare una sessione, è anche possibile sapere se una sessione è nuova, cioè se una sessione è stata appena creata dal server ma il client non ha ancora ricevuto l‘identificativo della stessa. Il metodo che consente di acquisire questa informazione è
public boolean isNew()
Figura 2 – L‘interfaccia HttpSession
L‘URL rewriting
Abbiamo visto come sia estremamente semplice gestire in una applicazione web Java EE la sessione utente dato che quasi tutto il lavoro che c‘è dietro a questo compito è assolto per noi dall‘application server in maniera trasparente. Il problema risiede però nel fatto che tutta la logica di funzionamento dell‘HttpSession parte dal presupposto che si possa fare affidamento sulla tecnica dei cookie. Sappiamo invece che lato client questa non è una certezza perché è sempre possibile istruire, per diverse ragioni, un browser internet a disabilitare i cookie. Un‘applicazione costruita con questo presupposto è quindi poco robusta perché non può funzionare in questa “sciagurata” eventualità . Fortunatamente è possibile però predisporre la nostra applicazione affinchà© funzioni anche con un browser che ha i cookie disabilitati. Basta utilizzare la tecnica dell‘URL Rewriting o “riscrittura dell‘URL”.
Si tratta di aggiungere ad ogni link contenuto nelle pagine della nostra applicazione l‘informazione relativa all‘identificativo di sessione, ovvero il jsessionid precedentemente menzionato. Questa tecnica agisce come backup della prima; in questo modo il server può sempre risalire all‘identificativo della sessione associata alla richiesta in quanto questo viene trasmesso accodato a ciascuna richiesta dell‘applicazione stessa. Per implementare la tecnica del URL rewriting occore fare quello che si definisce l‘encoding del URL. Esiste il metodo
public String encodeURL(String url)
della javax.servlet.HttpServletResponse che assolve a questo compito; riceve in input un URL e lo restituisce dopo aver effettuato l‘encoding. Esistono anche librerie di custom tag come quelle di Struts o della JSTL che consentono di scrivere i link di una pagina effettuando in automatico l‘encoding. In questo modo si è garantiti del funzionamento dell‘applicazione anche nel caso in cui i cookie siano disabilitati.
Conclusioni
In questo articolo abbiamo visto come sia possibile effettuare il session tracking in un‘applicazione web Java EE. È bene sottolineare come questa esigenza fondamentale di ogni applicazione web sia risolta in maniera egregia dalla Java EE, svincolando lo sviluppatore da gestioni complesse ma fornendo strumenti semplici ed efficaci in ogni circostanza.
Riferimenti
[1] Bryan Basham – Kathy Sierra – Bert Bates, “Head First – Servlet & Jsp”, O‘Reilly, 2004
[2] Autori Vari, “The J2EE 1.4 Tutorial”, Sun Microsystems, 2003
[3] Alfredo Larotonda “Le applicazioni web e Java – II parte: le servlet”, Mokabyte, Ottobre 2006