Linea guida: Progettazione dello stato per le applicazioni J2EE
Questa linea guida descrive i meccanismi di progettazione della gestione dello stato relativi ad un'applicazione J2EE.
Relazioni
Descrizione principale

Introduzione

Una buona gestione dello stato dell'applicazione è un aspetto importante nella progettazione di applicazioni distribuite. Questa linea guida fornisce una panoramica di alcuni tra i meccanismi e le considerazioni più comuni sulla gestione dello stato in un'applicazione J2EE.

Le considerazioni sulla progettazione riguardanti la gestione dello stato dovrebbero essere seguite durante la fase Elaborazione del progetto.  L'Architetto software deve esaminare gli approcci generali alla gestione dello stato come parte delle attività associate alla Disciplina Analisi & Progettazione Attività: Definizione di un'architettura candidata.  Durante il Compito: Analisi strutturale, l'Architetto software esamina i requisiti di scalabilità e di prestazione relativi all'applicazione per determinare quali tecniche di gestione dello stato dovranno essere utilizzate affinché l'applicazione raggiunga gli obiettivi di prestazione stabiliti.  Mentre la progettazione dell'applicazione viene perfezionata durante la fase Elaborazione, l'Architetto dovrà definire  i meccanismi di implementazione e di progettazione specifici a J2EE per gestire le informazioni di stato con l'applicazione nel Compito: Identificazione dei meccanismi di progettazione.

Come descritto nel Concetto: Configurazioni di distribuzione J2EE, le applicazioni J2EE possono essere composte da diversi livelli logici distribuiti lungo uno o più livelli fisici (macchine).  Dopo una breve panoramica tecnica sulla gestione dello stato, le sezioni rimanenti di questa linea guida tratteranno i vari meccanismi di progettazione ed implementazione per la gestione dello stato da impiegare in alcuni dei tanti livelli dell'applicazione.

Notare che l'Architetto software deve spiegare quali meccanismi sono stati selezionati come parte del Prodotto di lavoro: Documento dell'architettura software e fornire linee guida per l'utilizzo di tali meccanismi descritti dalle linee guida di progettazione specifiche al progetto.

Panoramica tecnica

Si tende sempre più a costruire applicazioni distribuite che interagiscono con internet in varie forme. Sebbene i fondamenti di internet siano molto spesso stateless per natura, occorre gestire lo stato per costruire qualsiasi tipo di applicazione business. Considerare un'applicazione internet in cui un  utente fa clic su un link da pagina A a pagina B. L' applicazione che elabora la richiesta di pagina B non ha più accesso alle informazioni utilizzate per l'elaborazione della pagina A.  Questo comportamento può essere plausibile per pagine web statiche, ma la maggior parte delle applicazioni business richiede informazioni riguardanti l'elaborazione precedente. È a questo punto che entrano in gioco i meccanismi di gestione dello stato forniti da J2EE.

Stato transitorio e stato permanente

Prima di studiare a fondo le linee guida di gestione dello stato è importante distinguere i vari tipi di informazioni di stato. Le informazioni di stato possono essere ampiamente divise in due categorie: transitorie (si hanno soltanto quando l'applicazione è attiva) e permanenti (subentrano quando l'applicazione è terminata).

Le informazioni di stato transitorie esistono solo finché è attiva l'entità che le contiene. Ad esempio, le informazioni di stato memorizzate come campo di una classe Java ordinaria. Se il contenitore che ospita questa classe viene chiuso per una qualsiasi ragione, le informazioni di stato andranno perse, a meno che i dati non siano stati copiati altrove, su un server di backup ad esempio.

Lo stato permanente esiste fin tanto che esistono i dati memorizzati impiegati per mantenere le informazioni di stato.  Le informazioni di stato permanenti sono generalmente memorizzate in un file o database e caricate dall'applicazione quando occorre.  Tutti i cambiamenti apportati alle informazioni di stato permanente devono essere trasmessi al database.  Gli aspetti di integrità e di recuperabilità della memorizzazione dei dati permanenti devono essere coerenti con quelli dei dati a cui accede l'applicazione. Un esempio di stato permanente è dato dalle informazioni memorizzate in un archivio dati, come un database relazionale.

Stato di sessione

I client del Web chiedono spesso di poter effettuare molteplici richieste di browser, con la possibilità di navigare da una pagina all'altra pur mantenendo le informazioni specifiche al client, come le voci di un carrello. Le applicazioni Web risolvono questa problematica creando un ID di sessione e associando dati di stato a questo ID di sessione. L'ID di sessione e lo stato associato si riferiscono ad uno stato di sessione.

Lo stato di sessione è una serie di dati associati ad una particolare interazione del client con un'applicazione Web in un lasso di tempo ristretto (minuti od ore, piuttosto che giorni). Dunque lo stato di sessione è un insieme di dati di breve durata che vengono solitamente cancellati dopo un periodo time-out, per evitare di consumare risorse.

Lo stato di sessione può essere memorizzato sul client o sul server, come si vedrà nelle sezioni successive. La piattaforma J2EE fornisce meccanismi personalizzati appositamente per gestire lo stato di sessione, in ragione della sua importanza nelle applicazioni basate sul Web.

Meccanismi di permanenza basilari

I meccanismi descritti di seguito sono quelli utilizzati più frequentemente dalle applicazioni Web per memorizzare lo stato.

Cookie

Le cookie sono piccoli file di testo memorizzati su client basati sul Web. Un server può memorizzare le cookie sul client. Le successive richieste del client inviano la coookie al server, dando a quest'ultimo accesso ai dati memorizzati nella cookie.

Principali problematiche inerenti alle cookie:

  • Molti utenti credono che le cookie compromettono la sicurezza e/o la privacy e, quindi, le disattivano.
  • Vi sono limiti alla dimensione delle intestazioni delle cookie e ciò riduce la capacità di memorizzazione dei dati.
  • Alcuni protocolli, come WAP (Wireless Access Protocol) non supportano le cookie.
  • Se il client si identifica tramite login da un altro luogo (come un'altra macchina), le cookie memorizzate nel suo pc di origine non sono disponibili.
  • I dati di stato devono poter essere rappresentati con valori stringa.

Riscrittura URL

La riscrittura URL è un meccanismo utilizzato per includere lo stato di sessione nelle URL referenziate in ogni pagina. Quando un server Web genera pagine per un client, codifica lo stato di sessione nelle URL della pagina. Poi l'utente fa clic su una URL e i dati memorizzati nella URL sono rispediti al server e permettono a quest'ultimo di ristabilire il contesto della sessione. Un meccanismo come questo si serve di campi HTML nascosti. Ecco alcune delle problematiche che tali meccanismi comportano:

  • Tutte le pagine di una determinata sessione devono essere gestite dal server, altrimenti il server potrebbe perdere traccia della sessione.
  • Lo stato non permane quando il cliente spegne il browser o si collega ad una URL specifica digitandola o utilizzando un segnalibro.
  • Come le cookie, i dati di stato non sono disponibili quando l'utente si collega da un altro luogo.
  • Analogamente alle cookie, i dati di stato devono essere rappresentati con valori stringa.

File piatto

Un file piatto è uno dei metodi più semplici per mantenere permanenti le informazioni di stato.  Al momento dell'inizializzazione, il file piatto è pronto a stabilire i valori di stato iniziali.  Ogni volta che si modifica lo stato, il file deve essere riscritto per salvare lo stato.  Alcuni inconvenienti legati al mantenimento dello stato dell'applicazione in un file piatto:

  • La scalabilità dell'applicazione viene contrariamente influenzata, poiché l'applicazione deve bloccare l'oggetto dell'applicazione per evitare l'accesso ai dati globali mentre le variabili dello stato di applicazione vengono aggiornate e riscritte in questo file piatto.
  • In gran parte dei casi, l'aggiornamento dei dati richiederà la riscrittura dell'intero file.
  • I file piatti non garantiscono sempre la recuperabilità in caso di errore.

XML

Il mantenimento di informazioni di stato permanenti in un file XML sta un gradino sopra rispetto ad un file piatto.  Si elencano qui alcuni vantaggi del mantenimento dello stato di applicazione in un file XML rispetto ad un file piatto:

  • Un file XML fornisce una struttura che non è presente in un file piatto.
  • Un file XML può essere analizzato utilizzando standard API.
  • Un file XML è generalmente più portatile.

Database

Il mantenimento delle informazioni di stato permanenti in un database consente la massima recuperabilità.  Alcuni dei vantaggi del mantenimento dello stato di applicazione in un database:

  • La progettazione delle tabelle fornisce una struttura.
  • Non occorre riscrivere l'intera applicazione se una variabile di applicazione viene aggiornata.  Si devono riscrivere soltanto le informazioni aggiornate.
  • L'uniformità può essere mantenuta coordinando il recupero dello stato di applicazione con quello del database di produzione.
  • Quando si richiede una grande affidabilità, il server del database può essere assemblato.

Si può accedere al database mediante API JDBC (Java Database Connectivity). JDBC può anche essere utilizzato per accedere ad altre fonti di dati tabulari che includono fogli elettronici e file piatti.

Meccanismi specifici a J2EE

La piattaforma J2EE fornisce meccanismi specifici alla gestione dello stato. Si tratta di meccanismi ad alto livello da poter configurare per utilizzare uno o alcuni tra i meccanismi di base descritti fin qui.

Contesto servlet

I servlet possono utilizzare questo contesto per salvare dati applicabili a molteplici client e sessioni client.

I dati memorizzati nel contesto servlet sono essenzialmente variabili globali relative all'applicazione J2EE.  Ne risulta che l'utilizzo dello stato dell'applicazione può avere un impatto significativo sulla progettazione dell'applicazione.  L'Architetto software inserire questi fattori nelle voci successive del Compito: Identificazione dei meccanismi di progettazione e stabilire al tempo stesso se il contesto del servlet è appropriato:

  • Il contesto servlet può essere mantenuto in un singolo processo e non condiviso da molteplici server (cluster).  Se le esigenze di scalabilità dell'applicazione non vengono soddisfatte, l'Architetto deve considerare la memorizzazione dello stato come una sessione di stato.  
  • Il contesto servlet è parte della memoria di processo, quindi solitamente non è mantenuto una volta terminato il processo.
  • Svariati thread possono accedere ai dati globali.  Il blocco e la sincronizzazione dei dati globali possono avere un impatto sulla scalabilità dell'applicazione.

Oggetto di sessione HTTP

I servlet e i JSP possono memorizzare dati associati ad una particolare sessione del client nell'oggetto di sessione HTTP. Se i dati vengono memorizzati in oggetti di sessione, rendere disponibili i dati di sessione in molteplici server può diventare problematico. Alcuni vendor consentono di indirizzare le richieste del client verso lo stesso server, pratica conosciuta come "server affinity".

L'oggetto di sessione HTTP è disponibile nel server durante l'elaborazione delle richieste del client, ma può essere memorizzato dal server tra le richieste, come può non esserlo. Il server può essere configurato per utilizzare qualsiasi meccanismo di permanenza basilare appena descritto, inclusa la memorizzazione dello stato di sessione in cookie sul client o in file o in un database del server. Può anche essere in grado di replicare i dati di sessione nella memoria dei vari server.

Il meccanismo viene selezionato configurando il server; i JSP e i servlet sono codificati indipendentemente dal meccanismo selezionato e accedono all'oggetto di sessione tramite un API indicato dalla specifica del servlet.

Enterprise JavaBean

Enterprise JavaBean include meccanismi di alto livello per la memorizzazione dei dati, basati sui meccanismi di livello inferiore precedentemente descritti, come i database e i file. I bean di sessione stateful sono utilizzati per memorizzare dati associati ad una particolare sessione client, mentre i bean di entità vengono impiegati per memorizzare dati a lungo termine. Vedere la Linea guida: EJB (Enterprise JavaBean) per lo stato memorizzato dagli EJB.

Progettazione dello stato di sessione

I client del Web chiedono spesso di poter effettuare molteplici richieste del browser, con la possibilità di navigare da una pagina all'altra pur mantenendo le informazioni specifiche al client, come le voci di un carrello. Le applicazioni Web risolvono questa problematica creando un ID di sessione e associando dati di stato a questo ID di sessione.

Lo stesso ID di sessione viene memorizzato sul client mediante uno o due meccanismi:

  • Cookie - il browser del client invia questa cookie al server per ciascuna richiesta che consente al server di ristabilire lo stato di sessione.
  • Riscrittura URL. Le URL di pagine distribuite al client dal server hanno l'ID di sessione codificato. Quando l'utente fa clic su una URL come questa, l'ID di sessione viene inviato al server e consente a quest'ultimo di ristabilire lo stato di sessione.

Il server è configurato per utilizzare l'approccio scelto. I servlet e i JSP devono essere codificati per lavorare indipendentemente dal metodo configurato. Nella fattispecie, utilizzare il metodo HttpServletResponse.encodeURL() per codificare tutte le URL. Questo metodo controlla se la riscrittura URL è abilitata e in caso affermativo esegue la codifica.

I dati associati ad un ID di sessione possono essere memorizzati nell'oggetto di sessione HTTP ed è possibile accedervi mediante JSP e servlet o in bean di sessione.

Sia l'ID di sessione che i relativi dati devono essere impostati per il time-out, affinché i dati di sessione che non sono stati utilizzati per molto tempo non consumino ulteriormente risorse. L'architetto ha il compito di selezionare un periodo appropriato di time-out.

Scelta del giusto meccanismo

Gli Architetti devono memorizzare lo stato di sessione nel client per ragioni di semplicità ed efficienza. Quando lo stato è gestito e memorizzato dal client, i server non devono utilizzare risorse per memorizzare le informazioni di stato o per assicurarne l'uniformità. Il lato negativo della memorizzazione di informazioni di stato con il client è che le informazioni devono essere inviate al server quando occorre e ciò provoca spesso problemi di latenza nella rete. Si devono anche fare considerazioni sulla sicurezza, se non si desiderano esporre nel client dati sullo stato di sessione. In questo caso si può ricorrere ala crittografia.

Se l'applicazione dispone di un ampio stato di sessione, è preferibile memorizzare tale stato sul server, che presenta raramente limiti di tipo e dimensione.

Generalmente lo stato di sessione con problemi di presentazione può essere memorizzato nell'oggetto di sessione HTTP, mentre lo stato dei bean di sessione stateful dovrebbe essere adatto ad implementare correttamente la logica di business. Si deve evitare di riprodurre i dati di stato - spostando piuttosto i dati di stato riprodotti nella sessione HTTP e, se necessario, inserirendoli nei bean di sessione come parametri di chiamata del metodo bean di sessione.

Se i dati di sessione memorizzati sul server devono sopravvivere agli errori di un nodo del server, utilizzare un meccanismo che consenta di riprodurre i dati di sessione o di renderli permamenti.

Progettazione di uno stato duraturo

I dati di sessione sono adatti a dati client di breve durata che hanno una scadenza. Possono tuttavia essere indispensabili anche a dati che sopravvivono per un periodo più lungo.

Quale sia il meccanismo adatto a questi dati dipende dalla natura dei dati da memorizzare. Le cookie, i file piatti, i file XML e i database sono delle opzioni. Per l'accesso database, la più adatta è generalmente un bean di entità. Vedere la Linea guida: Bean di entità per ulteriori dettagli.