http://www.webmasterpoint.org/jsp/home.asp In questa sede si intende descrivere JSP ( JavaServer Pages ) , una nuova tecnologia che permette di creare applicazioni di facile sviluppo, accesso ed impiego per il Web. La tecnologia Java si è dimostrata insuperabile quanto a connettività , affidabilità , scalabilità e sicurezza : applicazioni Java quali i servlet e le stesse pagine JSP offrono una tecnologia sicura , solida ed indipendente dalla piattaforma su cui operano, in grado di sfruttare le potenzialità di Java per lo sviluppo di funzionalità che spaziano dal semplice sviluppo di siti con contenuti dinamici al vero e proprio e-commerce. Dal punto di vista storico è interessante notare che il World Wide Web non è nato come ambiente per l ' esecuzione di applicazioni mentre oggi Internet rappresenta un mercato economico globale : infatti sta diventando il centro predominante per lo scambio di beni , servizi ed informazioni sia per le imprese che per i singoli consumatori. Conseguenza di quest 'evoluzione è che oggi le applicazioni Web sono uno degli elementi principali di Internet . La crescita del modello di programmazione Web si può organizzare in diverse fasi tecnologiche . Il primo modello operativo prevedeva la presenza di un server Web che non faceva altro che spedire documenti HTML su richiesta di un client ( il protocollo in cui il browser Web richiede il documento è l ' HTTP ). In quest ' ambiente i contenuti erano statici ,cioè non cambiavano mai se non tramite un intervento diretto di un operatore , di un uomo . Fig: Il modello a server statico Se i documenti fossero stati generati automaticamente da un programma il browser non se ne sarebbe accorto in quanto il risultato di una richiesta sarebbe stato comunque costituito da dati HTML ; inoltre la richiesta avrebbe potuto comprendere dei parametri incorporati nell 'indirizzo URL . Questo suggerisce che una richiesta HTTP può essere interpretata come una query ad un database e che i risultati della query possono essere utilizzati per costruire in modo dinamico un documento HTML. In quest ' ottica nacque una nuova specifica chiamata CGI ( Common Gateway Interface ). Fig: Contenuti dinamici generati da uno script CGI Quando un programma CGI viene richiamato da un server Web legge i parametri e le intestazioni inviategli con la richiesta ( sotto forma di coppie chiave valore e variabili d ' ambiente rispettivamente ) , svolge le attività specificate dall' applicazione ( normalmente un accesso ad un database ) e genera una risposta HTTP .La risposta viene inviata al server Web che ha effettuato la richiesta come se si trattasse di un normale documento HTML statico . Il grosso difetto del sistema CGI è che crea un nuovo processo per ogni richiesta HTTP: questo rappresenta un problema quando il traffico è elevato . Un significativo miglioramento venne introdotto dalla realizzazione , nel 1997 , dell' API Java Servlet seguita rapidamente dall ' API JSP( Java Server Pages ) . Queste tecnologie per server Web hanno combinato tutte le potenzialità di Java con la connettività a database , l ' accesso alle reti , le operazioni multithread e , soprattutto , un nuovo modello di elaborazione . I servlet e le pagine JSP operano da un ' unica istanza che rimane in memoria e utilizza più thread per rispondere simultaneamente a più richieste di servizi . Peraltro i servlet e le pagine JSP possono utilizzare l ' ambiente J2EE ( Java 2 Enterprise Edition ) che consente di realizzare applicazioni sofisticate e solide . Fig: Applicazioni dinamiche che utilizzano servlet , JSP e J2EE I servlet sono classi Java che estendono le funzionalità di un server Web generando dinamicamente le pagine Web . Un ambiente runtime chiamato servlet engine gestisce il caricamento e lo scaricamento dei servlet e collabora con il Server Web per dirigere le richieste ai servlet e per rinviare il loro output ai client Web . Fin dalla loro introduzione i servlet sono diventati l ' ambiente predominante per la programmazione Java del server . Essi presentano numerosi vantaggi : come già detto migliori prestazioni in quanto dopo la prima richiesta rimangono in memoria indefinitamente : la servlet engine carica una singola istanza della classe del servlet ed esaudisce le richieste utilizzando una serie di thread disponibili Semplicità poiché , al contrario degli applet Java che operano su una macchina virtuale Java generata dal browser Web , i servlet operano nell ' ambiente controllato del server e comunicano con il client utilizzando comandi HTTP eliminando problemi di compatibilità e di sicurezza . Memorizzazione delle sessioni HTTP: i server HTTP non sono dotati di funzionalità in grado di ricordare i dettagli delle precedenti richieste provenienti dallo stesso client ( spesso si dice che il protocollo HTTP non ha stati , ovvero non passa alcuna informazione da una richiesta alla successiva ); l' API Servlet fornisce una classe HTTPSession che supera questa limitazione . Accesso alla tecnologia Java : i servlet , essendo applicazioni Java , hanno un accesso diretto a tutte le funzionalità di Java , come la gestione dei thread , l ' accesso alla rete e la connettività con i database . Le pagine JSP che vengono prodotte automaticamente da un servlet , ereditano tutti questi vantaggi . Una pagina JSP è un modello di una pagina Web che utilizza codice Java per generare dinamicamente un documento HTML .Le pagine JSP vengono eseguite in un componente operante sul server chiamato container JSP che le traduce nei corrispondenti servlet Java . Per questo motivo i servlet e le pagine JSP sono intimamente collegati . Ciò che è possibile fare negli uni è , in genere , possibile eseguire anche nelle altre , sebbene ogni tecnologia abbia specifici punti di forza . Le pagine JSP hanno migliori prestazioni e scalabilità rispetto agli script CGI poiché sono persistenti in memoria e sono multithread ; ai vantaggi dei servlet ne aggiungono altri più specifici : Vengono ricompilate automaticamente quando necessario Poiché esistono nel normale spazio dei documenti del server Web, l ' indirizzamento delle pagine JSP è più semplice rispetto a quello dei servlet . Dato che le pagine JSP sono di tipo HTML sono compatibili con gli strumenti di sviluppo Web . Esistono tre tipi di pagine JSP : CODICE SORGENTE JSP: questa è la forma che viene effettivamente scritta dallo sviluppatore . Si tratta di un file di testo con l ' estensione .jsp contenente codice HTML , istruzioni Java e direttive ed azioni JSP che descrivono il modo in cui generare la pagina Web di risposta per una determinata richiesta . CODICE SORGENTE JAVA: il container JSP traduce il codice sorgente Java in codice sorgente servlet Java . Questo codice viene normalmente salvato nell ' area di lavoro e spesso è utile per eseguire operazioni di debugging. CLASSE JAVA COMPILATA : come per ogni altra classe Java , il codice generato per il servlet viene compilato per creare un file .class , pronto per essere caricato ed eseguito . Il container JSP gestisce automaticamente ognuna di queste forme sulla base della data in cui è avvenuta l ' ultima modifica a ciascun file . In risposta ad una richiesta HTTP , il container controlla se il codice sorgente .jsp è stato modificato dall ' ultima compilazione del codice sorgente .java . In caso affermativo il container ritraduce il codice sorgente JSP per produrre la nuova versione del codice sorgente Java . Nella seguente figura si illustra il processo utilizzato dal container JSP. Quando viene richiesta una pagina JSP , il container innanzitutto determina il nome della classe corrispondente al file .jsp . Se la classe non esiste o è meno recente del file .jsp ( ovvero il codice JSP è stato modificato dopo l ' ultima compilazione ) , allora il container crea il codice sorgente Java per un servlet equivalente e poi lo compila . Se non è ancora in esecuzione un ' istanza del servlet , il container carica la classe del servlet e crea un ' istanza . Infine il container crea un thread per gestire la richiesta HTTP nell ' istanza caricata . La tecnologia JSP ha numerosi vantaggi rispetto ad altre tecnologia oggi comunemente usate. Vediamone alcune Rispetto alle Active Server Pages (ASP) ASP è una tecnologia concorrente creata da Microsoft. I vantaggi delle JSP si notano principalmente su due fronti. In primo luogo, la parte dinamica è scritta in Java, non in VBScript o qualche altro linguaggio specifico per ASP. Il codice è così più potente e meglio si adatta alla produzione di applicazioni complesse che richiedono componenti riutilizzabili. Seconda cosa, JSP è portabile anche su altri sistemi operativi e Web servers; non si è così limitati all'uso di Windows NT/2000 e IIS. Si possono fare le stesse considerazioni confrontando JSP e ColdFusion; con le JSP si può usare il linguaggio Java e non si è legati a nessun particolare prodotto per server. Rispetto a PHP PHP è un linguaggio di scripting che ha la caratteristica di essere free, open source, HTML-embedded e che è in qualche modo simile sia a ASP che a JSP. Il vantaggio in questo caso consiste nel fatto che la parte dinamica è scritta in Java, linguaggio probabilmente già conosciuto dall'utente, che ha un'API esauriente per il networking, accesso ai database e consente di lavorare con oggetti distribuiti, mentre col PHP occorre imparare interamente il linguaggio specifico. Rispetto ai puri servlets Le JSP non forniscono alcuna possibilità di lavoro che non possa essere sfruttata utilizzando semplicemente un servlet. Infatti i documenti JSP sono automaticamente tradotti in servlet per essere esaguiti. Ma è molto più conveniente scrivere e modificare una pagina in HTML normale, piuttosto che avere milioni di statement println che generano l'HTML. Inoltre, in ambito business, separando la presentazione dal contenuto si può ottimizzare il lavoro di più persone: gli esperti di design possono costrire il codice HTML con i comuni tool di lavoro e passare il codice così ottenuto ai programmatori servlet per l'inserimento del contenuto dinamico. Rispetto ai Server-Side Includes (SSI) SSI è una tecnologia ampiamente supportata per l'inserimento in pagine Web statiche di parti definite esternamente. JSP ha maggiori vantaggi di uso poiché ha un set di tool per la costruzione delle parti esterne molto più ricco ed ampio. Si hanno inoltre maggiori possibilità per quanto riguarda la parte di risposta HTTP in cui viene ora inserita la parte esterna. SSI viene utilizzata normalmente per semplici inclusioni, non per l'utilizzo di parti di codice complesso, come possono essere l'utilizzo di data form, la creazione di connessioni a database, ed altre applicazioni di livello avanzato. Rispetto a JavaScript JavaScript, che è completamente distinto dal linguaggio di programmazione Java, è normalmente usato per generare dinamicamente HTML sul client, costruendo parti della pagina Web mentre il browser carica il documento. Questa è una possibilità molto utile ma risolve solo situazioni in cui le informazioni dinamiche sono basate sull'ambiente del client. Ad eccezione dei cookies, la richiesta dati HTTP non è utilizzabile dalle routine JavaScript sul client-side. Quindi, mancando i JavaScript di routine per il network programming, il codice JavaScript sul client non può avere accesso alle risorse contenute sul server-side, come database, cataloghi, informazione sul prezzo e molto altro. JavaScript può anche essere usato sui server, come viene notevolmente fatto sui server Netscape o come linguaggio di script per IIS. Java è però di gran lunga più potente, flessibile, affidabile e portabile.\ Rispetto all' HTML statico Il normale HTML non può contenere informazione dinamica, così le pagine di HTML statico non possono basarsi su informazione inserita dall'utente o su risorse dati del server-side. JSP è di semplice utilizzo, tale per cui sia abbastanza naturale e ragionevole incrementare il codice HTML con l'informazione dinamica che le JSP possono generare; si beneficia quindi dell'utilizzo di informazione dinamica in modo conveniente. Precedentemente l'inserimento di informazione dinamica era talmente complesso da precluderne l'utilizzo anche in molte applicazioni di grande valore. Gli script in JSP sono vere e proprie porzioni di codice inserite all' interno di pagine HTML che possono rappresentare dichiarazioni o espressioni. Il codice del file Java deve essere inserito all'interno dei tag <% %>,mentre per le dichiarazioni la sintassi cambia leggermente. Dichiarazioni la sintassi per le dichiarazioni è la seguente: <%! dichiarazione %> sia per la dichiarazioni di variabili, sia per la dichiarazione di metodi. Esempi: <%// dichiarazione di una stringa %> <% ! String stringa=new string("ciao a tutti") %> <% // dichiarazione di una funzione che dati due numeri in ingresso // restituisce la loro somma %> <% ! public int somma (int primo, int secondo){ return (primo + secondo); }//somma %> NOTA: Java mette a disposizione degli sviluppatori una classe (inclusa nel package java.lang) chiamata string, che permette, appunto, la gestione delle stringhe (da notare che da questa classe non è possibile derivare altre sottoclassi). Gli oggetti di tipo string possono essere inizializzati in più modi, ma normalmente i costruttori più utilizzati sono due: public String (): che costruisce una stringa vuota (perché sia allocata è necessario utilizzare l'istruzione nomeStringa=new String [ ] ); public String (string value): che costruisce una stringa contenente la stringa value. I metodi implementati da questa classe più utilizzati sono: o string.length (): restituisce il numero di caratteri che compongono la stringa escluso il terminatore; o string.charAt (int i): restituisce il carattere della stringa in posizione i; o string.concat (string str): restituisce una nuova stringa ottenuta dalla concatenazione delle stringa string con la stringa str; o string.equals (string str): confronta la stringa string con la stringa str, restituendo true se risultano uguali; o string.equals.IgnoreCase (string str): confronta la stringa string con la stringa str tenendo conto delle lettere minuscole e maiuscole; o string.compareTo (string str): confronta la stringa string con la stringa str, restituendo 0 se risultano uguali, un numero positivo se str precede in ordine alfabetico string e un numero negativo se str anticipa segue in ordine alfabetico string. Espressioni Sono utilizzate per inserire direttamente sull'output dei valori. La sintassi è la seguente: <% espressione %> L'espressione viene calcolata, convertita in una stringa e inserita nella pagina. Questo calcolo viene effettuato in run time, ossia quando la pagina viene richiesta, e perciò si suppone abbia completo accesso all'oggetto di interesse della richiesta. Esempio: <%= somma (2,3)%> Questa istruzione se inserita all'interno dei tag e stamperà a video l'output della funzione somma (in questo caso il numero 5, ottenuto dalla somma dei due valori in ingresso 2 e 3). Per semplificare queste espressioni è possibile utilizzare una serie di variabili predefinite (talvolta chiamate oggetti impliciti), le cui più importanti sono: RESPONSE : fornisce tutti i parametri per inviare il risultato dell'esecuzione della pagina JSP: quando un Web Server risponde ad una richiesta di un browser, tipicamente invia prima del documento vero e proprio una status line, nella quale è riportata la versione del protocollo HTTP, il codice di stato (che è un valore intero), e alcuni brevi messaggi relativi al codice di stato (ad es. "OK"). Questa operazione è effettuata tramite il metodo GetStatus dell'oggetto response. In particolare, i valori assumibili dal codice di stato sono i seguenti: o 100-199: sono valori di informazione, a cui il client deve rispondere con qualche altra azione; o 200-299: indicano che la request è stata effettuata con successo; o o o 300-399: tipicamente usati per file che sono stati spostati, contengono un'intestazione di location relativa al nuovo indirizzo; 400-499: indicano un errore del client; 500-599:indicano un errore del server Di solito ci si riferisce a queste costanti tramite il loro significato, per evitare errori tipografici: per esempio, per indicare al browser di continuare a visualizzare il precedente contenuto di una pagina in quanto non ne esistono altri disponibili si userà il codice Response.SetStatus(Response.SC_NO_CONTENT) piuttosto che Response.SetStatus(204). Uno dei valori che si possono trovare più frequentemente è 404 (SC_NOT_FOUND), il quale comunica al client che la risorsa richiesta non è reperibile a quel dato indirizzo. REQUEST: dà accesso ai parametri di richiesta, al tipo di richiesta (GET o POST), e all'intestazione HTTP (ad es. i cookies); permette quindi di accedere alle informazioni di intestazione specifiche del protocollo HTTP. Al momento della richiesta questo metodo incapsula le informazioni sulla richiesta del client e le rende disponibili attraverso alcuni suoi metodi. L'uso più comune è quello di accedere ai parametri inviati (i dati provenienti da un form per esempio) con il metodo getParameter("nomeParametro"), che restituisce una stringa con il valore del parametro specificato. Alto metodo molto importante è getCookies(), che restituisce un array di cookies. Gli altri metodi, i più importanti, sono: getAttributeNames() restituisce una variabile di tipo Enumeration contenente i nomi di tutti gli attributi coinvolti nella richiesta. getContentLength() restituisce un intero che corrisponde alla lunghezza in byte dei dati richiesti. getContentType() restituisce il tipo MINE della richiesta, cioè il tipo di codifica dei dati. getInputStream() restituisce un flusso di byte che corrisponde ai dati binari della richiesta. Particolarmente utile per funzioni di upload di file da client a server. getParameter(String) restituisce una stringa con il valore del parametro richiesto. getParameterNames() restituisce una variabile di tipo Enumeration contente i nomi dei parametri della richiesta. getParameterValues(String) restituisce un array contenente tutti i valori del parametro specificato (nel caso ci siano più parametri con lo stesso nome). getProtocol() Rappresenta il protocollo e la versione della richiesta. getRemoteHost() restituisce l'intero nome del dominio (ad es. whitehouse.gov) a cui appartiene il client richiedente. getServerName() restituisce l'indirizzo IP del server getServerPort() Indica la porta alla quale il server è in ascolto, tipicamente sotto forma di numero intero. getRemoteAddr() Restituisce in pratica l'indirizzo IP del visitatore sotto forma di una stringa (ad es. "198.137.240.15"). getRemoteUser() restituisce lo username della macchina richiedente, ed è utilizzato nei siti che richiedono una protezione. getPathInfo() restituisce informazioni extra sul path,che vengono inserite nell'URL dopo l'indirizzo del servlet. getQueryString() restituisce una stringa contenete l'intera querySting (tutti i caratteri dopo il punto di domanda). request.getServletPath() restituisce il percorso relativo della pagina jsp SESSION : Una delle funzionalità più richieste per un'applicazione Web è mantenere le informazioni di un utente lungo tutto il tempo della sua visita al sito. Questo problema è risolto dall'oggetto implicito Session che gestisce appunto le informazioni a livello di sessione, relative ad un singolo utente a partire dal suo ingresso alla sua uscita con la chiusura della finestra del browser. È possibile quindi creare applicazioni che riconoscono l'utente nelle varie pagine del sito, che tengono traccia delle sue scelte e dei suoi dati. È importante sapere che le sessioni vengono memorizzate sul server e non con dei cookies che devono però essere abilitati per poter memorizzare il così detto SessionID che consente di riconoscere il browser e quindi l'utente nelle fasi successive. I dati di sessione sono quindi riferiti e riservati ad un utente a cui viene creata un'istanza dell'oggetto Session e non possono essere utilizzati da sessioni di altri utenti. Per memorizzare i dati all'interno dell'oggetto session è sufficiente utilizzare il metodo setAttribute specificando il nome dell'oggetto da memorizzare e una sua istanza. Per esempio, per memorizzare il nome dell'utente al suo ingresso alla pagina ed averlo a disposizione i seguito e sufficiente fare session.setAttribute("nomeUtente", nome) a patto che nome sia un oggetto di tipo stringa che contenga il nome dell'utente. La lettura di una variabile di sessione precedentemente memorizzata è possibile grazie al metodo getAttribute che ha come unico ingresso il nome della variabile di sessione con cui avevamo memorizzato il dato che ci interessa reperire. Session.getAttribute("nomeUtente") restituisce il nome dell'utente memorizzato come visto in precedenza; se non vengono trovate corrispondenza con il nome dato in ingresso, restituisce null. Queste 2 sono le operazioni fondamentali relative all'oggetto session, mentre altri metodi utili sono : getAttributeNames() (restituisce un oggetto di tipo enumerativo di stringhe contenente i nomi di tutti gli oggetti memorizzati nella sessione corrente), getCreationTime() (restituisce il tempo di quando è stata creata la sessione), getId()(restituisce una stringa contenente il sessionID che come detto permette di identificare univocamente una sessione),getLastAccesedTime() (restituisce il tempo dall'ultima richiesta associata alla sessione corrente) ,getMaxInactiveInterval() (restituisce un valore intero che corrisponde all'intervallo massimo di tempo tra una richiesta dell'utente ad un'altra della stessa sessione),removeAttribute(nome_attributo) rimuove l'oggetto dal nome specificato dalla sessione corrente. OUT : Questo oggetto ha principalmente funzionalità di stampa di contenuti. Con il metodo print(oggetto/variabile) è possibile stampare qualsiasi tipo di dato, come anche per println() che a differenza del precedente termina la riga andando a capo. Si capisce comunque che l'andare o meno a capo nella stampa dei contenuti serve solo a migliorare la leggibilità del codice HTML. Si noti che Out è utilizzata quasi esclusivamente negli scriptlets, mentre le espressioni sono messe direttamente nello stream di output e quindi necessitano raramente di fare riferimento a out esplicitamente; SETBUFFERSIZE(int): imposta la dimensione in byte del buffer per il corpo della risposta, escluse quindi le intestazioni; FLUSHBUFFER(): forza l'invio dei dati contenuti nel buffer al client; CONFIG: permette di gestire tramite i suoi metodi lo startup del servlet associato alla pagina JSP, di accedere quindi a parametri di inizializzazione e di ottenere riferimenti e informazioni sul contesto di esecuzione del servlet stesso; EXCEPTION: questo oggetto è accessibile solo dalle pagine di errore (dove la direttiva isErrorPage è impostata a true). Contiene le informazioni relative all'eccezione sollevata in una pagina in cui il file è stato specificato come pagina di errore. Il metodo principale è getMessage() che restituisce una stringa con la descrizione dell'errore; APPLICATION : consente di accedere alle costanti dell'applicazione e di memorizzare oggetti a livello di applicazione e quindi accessibili da qualsiasi utente per un tempo che va dall'avvio del motore JSP alla sua chiusura, in pratica fino allo spegnimento del server. Gli oggetti memorizzati nell'oggetto application come appena detto sono visibili da ogni utente e ogni pagina può modificarli. Per memorizzare i dati all'interno dell'oggetto application è sufficiente utilizzare il metodo setAttribute specificando il nome dell'oggetto da memorizzare e una sua istanza. Per esempio, per memorizzare il numero di visite alla pagina è sufficiente fare application.setAttribute("visite", "0"). La lettura di un oggetto application precedentemente memorizzato è possibile grazie al metodo getAttribute che ha come unico ingresso il nome dell'oggetto application con cui avevamo memorizzato il dato che ci interessa reperire. application.getAttribute("visite") restituisce l'oggetto corrispondente, in questo caso semplicemente il valore 0. Se non vengono trovate corrispondenze con il nome viene restituito il valore null. Anche l'oggetto application come session possiede il metodo getAttributeNames() che restituisce un oggetto di tipo enumerativo di stringhe contenente i nomi di tutti gli oggetti memorizzati nell'applicazione in esecuzione. Per rimuovere un oggetto si utilizza il metodo removeAttribute("nomeoggetto"). Infine per accedere alle costanti di applicazioni, segnaliamo due metodi: il primo molto utile è getRealPath("\") che restituisce (con quella stringa in ingresso) il percorso completo su cui è memorizzato il file. Il secondo metodo restituisce delle informazioni, solitamente riguardanti la versione, del motore jsp che si sta utilizzando per l'esecuzione della pagina: application.getServerInfo(). Scriptlets Consentono di inserire nel corpo del codice qualcosa di più complesso di una semplice espressione, ossia consentono di inserire un codice arbitrario tramite la sintassi: <% codice %>. Essi hanno accesso alle medesime variabili automaticamente definite delle espressioni (request, response, session, out, ecc..), e consentono di eseguire alcuni task che non è permesso dalle espressioni: permettono infatti di settare il codice di stato, l'intestazione di risposta, aggiornamento di database, esecuzione di porzioni di codice contenenti loop, e altri costrutti complessi. Vediamo un esempio: se si desidera che l'output di un'elaborazione compaia nella pagina risultante, ciò è reso possibile dalla variabile out con la seguente sintassi: <% String queryData = request.getQueryString(); out.println(" Attached GET data: " + queryData); %> In questo caso particolare avrei ottenuto lo stesso risultato con questa espressione JSP: Attached GET data: <%=request.getQueryString() %> Questi oggetti sono finalizzati ad un migliore incapsulamento del codice, che è del resto lo spirito della programmazione Java, e descrivono le operazioni che è possibile compiere sugli oggetti attraverso l'uso delle JSP . Tale incapsulamento è da intendere in termini di inclusione e utilizzo di Java Bean. Le azioni standard per le pagine JSP sono le seguenti: : permette di utilizzare i metodo implementati all' interno di un JavaBean; : permette di impostare il valore di un parametro di un Bean; : permette di acquisire il valore di un parametro di un Bean; : permette di dichiarare ed inizializzare dei parametri all'interno della pagina. Sintassi: name="nomeParametro" value="valore"> dove i parametri indicano: name: nome del parametro dichiarato; value: valore del parametro appena dichiarato : permette di includere risorse aggiuntive di tipo sia statico che dinamico. Il risultato è quindi quello di visualizzare la risorsa, oltre alle informazioni già inviate al client. Sintassi: <JSP:INCLUDE< font>page="URLRisorsa" flush="true | false" /> dove i parametri indicano: page: URL della risorsa fa includere flush: attributo booleano che indica se il buffer deve essere svuotato o meno. Questa azione può venire completata con la dichiarazione di eventuali parametri legati agli oggetti inclusi: <JSP:INCLUDE< font>page="URLRisorsa" flush="true|false"> {} . : consente di eseguire una richiesta di una risorsa statica, un servlet o un'altra pagina JSP interrompendo il flusso in uscita. Il risultato è quindi la visualizzazione della sola risorsa specificata Sintassi: <JSP:FORWARD< font>page="URLRisorsa"/> dove page specifica l'URL della risorsa a cui eseguire la richiesta del servizio. Ovviamente questa azione può anch'essa venire completata con la dichiarazione di parametri: <JSP:FORWARD< font>page="URLRisorsa"> {} . Una delle caratteristiche di Java è quella di poter gestire le eccezioni, cioè tutti quelli eventi che non dovrebbero accadere in una situazione normale e che non sono causati da errori da parte del programmatore. Dato che JSP deriva esplicitamente da Java, e ne conserva le caratteristiche di portabilità e robustezza, questo argomento è di grande rilevanza. Errori al momento della compilazione Questo tipo di errore si verifica al momento della prima richiesta, quando il codice JSP viene tradotto in servlet. Generalmente sono causati da errori di compilazione ed il motore JSP, che effettua la traduzione, si arresta nel momento in cui trova l'errore ed invia al client richiedente una pagina di "Server Error" (o errore 500) con il dettaglio degli errori di compilazione. Errori al momento della richiesta Questi altri errori sono quelli su cui ci soffermeremo perché sono causati da errori durante l'esecuzione della pagina e non in fase di compilazione. Si riferiscono all'esecuzione del contenuto della pagina o di qualche altro oggetto contenuto in essa. I programmatori java sono abituati ad intercettare le eccezioni innescate da alcuni tipi di errori, nelle pagine JSP questo non è più necessario perché la gestione dell'errore in caso di eccezioni viene eseguita automaticamente dal servlet generato dalla pagina JSP. Il compito del programmatore si riduce al creare un file .jsp che si occupi di gestire l'errore e che permetta in qualche modo all'utente di tornare senza troppi problemi all'esecuzione dell'applicazione JSP. Creazione di una pagina di errore Una pagina di errore può essere vista come una normale pagina JSP in cui si specifica, tramite l'opportuno parametro della direttiva page, che si tratta del codice per gestire l'errore. Ecco un semplice esempio: PaginaErrore.jsp <%@ page isErrorPage = "true" %> Siamo spiacenti, si è verificato un errore durante l'esecuzione: <%= exception.getMessage()%> A parte la direttiva page il codice Java è composto da un'unica riga che utilizza l'oggetto exception (implicitamente contenuto in tutte le pagine di errore) richiamando l'oggetto getMessage() che restituisce il messaggio di errore. Uso delle pagine di errore Perché nelle nostre pagine JSP venga utilizzata una determinata pagina di errore l'unica cosa da fare è inserire la seguente direttiva: <% page errorPage = "PaginaErrore.jsp" %> che specifica quale pagina di errore deve essere richiamata in caso di errore in fase di esecuzione. cookies non sono altro che quell'insieme di informazioni associate ad un particolare dominio che vengono memorizzate sul client sotto forma di file di solo testo, in modo da poter riconoscere un particolare utente dell'applicazione. Con lo sviluppo di applicazioni sempre più complesse ed efficienti, l'utilizzo dei cookies è diventato indispensabile, perché se usati nel modo giusto, non fanno altro che migliorare la navigazione. Fatte queste premesse, vediamo quali sono le istruzioni che ci servono. Naturalmente la prima fase è quella di scrivere un cookie, compito del metodo addCookie() dell'oggetto response: response.addCookie(cookie) dove il parametro di ingresso cookie non è altro che una classe che ha alcuni metodi che ci permettono di impostare le proprietà del cookie. Ecco come: Cookie mioCookie = new Cookie ("nome", "valore"); definisce un oggetto Cookie con il ripettivo nome e valore; mioCookie.setPath("/"); specifica il percorso che ha il privilegio di scrittura e lettura del cookie, se omesso è inteso il percorso corrente; mioCookie.setAge(secondiDiVita); imposta il periodo di vita, espresso in secondi; mioCookie.setSecure(false); indica se il cookie va trasmesso solo su un protocollo sicuro, protetto cioè da crittografia; response.addCookie(mioCookie); scrive il cookie. A questo punto mioCookie è scritto sul client. Per leggerlo l'operazione è leggermente più complicata. L'oggetto request dispone infatti di un metodo getCookies() che restituisce un array di oggetti cookie trovati nel client. Una volta ottenuto l'array, è quindi necessario passare in rassegna tutti i suoi elementi fino a trovare quello che ci interessa. Cookie mioCookie = null; definisce in cookie che verrà letto; Cookie[] cookiesUtente = request.getCookies(); definisce l'array di cookie e legge quelli dell'utente; int indice = 0; indice per la gestione del ciclo; while (indice < cookiesUtente.length) { esegue il ciclo fino a quando ci sono elementi in cookieUtente; if (cookiesUtente[indice].getName().equals("nomeMioCookie"); break; se trova un cookie con il nome che stiamo cercando esce dal ciclo; indice++; }//whileA questo punto controllando il valore dell'indice siamo in grado di capire se abbiamo trovato il nostro cookie. If (indice < cookiesUtente.length) il cookie è stato trovato e viene messo nell'oggetto mioCookie; mioCookie = cookiesUtente[indice]; else mioCookie = null; il cookie non è stato trovato. Ora, se il cookie è stato trovato, è possibile accedere ai sui dati con i metodi dell'oggetto stesso, principalmente getValue() per ottenere il valore contenuto. Valore = mioCookie.getValue() Altri metodi sono: getName(): restituisce il nome getAge(): restituisce il periodo di vita in secondi getPath(): restituisce il percorso che ha il permesso di lettura/scrittura getSecure(): restituisce un booleano che dice se il cookie è sicuro oppure no. I Java bean sono componenti software esterni che permettono di semplificare l'inserimento di istruzioni in una pagina JSP: in paritocolare, i Beans API provvedono ad una standardizzazione del formato delle classi Java.Le JSP infatti sono estensioni dei servlet Java, di conseguenza consentono di ottenere tutti i risultati di questi ultimi. Lo svantaggio dei Servlet è però rappresentato, come per tutti gli script CGI, dalla difficoltà di manutenzione del codice HTML delle applicazioni eccessivamente complesse, in quanto il più delle volte contengono una quantità di codice scriptlet eccessiva per un programmatore non esperto in Java. Grazie ai Java Beans quindi i programmi possono reperire automaticamente informazioni riguardo le classi che seguono il formato API e di conseguenza creare e manipolare classi senza che lo user debba scrivere un codice esplicito. Si ottiene perciò permettendo quindi un ottimo incapsulamento del codice, peraltro riutilizzabile. Al programmatore quindi sarà pressochè invisibile la sezione di codice puro, sostituito da richiami ai metodi delle classi incluse. I 3 punti fondamentali dei Beans sono i seguenti: 1. Una classe bean deve avere un costruttore ad argomento nullo (vuoto): ciò è ottenibile definendo esplicitamente un costruttore o omettendoli tutti, per cui viene automaticamente creato un costruttore vuoto; 2. Una classe bean non deve avere variabili pubbliche; 3. Gli accessi ai valori persistenti devono avvenire tramite metodi denominati getXxx e setXxx. Esistono tre azioni standard per facilitare l'integrazione dei JavaBean nelle pagine JSP. <jsp:useBean> Permette di associare un'istanza di un JavaBean (associata ad un determinato ID) ad una variabile script dichiarata con lo stesso ID. In pratica offre la possibilità di associare la classe contenuta nel JavaBean ad un oggetto visibile all'interno della pagina, in modo da poter richiamare i suoi metodi senza dover ogni volta far riferimento al file di origine. Attributi: Id: identità dell'istanza dell'oggetto nell'ambito specificato. Scope: ambito dell'oggetto, le opzioni sono: page: gli oggetti con questo ambito sono accessibili solo all'interno della pagina in cui sono stati creati, in pratica possono venire paragonati alle variabili locali di un qualsiasi linguaggio di programmazione, vengono distrutte alla chiusura della pagina e i dati saranno persi; request: gli oggetti con questo ambito sono accessibili esclusivamente nelle pagine che elaborano la stessa richiesta di quella in cui è stato creato l'oggetto, quest'ultimo inoltre rimane nell'ambito anche se la richiesta viene inoltrata ad un'altra risorsa; session: gli oggetti definiti in quest'ambito sono accessibili solo alle pagine che elaborano richieste all'interno della stessa sessione di quella in cui l'oggetto è stato creato per poi venire rilasciati alla chiusura della sessione a cui si riferiscono, in pratica restano visibili in tutte le pagine aperte nella stessa istanza (finestra) del Browser, fino alla sua chiusura. Solitamente i bean istanziati in questo modo vengono utilizzati per mantere le informazioni di un utente di un sito; application: gli oggetti definiti in quest'ambito sono accessibili alle pagine che elaborano richieste relative alla stessa applicazione, in pratica sono validi dalla prima richieta di una pagina al server fino al suo shotdown. class: nome della classe che definisce l'implementazione dell'oggetto beanName: contiene il nome del bean che, come già accennato deve coincidere con il nome del file .class (senza estensione) Esempio: <jsp:useBean id="nomeBean" scope="session" class="classe" /> Crea un'istanza della classe classe con ambito session richiamabile attraverso l'id NomeBean: da questo momento sarà possibile accedere a metodi e variabili (pubbliche) attraverso la sintassi nomeBean.nomeMetodo e nomeBean.nomeVariabile, rispettivamente per metodi e variabili. <jsp:setProperty> Permette di impostare il valore di una delle proprietà di un bean. Ne esistono varie forme, vediamo la più comune. Attributi: name: nome dell'istanza di bean definita in un'azione property: rappresenta la proprietà di cui impostare il valore param: nome del parametro di richiesta il cui valore si vuole impostare value: valore assegnato alla proprietà specificata Esempio: <jsp:setProperty name="nome_bean" property="prop" param="nome_parametro" /> Permette di assegnare il valore del parametro nome_parametro alla proprietà prop del bean di nome nome_bean. <jsp:getProperty> Prende il valore di una proprietà di una data istanza di bean e lo inserisce nell'oggetto out implicito (in pratica lo stampa a video). Alternativamente si potrebbe usare una espressione JSP e chiamare esplicitamente un metodo sull'oggetto che il nome della variabile specificata con l'attributo id. Attributi: name: nome dell'istanza di bean da cui proviene la proprietà definita da un'azione property: rappresenta la proprietà del bean di cui si vuole ottenere il valore Vediamo subito un semplice esempio di bean, realizzato per contenere le informazioni di un utente durante la sua permanenza nel sito. InfoUtente.java public class InfoUtente { private String nome = null; private String email = null; private int pagineViste; public InfoUtente() { pagineViste=0; } public aggiornaPV(){ pagineViste++; } public int getPagineViste(){ return pagineViste; } public void setNome(String value) { > nome = value; } public String getNome() { return nome; } public void setEmail(String value) { email = value; } public String getEmail() { return email; } public String riassunto(){ String riassunto = null; riassunto = "Il nome dell'utente è"+nome+","; riassunto+= "il suo indirizzo e-mail è: "+email; riassunto+=" e ha visitato "+pagineViste+" del sito"; return riassunto; } }//InfoUtente Questo bean contiene il nome dell'utente ed i metodi per modificarlo e restituirlo, il suo indirizzo email con i relativi metodi, il numero di pagine viste dall'utente e un metodo che restituisce un riassunto schematico dei dati dell'utente. Ecco come utilizzarli: <html> <head><title>Utilizzo del Bean</title></head> <body> <jsp:useBean id="utente" scope="session" class="InfoUtente"/> Viene creata un'istanza del bean InfoUtente con ambito session, necessario per questo tipo di funzione: <jsp:setProperty name="utente" property="nome" value="Zina&Tram"/> La proprietà del bean possono essere impostate con l'azione setProperty o agendo direttamente con i metodi creati appositamente. <% utente.setNome("Zina&Tram"); utente.setEmail("[email protected]"); %> Lo stesso vale per la lettura dei bean che puo essere fatta con l'azione: <jsp:getProperty name="utente" property="nome"/> o agendo sui metodi creati: <% out.println(utente.getNome()); out.println(utente.riassunto()); %> Per incrementare il numero di pagine viste è sufficiente richiamare il metodo aggiornaPV() e per ottenere il valore getPagineViste(). <% utente.aggiornaPV(); out.println(utente.getPagineViste()); %> L'applicazione pratica con jsp che viene analizzata in seguito consiste nella creazione di un sondaggio, in cui gli utenti di un sito possono rispondere ad una domanda scegliendo tra le risposte proposte ed eventualmente visualizzare i risultati parziali delle votazioni. Come per tutti i sondaggi seri realizzati per un sito Internet è previsto il controllo del doppio voto, reso impossibile dalla memorizzazione degli indirizzi ip degli utenti che votano. L'applicazione è costituita da 4 file: sondaggio.htm, contenente il form da cui l'utente risponde alla domanda vota.jsp, che esegue la votazione proveniente dal form risultati.jsp, che visualizza i risultati parziali delle votazioni sondaggio.mdb, il database che gestisce tutto il sondaggio. Questo è costituito da due tabelle. La prima "frequenza" contiene un campo chiamato "risp" di tipo byte che indica il numero della risposta, e un campo "frequenze" di tipo intero che indica il numero di volte che si è votato per la rispettiva risposta. Nell'esempio, con 4 possibili risposte al sondaggio, la tabella è stata completata inserendo nelle prime 4 righe del campo "risp" i valori 0-1-2-3 e nel campo "frequenze", ovviamente, i valori 0-0-0-0. La seconda tabella si chiama "ip_tab" e contiene in un campo "ip" di tipo testo la lista degli indirizzi ip di tutti gli utenti che hanno effettuato il voto. Vediamo nel dettaglio gli altri 3 file: Sondaggio.htm <html><head> <title>Sondaggio</title> </head> <body> <b><big>Domanda:</big></b> <form action="vota.jsp"> <input name="risposta" type="radio" value="0">Risposta 1<br> <input name="risposta" type="radio" value="1">Risposta 2<br> <input name="risposta" type="radio" value="2">Risposta 3<br> <input name="risposta" type="radio" value="3">Risposta 4<br> <input type="submit" value="vota"> </form> <a href="risultati.jsp">Visualizza i risultati parziali</a> </font> </body> </html> Vota.jsp Questo file esegue in pratica la votazione, aggiornando il database dopo aver fatto il controllo sull'ip dell'utente. Non deve essere necessariamente modificato. Al limite si possono personalizzare i messaggi di eseguita o fallita votazione. <html> <head> <title>Sondaggio</title> </head> <body> <font face="verdana" color="#3300ff" size="2"> <% page errorPage = "PaginaErrore.jsp" %> <%@ page language="java" import="java.sql.*" %> <% Connection conn = null; //carica il file di classe del driver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //crea la connessione con l'origine dati conn = DriverManager.getConnection("jdbc:odbc:sondaggio","",""); //crea lo statement Statement st = conn.createStatement(); //legge il parametro contenente la risposta String preferenza = new String (request.getParameter("risposta")); String ip = new String(request.getRemoteAddr()); ResultSet rs = st.executeQuery("SELECT ip from ip_tab WHERE ip LIKE '"+ip+"'"); if(!rs.next()){ //l'ip non ha mai votato //esito dell'aggiormanento al Data base int esito; //crea la tringa SQL per l'aggiornamento String stringaSql = new String ("INSERT INTO ip_tab (ip) VALUES ('"+ip+"')"); st.executeUpdate(stringaSql); //crea la stringa SQL per l'aggiornamento stringaSql = "UPDATE frequenze SET frequenza=frequenza+1 WHERE risp LIKE '"+preferenza+"'"; esito = st.executeUpdate(stringaSql); //controlla che tutto sia andato bene if (esito==1) out.println("Votazione eseguita con successo"); else out.println("Errore, non stato possibile eseguire la votazione"); }//if else{ //l'utente ha gia votato out.println("Spiacenti, hai già votato!<br>"); out.println("Per ragioni di credibilità del sondaggio<br>"); out.println("ogni visitatore può votare una sola volta<br><br>"); }//else st.close(); conn.close(); %> <br><br> <a href="risultati.jsp">Visualizza i risultati parziali</a> </font> </body> </html> Risultati.jsp Questo è il file che esegue il compito più complicato. Deve estrarre dal database il numero di utenti che hanno votato in totale e per ogni singola risposta, calcolare la percentuale e stampare una breve tabella di riepilogo e un grafico che riassume visivamente l'andamento del sondaggio. Nel file appena visto deve essere modificato il numero di possibili risposte (riga 20) e il valore delle stringhe contenenti le risposte (righe 25-28). Tutto il resto del codice può rimanere invariato. <html> <head> <title>Risultati del sondaggio</title> </head> <body bgcolor=#FFFF99><center> <b><big>Domanda del sondaggio</b></big><br><br> <% page errorPage = "PaginaErrore.jsp" %> <%@ page language="java" import="java.sql.*" %> <% Connection conn = null; //carica il file di classe del driver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //crea la connessione con l'origine dati conn = DriverManager.getConnection("jdbc:odbc:sondaggio","",""); //crea lo statement Statement st = conn.createStatement(); /* --- DEFINIZIONE DI VARIABILI --- */ int numRisp = 4; //numero possibili risposte int votiTot; //numero totale dei voti float percentuale; //percentuale per ogni risposta int frequenze[] = new int[numRisp]; //numero di voti per ogni risposta String risposte[] = new String[numRisp]; //array di stringhe con le risposte risposte[0]="Risposta 1"; risposte[1]="Risposta 2"; risposte[2]="Risposta 3"; risposte[3]="Risposta 4"; //crea il recordset -> calcolo dei voti totali ResultSet rs = st.executeQuery("SELECT sum(frequenza) as tot from frequenze"); rs.next(); votiTot = rs.getInt("tot"); out.println("Totale dei voti: "+votiTot+"<br>"); //calcolo dei voti per ogni singola risposta e stampa for (int i=0; i<numRisp; i++){ rs=st.executeQuery("SELECT sum(frequenza) as tot from frequenze WHERE risp = "+i); rs.next(); frequenze[i]=rs.getInt("tot"); out.println(risposte[i]+": "+frequenze[i]+" voti<br>"); }//for %> <br><br> <table align=center border=0> <%//creazione del grafico dei voti for (int i=0; i<numRisp; i++){ //calcolo della percentuale percentuale = (float)frequenze[i]/votiTot*100; out.println("<tr valign='center' align='left'><td>"); out.println(risposte[i]+"</td><td>"); out.println("<img src='blu.gif' width="+percentuale*5+" height=20>"); out.println((int)percentuale+"%</td>"); }//for %> </tr> </table> <% st.close(); rs.close(); conn.close(); %> </body> </html> le JSP sono state create anche per facilitare l'implementazione di servizi di commercio elettronico, in rapida via di sviluppo soprattutto di questi tempi. Il più delle volte per comprare un qualsiasi tipo di oggetto sul web, si utilizza utilizzato quello che viene chiamato carrello della spesa elettronico, che permette di memorizzare gli oggetti che si intende acquistare ed eventualmente annullarne l'ordinazione. Come esempio si è supposto di dover creare un carrello della spesa per un negozio di CD musicali. Il progetto che implementa tale servizio è formato da tre file: Carrello.jsp: rappresenta il catalogo dei CD disponibili, con la possibilità di ordinazione; visCarr.jsp: visualizza il contenuto attuale del carrello, permettendo l'annullamento di un eventuale acquisto; Carrello.java: bean che contiene tutte le funzioni di memorizzazione, eliminazione e quant'altro, utili allo sviluppo delle pagine JSP. Per prima cosa è necessario esaminare il bean, affinché risultino chiare le funzioni utilizzate poi nelle due JSP. //Carrello.java import java.lang.String; import java.lang.Integer; import java.lang.Float; import java.util.Hashtable; import java.util.Enumeration; public class Carrello{ //variabile di tipo Hashtable utilizzata per memorizzare gli elementi presenti nel carrello protected Hashtable cd = new Hashtable(); //varibile intera utilizzata per la memorizzazione del numero di CD attualmente nel carrello private int numCd; //costruttore public Carrello() { numCd=0; }//Carrello //metodo per ottenere il numero di CD attualmente nel carrello public int totCD(){ return numCd; }//numCD // Inserimento di cd nel carrello // I: id: indice chiave di identificazione del CD // art: nome dell'artista // tit: titolo dell'album // prezzo: prezzo del CD public void aggiungiCd (String id, String art, String tit, float prezzo){ //inserimento in un vettore di stringhe degli attributi del CD appena inserito nel carrello //è inserito inoltre il numero di CD di quel tipo ordinati String[] dati_cd= {art, tit, Float.toString(prezzo) , "1", id}; numCd++; //se il CD è non già stato ordinato if (!cd.containsKey(id)){ //inserisci il CD nel carrello cd.put(id, dati_cd); }//if //altrimenti else { //incrementa il numero di CD di quel tipo ordinati int tmp; String[] datiTemp = (String[])cd.get(id); tmp = Integer.parseInt(datiTemp[3]); tmp++; datiTemp[3]=Integer.toString(tmp); cd.put(id, datiTemp); }//else }//aggiungiCd //Metodo di rimozione dal carrello di un CD //I: id: indice del CD da rimuovere public void rimuoviCd (String id){ //se il CD è presente nel carrello if (cd.containsKey(id)) { //decrementa il numero di CD numCd--; String[] temp = (String[])cd.get(id); //se il CD è presente in copia singola if (Integer.parseInt(temp[3]) == 1) //elimina il CD dal carrello cd.remove(id); //altrimenti else { //decrementa il numero di copie di quel CD ordinate int tmp = 0; String[] datiTemp = (String[])cd.get(id); tmp = Integer.parseInt(datiTemp[3]); tmp--; datiTemp[3]=Integer.toString(tmp); cd.put(id, datiTemp); }//else }//if }//rimuoviCd //Metodo per la creazione di un oggetto Enumeration utilizzato per scorrere velocemente //gli elementi nel carrello public Enumeration enum() { return cd.elements(); }//enum //Metodo che restituisce il prezzo totale dei CD inseriti nel carrello fino adesso public float spesaTot(){ float tot = 0.00f; String[] temp; //crea l'oggetto Enumeration Enumeration i = this.enum(); //finchè ci sono elementi nel carrello while (i.hasMoreElements()){ temp = (String[])i.nextElement(); //incrementa la spesa totale del prezzo del CD corrente tot += (Float.parseFloat(temp[2]) * Integer.parseInt(temp[3])); }//while return tot; }//spesaTot //Metodo che restituisce il prezzo di un CD moltiplicato per il numero delle copie ordinate //I: id:indice del CD public float prezzo(String id){ String[] temp; float tmp=0.0f; temp = (String[])cd.get(id); tmp = Float.parseFloat(temp[2]) * Integer.parseInt(temp[3]); return tmp; }//prezzo E' interessante notare come la classe Hashtable renda facile memorizzare e accedere alle informazioni, rendendole per certi aspetti molto simili ad un database. Infatti, suddetta classe (contenuta nel package java.util e derivata dalla classe astratta Dictionary) permette di memorizzare una collezione di oggetti (più specificatamente delle coppie oggetto-chiave) avente funzioni molto simili ai database: le chiavi non replicabili permettono infatti un veloce accesso ai dati.Sia le chiavi che gli oggetti devono essere di tipo Object. I metodi più importanti implementati da Hashtable sono: hashtable.size(): restituisce un intero contenente il numero di elementi inseriti in hashtable; hashtable.isEmpty (): restituisce un valore booleano che indica se il dizionario è vuoto o meno (il valore true segnala il dizionario vuoto); hashtable.get (Object chiave): restituisce l'oggetto a cui è associata la chiave chiave, se la chiave non viene trovata restituisce null;hashtable.put (Object chiave, Object elemento): inserisce in hashtable l'elemento elemento e gli associa la chiave chiave, se chiave è già stata inserita viene sostituito l'oggetto a lei associato e viene restituito, altrimenti viene restituito null; hashtable.remove (Object chiave): rimuove da hashtable l'elemento associato a chiave, se la chiave non esiste viene restituito null. Ad un oggetto di tipo Hashtable può venire associato un oggetto di tipo Enumeration, che permette di scorrere la collezione di oggetti, utilizzando i metodi: enumeration.hasMoreElements (): che restituisce il valore booleano true se ci sono ancora elementi da scorrere; enumeration.nextEle(): si sposta all'elemento successivo. Grazie alla creazione di questo bean la pagina Carrello.jsp (qui di seguito) presenta un buon incapsulamento del codice, facilitando sia l'interpretazione (è fatto prevalentemente a codice HTML) che la modifica. <!-- Carrello.jsp --> <HTML> <HEAD> <TITLE>Vendita CD On-line</TITLE> </HEAD> <BODY BGCOLOR="#33CCCC" text="#000099" vlink="#990099" alink="#000099"> <!-istanziazione del bean Carrello.jsp, con ambito session --> <jsp:useBean id="car" scope="session" class="Carrello" /> <% String id = request.getParameter("id"); //se è stato aggiunto un CD al carrello if (id != null){ //acquisisci i dati del CD String artista=request.getParameter("artista"); String titolo=request.getParameter("titolo"); float prezzo = Float.parseFloat(request.getParameter("prezzo")); //e aggiungilo al carrello car.aggiungiCd (id, artista, titolo, prezzo); }//if %> <font face="Verdana" size="6"> <center> CATALOGO COMPACT DISC A DISPOSIZIONE <br><br> </center> </font> <font face="Verdana"> <a href="visCarr.jsp"> Quantità attualmente nel carrello: </a> <%= car.totCD();%> <br><br> <center> <table width="60%" border="1" align="center" bordercolorlight="#990099" bordercolordark="#990099"> <tr> <th>Artista</th> <th>Titolo</th> <th>Prezzo</th> </tr> <tr> <form action="Carrello.jsp" method="post"> <td>Dream Theater</td> <td>Awake</td> <td>L.25000</td> <td><center><input type="submit" name="add" name="acquista" value="Aggiungi al carrello"></center></td> <input type="hidden" name="id" value="1"> <input type="hidden" name="artista" value="Dream Theater"> <input type="hidden" name="titolo" value="Awake"> <input type="hidden" name="prezzo" value="25000"> </form> <td> </tr> <tr> <form action="Carrello.jsp" method="post"> <td>Iced Earth</td> <td>The Dark Saga</td> <td>L.35000</td> <td><center><input type="submit" name="add" name="acquista" value="Aggiungi al carrello"></center></td> <input type="hidden" name="id" value="2"> <input type="hidden" name="artista" value="Iced Earth"> <input type="hidden" name="titolo" value="The Dark Saga"> <input type="hidden" name="prezzo" value="35000"> </form> <td> </tr> <tr> <form action="Carrello.jsp" method="post"> <td>Queen</td> <td>Innuendo</td> <td>L.35000</td> <td><center><input type="submit" name="add" name="acquista" value="Aggiungi al carrello"></center></td> <input type="hidden" name="id" value="3"> <input type="hidden" name="artista" value="Queen"> <input type="hidden" name="titolo" value="Innuendo"> <input type="hidden" name="prezzo" value="35000"> </form> <td> </tr> </table> </font> </center> </BODY> </HTML> Infine vediamo il codice di visCar.jsp: <!-- visCarr.jsp --> <!-- inclusione dei package per l'utilizzo di alcune funzioni standard --> <%@ page import="java.util.*" %> <%@ page import="java.lang.*" %> <!-- istanziazione del bean Carrello.jsp con ambito session --> <jsp:useBean id="car" scope="session" class="Carrello" /> <HTML> <HEAD> <TITLE>Carrello della spesa</TITLE> </HEAD> <BODY BGCOLOR="#33CCCC" text="#000099" vlink="#990099" alink="#000099"> <% String idtmp = request.getParameter("id"); //se è stato eliminato un CD dal carello if (idtmp != null){ car.rimuoviCd(idtmp); }//if %> <font face="Verdana" size="6"> <center> CARRELLO </center> </font><br><br> <font face="Verdana"> Quantità attualmente nel carrello: <%= car.totCD();%> <br><br> <center> <table width="60%" border="1" align="center" bordercolorlight="#990099" bordercolordark="#990099"> <tr> <th>Artista</th> <th>Titolo</th> <th>Prezzo (L.)</th> <th>Quantità</th> </tr> <% //creazione di un oggetto Enumeration Enumeration ogg = car.enum(); String[] temp; //finchè ci sono elementi nel carrello while (ogg.hasMoreElements()){ temp= (String[])ogg.nextElement(); %> <tr> <td><%= temp[0] %></td> <td><%= temp[1] %></td> <td>L.<%= car.prezzo(temp[4])%></td> <td><center><%= Integer.parseInt(temp[3]) %></center></td> <td><center><form action="visCarr.jsp" method="post"><input type="submit" name="rem" name="togli" value="Togli"></center></td> <input type="hidden" name="id" value= <%= temp[4]%>> </form> <td> </tr> <% }//while %> <tr> <td></td> <td>Tot</td> <td>L.<%= car.spesaTot()%></td> <td><center><%= car.totCD()%></center></td> </tr> </table> <font size="2"> [ <a href="Carrello.jsp">Indietro</a> ] </font> </center> </BODY> </HTML> In questo caso è stata utilizzata la direttiva page (spiegata precedentemente) affinché venissero inclusi nella pagina alcuni package di utilità. SITO WEB -------------------Il progetto che abbiamo realizzato è un sito di sicurezza informatica utile, ad esperti e non del settore, per tenersi costantemente informati sui tipi di attacchi in circolazione e sui sistemi che possono esserne colpiti. Il sito contiene un database, che ne costituisce la parte fondamentale: è, infatti, grazie ai dati in esso contenuti che possono essere soddisfatte le richieste degli utenti che si collegano. In tale base di dati si trovano informazioni sulle vulnerabilità dei sistemi, ossia sulle possibili crepe in un'applicazione o in un processo a fronte di situazioni inaspettate, e su chi le ha scoperte. Ci sono poi delle notizie supplementari sulle patch (rettifiche dei programmi vulnerabili in cui sono state aggiunte o corrette piccole parti dei programma stessi), sui sistemi operativi in cui le vulnerabilità elencate sono state riscontrate e, infine, sui software che utilizzano queste debolezze dei sistemi per comprometterli (gli exploit) con i rispettivi autori. Il sito viene costantemente aggiornato, tramite un'area privata, dall'amministratore, che inserisce nel database i nuovi dati di cui viene a conoscenza perché gli utenti possano usufruirne il prima possibile. Nella home page, inoltre, è presente una sezione per le news in cui sono riportate le ultime notizie relative al mondo della sicurezza informatica. Infine, per chi voglia avere delle informazioni specifiche, è possibile interrogare il database grazie ad un'area del sito adibita a questo scopo in cui viene richiesta la compilazione di brevissimi form: si possono richiedere, per esempio, i dati relativi alle vulnerabilità associate ad un determinato sistema operativo oppure gli exploit che potrebbero colpirlo. Applicazioni web in JAVA Prima di iniziare con la descrizione del sito web che abbiamo creato, oggetto della nostra tesina, occorre spiegare di quale tecnologia ci siamo serviti e, soprattutto, dei motivi che ci hanno spinto a farlo: sarà dunque necessario prendere confidenza con alcuni termini e concetti di fondamentale importanza ai quali nel seguito faremo frequentemente riferimento. Il Web ha un'architettura client/server, vale a dire applicazioni basate su server comunicano con stazioni di lavoro client tramite una rete. Un' applicazione web è un programma che viene eseguito su un server web. Un server web è un software preposto a fornire contenuti Internet agli utenti: esso accetta la richiesta di un documento da parte di un browser o di un generico client http, lo recupera dal disco e lo restituisce al chiamante. Un client web è un client che interagisce con un server web utilizzando il protocollo http: egli avvia un browser, quale Internet Explorer o Netscape Navigator, e richiede un documento specificando l'indirizzo Internet della pagina web in cui esso si trova, l'url, che lo identifica univocamente all'interno della rete. Agli albori del web tutti i contenuti informativi presenti in rete erano di tipo statico: l'informazione da inserire veniva stabilita al momento della creazione della pagina e non cambiava da una richiesta all'altra, o da un utente all'altro, fino a che il webmaster non aggiornava il sito sostituendo i documenti html che lo costituivano. Oggigiorno il web è molto più dinamico: la sua tecnologia si è evoluta enormemente non solo a livello di client ma soprattutto sul lato server. Dal lato client, un primo tipo di tecnologia utilizzato nello sviluppo di siti dinamici sono state le Applet Java, piccole applicazioni create per essere eseguite all'interno di un browser ed estenderne le funzionalità, col compito, quindi, di trasformare una pagina web in una applicazione interattiva. Una seconda innovazione introdotta nella struttura del web dinamico sono stati gli script lato client: i linguaggi di scripting, come JavaScript e VBScript, sono linguaggi interpretati in quanto i programmi non vengono compilati prima di essere eseguiti, ma vengono interpretati una riga per volta. Il vantaggio di un tale approccio consiste nella possibilità di alleggerire parte del lavoro del server perché permette a piccole applicazioni, come quelle per la convalida di un modulo, di essere eseguite sul client. Pagina 2 di 3 A questo tipo di interattività lato client è stata però preferita un'elaborazione che sposta la logica dell'applicazione sul server: in questo modo è possibile ridurre i requisiti che il browser utilizzato dall'utente deve soddisfare, in quanto, piuttosto che imporre il supporto di applet Java o di altre tecnologie client-side, al browser viene richiesto esclusivamente di svolgere la propria funzione di visualizzazione di pagine web, mentre l'invio di informazioni al server avviene tramite i comuni "form" html. Da questo punto di vista, tra le tecnologie che supportano siti web dinamici, troviamo quelle che consentono l'implementazione delle pagine dinamiche: all'interno della pagina htmL vengono inseriti particolari tag, elaborati sul lato server, che permettono di eseguire del codice sviluppato dal programmatore. In quest'ambito è molto affermata la tecnologia PHP: essa si basa su un linguaggio di scripting simile al Perl, è dotata di un'ampia libreria di base con le più disparate funzionalità ed è inoltre disponibile per diverse piattaforme. Sul versante Microsoft, invece, l'offerta per la creazione di contenuto dinamico per il web sono le pagine ASP, documenti HTML in cui è possibile inserire codice VBA (Visual Basic for Applications), e compatibili solo con il server web di Microsoft. All'interno di questo panorama, spiccano le tecnologie del linguaggio Java per lo sviluppo di siti web dinamici: le Servlet e le Java Server Pages (JSP). Una servlet è un componente web sviluppato in Java che genera contenuto dinamico, il cui scopo è di estendere le funzionalità di un server web, mentre le JSP sono la tecnologia, complementare a quella delle servlet come avremo modo di vedere meglio nel seguito, per la creazione di pagine web dinamiche. Questi standard sono molto diffusi in quanto dispongono di caratteristiche migliorative che li differenziano dalle altre tecnologie disponibili, come PHP e ASP, e che possiamo riassumere in diversi punti: Efficienza. Il modello di esecuzione delle servlet è più efficiente rispetto a quello di una applicazione CGI: nel modello CGI viene creato un nuovo processo per ogni richiesta da esaudire, nel caso delle servlet, invece, ad ogni richiesta corrisponde la creazione di un thread, operazione molto meno onerosa per il server. Portabilità. Un'applicazione web sviluppata in Java è indipendente dal server web e dal sistema operativo: essa è portabile su tutte le piattaforme per cui esista una Virtual Machine e fornisce quindi una maggiore flessibilità. Robustezza. Un aspetto importante delle servlet è la robustezza: il codice Java gira all'interno della Virtual Machine che è un elemento isolante rispetto al sistema operativo. Eventuali errori di programmazione non possono creare malfunzionamenti tali da danneggiare il corretto funzionamento del web server. Inoltre le servlet sono immuni dagli attacchi dei pirati informatici in quanto la Virtual Machine e il Class Loader si occupano di isolare e verificare il codice che viene eseguito. Scalabilità. L'architettura delle servlet consente in modo piuttosto naturale di introdurre tecniche di bilanciamento del carico (load balancing) suddividendolo tra più server. Potenza. La persistenza di una servlet su più richieste (una servlet rimane in memoria fino a quando non viene terminata) consente di condividere facilmente informazioni tra i thread corrispondenti e di sincronizzare le richieste; questo semplifica notevolmente, ad esempio, la realizzazione di applicazioni di tipo collaborativo. Accesso alle API standard. Basandosi sulla piattaforma Java, le servlet possono accedere ad un ampio ventaglio di API quali JDBC (Java Database Connectivity) per l'accesso ai database relazionali, JAXP (Java API for XML Processing) che permette di trattare con documenti XML, JCA (Java2EE Connection Architecture) che consente l'integrazione di applicazioni esistenti, ecc. Libreria di base. Il codice di implementazione delle servlet può fare affidamento su un ampia gamma di funzioni presenti nella libreria di base di Java e nelle sue estensioni, che è estremamente completa (supera di diverse lunghezze quelle disponibili in PHP o ASP). Questo aspetto può comportare un netto risparmio del tempo di sviluppo, in quanto molte funzionalità non devono essere implementate ma possono essere semplicemente riutilizzate. Gestione delle sessioni. http è per sua natura un protocollo stateless: per il server ciascuna richiesta è svincolata dalla precedente; con il solo http non si è quindi in grado di determinare se più richieste sono legate ad uno stesso utente. Le servlet, invece, offrono una gestione integrata delle sessioni utente in grado di indicare se una richiesta è stata inoltrata ad un utente già attivo. Tutti questi vantaggi fanno della tecnologia delle servlet uno dei maggiori successi del linguaggio Java, testimoniato dall'ampia accettazione riscontrata nelle aziende che hanno adottato questo standard. Le altre alternative (come CGI, PHP, ASP) non hanno tutti i lati positivi delle servlet: molte ne hanno qualcuno, ma nessuna li ha tutti. Se le servlet sono le estensioni del server del Java, le Java Server Pages (JSP) sono una tecnologia ad esse complementare che si colloca, come suggerisce il nome, nel contesto delle server pages, caratterizzate da diversi elementi: Sono dinamiche in quanto il loro output può dipendere da fattori quali il momento in cui vengono eseguite, il risultato di operazioni sul database, informazioni fornite dall'utente e così via. Sono tecnologie lato server, nel senso che l'esecuzione delle componenti dinamiche avviene sul server e ciò che viene inviato al browser è esclusivamente il risultato prodotto dall'esecuzione della pagina. Consentono l'immersione del codice nell'HTML della pagina; in tal modo i contenuti dinamici della pagina vengono generati da frammenti di programma (scriplet) mentre le parti statiche, che vengono lasciate immutate, ne definiscono l'aspetto grafico. Da un punto di vista fisico quindi una pagina JSP è un semplice file testuale il cui contenuto è, solitamente, HTML oppure XML. La cosa che rende interessante una pagina JSP è la possibilità di inserire al suo interno delle componenti dinamiche che vengono eseguite ad ogni accesso alla pagina e possono essere utilizzate per generare un output personalizzato. Il grande vantaggio delle JSP è che queste vengono compilate in servlet, usufruendo di fatto di tutte le caratteristiche di queste ultime. Ci si potrebbe dunque chiedere perché esistano in Java due tecnologie di presentazione di informazioni su http, infatti tutto ciò che è realizzabile in JSP è creabile come servlet e viceversa, e la risposta è che le due tecnologie hanno in realtà scopi leggermente diversi. Le pagine JSP, infatti, presentano una differenza notevolmente rilevante rispetto alle servlet, in quanto consentono di attuare una separazione dei ruoli nella fase della loro creazione: i grafici web possono focalizzare la loro attenzione sull'estetica della pagina mentre il programmatore Java può aggiungere il contenuto dinamico. Inoltre, nelle pagine JSP, i programmatori, preposti allo sviluppo della logica dell'applicazione, non devono essere esperti di Java come deve essere, al contrario, nella scrittura delle servlet. Alla luce di quanto detto, appare dunque chiaro il motivo per cui la nostra scelta è ricaduta sulla tecnologia JSP: innanzitutto l'abbiamo preferita al PHP e all'ASP perché, pur essendo sicuramente più difficile da implementare, è tuttavia molto più potente ed offre tutti i vantaggi che abbiamo descritto; in secondo luogo, non essendo espertissimi programmatori Java, abbiamo potuto sfruttare l'opportunità, offertaci dal JSP ma non dalle servlet, di poter conoscere solo le basi di questo linguaggio per poter comunque aggiungere contenuti dinamici al nostro sito. E' importante capire ora come una pagina JSP cambi quando, per poter essere eseguita, viene trasformata in una servlet equivalente. Fig. 1 Applicazioni web in JAVA Come si può facilmente vedere dalla figura riportata sopra, per prima cosa una pagina JSP viene tradotta nel codice servlet appropriato che è un file .java. Successivamente il codice viene compilato in un file .class che viene poi eseguito. A questo punto viene generato e inviato in risposta al client il documento HTML di output. Potrebbe questo sembrare un processo dispendioso in termini di prestazioni, tuttavia, a parte la prima chiamata alla pagina JSP, le richieste successive non passano più attraverso la fase di traduzione, ma si dirigono direttamente al file .class compilato. Pagina 1 di 2 Definizione dello schema della base di dati create table Vulnerabilita ( codice character(4) primary key, nomev character(20) not null, autore character(4) not null references Autore(id), datap character(10), dataa character(10) not null, serviziointernet character(6) not null, cve character(15) not null, pericolosita character(5) not null, tipovulnerabilita character(10) not null, usotipico character(15) not null, info blob ); create table Exploit ( nome character(20), datap character(10), dataa character(10) not null, versione character(4), dimensione numeric(10) not null, tipofile character(3) not null, usotipico character(15) not null, vulnerabilita character(4) not null references Vulnerabilita(codice), primary key (nome, vulnerabilita) ); create table Autore ( id character(4) primary key, nomea character(30) not null, linksito character(30), email character(30), tipoautore character(20) not null ); create table Patch ( nome character(20) primary key, linksito character(30) not null, dimensione numeric(10), vulnerabilita character(4) not null references Vulnerabilita(codice) ); create table SistemaOperativo ( codice character(4) primary key, nome character(20) not null, release character(20) not null, tecnologia character(10) not null, servicepack numeric(1), unique (nome, release, tecnologia) ); create table Bersaglio ( sistemaoperativo character(4)not null references SitemaOperativo(codice), vulnerabilita1 character(4) not null references Vulnerabilita(codice), primary key (sistemaoperativo, vulnerabilita) ); create table Realizzazione ( exploit character(20) not null references Exploit(nome), autore character(4) not null references Autore(id), vulnerabilita character(4) not null references Exploit(vulnerabilita), primary key (autore, exploit, vulnerabilita) ); create table News ( titolo character(50) not null, data char(10) not null, autore character(30) not null, testo blob, primary key (titolo,data) ); Pagina 2 di 2 Codifica delle operazioni 1. Inserire una nuova vulnerabilità con il relativo autore e sistema operativo Insert into Vulnerabilita(codice, nomev, autore, datap, dataa, serviziointernet, cve, pericolosita, tipovulnerabilita, usotipico, info) values(' ',' ',.) Insert into Autore (id, nomea, linksito, email, tipoautore) values(' ',' ',.) Insert into Bersaglio (sistemaoperativo, vulnerabilita1) values(' ',' ',.) Insert into SistemaOperativo (codice, nome, release, tecnologia, servicepack) values(' ',' ',.) 2. Inserire un nuovo exploit con il relativo autore Insert into Exploit (nome, datap, dataa, versione, dimensione, tipofile, usotipico, vulnerabilita) values(' ',' ',.) Insert into Autore (id, nomea, linksito, email, tipoautore) values(' ',' ',.) Insert into Realizzazione (exploit, autore, vulnerabilita) values(' ',' ',.) 3. Inserire una nuova patch Insert into Patch (nome, linksito, dimensione, vulnerabilita) values(' ',' ',.) 4. Inserire una nuova news Insert into News (titolo, data, autore, testo) values(' ',' ',.) 5. Dati nome, release e tecnologia di un determinato Sistema Operativo, mostrare tutte le vulnerabilità ad esso associate con le rispettive patch (se esistono). select Vulnerabilita.*, Patch.* from SistemaOperativo join Bersaglio on SistemaOperativo.codice = Bersaglio. sistemaoperativo join Vulnerabilita on Bersaglio.vulnerabilita1 = Vulnerabilita.codice left join Patch on Vulnerabilita.codice = Patch.vulnerabilita where SistemaOperativo.nome = ' ' and SistemaOperativo.release = ' ' and SistemaOperativo.tecnologia = ' ' 6. Dato il nome di una determinata vulnerabilità, estrarre tutti i Sistemi Operativi affetti da tale vulnerabilita' e le relative patch (se esistono). select SistemaOperativo.*, Patch.* from Vulnerabilita left join Patch on Vulnerabilita.codice = Patch.vulnerabilita join Bersaglio on Vulnerabilita.codice = Bersaglio.vulnerabilita1 join SistemaOperativo on Bersaglio.sistemaoperativo = SistemaOperativo.codice where Vulnerabilita.codice = ' ' or Vulnerabilita.nome = ' ' 7. Dati nome, release e tecnologia di un determinato Sistema Operativo, mostrare tutti gli exploit ad esso associati con il relativo autore. select Exploit.*, Autore.* from SistemaOperativo join Bersaglio on SistemaOperativo.codice = Bersaglio. sistemaoperativo join Vulnerabilita on Bersaglio.vulnerabilita1 = Vulnerabilita.codice join Exploit on Vulnerabilita.codice = Exploit.vulnerabilita join Realizzazione on Exploit.nome = Realizzazione.exploit join Autore on Realizzazione.autore = Autore.id where SistemaOperativo.nome = ' ' and SistemaOperativo.release = ' ' and SistemaOperativo.tecnologia = ' ' 8. Trovare gli Exploit relativi ad una stessa Vulnerabilità mostrando per ciascuno di essi il nome della Vulnerabilità in questione, il nome dell'Exploit e il nome del relativo Autore select V.Nome, R.Exploit, A.Nome from Realizzazione R join Vulnerabilita V on R.Vulnerabilita = V.Codice join Autore A on R.Autore = A.ID group by(R.Exploit) 9. Visualizzazione della tabella Vulnerabilità select * from Vulnerabilita 10. Visualizzazione della tabella Exploit select * from Exploit 11. Visualizzazione della tabella Autore select * from Autore 12. Visualizzazione della tabella Patch select * from Patch 13. Visualizzazione della tabella SistemaOperativo select * from SistemaOperativo 14. Visualizzazione della tabella Bersaglio select * from Bersaglio 15. Visualizzazione della tabella Realizzazione select * from Realizzazione 16. Visualizzazione della tabella News select * from News 17. Visualizzazione del codice dell'ultima vulnerabilità inserita (utile per assegnare il codice ad una nuova vulnerabilità da inserire nel database) select max(codice) from Vulnerabilita 18. Verifica che una nuova vulnerabilità da inserire non esista già nel database con un altro codice select * from Vulnerabilita where nomev=' ' and autore=' ' and datap=' ' and dataa=' ' and serviziointernet=' ' and cve=' ' and pericolosita=' ' and tipovulnerabilita=' ' and usotipico=' ' and info=' ' 19. Visualizzazione del codice dell'ultimo autore inserito (utile per assegnare il codice ad una nuova autore da inserire nel database) select max(id) from Autore 20. Verifica che una nuovo autore da inserire non esista già nel database con un altro codice select * from Autore where nome=' ' and email=' ' and linksito=' ' and tipoautore=' ' 21. Visualizzazione del codice dell'ultimo sistema operativo inserito (utile per assegnare il codice ad una nuovo sistema operativo da inserire nel database) select max(codice) from SistemaOperativo 22. Verifica che un nuovo sistema operativo da inserire non esista già nel database con un altro codice select * from SistemaOperativo where nome=' ' and release=' ' and tecnologia=' ' and servicepack=' ' 23. Visualizzazione delle news del giorno select * from News where TO_DAYS(NOW()) - TO_DAYS(data) < 1