j2007 02 jj3

64

Upload: turing-club

Post on 07-Jun-2015

475 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: j2007 02 jj3
Page 2: j2007 02 jj3
Page 3: j2007 02 jj3

EDITORIALEwww.infomedia.it

n.3 - marzo/aprile 2007 3

JAVA Journal

BIMESTRALE - ANNO 1 - N.3

D I R E T T O R E R E S P O N S A B I L E MA R I A L E T I Z I A MA R I

(M M A R I@I N F O M E D I A . I T )

D I R E T T O R E E S E C U T I V O

MI C H E L E SC A B A R R À

(M I C H E L E .S C I A B A R R A@J A V A J O U R N A L . I T )

E D I T O R I A L B O A R D

UG O LA N D I N I , ST E F A N O SA N N A, FA B I O ST A R O, TO N Y MO B I L Y

R E D A Z I O N E

M I R E L L A D I G I R O L A M O

C O L L A B O R A T O R IM A T T E O B A C C A N

A N D R E A C O L L E O N IJ A C O P O G I U D I C I

U G O L A N D I N IFE D E R I C O PA P A R O N I

S T E F A N O S A N N AR O B E R T O S I D O T I

FA B I O S T A R OD O M E N I C O VE N T U R A

LU I G I ZA N D E R I G H I

GR U P P O ED I T O R I A L E IN F O M E D I A S R L

V I A VA L D E R A P.11656038 PO N S A C C O (PI ) I T A L I A

TE L 0587736460 FA X 0587732232E -M A I L I N F O@I N F O M E D I A . I T

S I T O WE B W W W. I N F O M E D I A . I T

D I R E Z I O N E NA T A L E FI N O (N F I N O@I N F O M E D I A . I T )

C O N T A T T I

TE C H N I C A L B O O K(B O O K@I N F O M E D I A . I T )

M A R K E T I N G & A D V E R T I S I N GSE G R E T E R I A : 0587736460

M A R KE T I N G@I N F O M E D I A . I T

A M M I N I S T R A Z I O N E(A M M I N I S T R A Z I O N E@I N F O M E D I A . I T )

S E G R E T E R I A ( I N F O@I N F O M E D I A . I T )

G R A F I C AS T E F A N O B E L L A N I

(G R A F I C A@G R U P P O I N F O M E D I A . I T )

U F F I C I O A B B O N A M E N T ITE L 0587736460 FA X 0587732232

A B B O N A M E N T I@I N F O M E D I A . I T

W W W. I N F O M E D I A . I T

J A V A E T U T T I I M A R C H I D E R I V A T I S O N O M A R C H I O M A R C H I R E G I S T R A T I D I SU N M I C R O S Y S T E M S , I N C . N E G L I USA E I N A L T R I PA E S I . I L GR U P P O E D I T O R I A L E I N F O M E D I A È I N D I P E N -

Ajax: ritorno al passato Tempi complicati per noi programmatori Java, almeno per chi ha voglia di indiriz-zare la propria carriera in una direzione ben precisa. Fino a poco tempo fa non c’era dubbio che programmare in Java spesso significava programmare per il Web.Oggi le cose si sono fatte meno certe: da un lato assistiamo allo sviluppo della piatta-forma Micro Edition, dall’altra all’attecchire di Java come piattaforma di sviluppo a tutto tondo, quindi perfettamente accettabile anche per applicazioni Desktop (cosa fino a quale anno fa una via di mezzo tra follia ed eresia).Allora, cosa siamo diventati? In un certo senso, lo sviluppo di Java è omogeneo con lo sviluppo del Web. Java è prima di tutto e soprattutto, un linguaggio multipiat-taforma. Il terreno fertile per la prima ondata è stato quello della programmazione Web, con la sua moltitudine di server di tipo diverso. Ma il Web è cresciuto, è diventato pervasivo, onnipresente, omnicomprensivo. Via http ci passa di tutto, che siano file, email o transazioni di qualunque tipo. E quindi le applicazioni che in qualche modo hanno a che fare con il Web si sono moltiplicate. Per esempio le applicazioni mobili, per chi lavora nell’ambiente Micro Edition, sono in realtà nella maggior parte dei casi client di applicazioni Web, o browser specia-lizzati di servizio Web. Lo stesso si può dire di molte applicazioni Desktop scritte in Java, che si collegano in qualche modo, soprattutto usando i Web Service, a qualche sito web per scambiare informazioni. Sono quindi dei cosiddetti “rich-client”. I rich-client in realtà sono la ri-edizione del vecchio modello client-server di molti anni fa, con gli elementi innovativi del supporto multipiattaforma e dell’essere di-stribuiti su rete geografica anziché locale. Ma il problema è che i rich-client sono delle applicazioni Desktop che vanno installate. E non sempre conviene. Aumenta i costi di manutenzione, e non di poco.Il web si è dimostrato da molto tempo migliore, con le sue pagine HTML che in pratica sono pezzi di una applicazione che non richiedono di essere installate, ma vengono caricate on-demand.A voler proprio fare analogie, le applicazioni Web sono la riedizione dei vecchi ter-minali a carattere, in cui comandava il server e il terminale non faceva altro che “obbedire” visualizzando le informazioni. Una comodità preziosa che si è persa con l’avvento delle GUI. Naturalmente la relativa staticità del modello Web, che prose-gue inesorabilmente, pagina dopo pagina, ha sempre sofferto della scarsa interatti-vità rispetto alle applicazioni GUI.A chiudere il cerchio sembra averci pensato la riscoperta del JavaScript potenziato con la necessità di non dover ricaricare le pagine, e arricchito di un formato dati, che in teoria sarebbe l’XML (e che in pratica è più spesso il JSON). Ma l’acronimo AJAX è orami rimasto incollato nelle nostre menti per descrivere la tecnica di Asincronous Javascript And XML. L’idea è semplice, l’implementazione è complessa. Questa tecnica è in pratica il ritorno alle origini. Quasi subito nell’html è stato aggiunto il javascript, dotato poi della capacità di cambiare la pagina senza ricaricarla (il vecchio DHTML). Ma tra Java applet prima, Flash dopo, e nel mezzo tanta confusione, ci si era dimenticati del fatto che tutto questo si poteva fare sem-plicemente in JavaScript. Ci ha pensato Google a ricordarcelo, con il suo approccio a riconsiderare in maniera nuova quello che già c’è. E Google Maps e Gmail ci hanno mostrato che si possono realizzare applicazioni quasi desktop usando solo il JavaScript. La quantità di librerie che sono venute fuori in pochi anni è sconvolgente. Anche se ancora non è chiaro chi o cosa prevarrà o diventerà pervasivo. Il nostro speciale cerca comunque di indagare su questi aspetti e si occupa in dettaglio degli strumenti ad oggi più importanti per trattare questa tecnica.Concludo con due comunicazioni di servizio. La prima è l’entrata di Fabio Staro nell’editorial board, con la sua nuova rubrica Orizzonti Enterprise. E la seconda è la decisione di offrire il Video Corso Java a tutti gli abbonati a JavaJournal, senza più limitazioni di data di abbonamento. Basta abbonarvi e richiederlo, e vi sarà dato l’accesso.

Michele SciabarràDirettore Esecutivo

Java Journal

Page 4: j2007 02 jj3

Speciale AJAXAJAX e Java:un’accoppiata vincentedi Luigi Zanderighi 8AJAX facile con prototype.jsdi Domenico Ventura 14Google Web Toolkitdi Jacopo Giudic 20

EducationalIntroduzione agli EJB 3.0 - Prima parte di Fabio Staro 31Tutto Java in un Hello Worlddi Federico Paparoni 40

Focus Introduzione a Strutsdi Andrea Colleoni 47Programmazione AOP con AspectJdi Matteo Baccan 54

RubricheOrizzonti EnterpriseTutto ciò che è tendenza nel mondo JEE

di Fabio Staro 28

IdiomaticaTutto ciò che è tendenza nel mondo JEEdi Ugo Landini 61

SOMMARIO Marzo/Aprile 2007

numero 3 JAVA Journal

n.3 marzo/aprile 2007

Page 5: j2007 02 jj3
Page 6: j2007 02 jj3

IN VETRINA JAVA JOURNAL 3

n.3 - marzo/aprile 20076

IN VETRINA JAVA JOURNAL 3

Scrivi a [email protected] specificando nell’oggetto della e-mail:

IN VETRINA JAVA JOURNAL 2OPPURE

inviaci il coupon al numero di fax 0587/732232

Potrai acquistare i libri qui riportaticon uno SCONTO ECCEZIONALE

del 10% anche se acquisti solo un libroOPPURE

del 20% se acquisti 3 libri

JAVA JOURNAL 3

10 Computer Programming - n. 167 - Aprile 200710

IN VETRINA CP 167IN VETRINA CP 167Il manuale del giovane

hacker3. ed.

di W. Wang

Il testo, completamente rivisto e aggiornato dal punto di vista dei contenuti, ma inalterato dal punto di vista dell’informazione e del-l’esposizione dei concetti, prende in considerazione tutti gli ultimi sviluppi in fatto di attacchi e frodi digitali.

Tecniche Nuove416 pp - 19,90 EuroISBN 8848120059

Special Edition Using Microsoft® Windows® Vista

di R. Cowart, B. Knittel

Il libro offre una vasta gamma di consigli per IT managers che vogliamno sviluppare Windows in maniera semplice ed efficiente. Vengono mostrate le caratteristi-che per il setup di rete, hardware incluso.

Que1512 pp - 44,95 EuroISBN 9780789734723

La parte abitata della Retedi S. Maistrello

Il libro prende avvio dalla geografia del mondo digitale ed esamina gli strumenti con cui se ne acquisisce la residenza, per poi approfondire i processi che determinano i com-portamenti online, i meccanismi della collaborazione e il modo in cui si misurano i benefici individuali e collettivi.

Tecniche Nuove184 pp - 14,90 EuroISBN 9788848119726

Visual Basic® 2005La Guida Completa

di Ron Petrusha

Ogni argomento viene spiegato illustrando la sintassi dei comandi, riportando esempi di codice ed esempi di programmi reali. Le appendici, disponibili online, con-tengono informazioni su costanti ed enumerazioni, compilazione di applicazioni dalla riga di comando e conversione dei dati. Il libro può trovare la sua collocazione sulla scrivania di ogni programmatore, sia per la fase di codifica sia per quella di debug.

Mc Graw Hill930 pp - 60,00 EuroISBN 9788838644696

Ajax on Javadi S. Douglas Olson

Una guida pratica pensata per gli sviluppatori Java. Il libro mira a rendere le applica-zioni web in Java più responsive e dinamiche; include strategie per integrare Ajax in applicazioni JSP e JSF e per usare Ajax con Struts.

O’Reilly228 pp - 32,00 EuroISBN 9780596101879

Effective Prototyping for Software Makers

di J. Arnowitz, M. Arent e N. Berger

Il libro, ricco di illustrazioni a co-lori e di esempi, offre linee guida spiegate nel dettaglio per 9 comuni tecniche di prototipazione. I template e le risorse citate nel testo sono disponibili sul Web per il riutilizzo.

Morgan Kaufmann624 pp - 57,40 EuroISBN 9780120885688

HTML, XHTML e CSSdi E. Castro

Con questa guida, best-seller as-soluto alla sesta edizione originale, scoprirete che standardizzazione non significa monotonia e unifor-mità, e che la creazione di siti web creativi ma rigorosi è davvero possi-bile, anzi: è facile e divertente!

Tecniche Nuove456 pp - 34,90 EuroISBN 9788848119146

Beginning JBoss® Seam: From Novice to

Professionaldi di J. F. Nusairat

Il libro introduce i fondamenti di JSF and EJB 3 che Seam usa. Offre in-formazioni sia di base che avanzate sulle funzioni e sui tools di Seam. L’autore e’ uno sviluppatore esperto di Java/J2EE, da anni consulente per applicazioni Java innovative e robuste.

Apress376 pp - 49,50 EuroISBN 1590597923

aggiornato dal punto di vista dei contenuti, ma inalterato dal punto di vista dell’informazione e del-

del mondo digitale ed esamina gli strumenti con cui se ne acquisisce

sviluppatori Java.

zioni web in Java più responsive e

soluto alla sesta edizione originale, scoprirete che standardizzazione

di consigli per IT managers che vogliamno sviluppare Windows in

esempi di programmi reali. Le appendici, disponibili online, con-tengono informazioni su costanti ed enumerazioni, compilazione di applicazioni dalla riga di comando e conversione dei dati. Il libro può trovare la sua collocazione sulla

spiegate nel dettaglio per 9 comuni tecniche di prototipazione.

and EJB 3 che Seam usa. Offre in-formazioni sia di base che avanzate sulle funzioni e sui tools di Seam.

Page 7: j2007 02 jj3

IN VETRINA JAVA JOURNAL 3

n.3 - marzo/aprile 20076

IN VETRINA JAVA JOURNAL 3

Scrivi a [email protected] specificando nell’oggetto della e-mail:

IN VETRINA JAVA JOURNAL 2OPPURE

inviaci il coupon al numero di fax 0587/732232

Potrai acquistare i libri qui riportaticon uno SCONTO ECCEZIONALE

del 10% anche se acquisti solo un libroOPPURE

del 20% se acquisti 3 libri

JAVA JOURNAL 3

IN VETRINA CP 167IN VETRINA CP 167

Scrivi a [email protected] specificando nell’oggetto della e-mail:

IN VETRINA Computer Programming n. 167OPPURE

inviaci il coupon al numero di fax 0587/732232

Potrai acquistare i libri qui riportaticon uno SCONTO ECCEZIONALE

del 10% anche se acquisti solo un libroOPPURE

del 20% se acquisti 3 libri

CP 167

Founders at Work: Stories of Startups’ Early Days

di J. Livingston

Il testo presenta una collezione di interviste ai grandi dell’informatica, persone che oggi sono celebrità: fondatori come Steve Wozniak (Ap-ple), Caterina Fake (Flickr), Mitch Kapor (Lotus), Max Levchin (PayPal) e Sabeer Bhatia (Hotmail) raccon-tano idee e scommesse del tempo in cui hanno iniziato a metter su le proprie aziende.

Apress456 pp - 35,00 EuroISBN 1590597141

JavaServer(TM) FacesLa Guida Completadi C. Schalk e E. Burns

Il volume si apre con un’introdu-zione che consente di creare con la massima rapidità una prima applicazione JSF. Quindi esamina in dettaglio ogni singolo aspetto di JSF: il ciclo di vita per l’elaborazio-ne delle richieste, la navigazione fra le pagine, lo sviluppo di componen-ti, AJAX (Asynchronous JavaScript and XML), le attività di conversione/convalida, la localizzazione e la sicurezza.

Mc Graw Hill780 pp - 56,00 EuroISBN 9788838644726

Windows VistaThe Definitive Guide

di W. R. Stanek

Una guida completa per migliorare le prestazioni del sistema operativo e per la manutenzione del computer indipendentemente dalla versione di Windows Vista posseduta.

O’ Reilly942 pp - 47,20 EuroISBN 9780596528003

fondatori come Steve Wozniak (Ap-

e Sabeer Bhatia (Hotmail) raccon-

zione che consente di creare con

applicazione JSF. Quindi esamina

JSF: il ciclo di vita per l’elaborazio-

ti, AJAX (Asynchronous JavaScript

Scrivi a [email protected] specificando nell’oggetto della e-mail:

IN VETRINA Java Journal n.3OPPURE

inviaci il coupon al numero di fax 0587/732232

Potrai acquistare i libri qui riportaticon uno SCONTO ECCEZIONALE

del 10% anche se acquisti solo un libroOPPURE

del 20% se acquisti 3 libri

Page 8: j2007 02 jj3

JAVA Journal

8 n.3 - marzo/aprile 2007

speciale AJAX

Capire come funziona AJAX non è un optional

>> di Luigi Zanderighi ([email protected])

Dopo mesi di scetticismo e perplessità su AJAX, avete finalmente deciso di fare il grande passo e introdurre que-sta tecnologia all’interno di un nuovo progetto. Senza preoccuparvi di come funziona il meccanismo sottostante

avete scaricato uno script che fa al caso vostro. Ma ora sudate freddo. Le cose non funzionano. Lo script che avete scaricato per qualche motivo si è rotto e non sapete dove mettere le mani. Prima era sempli-ce, ora con AJAX in mezzo non si capisce dove può essere il problema. Capite che è giunto il momento di fare ciò che avete evitato fino ad ora: capire come funziona AJAX.

AJAX, a differenza delle altre tecnologie con cui siamo abituati a trattare, non gode di specifiche tecniche: in effetti AJAX non è né un linguaggio né un framework, ma definisce una tecnica di sviluppo costituita da un insieme di tecnologie. AJAX significa letteralmente Asynchronous Java-script and XML, e nasce dall’unione di HTML, Java-script, dell’oggetto XMLHttpRequest (XHR) e di una o più tecnologie lato server. Un grosso limite dell’HTML è sempre stato la man-canza di comunicazione tra client e server. Microsoft per prima ha aggirato questo problema già nei brow-ser IE4, con il controllo ActiveX Microsoft.XMLHTTP. Nell’Aprile 2006 il consorzio W3 ha rilasciato le specifiche per l’oggetto XHR che definisce le API che forniscono le funzionalità di trasferimento dati tra client e server, aprendo così ufficialmente le porte alla interoperabilità tra client e server.

JavaScript

Il primo passo per capire AJAX è studiarne le tecno-logie abilitanti, ossia le tecnologie che messe insieme rendono possibile sviluppare con la tecnica AJAX.Partiamo con dal ruolo di Javascript lato client. Già alla fine degli anni ’90 si faceva uso di DHTML, ma l’uso di Javascript non ha mai trovato ampio con-senso per mancanza di standard. Negli ultimi tempi il divario tra le API e le funzionalità offerte dai vari browser si è notevolmente ridotta e ora si può conta-re su un insieme molto esteso di funzioni sovrappo-nibili. Questa sovrapposizione non è ancora completa e tutti gli script devono tenerne conto.La grossa differenza, che ha sempre contraddistinto MS Internet Explorer dagli altri browser, è il modo con cui si recupera il riferimento di un elemento a cui è stato assegnato un id all’interno del codice HTML, ossia:

document.getElementById(id)

oppure

document.all[id]

Per mascherare questa diversità, di solito si fa uso di uno script “wrapper” che contempla ambedue le precedenti notazioni. Il frammento che segue è un esempio di codice Java-script in grado di recuperare gli elementi indipenden-temente dal browser:

// Funzione per recuperare un elemento dall’id

function getElement(id) { var element;

AJAX e Java:un’accoppiata vincente

Page 9: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 9

AJAX speciale

if(document.getElementById) element = document.getElementById(id); else element = document.all[id]; return element;}

Questa funzione serve agli script AJAX per recuperare gli elementi HTML con cui interagire. uno script ajax in ge-nere viene attivato a seguito di un evento che si verifica nella pagina HTML (onclick, onmoueover,....), esegue una richiesta al server e modifica il codice HMTL della pagina sulla base del risultato ottenuto.

XMLHttpRequest

Il cuore di AJAX risiede nell’oggetto XHR che consente ai client di interagire con il server. I metodi standard che pos-sono essere invocati su questo oggetto sono quelli definiti dalle specifiche del consorzio W3C (Listato 1), ossia:

• open • send• abort• getAllResponseHeaders• getResponseHeader

La chiamata “open” può essere eseguita sia in modalità sincrona (bloccante) sia in modalità asincrona e quindi non bloccante. Nel caso di chiamata asincrona occorre gestire l’evento di risposta del server. Le chiamate asincro-ne vengono fatte registrando un EventListener sull’evento onreadystatechange dell’oggetto XHR. Anche per l’oggetto XHR occorre un codice Javascript particolare per garantire la compatibilità con le vecchie versioni di Explorer, quando XHR non era standard ma era già largamente utilizzato da Microsoft. Il Listato 2 riporta uno dei meccanismi per recuperare l’oggetto XHR anche per le vecchie versioni dei browser.

Lato server

Ogni controllo AJAX necessita di una componente lato ser-ver che deve essere sviluppata, anche quando si vogliono utilizzare servizi XML già disponibili sul web.L’oggetto XHR ha infatti una limitazione, imposta per motivi di sicurezza e di privacy: le richieste possono essere

indirizzate solo verso la URL da cui proviene il Javascript che esegue la chiamata remota.Questa limitazione porta ad una considerazione impor-tante: deve necessariamente essere sviluppata una com-ponente server, che deve essere distribuita sullo stesso server da cui scaricate il Javascript. Immaginate di voler inserire nella vostra pagina HTML un Javascript, che legge tramite XHR un feed RSS da una URL esterna e mostra il contenuto nella pagina. Per farlo, dovrete scrivere un po’ di codice lato server che funga da proxy nei confronti del feed esterno.

Esempio pratico: verifica dinamica dei form

Vediamo un esempio pratico di utilizzo di AJAX. Esegui-remo la verifica lato server di un campo di un form prima che venga eseguito il submit del form stesso. Controlli di questo tipo possono essere eseguiti, ad esempio, durante la compilazione dei form da parte dell’utente, per evidenziare problemi nei dati inseriti prima che venga premuto il pul-sante di submit, oppure suggerendo direttamente i valori alternativi (nickname in uso, email già registrata, ecc.). In questo esempio, verifichiamo che la lunghezza del va-lore di un campo inserito dall’utente sia di 5 caratteri. Se la lunghezza del testo inserito è 5 caratteri, mostriamo una stringa di conferma; in tutti gli altri casi mostriamo un messaggio d’errore.Come prima cosa definiamo la struttura dell’XML della

TABELLA 1 Stati dell’oggetto XMLHttpRequest ricavabili dalla proprietà onreadystatechange

Valore Stato Descrizione0 Uninitialized Non è stato ancora richiamato alcun metodo

1 Open È stato richiamato il metodo open() ma non il metodo send()

2 Sent È stato richiamato anche il metodo send()

3 Receiving Viene ricevuta la risposta del server

4 Loaded La risposta è stata interamente letta

AJAX significa

letteralmente

Asynchronous

Javascript and XM

Page 10: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200710

speciale AJAX

risposta del server:

<message><status>$STATUS</status><text>$TEXT</text></message>

Il frammento XML è molto semplice: con status indichiamo l’esito della verifica e con text il messaggio esteso generato dal server.Ora creiamo la pagina JSP form.jsp in cui inseriamo un form con un campo di input:

<form> Inserisci testo: <input type=”text” id=”ajax_field” size=”20” onblur=”check()”/> </form>

Il pulsante di submit e la action del form sono volutamente omessi perché irrilevanti ai fini dell’esempio. Occorre notare i seguenti particolari:

• al campo di input viene assegnata una funzione Ja-vascript sull’azione onblur, ossia quando viene perso il fuoco• al campo di input viene assegnato un id per consentir-ne l’identificazione dalla funzione Javascript AJAX.

A questo punto, dobbiamo creare nella pagina la sezione in cui andiamo a inserire il messaggio prodotto dallo script AJAX, come risposta del server. Ciò viene fatto, banalmen-te, con una sezione <div> di cui possiamo manipolarne il contenuto tramite l’invocazione al metodo innerHTML(). Subito dopo la chiusura del tag <form> inseriamo il se-guente codice HTML:

<div id=’ajax_msg’></div>

Anche qui abbiamo assegnato un id per recuperare l’ele-mento dallo script. Ora scriviamo il codice della funzione check():

function check(){

Recuperiamo il valore inserito dall’utente:

var valore=getElement(‘ajax_field’).value;

Recuperiamo l’oggetto XHR in funzione del browser: var xhr = getXMLHttpRequest();

Recuperiamo la zona in cui scrivere il messaggio di ajax:

var msg = getElement(‘ajax_msg’);

Eseguiamo la richiesta verso il server:

xhr.open(“get”,”AjaxServlet?value=”+escape(valore),true);

• il primo parametro indica che la request è di tipo get (i valori ammessi sono get/post);• il secondo indica la URL; • con il terzo parametro indichiamo che la richiesta è asincrona, quindi non bloccante.

Assegniamo ora una funzione sul cambio di stato della request (la funzione verrà chiamata anche quando lo stato passa a completato):

xhr.onreadystatechange = function() {

LISTATO 1 Definizione completa dell’interfaccia XHR

interface XMLHttpRequest { attribute EventListener onreadystatechange; readonly attribute unsigned short readyState; void open(in DOMString method, in DOMString url); void open(in DOMString method, in DOMString url, in boolean async); void open(in DOMString method, in DOMString url, in boolean async, in DOMString user); void open(in DOMString method, in DOMString url, in boolean async, in DOMString user,

in DOMString password); void setRequestHeader(in DOMString header, in DOMString value); void send(); void send(in DOMString data); void send(in Document data); void abort(); DOMString getAllResponseHeaders(); DOMString getResponseHeader(in DOMString header); readonly attribute DOMString responseText; readonly attribute Document responseXML; readonly attribute unsigned short status; readonly attribute DOMString statusText;};}

Page 11: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 11

AJAX speciale

Lo stato 4 equivale al completamento della richiesta al server. Nel Riquadro 1 troviamo l’elenco di tutti gli stati possibili per l’oggetto XHR

if(xhr.readyState === 4) {

Se la richiesta al server è andata a buon fine, (stato HTTP 200), scriviamo il codice HTML nella sezione dedicata, in caso di errore scriviamo il codice dell’errore HTTP e il mes-saggio completo:

if(xhr.status === 200) { msg.innerHTML = parse(xhr.responseXML); }else{ msg.innerHTML = “ERROR “+xhr.status+” - “+xhr.statusText } } }

Dopo aver registrato le funzione di callback possiamo ese-guire la chiamata:

xhr.send(null);

L’ultimo passo, prima di poter eseguire questo semplice esempio, è scrivere il codice lato server. In una servlet che mappiamo come /AjaxServlet scriviamo nel metodo doGet il codice del Listato 3. Il codice è molto semplice e non necessita di particolari commenti.

Strumenti e framework

Nell’esempio che abbiamo visto poc’anzi, abbiamo scritto sia il codice client sia il codice server, partendo da zero. Per farlo abbiamo dovuto sfoggiare le nostre competenze nei linguaggi HTML, Javascript e Java. L’esempio era però molto semplice: non ci siamo preoccupati di aggiungere quei controlli che sarebbero indispensabili in un ambiente

di produzione (ad esempio: errore o mancata risposta del server, limitazione di accesso al servizio XML, ecc.). Sarebbe buona prassi, per un lavoro fatto a regola d’arte, che fossero coinvolte tre figure professionali: sviluppatore lato server, sviluppatore Javascript e grafico specialista in HTML. Uno scenario di questo tipo è difficile che si presen-ti, sopratutto in Italia dove gli sviluppatori sono chiamati a conoscere qualunque cosa. Alcuni framework aiutano nel-la realizzazione di controlli e funzionalità AJAX, rendendo trasparente allo sviluppatore il dialogo client/server e la componente Javascript.

GWT

Il primo framework che vediamo è il Google Web Toolkit. Utilizzando GWT ci occuperemmo solo di scrivere il con-trollo lato server. Ogni elemento “attivabile” con AJAX dispone di una classe, che possiamo estendere per fornire le funzionalità client dinamiche. Ad esempio disponiamo

LISTATO 2 Funzione Javascript per recuperare l’oggetto XHR

function getXMLHttpRequest() {

var XHR = null;

if(typeof(XMLHttpRequest) === “function” || typeof(XMLHttpRequest) === “object”) XHR = new XMLHttpRequest(); else if(window.ActiveXObject) { var clientAgent = navigator.userAgent.toUpperCase(); if(browserUtente.indexOf(“MSIE 5”) < 0) XHR = new ActiveXObject(“Msxml2.XMLHTTP”); else XHR = new ActiveXObject(“Microsoft.XMLHTTP”); } return XHR;

}

La chiamata ‘open’ può essere eseguita sia

in modalità sincrona (bloccante) sia in

modalità asincrona e quindi non bloccante

Page 12: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200712

speciale AJAX

dell’oggetto Button() con tutti i metodi definiti in DHTML come ad esempio onclick(). Tra le caratteristiche interessanti di GWT troviamo un wizard da riga di comando che genera lo scheletro di una prima applicazione e i file di progetto per Eclipse. Altra ca-ratteristica importante è la possibilità di eseguire il codice in “hosted mode”, ossia senza l’intervento di un browser esterno, ma utilizzando un browser speciale che viene for-nito insieme con il framework.Riporto un blocco di codice tratto dal sito del webtoolkit per mostrare la semplicità del codice:

public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button(“Click me”, new ClickListener() { public void onClick(Widget sender) { Window.alert(“Hello, AJAX”); } }); RootPanel.get().add(b); }}

JSF

JSF (Jave Server Faces) basa la propria architettura sul-l’uso di componenti. Ogni componente esegue il rendering di bean specifici (chiamati backing-bean). A ogni compo-nente possono essere assegnati degli actionListener su eventi che si verificano sul client su cui viene renderizzato il bean. L’approccio è molto simile a quello adottato dalle interfacce swing per la gestione degli eventi.Questo tipo di architettura si è mostrata terreno molto fertile per lo sviluppo di funzionalità AJAX. In JSF poter disporre di funzionalità AJAX significa avere dei componenti che per costruzione sono in grado eseguire

le chiamate AJAX. In genere con JSF accade che, come per i componente swing, chi sviluppa utilizza ciò che trova già pronto, eventualmente con qualche estensione. Solo in casi eccezionali ci si cimenta nella sviluppo di componenti completamente nuovi con tutte le problematiche annesse. JSF è quindi un ottimo candidato per applicazioni che fan-no uso di AJAX; ma l’uso di JSF non è indice dell’utilizzo di AJAX. Occorre trovare i componenti giusti per disporre di controlli avanzati AJAX.Alcuni esempi di componenti JSF/AJAX si possono trovare nella sandbox di myfaces. Tra le cose interessanti troviamo dropdown che si popolano sulla base di valori di altri ele-menti di un form, suggerimenti dinamici in fase di digita-zione e verifica della validità dei valori su onblur.

LISTATO 3 La servlet client del nostro esempio

PrintWriter out = response.getWriter();

String text = null;String color= null;

if (request.getParameter(“value”)==null || request.getParameter(“value”).equals(“”)) { text=”Valorizzare il campo”; color=”grey”;} else if (request.getParameter(“value”).length()==5) { text=”La lunghezza della stringa è corretta”; color=”green”; } else { text=”La lunghezza (“+request.getParameter(“value”).length()+ “) della stringa non è corretta”; color=”red”; }}out.print(“<message><color>”+color+”</color><text>”+text+”</text></message>”);out.close();

Al campo di input

viene assegnato un

id per consentirne

l’identificazione

Page 13: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 13

AJAX speciale

ECHO2

È probabilmente quanto di più completo si possa tro-vare oggigiorno in Java su AJAX. ECHO2 è un web framework che dispone di una libreria molto completa di componenti per realizzare applicazioni con frontend molto ricchi e complessi. ECHO2 dispone anche di un ambiente di sviluppo visuale avanzato, in grado di aiutare notevolmente in fase di sviluppo. Le librerie di ECHO2 sono disponibili con licenze lgpl o mpl, mentre l’ambiente di sviluppo è proprietario. Per utilizzare ECHO2 non è indispensabile utilizzare l’ambiente vi-suale anche se si perdono molti dei benefici della piat-taforma, come i wizard e i suggerimenti.Gli esempi presenti sul sito del produttore (http://demo.nextapp.com) descrivono le potenzialità del fra-mework meglio di qualunque descrizione testuale.

Firebug

Uno dei problemi di chi sviluppa con AJAX è monitorare il dialogo client/server per individuare facilmente dove possono annidarsi eventuali problemi. L’ultimo stru-mento che consiglio è Firebug. Si tratta di un plugin per Firefox in grado di intercettare, tra le altre cose, l’uso del oggetto XHR, mostrando sia la chiamata che la risposta.

Conclusioni

Sviluppare con la tecnica AJAX consente di realizzare vere e proprie applicazioni client. Il browser non mostra più semplici pagine ma potenzialmente una singola pagina che continua ad aggiornarsi dinamicamente in funzione delle interazioni con l’utente. Per capire a fondo le poten-zialità basta vedere Gmail di Google, con il suo sistema di chat o il nuovo frontend per la posta di Yahoo!. AJAX comporta una serie di conseguenze, che impongono un attento studio prima di essere utilizzato indistintamente. Le prime considerazioni sono sull’accessibilità. Una applica-zione AJAX sarà difficilmente accessibile da altri sistemi, in particolare dai motori di indicizzazione. Siti per i quali è fon-damentale l’indicizzazione o per i quali è previsto l’accesso da altre piattaforme non dovrebbero fare uso di Javascript e quindi di AJAX. Un’altra considerazione è sulla sicurezza: esporre servizi web è come mostrare il fianco al nemico. Oc-corre utilizzare tutti gli accorgimenti per evitare che altri ne abusino (ad esempio con un blocco su referrer) e per i dati sensibili occorre sempre proteggere l’accesso e fornire i dati solo in HTTPS. Sono accorgimenti comuni ma spesso trascu-rati, per la percezione errata che nessuno conosce il servizio e quindi nessuno lo chiamerà direttamente.

Note Biografiche

Luigi Zanderighi è Ingegnere del software ed è esperto nella pro-gettazione di architetture distribuite e di software Java.

Dada S.p.A. è una Internet Company quotata alla Borsa di Milano e presente sui principali mercati internazionali, leader nel settore dei servizi Community ed Entertainment (Internet & Mobile).

Il nostro è un mondo con una forte componente internazionale, in cui ogni dipendente e collaboratore si identifica con l’Azienda, un mondo dove la passione per le nuove tecnologie contribuisce al successo dell’Azienda, oltre che alla crescita personale e professionale.Siamo convinti che dal confronto delle idee nascano le soluzioni più brillanti, che il team-working sia un valore condiviso ed una realtà quotidiana radicata nel piacere di rapportarsi con gli altri.

A seguito della forte crescita del nostro business ricerchiamo

Sviluppatori per il prodotto Dada.net (www.dada.net)Il candidato ideale ha maturato una significativa esperienza di sviluppo software per il WEB.

Requisiti:o Formazione in ambito informatico o elettronicoo Buona conoscenza della lingua ingleseo Comprovata conoscenza di uno o più linguaggi di programmazione:

• PHP• Perl• J2ME• HTML, CSS e Javascript • Javascript e Actionscript

Titoli preferenziali:Passione per il mondo Internet, le nuove tecnologie, l’integrazione tra sistemi, lo studio e la realizzazione di community dedicate al mondo consumer dell’entertainment (web e mobile).Completano il profilo autonomia e spirito d’iniziativa, orientamento ai risultati e motivazione ad inserirsi in un contesto giovane e molto dinamico.

Sede di lavoro: Firenze.Se siete interessati ad incontrarci, aspettiamo le vostre candidature (Rif.: DEV07) all’indirizzo [email protected] (autorizzando il tratta-mento dei dati personali ai sensi del D.Lgs. 196/03). Per approfondimenti, visitate il nostro sito istituzionale: http://dada.dada.net/it/.

Page 14: j2007 02 jj3

JAVA Journal

14 n.3 - marzo/aprile 2007

speciale AJAX

Prototype è una libreria Javascript che rende facile e divertente la programmazione Javascript per le pagine web. Impariamo ad usarla e a sfruttarne le potenzialità AJAX e di manipolazio-ne del DOM

>> di Domenico Ventura ([email protected])

La maggior parte dei framework e delle librerie opensource che si trovano in rete hanno l’ambizione di semplificare la vita al programmatore. Prototype è fra le poche che raggiunge pienamente questo scopo. Nata con l’obiettivo di rendere la

programmazione Javascript meno confusionaria, più strutturata, in poche parole più divertente, Prototype è nota per essere la libreria Javascript distribuita e usata in Ruby on Rails per gestire le chiamate AJAX lato client. Ciò nonostante Prototype può tranquilla-mente essere usata in qualunque progetto web.Tra i numerosi punti di forza di Prototype, e sono tan-ti, non può però essere annoverata la documentazio-ne, che (almeno sino al lancio del nuovo sito, a fine febbraio) è sempre stata carente, se non completa-mente mancante, costringendo quasi sempre il pro-grammatore ad andare per tentativi o a leggere diret-tamente il sorgente all’interno della libreria. Questo articolo fornisce una panoramica su Prototype, sulle funzionalità e sugli oggetti base, in particolare quelli legati al supporto per AJAX, alla gestione dei form e del DOM.

Per iniziare

L’ultima versione di Prototype, che attualmente è la 1.5.0, può essere scaricata dal sito ufficiale http://www.prototypejs.org/. La libreria si compone di un solo file, prototype.js appunto, che deve essere inclu-so all’interno delle pagine web con il tag <script>:

<script type=”text/javascript”

src=”prototype.js” > </script>

A questo punto la nostra pagina è pronta per utilizza-re in pieno tutte le potenzialità di Prototype!

Tutti quei $ $ $ qua e là

Una delle prime cose che saltano agli occhi esami-nando del codice che utilizza Prototype (o analiz-zando direttamente il sorgente di Prototype) sono le tante chiamate $(...), $F(...), $$(...), che danno un po’ l’impressione di un listato Perl. In realtà que-ste sono funzioni di utilità generale, tra quelle che maggiormente adempiono al dovere di semplificarci la vita, evitandoci di scrivere del codice ripetitivo. Ve-diamone alcune nel dettaglio.

AJAX facile con prototype.js

Prototype è fra le poche

librerie che realmente

semplificano il compito

del programmatore

Page 15: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 15

AJAX speciale

La funzione $( )

La funzione $( ) è un collegamento alla usatissima fun-zione DOM document.getElementByID(). Come questa, restituisce un riferimento all’elemento DOM il cui ID è passato come parametro. Ecco un esempio:

var el = $(“unDiv”);alert(el.innerHTML);

La funzione $() può accettare anche diversi ID come para-metri, e in questo caso restituisce un array degli elementi corrispondenti agli ID:

var elList = $(“unDiv”,”altroDiv”)for(int i=0; i < elList.length; i+) alert(elList[i].innerHTML);

Oltre che una stringa che identifica un ID, la funzione $( ) può accettare come parametro anche un riferimento ad un elemento del DOM: in questo caso la funzione restituisce l’elemento stesso, ma esteso con le funzionalità aggiuntive definite da Prototype. Vedremo nel proseguo cosa questo implica e come la funzione $( ) aiuti nella manipolazione degli oggetti del DOM.Questo aspetto rende la funzione $( ) una delle principali e basilari dell’intera libreria: viene usata all’interno di Pro-totype un po’ come un piccolo coltellino svizzero multiuso! Ad esempio, molte delle funzioni della libreria Prototype hanno questa struttura:

function aFunction(element){ element = $(element) //resto della funzione}

In questo modo è possibile passare come parametro alla

TABELLA 1 Opzioni per le richieste AJAX

Opzione Descrizione Default

contentType Indica l’header contentType della richiesta HTTP che verrà effettuata

‘application/x - w w w - f o r m -urlencoded’

encoding Indica l’encoding dei contenuti della richiesta AJAX

‘UTF8’

method Specifica se la richiesta deve essere fatta in get o in post

‘post’

parameters

L’elenco dei parametri da passare alla richie-sta, URL encoded. Questi verranno passati nella URL per le richieste Get, o nel corpo della richiesta per gli altri tipi di richieste.

‘’

insertion

Utilizzato solo da Ajax.updater, indica dove i nuovi contenuti verranno inseriti. Può essere Insertion.Before, Insertion.Top, Insertion.Bottom. Insertion.After

undefined

frequencyUtilizzato da Ajax.PeriodicalUpdater, indica l’intervallo (e non la frequenza!) tra due chia-mate, in secondi

undefined

decay

Utilizzato da Ajax.PeriodicalUpdater, indica di quanto aumentare l’intervallo fra due chiama-te consecutive, nel caso la risposta ricevuta sia la stessa della chiamata precedente.Ad esem-pio: decay=2, significa che in caso si ottengano due risposte uguali, la prossima chiamata sarà fatta dopo 2*frequency secondi. E l’intervallo sarà di nuovo moltiplicato per due in caso di una nuova risposta uguale alla precedente.

undefined

Page 16: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200716

speciale AJAX

funzione sia la stringa con l’ID dell’elemento, sia l’ele-mento stesso. Nel proseguo della funzione si utilizza poi l’elemento esteso da Prototype con le sue funzionalità aggiuntive.

La Funzione $F( )

Anche la funzione $F( ) è una scorciatoia molto comoda: per-mette di ottenere il valore di un qualsiasi elemento di input, passando come parametro il suo ID. Il Listato 1 riporta un esempio che mostra un alert con il valore inserito nel campo nome quando si effettua un click sul pulsante mostra.

Document.getElementByClassName()

Questa funzione consente di ottenere un array di tutti gli elementi della pagina che hanno la classe CSS passata come parametro. Si può anche passare un riferimento ad un elemento della pagina come parametro opzionale: in questo caso la ricerca avviene solo sui figli di tale elemen-to.Ad esempio, se vogliamo ottenere la lista di tutti gli ele-menti di classe test, scriveremo:

document.getElementByClassName(“test”);

Un altro esempio; per ottenere la lista di tutti gli elementi di classe test contenuti all’interno di un elemento (un div, un form) di ID “login”, scriveremo:

document.getElementByClassName(“test”, $(“login”));

La funzione $$( )

La funzione $$( ), introdotta a partire dalla versione 1.5, è un potente mezzo di navigazione all’interno del DOM: consente infatti di accedere agli elementi della pagina uti-lizzando la stessa modalità e sintassi dei CSS Selector. La funzione $$( ) ha come parametri una o più regole di selezione CSS e ritorna un array di elementi del DOM che soddisfano tali regole. Il Listato 2 mostra alcuni esempi di utilizzo della funzione $$( ).Questa funzione va usata con cautela e con particolari at-

tenzioni, in quanto un utilizzo poco attento potrebbe avere un notevole impatto negati-vo sulle prestazioni.

E AJAX?

Sin qui abbiamo visto una serie di funzioni di uso generico, sicuramente molto utili e ben fatte, ma uno degli scopi principali per utilizzare Prototype è poter avere delle funzionalità AJAX! Vediamo allora come utilizzare la libreria al meglio per creare

delle pagine AJAX.Per centralizzare tutte le funzionalità AJAX, Prototype crea e rende pubblico un oggetto denominato, appunto, Ajax: questo si fa carico di gestire dietro le quinte tutte le dif-ferenze di implementazione e di utilizzo sui vari browser dell’oggetto XMLHttpRequest, assicurando così la fruibili-tà delle nostre applicazioni con qualunque browser.Nella pratica, per la realizzazione di funzionalità AJAX, bisogna utilizzare delle sottoclassi dell’oggetto Ajax. Vedia-mole in dettaglio.

Ajax.Request

Il modo più semplice e immediato di creare una chiamata AJAX è istanziare un oggetto Ajax.Request. Ad esempio:

new Ajax.Request (“/unaURL”, { method:”get” });

Il primo parametro del costruttore indica a quale URL indirizzare la richiesta. Il secondo parametro è un ogget-to Javascript, creato in questo caso secondo la notazione JSON, che indica le opzioni da utilizzare per la richiesta AJAX: nell’esempio indica che la richiesta HTTP deve es-sere fatta in GET.Questo secondo parametro merita qualche spiegazione in

LISTATO 1 Esempio di utilizzo della funzione $F( )

<script> function mostraNome(){ alert(“Il tuo nome è: “ + $F(“nome”));}</script>

<input type=”text” id=”nome” /><input type=”button” value=”mostra” onclick=”mostraNome()” />

LISTATO 2 Esempi di utilizzo della funzione $$( )

// Tutti i form della pagina:$$(“form”);

// Tutti i link della pagina // con attributo href=”#” (wow!)$$(“A[href=’#’]”);

// Tutti i th di classe prezzo // del div di ID data$$(“div#data th.prezzo”);

// Tutti gli elementi di classe link// nei div head o foot$$(“div#head .link”, “div#foot .link”);

Page 17: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 17

AJAX speciale

più: è comune a tutte le classi dell’oggetto AJAX e consente di specificare le opzioni da usare in una singola richiesta AJAX. La Tabella 1 elenca le opzioni di più comune utiliz-zo: tutte hanno un default, di modo che possiamo specifi-care solo quelle che realmente si intende modificare.L’esempio appena mostrato non serve realmente a molto: dopo aver invocato la URL “/unaURL” non specifica cosa fare della risposta che si ottiene. Poiché le richieste AJAX sono per definizione asincrone, la gestione dell’output (così come delle condizioni di errore) deve essere compiu-ta tramite delle callback. Anche le callback da usare vanno definite nel parametro che indica le opzioni. Il Listato 3 mostra un altro esempio di utilizzo di Ajax.Request, completo di callback per la gestione dell’er-rore e della risposta AJAX. In questo secondo esempio ven-gono definite due callback: una da chiamare nel caso che la richiesta Ajax sia andata a buon fine e una da chiamare in caso di errore. Nella prima callback, il parametro resp che viene passato è l’oggetto XMLHttpRequest originario, di cui si possono usare le proprietà responseText o responseXML. La Tabella 2 riporta l’elenco delle callback più comuni.

Ajax.Updater e Ajax.PeriodicalUpdater

Un uso molto comune di AJAX consiste nell’utilizzarlo per aggiornare dinamicamente, e senza dover ricaricare l’intera pagina, solo alcune sezioni della pagina stessa. A tale scopo l’oggetto Ajax di Prototype mette a disposizione la classe Ajax.Updater. Questa, dato l’ID dell’elemento da aggiornare e la URL da chiamare, realizza proprio questa funzionalità.

Supponiamo, ad esempio, di voler mostrare l’elenco dei prodotti disponibili in un catalogo per tipologia: avremo una tendina di selezione dei diversi tipi di prodotti dispo-nibili (libri, DVD, CD, ecc.) e, al cambiamento di selezione da parte dell’utente, la lista visualizzata viene aggiornata dinamicamente con una chiamata AJAX. Ecco come usare l’oggetto Updater in questo caso:

new Ajax.Updater(“prodotti”, “/prodotti.do”,

TABELLA 2 Callback per le richieste AJAX

Callback Descrizione

onComplete Chiamata alla fine del ciclo di vita di una richiesta AJAX.

onExceptionChiamata qualora durante la richiesta AJAX venga sollevata un eccezione dall’oggetto XMLHttpRequest. Prende come parametri l’oggetto XMLHttpRequest e l’eccezione incontrata.

onFailure Chiamata quando la richiesta AJAX viene completata ma la risposta ottenuta indica un errore (codice HTTP diverso da 2xx)

onSuccessChiamata quando la richiesta AJAX viene completata con successo (codice HTTP uguale a 2xx). Viene eseguita prima di onComplete.

onXXX

Dove XXX è uno specifico codice di risposta HTTP. Chiamata quando la richiesta AJAX viene completata e il codice HTTP della risposta è XXX. Queste callback vengono eseguita prima di onComplete e fanno si che onFailure e onSuccess non vengano chiamate

onCreate Usata dalla sola classe Responders: viene chiamata alla creazione di una qualsiasi richiesta AJAX

LISTATO 3 Esempio di una chiamata AJAX completa di

callback

new Ajax.Request( “/trovaUtente.do”, { method:”get”, parameters: “userId=888”, onSuccess: function(resp) { alert(“Salve utente “ +resp.responseText); }, onFailure: function { alert(“C’è stato” + “un errore...”); } });

Page 18: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200718

speciale AJAX

{parameters:”tipo=” + $F(“tipo”)});

Il primo parametro indica l’ID dell’elemento da aggior-nare, il secondo la URL a cui inviare la richiesta e il ter-zo parametro specifica le opzioni da passare. Di default l’aggiornamento eseguito da Updater avviene sull’intero elemento, ma utilizzando tra i parametri l’opzione “in-sertion” si può indicare dove inserire il nuovo contenuto rispetto all’elemento indicato.

Di funzionamento molto simile alla classe Updater è l’oggetto PeriodicalUpdater: in questo caso l’elemento in-dicato viene aggiornato in maniera periodica ad intervalli prefissati.Se ad esempio si volesse avere un’area della pagina dedicata alle previsioni meteorologiche, aggiornata dinamicamente ogni minuto, si potrebbe usare Ajax.PeriodicalUpdater in questo modo:

new Ajax.PeriodicalUpdater(“previsioni”, “/previsioni.do”, { frequency: 60, parameters:”provincia=” + $F(“pv”) });

Ajax.Responders

Un altro oggetto molto comodo da utilizzare è l’Ajax.Responders: consente di registrare delle callback co-muni a tutte le chiamate Ajax che vengono originate dalla pagina. Ad esempio, può essere utilizzato per mostrare una piccola animazione o un messaggio di caricamento in corso tutte le volte che la pagina effettua una richiesta Ajax:

Ajax.Responders.register({ onCreate: function(){ $(“loadingDiv”).innerHtml = “caricamento in corso...”;},

onComplete: function(){ $(“loadingDiv”).innerHtml = “”;}})

In questo esempio, ad ogni richiesta Ajax che viene ori-ginata dalla pagina, nel div di ID “loadingDIV” compare la scritta “caricamento in corso...”, che scompare al com-pletamento delle richiesta Ajax. Un altro possibile utilizzo consiste nel centralizzare la gestione delle eccezioni, in modo da registrare e definire una sola volta la callback onException.

Estensioni di Prototype al DOM

Una parte cospicua di Prototype è dedicata alle estensioni degli oggetti DOM. Prototype aggiunge tante utili funzio-nalità agli oggetti del DOM, di modo che utilizzando Proto-type è possibile avere del codice come il seguente:

$(“unDiv”).addClassName(“cl”).show();

Questa linea di codice aggiunge la classe “cl” all’elemento di ID “unDIV” e lo rende visibile.Prototype estende la classe Element, di modo che le funzionalità aggiuntive sono quindi presenti in tutti gli elementi del DOM. Per utilizzare le estensioni del DOM ci sono due modalità. La prima prevede l’uso dei metodi della classe Element di Prototype passando l’ID dell’elemento al metodo da invocare. Ad esempio:

Element.update(“unDiv”, nuovoHtml);

L’altro modalità per utilizzare le estensioni del DOM di Prototype consiste nell’utilizzare direttamente gli oggetti estesi, ovviamente tramite la funzione $( ):

$(“unDiv”).update(nuovoHtml);

La funzione $( ) è abbastanza intelligente da fare in modo che un elemento del DOM venga esteso da Prototype una sola volta.Fra le funzioni aggiunte dalla classe Element ci sono:

• Funzionalità di navigazione nel DOM (metodi up, down, next, previous, remove)• Funzionalità di manipolazione degli stili (metodi get-Style, getWidth, addclassName, classNames, setStyle)• Funzionalità di gestione della visibilità dell’elemento (metodi show, hide, toggle)

Oltre a queste funzioni, comuni a tutti gli elementi del DOM, alcuni particolari tipi di oggetti hanno altre funzio-nalità in più. È il caso dei form e degli elementi di input. Questi vengono estesi da Prototype tramite le classi Form e Form.Element. Utilizzando Prototype sui i form è possibile:

• Abilitare o disabilitare l’intero form tramite le funzioni enable() e disable();• Ottenere il primo elemento di input non hidden e non disabilitato e dargli il focus con le funzioni getFirstEle-ment() e focusFirstElement()

Creare delle pagine

AJAX cross-broweser in

pochi secondi

Page 19: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 19

AJAX speciale

• Ottenere una stringa da utilizzare per le richieste Ajax (cioè qualcosa del tipo “nome=paolino&cognome=paperino”) a partire da tutti i campi di un form con la fun-zione serialize().

Funzionalità simili sono presenti per gli elementi di input dei form.

Controllare i cambiamenti sui form

Con Prototype è possibile monitorare un form (o solo un suo elemento), in modo da eseguire delle azioni ogniqual-volta questo venga modificato. Le classi che consentono questo sono Form.Observer o Form.EventObserver (op-pure le analoghe Form.Element.Observer e Form.Element.EventObserver per i singoli elementi di input). Ecco un esempio di utilizzo:

new Form.Observer($(“mioForm”), 1, validaInput)

new Form.Element.EventObserver($(“email”), controllaEmail)

In entrambi i casi viene registrata come callback una fun-zione di validazione dell’input. La differenza tra le due classi sta nel fatto che Observer controlla periodicamente (nell’esempio di sopra ogni secondo) se il form in oggetto è cambiato, mentre EventObserver è basato sugli eventi. La callback in questo secondo caso viene quindi invocata solo quando un evento indica che il form (o l’elemento di input) è stato modificato. Questo implica che EventObser-ver può essere utilizzata solo con elementi che supportano gli eventi onChange o onClick.

Oggetto Insertion

L’oggetto Insertion di Prototype permette di inserire, in maniera dinamica e portabile su tutti i browser, blocchi di HTML all’interno o intorno ad un dato elemento della pagina. Per selezionare in maniera accurata dove inserire i contenuti aggiuntivi rispetto all’elemento indicato, Inser-tion ha quattro sottoclassi: Before, After, Top e Bottom. Ad esempio, per inserire il testo “ciao mondo!” dopo l’ele-mento di ID “titolo”:

new Insertion.After(“titolo”, “<p> ciao <b>mondo!</b> </p>”)

Il Listato 4 mostra dove il testo aggiuntivo verrà inserito a seconda della sottoclasse di Insertion che si utilizza.

Conclusioni

Prototype è una libreria Javascript di grande utilità, che permette di creare pagine per applicazioni Web 2.0 in maniera rapida e efficace. In questo articolo ci siamo par-ticolarmente concentrati nel dare una visione d’insieme delle funzionalità AJAX, di manipolazione e di gestione del DOM, ma Prototype offre molto di più. Ad esempio non abbiamo parlato delle estensioni alla classe Array e della classe Enumerable, delle funzionalità correlate alla creazione di oggetti, della gestione dei tipi Hash.Il nuovo sito, lanciato con la versione 1.5 della libreria, è inoltre un notevole passo in avanti per quanto la riguarda la documentazione. Prototype è anche un ottimo esempio di codice Javascript ottimamente scritto. Prova di questo è anche il fatto che altre ottime librerie Javascript per AJAX, scriptaculous e moo.fx fra tutte, siano basate proprio su Prototype.

Links

[1] Sito ufficiale: http://www.prototypejs.org[2]_Ottimo tutorial e reference guide:

http://www.sergiopereira.com/articles/prototype.js.html[3] Scriptaculos: http://script.aculo.us[4] Moo.fx: http://moofx.mad4milk.net/

LISTATO 4 Differenze tra le sottoclassi di Insertion

Insertion.Before <div id=mioDIV> Insertion.Top <p>Contenuto dell’elemento mioDIV Insertion.Bottom </div>Insertion.Bottom

Note Biografiche

Domenico Ventura si è laureato in ingegneria informatica al Po-litecnico di Torino nel 1999 e da allora si occupa di system in-tegration e di realizzare applicazioni web. Attualmente lavora come senior consultant presso Reply s.p.a., dove si occupa di so-luzioni di Knowledge Management, di Enterprise Content Ma-nagement e di Business Intelligence. É membro e coordinatore del Jug Torino.

Funzioni semplici di

manipolazione del DOM

e per creare effetti

visuali

Page 20: j2007 02 jj3

JAVA Journal

20 n.3 - marzo/aprile 2007

speciale AJAX

Creare un progetto AJAX partendo da zero comporta una ottima conoscenza di javascript ol-tre che di XML, HTML, CSS e delle compatibilità dei vari browser. Tuttavia, il progetto GWT (Google Web Toolkit) permette agli sviluppatori Java di creare siti in AJAX senza dover scrive-re neanche una linea di codice javascript.

>> di Jacopo Giudici ([email protected])

Il Google Web Toolkit [1] è un framework svi-luppato dal Google Team che permette di com-pilare del codice Java trasformandolo in pagine che utilizzino la tecnologia AJAX. Con la nascita dell’acronimo AJAX, le grandi compagnie di software hanno realizzato meto-

di più o meno efficaci per semplificare il lavoro degli sviluppatori creando dei framework per la creazione di pagine contenenti la nuova tecnologia a partire dai linguaggi di programmazione proprietari. Microsoft ha sviluppato Atlas per ASP.NET [2], Yahoo ha reso disponibile le User Interface Library [3] e anche la comunità Open Source si è prodigata nella creazione di svariati progetti, tra i quali il più famoso è proba-bilmente Sarissa [4].L’approccio di Google è, tuttavia, originale e permette ai puristi Java di creare degli interi siti AJAX inte-grandoli con le tecnologie che già utilizzano quali, ad esempio, Servlet, JSP e EJB, senza dover necessaria-mente conoscere javascript.

L’installazione dei GWT e la creazione del pri-mo progetto

I Google Web Toolkit (da ora GWT) sono delle libre-rie Java con a corredo una serie di programmi che permettono la creazione rapida di classi Java trasfor-mabili tramite compilazione in pagine HTML-AJAX. I progetti creati con i GWT sono pronti per essere modificati, compilati o valutati tramite strumenti tipici della programmazione Java, quali, ad esempio, Eclipse, Ant e JUnit. Il nucleo dei GWT è composto da una serie di librerie Java e quindi indipendenti dalla piattaforma; tuttavia, alcuni programmi contenuti nel pacchetto sono dei file di script dipendenti dal sistema operativo. Proprio per questo, i GWT posso-no essere scaricati in due versioni: per Windows e per Linux/MacOS. Dopo aver scaricato il file adatto al vostro sistema operativo e averlo decompresso, l’installazione è terminata. L’unico ulteriore passo, non necessario ma consigliato, è l’inserimento nel PATH della cartella creata dalla decompressione del file, contenente i vari script per creare o modificare progetti e classi GWT.All’interno della cartella decompressa contenente i GWT, esistono due file di script: projectCreator e ap-plicationCreator: file .cmd sotto Windows e .sh sotto Linux/MacOS. Per creare un nuovo progetto, creiamo una cartella chiamata JavaJournal che conterrà il pro-getto e quindi navighiamo fino a quella cartella con la shell dei comandi. Da qui, lanciamo il comando:

projectCreator –eclipse javajournal –ant javajournal

Il comando funziona solo se abbiamo inserito la

Google Web Toolkit

L’approccio di Google è originale e

permette di creare siti AJAX senza conoscere

javascript

Page 21: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 21

AJAX speciale

cartella contenente i GWT nel PATH, altrimenti dovremo fornire il percorso completo per utilizzare l’applicazione: ad esempio C:\gwt-1.3.3-windows\projectCreator … . Questo comando crea un progetto pronto ad essere utiliz-zato con Eclipse e Ant all’interno della cartella in cui ci troviamo. Tra i file che vengono creati, oltre a quelli neces-sari per poter utilizzare il progetto con Eclipse, viene creato un file chiamato javajournal.ant.xml che serve a compilare l’applicazione con Ant la cui sintassi è stata trattata nel numero 2 di JavaJournal.Dopo aver creato il progetto con l’utilità projectCreator, creiamo l’applicazione che verrà trasformata in codice AJAX da GWT con il comando applicationCreator in que-sto modo:

applicationCreator –eclipse javajournal it.jj.client.Reviews

Questo comando crea, all’interno della struttura presente, una serie di file, tra cui la classe principale, nel nostro caso Reviews, che si deve sempre trovare in un package di nome client, nel nostro caso it.jj.client. Oltre a questo file, vengono creati nella cartella principale due script che permettono la compilazione e il test immediato della nostra applicazione. Per vedere il risultato dei nostri sforzi, proviamo a eseguire il file Reviews-shell.cmd. Il risultato dovrebbe essere quello di figura1.

L’applicazione di base

Ogni volta che creiamo un’applicazione con il comando applicationCreator, viene preparata una classe java che, compilata, da come risultato la pagina HTML di figura1. La pagina è già dinamica e utilizza javascript, come si com-prende facendo click sul pulsante Click Me. Questa sempli-ce pagina sarà il progetto principale da cui partiremo per

FIGURA 1 L’applicazione di base Reviews

Le interfacce utenti

create con GWT sono

simili nei metodi di

utilizzo a quelle create

con Swing

Page 22: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200722

speciale AJAX

creare la nostra applicazione AJAX.Per meglio capire come avvenga questa tra-sformazione, vediamo i file più importanti creati dall’esecuzione di applicationCreator e, per farlo, carichiamo innanzitutto il pro-getto in Eclipse con questi passaggi:

1. selezioniamo File->New->Project…2. dalla finestra che compare selezioniamo

Java Project e facciamo click su Next3. diamo un nome al progetto, selezionia-

mo la voce Create project from existing source e selezioniamo alla voce Di-rectory: la cartella javajournal creata in precedenza.

Facendo quindi click su Finish avremo un nuovo progetto in Eclipse con i colle-gamenti alle librerie GWT necessarie alla compilazione.All’interno della struttura dell’applicazio-ne, oltre ai file visti in precedenza, altri file sono necessari per la creazione della pagina AJAX:

− Il file Reviews.java che si trova nel package it.jj.client. Aprendo questo file, che andre-mo poi a modificare, vediamo come esso sia composto interamente da codice java che Eclipse riconosce senza segnalarci errori.

− Il file Reviews.html che si trova nel packa-ge it.jj.public. Il file Reviews.html è un semplice file HTML che contiene lo scheletro HTML dell’applicazione, oltre ai vari riferimenti a codici javascript esterni, a fogli di stile e, soprattutto, ai moduli GWT che verranno iniet-tati nella pagina durante il suo caricamento.

− Il file Reviews.gwt.xml che si trova nel package it.jj. Questo file fornisce alcune variabili necessarie alla compilazione dei moduli GWT. Nell’applicazione di base, nel file c’è un riferimento alla libreria com.google.gwt.user.User necessa-ria al compilatore per la creazione del modulo. Inoltre, sempre nel file, c’è il riferimento alla classe principale

che deve essere compilata per creare il modulo stesso. In particolare, si noti come it.jj.client.Reviews sia definito come Entry Point, il che significa che la classe it.jj.client.Reviews.java verrà trasformata nel primo modulo javascript eseguito dalla pagina Reviews.html.

Ora che conosciamo i passaggi che definiscono quale clas-se verrà trasformata nel modulo GWT Reviews, vediamo il codice contenuto nell’applicazione di base riportato nel listato1.Cominciamo dicendo che le interfacce utenti create con GWT sono simili nei concetti e nei metodi di utilizzo a quelle create con Swing. Nonostante in queste pagine AJAX ci sia la possibilità di accedere direttamente al DOM tramite particolari interfacce fornite dai GWT, è senz’altro più semplice utilizzare le classi grafiche messe a disposi-zione dal framework e lasciare che il compilatore crei le pagine automaticamente.In particolare, nel codice della classe Reviews vengono dichiarate delle variabili di tipi simili a quelli che potrem-mo trovare in una classe Swing: Button e Label. Come è possibile vedere nella pagina Widget Gallery nella documen-tazione online dei GWT, la prima di queste variabili verrà visualizzata in HTML come un pulsante e la seconda come una semplicissima etichetta di testo. Quindi, prima che questi due oggetti vengano inseriti nella pagina web, viene collegata un istanza della classe ClickListener alla variabile button, in modo simile a quello che faremmo con un pul-sante Swing attribuendogli un ActionListener:

LISTATO 1 Il codice dell’applicazione di base

package it.jj.client;

import com.google.gwt.core.client.EntryPoint;import com.google.gwt.user.client.ui.Button;import com.google.gwt.user.client.ui.ClickListener;import com.google.gwt.user.client.ui.Label;import com.google.gwt.user.client.ui.RootPanel;import com.google.gwt.user.client.ui.Widget;

public class Reviews implements EntryPoint { public void onModuleLoad() { final Button button = new Button(“Click me”); final Label label = new Label();

button.addClickListener(new ClickListener() { public void onClick(Widget sender) { if (label.getText().equals(“”)) label.setText(“Hello World!”); else label.setText(“”); } });

RootPanel.get(“slot1”).add(button); RootPanel.get(“slot2”).add(label); }}

FIGURA 2 Il progetto caricato in Eclipse

Page 23: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 23

AJAX speciale

button.addClickListener(new ClickListener() { public void onClick(Widget sender) { if (label.getText().equals(“”)) label.setText(“Hello World!”); else label.setText(“”); }});

Con questo codice viene creata la pagina di esempio vi-sta in precedenza e, facendo click sul pulsante Click Me, nell’etichetta comparirà la scritta “Hello World”, mentre facendo click una seconda volta, il contenuto dell’etichetta verrà eliminato.L’ultimo passaggio del codice permette di inserire le due componenti nella pagina HTML Reviews.html che, come detto prima, contiene già il codice che produrrà lo sche-

letro della pagina. In particolare, il codice che ci permette di localizzare la posizione dei nostri moduli GWT è il se-guente:

<td id=”slot1”></td><td id=”slot2”></td>

Al lancio del codice javascript, verranno recuperati gli oggetti della pagina in cui inserire i moduli GWT tramite il comando getElementById(), che, come dice il nome, è in grado di trovare una parte della pagina HTML semplice-mente grazie al suo attributo id. Per collegare agli elemen-ti HTML i nostri moduli GWT scritti in Java, utilizziamo quindi il seguente codice:

RootPanel.get(“slot1”).add(button);RootPanel.get(“slot2”).add(label);

Il RootPanel può essere visto come il ContentPane in una classe Swing, ossia come il contenitore superiore al quale vengono poi aggiun-ti i vari componenti. In questo caso, il modulo Reviews recupererà durante il caricamento dell’HTML i due oggetti di tipo <td> identificati dagli id slot1 e slot2 e inserirà nel primo l’oggetto but-ton e nel secondo l’oggetto label creati in precedenza.

L’applicazione Reviews

L’applicazione Reviews, che verrà creata dall’applicazione di base, visualizzerà una lista di articoli dei primi due nu-meri di JavaJournal in una struttura ad albero. I nomi degli articoli saranno selezionabili e, facendo click su un titolo nell’albero, dovranno comparire in una finestra popup l’eventuale link all’arti-colo e il link per comunicare via email con l’autore.Per creare questa applicazione, avremo bisogno di modificare il file Reviews.html e il file Reviews.java. Il listato2 e il listato3 riportano, rispettivamente, il codice della pagina Reviews.html e della classe Reviews.java.Nel file HTML vengono inseriti una serie di stili CSS per modificare i vari oggetti creati dalla compilazione della classe Reviews.java. Nei javadocs, forniti a corredo dei Toolkit, vengono riportate le varie classi di stile per ogni oggetto inseribile dalle classi GWT nelle pagine HTML. Nel nostro esempio, il primo oggetto che andremo a creare sarà una struttura ad albero, derivata dalla classe com.google.gwt.user.client.ui.MenuBar. Nei javadocs, viene specificato che, per modificare l’aspetto delle varie parti di una MenuBar bisogna modificare le

LISTATO 2 La pagina Reviews.html

<html> <head> <title>JavaJournal Reviews</title> <style> body,td,a,div,.p{font-family:arial,sans-serif} div,td{color:#000000} a:link,.w,.w a:link{color:#0000cc} a:visited{color:#551a8b} a:active{color:#ff0000} .gwt-MenuBar { background-color: #C3D9FF; border: 1px solid #87B3FF; cursor: default; } .gwt-MenuBar .gwt-MenuItem { padding: 1px 4px 1px 4px; /*font-size: smaller;*/ cursor: default; display: block; } .gwt-MenuBar .gwt-MenuItem-selected { background-color: #E8EEF7; } .myPopup { background-image: url(gray_gradient.gif); background-repeat: repeat-x; border: 1px solid #AAAAAA; padding: 4px; } </style> <meta name=’gwt:module’ content=’it.jj.Reviews’> </head> <body> <script language=”javascript” src=”gwt.js”></script> </body></html>

Page 24: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200724

speciale AJAX

LISTATO 3 La classe Reviews.java

package it.jj.client;

import com.google.gwt.core.client.*;import com.google.gwt.user.client.ui.*;

public class Reviews implements EntryPoint { private VerticalPanel treeRev = new VerticalPanel(); private DockPanel page = new DockPanel(); public void onModuleLoad() { addTree(); treeRev.setWidth(“100%”); page.add(treeRev, DockPanel.WEST); RootPanel.get().add(page); } public void addTree() { Tree tree = new Tree(); TreeItem root1 = new TreeItem(imageItemHTML(“riviste_jj.jpg”, “#1”)); tree.addItem(root1); root1.addItem(nuovoArticolo(“Java Server Faces”, “Michele Sciabarr&agrave;”, “[email protected]”)); root1.addItem(nuovoArticolo(“Le novit&agrave di JSF 1.2”, “Andrea Nasato”, “[email protected]”)); root1.addItem(nuovoArticolo(“Java Card”, “Matteo Campanella”, “[email protected]”)); root1.setState(true); TreeItem root2 = new TreeItem(imageItemHTML(“riviste_jj.jpg”, “#2”)); tree.addItem(root2); root2.addItem(nuovoArticolo(“J2ME Best Practice”, “Andrea Nasato”, “[email protected]”)); root2.addItem(nuovoArticolo(“Apache Ant”, “Michele Ferretti”, “[email protected]”)); root2.setState(true); treeRev.add(tree); } /* * Le variabili recuperate dal metodo vengono definite static perchè dovranno * essere utilizzate all’interno dell’istanza di ClickListener */ private HTML nuovoArticolo(final String nomeArticolo, final String autore, final String mail) { /* * Inserisco nell’html, come href un riferimento a javascript senza nome del metodo * da eseguire: sarà poi il metodo addClickListener a inserire il giusto codice */ final HTML link = new HTML(“<a href=’javascript:;’>” + nomeArticolo + “</a>”); link.addClickListener(new ClickListener() { public void onClick(Widget sender) { MyPopupPanel popup = new MyPopupPanel(nomeArticolo, autore, mail); int left = link.getAbsoluteLeft() + 32; int top = link.getAbsoluteTop() + 8; popup.setPopupPosition(left, top); popup.show(); } }); return link; } private static class MyPopupPanel extends PopupPanel { public MyPopupPanel(String nomeArticolo, String autore, String mail) { /* * L’utilizzo del costruttore PopupPanel(true) permette di settare la variabile * auto-hide a true, nascondendo il pannello popup al primo click esterno allo stesso */ super(true); HTML html = new HTML(“<a href=\”#\”>” + nomeArticolo + “</a>” + “<br /><img src=\”inbox.gif\” /> “ + “<a href=\”mailto:” + mail + “\”>” + autore + “</a>”, true); setWidget(html); setStyleName(“myPopup”); } } private String imageItemHTML(String imageUrl, String title) { return “<span><img style=’margin-right:4px’ src=’” + imageUrl.toLowerCase() + “’>” + title + “</span>”; }}

Page 25: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 25

AJAX speciale

FIGURA 3 L’aspetto finale dell’applicazione Reviews

seguenti classi CSS:

.gwt-MenuBar {}

.gwt-MenuBar .gwt-MenuItem {}

.gwt-MenuBar .gwt-MenuItem-selected {}

Il secondo oggetto che dovremo modificare tramite CSS, invece è un oggetto di tipo PopupPanel, che non ha un CSS che gli sia abbinato automaticamente dai GWT come la classe MenuBar. In questo caso, oltre a definire la classe CSS nella pagina HTML, dovremo inserire nel codice Java la seguente riga di codice:

setStyleName(“myPopup”);

per legare la classe dei vari popup, MyPopupPanel, della quale discuteremo più avanti, allo stile definito nel codice HTML: .myPopup. In questa classe CSS viene inoltre defini-to uno stile che necessita di una immagine per poter creare lo sfondo del popup:

background-image: url(gray_gradient.gif);

Le immagini necessarie all’applicazione, per essere inserite nella pagina, devono essere salvate nella cartella public, dove si trova il file Reviews.html e che è la cartella princi-pale della nostra applicazione AJAX.Mentre il file Reviews.html contiene i codici per definire l’aspetto della pagina HTML, il file Reviews.java contiene il codice che definisce il comportamento della pagina, a parti-re dalla sua composizione. A differenza dell’applicazione di

base, abbiamo deciso di non inserire uno scheletro nel corpo della pagina HTML ma di eseguire solamente il codice conte-nuto nel modulo javascript gwt.js con il seguente comando:

<script language=”javascript” src=”gwt.js”></script>

La classe EntryPoint del nostro modulo GWT Reviews dovrà creare l’applicazione gestendo completamente il posizionamento degli oggetti. Questa suddivisione della pagina viene fatta utilizzando due tipi di oggetti: panel e

widget. Panel e widget sono due super-classi che vengono estese rispettivamen-te dai contenitori per oggetti dinamici e dagli oggetti stessi. Ogni oggetto grafico in GWT estende una di queste due classi, ereditandone i metodi necessari per es-sere visualizzati nella pagina.Nel metodo onModuleLoad() è contenuta l’intera suddivisione della pagina trami-te pannelli. Qui vengono creati e posizio-nati due pannelli:

1. un pannello principale, di tipo DockPanel chiamato page;2. un secondo pannello di tipo VerticalPanel chiamato treeRev.

Il pannello treeRev viene aggiunto al pan-nello page con il comando:

page.add(treeRev, DockPanel.WEST);

e infine, il pannello page viene inserito nella pagina con il comando:

RootPanel.get().add(page);

Per chi ha conoscenze di Swing, il primo comando è semplice da com-prendere; per chi invece non ha mai

I progetti creati con i

GWT sono pronti per

Eclipse, Ant e JUnit

Page 26: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200726

speciale AJAX

utilizzato Swing e il BoxLayout, basti sapere che il comando page.add(treeRev, DockPanel.WEST); aggiunge a page il pannello treeRev posizionandolo ad Ovest, cioè attaccato al bordo sinistro del contenitore. Il metodo onModuleLoad() esegue anche il comando ad-dTree() che crea un menu ad albero utilizzando la classe Tree. I comandi utilizzati per creare l’albero sono tre:

1. il comando Tree tree = new Tree(); che istanzia l’albe-ro.

2. il comando TreeItem <variabile> = new TreeItem(); che crea un nodo dell’albero contenente del codice HTML.

3. il comando <variabile>.addItem(<nodo>); che lega un nodo all’albero o al ramo superiore.

Quindi, con il comando setState(true); determino che il nodo dell’albero sia espanso, mentre con il comando treeRev.add(tree); inserisco l’albero nel pannello treeRev, facendolo quindi visualizzare sul lato sinistro della pagi-na.I nodi dell’albero devono essere scritti in HTML e, per inserire i vari nodi, l’applicazione utilizza due metodi appositi per la creazione delle stringhe formattate: imageI-temHTML() e nuovoArticolo(). Il primo di questi due metodi crea un area di tipo <span> contenente un immagine e un testo; il secondo crea il codice HTML della finestra Po-pup. La finestra verrà visualizzata istanziando un pannello particolare di tipo MyPopupPanel che, a sua volta, estende la classe PopupPanel. La classe MyPopupPanel contiene un oggetto di tipo HTML, ossia una Label contenente codice HTML con i riferimenti all’articolo e all’autore, passati al metodo tramite il suo costruttore. L’oggetto HTML così creato viene settato come widget principale della classe MyPopupPanel, diventando il corpo dell’oggetto. Il metodo nuovoArticolo() crea quindi un altro oggetto di tipo HTML, collegandoci un istanza della classe clickLi-stener, esattamente come in precedenza veniva fatto per il pulsante nell’applicazione di base. Il metodo onClick() istanzia una variabile di tipo MyPopupPanel e ne definisce la posizione. Il pannello di popup viene quindi mostrato tramite l’esecuzione del metodo show() della variabile creata.

Conclusioni

Dopo aver completato la scrittura del modulo, la compila-zione avviene utilizzando ant oppure lanciando il comando Reviews-compile.cmd. Al termine della compilazione, trove-remo una cartella www con all’interno una serie di file. Questi file sono il risultato della compilazione del modulo e della sua trasformazione in AJAX, suddivisi per browser. Al caricamento della pagina AJAX, una serie di comandi javascript valuteranno quale browser tenti di accedere al codice e caricheranno al giusta versione dei moduli GWT. Inoltre, la compilazione crea una cartella chiamata tomcat che conterrà, al momento, una serie di file di configura-zione del server Apache Tomcat. Questa cartella serve a configurare Tomcat per applicazioni GWT più complesse che necessitino di comunicazione con oggetti quali Servlet

o Jsp utilizzando le RPC (Remote Procedure Calls) con parti-colari classi GWT.I GWT, come visto, permettono la creazione di pagine AJAX senza dover conoscere javascript e le sue implicazioni ma solamente inserendo particolari classi nel codice Java e, soprattutto, utilizzando metodi simili a quelli che vengono utilizzati con altri strumenti. Seguendo la politica di Google del “no-evil”, come riporta-to sul sito, i GWT vengono rilasciati sotto licenza Apache 2.0 Open Source License permettendo la navigazione del codice più complesso e, come auspicabile, un veloce migliora-mento delle funzionalità più interessanti. In particolare, il Google Team vuole rendere stabili, entro il 2008, i mec-canismi di RPC che permettono la comunicazione client-server. Questo processo potrebbe fornire agli sviluppatori la possibilità di creare con pochi comandi dei web-service utilizzando solo codice Java e client personalizzati e visua-lizzabili tramite browser.Il progetto è solo agli inizi ma, visto che Google è l’azienda capofila, ci si può aspettare un salto in avanti da un mo-mento all’altro, cosa auspicabile sia per il programmatore esperto che per il neofita che non deve così imparare altri linguaggi oltre a Java.

Riferimenti

1 http://code.google.com/webtoolkit/2 http://ajax.asp.net/3 http://developer.yahoo.com/yui4 http://sarissa.sourceforge.net/

Note Biografiche

Jacopo Giudici si occupa di applicazioni per il Web, di RFID e di domotica su piattaforme J2ME, J2EE e .NET. Progetta e tiene corsi di formazione aziendali sulla sicurezza delle reti informa-tiche e sulla programmazione Java per ambienti distribuiti.Ha lavorato per Microsoft, BottegaVerde, CONAD, Confartigiana-to e ha pubblicato una collana di 6 libri con DeAgostini Scuola sui Sistemi Elettronici-Informatici per il triennio degli istituti tecnici superiori.

I GWT vengono

rilasciati sotto licenza

Apache 2.0 Open

Source License

Page 27: j2007 02 jj3
Page 28: j2007 02 jj3

SPEECH Login TopicFREE

• non dipende dallo stato di altri servizi (stateless);• è ricercabile e recuperabile dinamicamente;• è definito dalla sua interfaccia (contract), indipendente dalla

implementazione tecnologica del servizio stesso;

Quanto riportato, evidenzia come un servizio sia debolmente accoppiato (loosely coupled), sia da un punto di vista tecnolo-gico, in quanto il servizio può essere implementato mediante tecnologie eterogenee, per esempio JEE o .NET, esponendo tuttavia una interfaccia standard, e sia da un punto di vista funzionale, in quanto il servizio è sì componibile insieme ad altri servizi per la costituzione di processi di business comples-si, ma è intrinsecamente autoconsistente. In sintesi un servizio di business è definito da una interfaccia pubblicabile sulla rete ed è ricercabile ed invocabile indipen-dentemente dal linguaggio e dalla piattaforma di implemen-tazione. Pertanto in una architettura SOA sono definiti i ruoli di service consumer, service provider e service registry. Il consu-mer è l’entità che richiede un servizio, il provider è l’entità che fornisce il servizio ed infine il registry è un repository in rete di tutti i servizi consultabili e fruibili. Quanto finora espresso presenta similitudini con i termini presenti nello sviluppo

SOA, Web Services e BPEL: un po’ di chiarezza.Orizzonti Enterprise, rubrica su ciò che è innovativo nel mondo enterprise, si propone come un momento di analisi il cui obiettivo è collo-care nel giusto ambito di competenza le tecnologie di … “ten-denza”. In questo articolo definiamo una architettura a servizi e alcune tecnologie correlate a tale paradigma di sviluppo.

Una architettura SOA, acronimo di Service Oriented Architecture, è una architettura software atta a supportare l’uso di servizi per soddisfare le richieste degli utenti. Un servizio in SOA è business driven, ossia è un componente che presenta un reale significato per gli esperti funzionali e di dominio. In modo puntuale un servizio:

• è una funzione di business auto-contenuta;

ORIZZONTI ENTERPRISE

Tutto ciò che è tendenza nel mondo JEE>> di Fabio Staro ([email protected])

FIGURA 1 Pila dei protocolli dei web service (adattata da: http://it.wikipedia.org/wiki/Web_service)

n.3 - marzo/aprile 2007 28

Page 29: j2007 02 jj3

SPEECH Login TopicFREEORIZZONTI ENTERPRISE

dei componenti web service. Ma quale rapporto intercorre tra SOA e i web service? I web service sono una specifica tecnologica attraverso la quale pubblicare e invocare sul web dei servizi; SOA è un paradigma architetturale (architectural pattern) per il software design. In sintesi i web service sono una implementazione, la principale, è vero, ma non l’unica (se si pensa per esempio al mondo CORBA), del paradigma SOA. La Figura 1 mappa i ruoli di una architettura SOA sui protocolli di rete utilizzati per definire, localizzare ed invocare i servizi web. Con riferimento alla figura, possiamo definire i tre pro-tocolli di riferimento:

• SOAP, acronimo di Simple Object Access Protocol, è un protocollo in formato XML per lo scambio dei messaggi tra componenti software;

• WSDL, acronimo di Web Services Description Language, è un linguaggio formale in formato XML per descrivere l’in-terfaccia pubblica di un servizio web; ed infine,

• UDDI, acronimo di Universal Description Discovery and Integration, è un registro attraverso il quale pubblicare e ricercare i servizi in rete.

Tuttavia, nel mondo reale le interazioni commerciali ed indu-striali sono complesse e non si esauriscono con l’invocazione di un singolo servizio, ma necessitano della composizione di vari servizi per il soddisfacimento dei processi di business. BPEL, acronimo di Business Process Execution Language, è un linguaggio basato su XML mediante il quale è possibile definire il processo di business coordinando l’invocazione di vari servizi (web services orchestration).Come si relaziona la piattaforma JEE 5 con il mondo SOA ed in particolare con i web service? La piattaforma JEE 5

ha notevolmente migliorato il supporto per i web service e al contempo lo ha semplificato attraverso l’uso delle annotazioni (cfr: JSR 181, Web Services Metadata for the Java Platform). In particolare esporre un EJB di tipo stateless come web service è estremamente semplice. Attraverso l’annotazione

javax.jws.WebMethod

è possibile identificare i metodi che saranno esposti come ope-razioni del web service mentre attraverso l’annotazione

javax.jws.WebService

si dichiara un session bean che funge da web service endpoint. Di seguito è riportato un semplice listato di esempio.

…@Stateless(name=”CodiceFiscale”)@WebServicepublic class CodiceFiscaleBean { @WebMethod(operationName=”verificaCodice”) public boolean verifica(String cf) { …}…}…

L’appuntamento è alla prossima puntata, dove parleremo della moda del momento: gli ESB (Enterprise Service Bus) e di BPEL.

n.1 - novembre/dicembre 2006 29

Page 30: j2007 02 jj3
Page 31: j2007 02 jj3

JAVA Journal

31n.3 - marzo/aprile 2007

educational

Introduzione agli EJB 3.0Con la nuova specifica 3.0 la SUN ha eseguito una reingegnerizzazione della tecnologia EJB ar-ricchendo l’API di nuove caratteristiche e semplificando, in modo radicale, lo sviluppo dei bean enterprise.

>> di Fabio Staro ([email protected])

Premessa

Nelle applicazioni di classe enterprise l’uso della tecnologia degli Enterprise JavaBeans è argomento controverso tra i software architect poichè i servizi messi a disposizione da un container EJB non sem-pre bilanciano la complessità di sviluppo e deploy. Con l’avvento degli EJB versione 2.0 il progettista J2EE aveva a disposizione una tecnologia complessa ma matura per realizzare applicazioni di classe enter-prise, ossia applicazioni con un forte carattere distri-buito e transazionale. La specifica degli EJB 2.x pre-senta tre tipi di Enterprise JavaBeans: i Session Bean, i Message-Driven Bean e gli Entity Bean. Senza entrare in dettaglio possiamo sintetizzare il carattere specifico dei tre tipi di Enterprise JavaBeans (cfr. Tabella 1):

• i componenti di tipo Session Bean realizzano tipica-mente i processi per la logica di business;

• i componenti di tipo Message-Driven Bean risolvono i processi di tipo asincrono;

• ed infine i componenti Entity Bean consentono la persistenza dei dati essendo di fatto una tecnologia ORM (Object Relational Mapping).

Come si è detto in precedenza, le applicazioni che beneficiano maggiormente della presenza degli Enterprise JavaBeans presentano componenti tran-sazionali e delocalizzabili. Infatti i componenti EJB possono essere “facilmente” distribuiti su diversi ser-ver, consentendo di fatto una migliore suddivisione del carico computazionale, e possono garantire, se ve ne fosse la necessità, un contesto transazionale unico interagendo con diversi resource manager, per esempio

Prima Parte

TABELLA1 tipi di EJB

Enterprise Bean Descrizione

Session Bean

Sono i componenti enterprise per lo sviluppo della logica di business. Si suddividono in due tipi: gli Stateless Session Bean e gli Stateful Session Bean. I primi sono senza stato, ossia ogni metodo del bean rappresenta una funzione di business fine a se stessa mentre i secondi consentono di conservare lo stato durante le varie invocazioni che avvengono con il client.

Message-Driven Bean

Sono componenti enterprise per l’elaborazione asincrona. Sono generalmente in ascolto su una coda o un topic JMS.

Entity Bean

Sono una tecnologia per la persistenza dei dati. Si dividono in BMP e CMP. Nei bean di entità di tipo BMP gli statement SQL sono scritti dallo sviluppatore del bean mentre nei bean di entità di tipo CMP gli statement SQL sono generati in automatico dal container EJB.

Page 32: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200732

educational

database e/o code JMS. Mostriamo di seguito uno scenario complesso e tuttavia realizzabile semplicemente attraverso l’uso di EJB. Si osservi la Figura 1: una applicazione client invoca un bean enterprise X che esegue tre operazioni. Più precisamente:

• invia un messaggio verso un sistema di messagistica, per esempio una coda JMS;

• aggiorna i dati presenti in un primo database; • e poi invoca un secondo bean enterprise Y (che potrebbe

anche risiedere su un diverso server).

A sua volta il bean enterprise Y esegue una operazione di aggiornamento su un secondo database. Lo scenario de-scritto è una complessa transazione distribuita su diversi re-source manager. Grazie ai servizi offerti dall’application server, dove risiedono i componenti EJB, assicurare la semantica transazionale appena descritta non richiede uno sforzo particolare nello sviluppo, se non l’uso delle normali API JDBC e JMS, poiché è il server EJB a garantire il contesto transazionale attraverso l’uso del two-phase protocol [2] e del-le API JTA [3] e JTS [4].

L’esempio presentato è un caso complesso e limite. In effetti i componenti EJB in una architettura Java portano una serie di benefici che di seguito elenchiamo riman-dando alla copiosa letteratura sul tema per gli opportuni approfondimenti:

• Supporto alle transazioni distributite;• Delocalizzazione delle componenti di business;• Supporto per la gestione della sicurezza role-based;• Supporto al pooling e al caching delle istanze dei bean;• Supporto allo sviluppo di web service.

Tuttavia a fronte dei benefici sopra elencati sviluppare un EJB versione 2.x richiede una buona dose di “pazienza” e una sicura competenza. Per esempio, per sviluppare un EJB di tipo Session Bean è necessario creare:

• due interfacce; • una classe concreta; • e un file XML che descrive la configurazione del compo-

nente.

Inoltre la classe concreta che rappresenta il bean vero e pro-prio deve implementare l’interfaccia javax.ejb.SessionBean e, di conseguenza, deve implementare una serie di metodi di callback, invocati dal container EJB durante il ciclo di vita del componente, che nulla hanno a che fare con la logica di business. Nel caso degli Entity Bean, poi, la complessità aumenta a tal punto che, sebbene rappresentano la tecno-logia “ufficiale” per la persistenza dei dati, molto spesso non sono usati nei progetti per la presenza di alternative più semplici, flessibili e performanti (cfr. Hibernate [5]). Con la specifica degli EJB 3.0 la SUN ha eseguito una

FIGURA 1 una applicazione client invoca un bean enterprise X che esegue varie operazioni

Page 33: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 33

educational

radicale reingegnerizzazione della tecnologia arricchendo notevolmente l’API ma soprattutto semplificando note-volemte lo sviluppo dei componenti. A testimonianza di ciò riportiamo quanto segue, direttamente dal documento della specifica:

…La release EJB 3.0 dell’architettura Enterprise JavaBeans fornisce allo sviluppatore di applicazioni enterprise una API nuova e sem-plificata. Questa API è mirata alla facilità di sviluppo e rappresen-ta una semplificazione delle API definite dalle precedenti versioni della specifica EJB.…

In questo primo articolo introdurremo alcune delle princi-pali “feature” degli EJB 3.0 e fin dai primi esempi si evi-denzierà lo sforzo, pienamente riuscito da parte degli au-tori della specifica, di semplificare e razionalizzare il lavoro degli sviluppatori Java. Questo articolo è una introduzione alla specifica 3.0 sebbene si dà per acquisita almeno una

conoscenza di base della specifica 2.x e delle problematiche inerenti alla tecnologia EJB in generale. L’esempio riporta-to è stato verificato con l’application server JBoss versione 5.0 [6] e con il database MySQL versione 5.0.27 [7].

Gestione di una biblioteca

L’esempio da realizzare, volutamente semplice al fine di soffermarci sugli aspetti tecnici e non funzionali, è un componente per la gestione di una biblioteca. Il compo-nente consente una operazione di ricerca, restituendo l’elenco dei libri di un autore, e una operazione di assegna-mento di un libro presente in biblioteca ad un utente che ne ha fatto richiesta. Pertanto la interfaccia di business del componente è semplicemente:

public interface GestoreBiblioteca { public List<Libro> getLibri(String nomeAutore); public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile;}

Per implementare il componente gestore della biblioteca come un EJB 3.0 di tipo session stateless è sufficiente:

• Creare una classe che implementi l’interfaccia di busi-ness GestoreBiblioteca;

• Annotare la classe con l’annotazione @javax.ejb.Stateless;

Lo stralcio di codice che segue riporta la definizione della classe GestoreBibliotecaBean:

@Stateless (name=”Biblioteca”)

TABELLA 2 Alcune differenze tra la versione EJB 2.x e 3.x

EJB session 2.x EJB session 3.x

Business interfaceInterfaccia che estende javax.ejb.EJBObject o

javax.ejb.EJBLocalObject

Semplice interfaccia Java eventualmente annotata.

Bean Class

Classe che deve implementare la interfaccia javax.ejb.SessionBean e di conseguenza implementare i metodi

di callback: ejbActivate(), ejbPassivate, ejbRemove(), setSessionContext().

POJO che implementa la business interface e dichiarato

con la annotazione @Stateless o @Stateful.

Home interfaceObbligatoria. Deve estendere o la interfaccia javax.ejb.EJBHome o la

interfaccia javax.ejb.EJBLocalHome.Non presente.

Deployment Descriptor

Obbligatori.Non obbligatori. La via

preferenziale per caratterizzare un EJB è attraverso le annotazioni

Dependency Injection

Non presente. Presente.

Gli Entity Bean

versione 3 sono in

pratica un ORM

Page 34: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200734

educational

public class GestoreBibliotecaBean implements GestoreBiblioteca {…}

Le poche righe di codice sopra riportate sono di fatto il no-stro EJB 3.0 di nome Biblioteca e mostrano un carattere di-stintivo ed innovativo degli EJB 3.0 rispetto alle precedenti versioni 2.x e 1.x: gli EJB 3.0 sono POJO, acronimo di Plain Old Java Object, ossia semplici classi Java che non devono implementare interfacce particolari e/o metodi di callback

e che non hanno un legame diretto con un container o con un application server. Con gli EJB 3.0 non sono più obbli-gatori i file XML di configurazione, i talvolta complessi e sicuramente prolissi deployment descriptor, essendo possibile definire tutte le caratteristiche di un EJB attraverso le an-notazioni. La Tabella 2 riporta alcune differenze e sempli-ficazioni che si hanno per gli EJB di tipo session passando dalla versione 2.x alla versione 3.x.

Il carattere remoto o locale di un EJB si definisce attraver-so le due annotazioni

LISTATO 1 La classe GestoreBibliotecaBean

package it.articolo.ejb;

import it.articolo.ejb.interceptors.LogInterceptor;import it.articolo.ejb.interceptors.PerformanceInterceptor;import java.util.List;import javax.annotation.Resource;import javax.ejb.Stateless;import javax.interceptor.Interceptors;import javax.sql.DataSource;import javax.ejb.TransactionManagement;import javax.ejb.TransactionAttribute;import javax.ejb.TransactionManagementType;import javax.ejb.TransactionAttributeType;import org.apache.commons.logging.LogFactory;import org.apache.commons.logging.Log;

@Stateless (name=”Biblioteca”)@TransactionManagement(TransactionManagementType.CONTAINER)public class GestoreBibliotecaBean implements GestoreBiblioteca { private static Log oLogger = LogFactory.getLog(GestoreBibliotecaBean.class); @Resource (name=”jdbc/exampleDatasource”) DataSource theDatasource = null;

@Interceptors({PerformanceInterceptor.class, LogInterceptor.class}) public List<Libro> getLibri(String nomeAutore) { oLogger.info(“Invocato metodo EJB (CON INJECTION)”); List<Libro> oListaLibri = new DAOGestoreBiblioteca().getLibri(nomeAutore, theDatasource); return oListaLibri; }

@TransactionAttribute(TransactionAttributeType.REQUIRED) public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile { assegnaLibro(persona, libro); boolean result = diminuisciNumeroCopie(libro); if (!result) throw new LibroNonDisponibile(“Il libro: “+libro.getTitolo()+” non è disponibile per il prestito”); }

private boolean diminuisciNumeroCopie(Libro libro) throws LibroNonDisponibile {boolean operationResult = new DAOGestoreBiblioteca().diminuisciNumeroCopie(libro, theDatasource); return operationResult; }

private void assegnaLibro(Persona persona, Libro libro) { new DAOGestoreBiblioteca().assegnaLibro(persona, libro, theDatasource); }

}

Page 35: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 35

educational

contemporaneamente locale e remota ma che un EJB può implementare più interfacce di business.

La dependency Injection

Il componente GestoreBiblioteca deve poter accedere al da-tabase per poter espletare le sue funzioni di ricerca e di assegnamento (cfr. Listato 1). Con la precedente versione 2.x degli EJB i passi necessari per accedere ad un database, dopo aver definito un oggetto datasource sull’application server, sono:

• Definire una reference nel file ejb-jar.xml per il datasour-ce;

• Connettersi al contesto JNDI;• Eseguire una operazione di lookup della risorsa sull’albe-

ro JNDI, eseguendo poi il cast opportuno;

Le righe di codice che seguono sono esemplificative dei passi sopra enunciati (il primo frammento di codice è re-

@javax.ejb.Remote

@javax.ejb.Local

Un componente EJB locale può essere invocato solo da applicazioni client che risiedono nella medesima Java Virtual Machine mentre un componente EJB che espone una interfaccia remota può essere invocato da applicazioni client che risiedono in una diversa Java Virtual Machine ed in generale su altri computer. Nel nostro esempio il com-ponente gestore della biblioteca può essere invocato da applicazioni client che non girano nella medesima JVM e pertanto l’interfaccia di business del gestore è caratterizza-ta dall’annotazione @Remote:

@Remotepublic interface GestoreBiblioteca { …}

Osserviamo che una interfaccia di business non può essere

LISTATO 2 Metodo business assegna () della classe GestoreBibliotecaBean

…@TransactionManagement(TransactionManagementType.CONTAINER)public class GestoreBibliotecaBean implements GestoreBiblioteca { … @TransactionAttribute(TransactionAttributeType.REQUIRED) public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile { assegnaLibro(persona, libro); boolean result = diminuisciNumeroCopie(libro); if (!result) throw new LibroNonDisponibile(“Il libro: “+libro.getTitolo() +” non è disponibile per il prestito”); }

private boolean diminuisciNumeroCopie(Libro libro) throws LibroNonDisponibile { boolean operationResult = new DAOGestoreBiblioteca().diminuisciNumeroCopie(libro, theDatasource); return operationResult; }

private void assegnaLibro(Persona persona, Libro libro) { new DAOGestoreBiblioteca().assegnaLibro(persona, libro, theDatasource); }…}

LISTATO 3 Definizione del datasource verso MySQL in Jboss

<?xml version=”1.0” encoding=”UTF-8”?><datasources> <local-tx-datasource> <jndi-name>theDataSource</jndi-name> <connection-url>jdbc:mysql:///test</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name></user-name> <password></password> <exception-sorter-class-name/> </local-tx-datasource></datasources>

Page 36: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200736

educational

lativo al deployment descriptor, il file ejb-jar.xml, mentre il secondo alla classe del bean).

…<resource-ref><description></description><res-ref-name>jdbc/exampleDatasource </res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth><res-sharing-scope>Shareable</res-sharing-scope></resource-ref>…

…// Codice per ottenere il contesto JNDIContext initCtx = new InitialContext();// Operazione di lookupjavax.sql.DataSource ds = (javax.sql.DataSource) initCtx.lookup(“java:comp/env/jdbc/exampleDatasource”);…

In generale i passi necessari per eseguire le operazioni di lookup sull’albero JNDI per una risorsa esterna sono ripeti-tivi e soprattutto sono dettati dal contesto tecnologico e non dalla logica di business. Inoltre, la dipendenza di un componente EJB dall’API JNDI rende complesso il test unitario del componente al di fuori di un container EJB. Il problema è che nelle righe di codice sopra riportate la classe del bean enterprise ha un legame diretto con la tec-nica attraverso la quale si recupera un riferimento ad una risorsa esterna (nell’esempio un datasource, ma di fatto può anche essere una queue o un topic JMS, un altro EJB, ecc.). La dependency injection rovescia tale paradigma essendo il container EJB a passare alla classe del bean enterprise una reference alla risorsa esterna. Detto in altri termini, il con-tainer EJB inietta nel bean enterprise una reference per la risorsa esterna prima che sia eseguito un qualsiasi metodo di business del bean. Lo stralcio di codice che segue mostra

come le operazioni di lookup sono di fatto eliminate nella nuova specifica EJB 3.0:

…public class GestoreBibliotecaBean implements GestoreBiblioteca{ @Resource (name=”jdbc/exampleDatasource”) DataSource theDatasource = null;} …

Attraverso l’annotazione @javax.annotation.Resource è va-lorizzato da parte del container l’oggetto theDatasource di tipo javax.sql.DataSource prima che sia invocato un qualsiasi metodo di business dell’EJB da parte di un client.In modo analogo, attraverso l’annotazione @javax.ejb.EJB è possibile referenziare un secondo componente EJB. Di seguito un esempio di codice:

…public class GestoreBibliotecaBean implements GestoreBiblioteca { @EJB SecondEJB secondEJB; … }…

La sintassi equivale ad eseguire una operazione di lookup dell’EJB individuato dalla reference java:comp/env/ejb/secondEJB. Per apprezzare la semplificazione introdotta riportiamo di seguito il codice presente in un EJB 2.x per risolvere la medesima reference al secondo EJB:

…Context ctx = new InitialContext();SecondEJBHome secondEJBHome = (SecondEJBHome)javax.rmi.Porta

LISTATO 4 Il file jboss.xml

<?xml version=”1.0” encoding=”UTF-8”?><!DOCTYPE jboss PUBLIC “-//JBoss//DTD JBOSS 3.2//EN” “http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd”><jboss><unauthenticated-principal>nobody</unauthenticated-principal><enterprise-beans><session><ejb-name>Biblioteca</ejb-name><resource-ref><res-ref-name>jdbc/exampleDatasource</res-ref-name><jndi-name>java:theDataSource</jndi-name></resource-ref><method-attributes/></session></enterprise-beans><resource-managers/></jboss>

Page 37: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 37

educational

bleRemoteObject.narrow( ctx.lookup(“java:comp/env/ejb/secondEJB”), SecondEJBHome.class);SecondEJB secondEJB = secondEJBHome.create();…

Gestione delle transazioni

Il gestore della biblioteca ha tra le sue funzionalità la possibilità di assegnare un libro ad un utente che ne fa richiesta. L’operazione di assegnamento si compone di due passi fondamentali: il primo passo è il vero e pro-prio assegnamento del libro all’utente della biblioteca mentre il secondo passo è la verifica che vi sia almeno una copia del libro in biblioteca per poterlo imprestare (i passi sono stati così strutturati per mostrare la gestio-ne automatica delle transazionin da parte del container EJB). Nel caso in cui il libro risultasse non disponibile la precedente operazione di assegnamento deve essere annullata.

La specifica EJB 3.0 definisce due annotazioni per la ge-stione delle transazioni:

• @TransactionManagement• @TransactionAttribute

Attraverso l’annotazione @TransactionManagement si di-chiara se le transazioni sono gestite automaticamente dal container EJB o manualmente dallo sviluppatore dell’EJB attraverso l’API JTA; mentre con l’annotazione @Transac-tionAttribute è possibile definire il comportamento transa-zionale di un metodo di business dell’EJB. I valori validi per l’annotazione @TransactionManagement sono definiti nella enumerazione TransactionManagementType presente nel package javax.ejb e sono:

• CONTAINER• BEAN

Mentre i valori validi per l’annotazione @TransactionAttri-

LISTATO 5 La classe client che invoca l’EJB

package it.articolo.client;

...

public class Client { public static void main(String[] args) throws NamingException { Client oClient = new Client(); Object oObject = oClient.lookupEJB(“Biblioteca/remote”); GestoreBiblioteca oEJB = (GestoreBiblioteca)oObject; List<Libro> libri = oEJB.getLibri(null); // VISUALIZZA A CONSOLE TUTTI I LIBRI oClient.log(libri.toString()); Persona persona = new Persona(); persona.setCognome(“Fabio”); persona.setNome(“Staro”); try { // OPERAZIONE DI ASSEGNAMENTO DI UN LIBRO oEJB.assegna(persona, libri.get(0)); } catch (LibroNonDisponibile e) { oClient.log(“ECCEZIONE:”+e.getMessage()); } } private Object lookupEJB(String nomeEJB) throws NamingException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, “org.jnp.interfaces.NamingContextFactory”); props.put(Context.PROVIDER_URL, “jnp://localhost:1099”); Context ctx = new InitialContext(props); return ctx.lookup(nomeEJB); } private void log(String msg) { out.println(“[“+this.getClass().getName()+”]:”+msg); }

}

Page 38: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200738

educational

bute sono definiti nella enumerazione TransactionAttribu-teType, sempre presente nel package javax.ejb, e sono:

• NOT_SUPPORTED• REQUIRED• REQUIRES_NEW• SUPPORTS• MANDATORY• SUPPORTS

La semantica dei valori sopra riportati è ben schematizzata nella Tabella 3. A titolo di esempio osservando la Tabella 3 possiamo notare che se un componente client che non ha iniziato una transazione invoca un metodo di un EJB per il quale il valore dell’annotazione @TransactionAttribute è REQUIRED il container EJB inizia una transazione nella quale esegue il metodo di business. Viceversa, se sempre il medesimo componente client inizia una transazione e invoca il metodo precedente dell’EJB, allora il container non inizia una nuova transazione ma esegue il metodo di business nel contesto transazionale del client. Se una o entrambe le annotazioni sono omesse, varranno i valori di default, che sono:

• CONTAINER per l’annotazione @TransactionManage-ment

• REQUIRED per l’annotazione @TransactionAttribute

Per illustrare la gestione automatica delle transazioni da parte del container riprendiamo l’esempio della biblioteca e la classe GestoreBibliotecaBean. Questa presenta il metodo di business assegna(). Il metodo fa due operazioni elemen-tari: assegna il libro richiesto ad un utente della biblioteca (operazione che si semplifica in un comando di inserimen-to sulla base dati) e diminuisce il numero di copie presenti in biblioteca per il libro richiesto (operazione di aggiorna-mento sulla base dati). Lo stralcio di codice nel Listato 2 mostra il metodo di business assegna ().

Il metodo diminuisciNumeroCopie() verifica per il libro ri-chiesto il numero di copie presenti in biblioteca e nel caso in cui il libro richiesto risulta presente, aggiorna il numero di copie diminuendone il valore di una unità. Il metodo nel caso di indisponibilità per il libro richiesto lancia la eccezione applicativa LibroNonDisponibile. In caso di ecce-zione, la precedente operazione di assegnazione del libro all’utente richiedente, effettuata dal metodo assegna (), deve essere sottoposta a rollback . L’eccezione LibroNonDi-sponibile è così definita:

…@ApplicationException(rollback=true)public class LibroNonDisponibile extends Exception { public LibroNonDisponibile(String message) { super(message); }

public LibroNonDisponibile(String message, Throwable cause) { super(message, cause);

}}…

Attraverso l’annotazione

@ApplicationException(rollback=true)

si informa il container EJB di eseguire una operazione di rollback automatica al verificarsi della eccezione.

Metodi interceptor

Un’altra interessante caratteristica degli EJB 3.0 sono gli interceptor. La definizione di un interceptor è fornita diretta-mente dalla specifica:

“Un interceptor è un metodo che intercetta l’invocazione di un metodo business o di un evento callback del ciclo di vita. Un meto-do interceptor può essere definito nella classe bean o in una classe interceptor associata al bean.”

Attraverso un metodo interceptor è possibile eseguire delle funzionalità prima e dopo l’invocazione di un metodo di business. Il metodo interceptor può essere dichiarato o nella stessa classe del bean o in una classe separata che prende il nome di interceptor class. Riprendiamo ora l’esempio della biblioteca e supponiamo di voler misurare il tempo di ese-cuzione del metodo getLibri() e di voler memorizzare, per esempio su tabella, l’utente che ha invocato il metodo e altre informazioni di contesto. Attraverso l’uso di due inter-ceptor class è possibile separare l’operazione di misura della performance e l’operazione di logging dalla operazione di business vera e propria, migliorando in tal modo la chia-rezza e la manutenibilità del codice. Di seguito è riportato uno stralcio della classe GestoreBibliotecaBean.

@Stateless (name=”Biblioteca”)public class GestoreBibliotecaBean implements GestoreBiblioteca { @Interceptors({PerformanceInterceptor.class, LogInterceptor.class})

Il Server EJB

garantisce il contesto

transazionale

Page 39: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 39

educational

public List<Libro> getLibri(String nomeAutore) {… }}

E, a titolo di esempio, il codice della classe interceptor PerformanceInterceptor:

…public class PerformanceInterceptor { private static Log oLogger = LogFactory.getLog(PerformanceInterceptor.class); @AroundInvoke public Object performance(InvocationContext ctx) throws Exception { long start = System.currentTimeMillis(); try { return ctx.proceed(); } finally { long end = System.currentTimeMillis(); oLogger.info(“IL METODO:”+ctx.getMethod().getName()+ “ E’ STATO ESEGUITO IN:”+(end-start)+” MILLISECONDI”); } }}…

Osservando il codice si nota che attraverso l’annotazione @Interceptors è possibile dichiarare una o più interceptor class e con l’annotazione @AroundInvoke si definisce il metodo che agisce da interceptor. A questo metodo è fornito come parametro di input un oggetto che implementa l’interfac-cia InvocationContext che è così definita:

…public interface InvocationContext {public Object getTarget();public Method getMethod();public Object[] getParameters();public void setParameters(Object[] params);public java.util.Map<String, Object> getContextData();public Object proceed() throws Exception;}…

L’interfaccia InvocationContext fornisce i metadati attraver-so i quali è possibile gestire la catena di invocazione degli interceptor (nell’esempio riportato la catena di invocazione è costituita dalle classi PerformanceInterceptor, LogInterceptor e, ovviamente, GestoreBibliotecaBean). In particolare gli in-terceptors in una catena di invocazione possono passarsi e condividere dati di contesto recuperandoli attraverso il me-todo getContextData() sulla istanza dello oggetto Invocation-Context. Gli altri metodi dell’interfaccia InvocationContext sono:

• getTarget(): restituisce l’oggetto sul quale sarà invocato il metodo di business;

• getMethod(): restituisce il metodo di business invocato;• getParameters(): restituisce i parametri che saranno usati

come input nella esecuzione del metodo di business;• setParameters(): consente di impostare nuovi parametri di

input per l’esecuzione del metodo di business;• proceed (): esegue il metodo successivo nella catena di

invocazione.

L’invocazione di un interceptor method avviene nello stesso contesto transazionale e di sicurezza del metodo di busi-ness e un interceptor method può rilanciare runtime exception o application exception definite nella firma del metodo di business.

Deploy del componente

Il packaging del componente come EJB 3.0 è estremamen-te semplice. È sufficiente creare un file .jar che contiene la classe bean, l’interfaccia di business e le eventuali classi interceptor. Come si è detto all’inizio dell’articolo, i file de-ployment descriptor sono opzionali, ma se presenti devono essere all’interno della cartella META-INF. Il deploy del componente nell’application server JBoss 5 è la semplice copia del file .jar nella directory deploy del server.

Conclusioni

In questo primo articolo abbiamo introdotto alcune ca-ratteristiche degli EJB 3.0 evidenziando le semplificazioni introdotte. Per quanto si è mostrato, è chiaro come gli EJB 3.0 possano definirsi “fine-grained object” non più complessi di un normale bean Java con la presenza di annotazioni, al contrario degli EJB versione 2.x visti come “corse-grained heavyweight object”. Nei prossimi articoli approfondiremo ulteriormente le nuove caratteristiche soffermandoci poi sui message-driven bean e sui nuovi bean di entità.

Riferimenti

[1]: JSR 220: Enterprise JavaBeans,Version 3.0, http://java.sun.com/products/ejb/docs.html.[2]: http://en.wikipedia.org/wiki/Two-phase_commit[3]: http://java.sun.com/products/jta/[4]: http://java.sun.com/products/jts/[5]: http://www.hibernate.org/[6]: http://www.jboss.com/.[7]: http://www.mysql.com/

Note Biografiche

Fabio Staro, dottore in Fisica è Responsabile Tecnico per i pro-getti Java presso la Direzione Ricerca ed Innovazione di Engi-neering Ingegneria Informatica S.p.A.

Page 40: j2007 02 jj3

JAVA Journal

40 n.3 - marzo/aprile 2007

educational

Tutto Java in un Hello WorldIn questo articolo vediamo come sia possibile scrivere un Hello World senza fermarci al semplice System.out.println(). Vedremo infatti collegate diverse tecnologie Java, che si legano una con l’altra per veicolare un messaggio di prova.

>> di Federico Paparoni ([email protected])

Q uante volte avete incominciato a studia-re un linguaggio di programmazione? La cosa più bella in questi momenti è quan-do ancora non sapete niente di quello che

vi trovate davanti, non avete capito bene come è or-ganizzato, vi affannate per cercare di capire se c’è un IDE grafico che può aiutarvi e passate un bel po’ di tempo su Google per cercare qualche articolo che vi possa illuminare. Nonostante ciò, quando si inizia a studiare un nuovo linguaggio, il classico HelloWorld, un semplice programma che scrive semplicemente a schermo una stringa di testo, è la cosa che viene fatta abbastanza semplicemente e vi invoglia a continua-re, anche perché pensate “Ora voglio proprio vedere come fare….”. Purtroppo dedicandoci ad un linguag-gio in particolare, in questo caso Java, non possiamo provare spesso questa emozione. Oggi in questo arti-colo proveremo a scrivere un HelloWorld che attra-versi tutto Java (o comunque una buona parte), per vedere come tutte le tecnologie Java possono essere legate insieme.

Architettura dell’applicazione

L’architettura della nostra applicazione è abbastanza ingarbugliata e quindi richiede un attimo di attenzio-ne per essere capita. Diciamo che tutto ciò viene fatto per legare diverse tecnologie Java insieme e quindi bisogna capire bene dove ciascuna componente entra in gioco. Nella Figura 1 viene riportato un diagram-ma della nostra applicazione che ci permette di avere un’idea chiara di quello che succede. Come punto di partenza abbiamo un’applicazione JavaME che si collega ad una Servlet. L’applicazione invierà tramite una classica connessione HTTP il messaggio. Succes-sivamente la Servlet invierà questo messaggio ad un oggetto RMI (Remote Method Invocation), che viene

istanziato all’avvio dell’applicazione server. L’imple-mentazione dell’oggetto RMI provvede quindi ad inviare ad una coda JMS (Java Message Service) il messaggio testuale. In questo caso utilizzeremo una coda JMS messa a disposizione dall’application server BEA WebLogic. Dall’altro capo della coda ab-biamo in listening un oggetto che provvede, appena arriva un messaggio, ad inserirlo tramite JDBC (Java Database Connectivity) nel nostro database. Infine abbiamo un’applicazione classica desktop che richie-de di continuo una pagina JSP (Java Server Pages), la quale utilizzando JSTL (JavaServer Pages Standard Tag Library) provvederà a restituirci il messaggio ap-pena questo sarà disponibile nel nostro database. Insomma un bel giro di classi, metodi e tecnologie. Incominciamo ora a vedere la prima applicazione da realizzare, ovvero quella JavaME.

JavaME

L’applicazione che in questo caso dobbiamo realiz-zare è abbastanza semplice. Dovremo creare un’in-terfaccia che permette di avviare la richiesta HTTP,

Un’applicazione

JavaME che si collega

ad una Servlet

Page 41: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 41

educational

utilizzando un Form classico, come viene riportato qui di seguito

…d = Display.getDisplay(this);form=new Form(“Java Hello World”);form.append(“To launch the Java Hello World, press

Start command”);start=new Command(“Start”,Command.OK, 1);exit=new Command(“Exit”,Command.EXIT, 2);form.addCommand(start);form.addCommand(exit);form.setCommandListener(this);d.setCurrent(form);…

In questo modo abbiamo presentato all’utente un’in-terfaccia con due comandi disponibili: Start e Exit. Per intercettare i comandi che abbiamo inserito nell’inter-faccia dobbiamo implementare l’interfaccia Comman-dListener, ovvero è necessario implementare il metodo commandAction() dove faremo partire la vera e propria connessione verso il server HTTP. Nel Listato 1 è ripor-tata la classe che permette di inviare la richiesta HTTP, ed è implementata estendendo la classe Thread, per evi-tare il deadlock della nostra applicazione. Come potete vedere, viene effettuata una chiamata HTTP utilizzando HttpConnection, un’interfaccia standard disponibile sulla piattaforma JavaME. La URL che viene richiamata è quella della Servlet che dobbiamo implementare, alla quale viene passato un parametro che specifica il mes-saggio che vogliamo inviare. Alla fine dell’esecuzione di questo Thread, viene restituito all’interfaccia grafica il messaggio di risposta della Servlet. In Figura 2 potete

vedere l’emulatore JavaME che mostra la MIDlet dopo l’esecuzione.

Servlet

La Servlet ha due fasi distinte che devono essere analizza-te nella nostra applicazione: l’avvio e l’elaborazione della richiesta. Durante l’avvio dobbiamo utilizzare il metodo init() della Servlet per inizializzare tutte le risorse di cui avremo bisogno per il corretto funzionamento della no-stra applicazione. Qui di seguito viene riportato il metodo init(), che viene richiamato nel momento in cui l’applica-zione server viene installata/avviata.

public void init() throws ServletException { try { System.out.println(“Start servlet”); Registry registry = LocateRegistry.createRegist

ry(1199); HelloRMIImpl helloRMIImpl = new HelloRMIImpl(); registry.bind(“HelloRMI”, helloRMIImpl); System.out.println(“Registrato oggetto RMI”);

jmsReceiver=new HelloJMSReceiver(); System.out.println(“Avviato JMS receiver”); } catch(Exception e) { System.out.println(“init: “+e.toString()); }}

Prima di tutto viene creato un registro RMI, nel quale viene inserito un oggetto RMI che in seguito andremo ad

FIGURA 1 Architettura della nostra applicazione

Page 42: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200742

educational

analizzare. In questo caso abbiamo creato direttamente un registro all’interno di una web application, una cosa non troppo “pulita”. Di solito, infatti, sarebbe meglio avere il registro RMI separato, creato utilizzando l’eseguibile rmiregistry.bat (o rmiregistry.sh) incluso nella distribuzio-ne standard di JavaSE. In questo caso abbiamo fatto così per vedere come poter inizializzare il registro direttamente da codice Java. Oltre all’oggetto RMI, che viene inserito nel registro, dobbiamo inizializzare l’oggetto Java che si occu-perà di mettersi in listening sulla coda JMS. Ora possiamo vedere il metodo doGet() della Servlet, che si occuperà di gestire la richiesta che proviene dal programma JavaME.

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException { try { HelloRMI obj = (HelloRMI)Naming.lookup(“rmi:

//127.0.0.1:1199/HelloRMI”); obj.sendHello((String)request.getParameter(“msg”)); response.setContentType(“text/html;charset=UTF-8”); PrintWriter out = response.getWriter(); out.println(“HelloWorld avviato!”); out.close(); } catch(Exception e) { System.out.println(“processRequest:

“+e.toString()); }}

Questo metodo utilizza direttamente l’oggetto HttpServ-letRequest per avere le informazioni che sono state inviate dalla MIDlet. Come possiamo vedere, viene recuperato il parametro msg della richiesta HTTP e viene passato come parametro al metodo sendHello() del nostro oggetto RMI. Infine, viene restituita alla MIDlet la stringa “HelloWorld avviato!”, che abbiamo già visto precedentemente nella Figura 1. In questo modo il nostro messaggio ha già effettuato un paio di salti, dalla MIDlet alla Servlet fino all’oggetto RMI.

RMI

Abbiamo visto come nel metodo doGet() della Servlet abbiamo utilizzato l’interfaccia HelloRMI. Questa estende l’interfaccia java.rmi.Remote e specifica quali metodi do-vranno essere esposti dal nostro oggetto remoto (anche se in questo caso stiamo eseguendo tutto in locale). Di seguito potete vedere l’interfaccia HelloRMI che abbiamo definito:

package it.javajournal;import java.rmi.Remote;import java.rmi.RemoteException;

public interface HelloRMI extends Remote { void sendHello(String message) throws RemoteException;}

L’unico metodo di questa interfaccia è sendHello(), che può lanciare eccezioni di tipo RemoteException. Ed è quindi ciò

FIGURA 2 Emulatore JavaME con l’applicazione di Hello World avviata

Inserire un messaggio

in una coda JMS

Page 43: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 43

educational

che un client remoto può sapere di un oggetto RMI. Per utilizzare un oggetto RMI, come abbiamo fatto qui, dob-biamo caricarlo dal registro RMI e poi richiamare i suoi metodi. È necessario che il client conosca l’interfaccia di questo oggetto, per poter invocare i metodi che esso offre. Nel Listato 2 si può invece osservare l’implementazione dell’interfaccia HelloRMI. In questo caso, nel metodo sen-dHello(), si può vedere come abbiamo realizzato l’ulteriore salto per il nostro messaggio. Per fare ciò ci siamo connessi ad una coda JMS messa a disposizione dall’Application Server BEA WebLogic 8.1 e abbiamo inserito il nostro mes-saggio. In questo esempio è stata utilizzata una Queue, e grazie al ConnectionFactory standard di BEA abbiamo inseri-to un TextMessage creato con il messaggio che viene passato come parametro al metodo sendHello(). Nella Figura 3 si osserva la configurazione della coda JMS sulla console di amministrazione di BEA.

JMS

Siamo arrivati quindi all’implementazione del listener JMS. Anche in questo caso, come nella Servlet, dobbiamo distinguere due diversi momenti, quello dell’inizializza-zione e quello del metodo onMessage(), che viene richia-mato ogni volta che è presente un messaggio nella coda. Nel Listato 3 è riportata l’implementazione della classe HelloJMSReceiver, che si occupa appunto di gestire la coda

JMS. Questa classe implementa l’interfaccia javax.jms.MessageListener e nel costruttore si collega alla coda JMS che già abbiamo visto. In questo caso, però, la coda viene utilizzata soltanto per ricevere i nuovi messaggi che ven-gono inseriti, quindi il nostro oggetto si comporterà come consumatore, rispetto all’oggetto HelloRMIImpl che è il produttore. Come abbiamo visto precedentemente, que-sto oggetto viene istanziato nel metodo init() della Ser-vlet, quindi da quel momento in poi è in listening sulla coda it.javajournal.queue. Quando viene inserito l’oggetto TextMessage nella coda, viene richiamato il metodo onMes-sage(), che provvede ad inserire il nostro messaggio all’in-terno di un database utilizzando JDBC. In questo caso viene utilizzato il DataSource /weblogic/jdbc/jts/HelloDS che è stato precedentemente configurato nel nostro Applica-tion Server. Un DataSource non è altro che un’interfaccia definita nelle API JDBC che permette di ottenere una connessione verso un database. La comodità di richia-mare un DataSource definito esternamente è relativa agli aspetti di configurazione. Praticamente, se dobbiamo utilizzare un database diverso, un utente diverso, o un driver JDBC diverso, non dovremo effettuare questi cam-biamenti nel codice ma direttamente nel pannello di am-ministrazione del nostro Application Server. In Figura 4 potete vedere la configurazione che viene utilizzata per il DataSource che abbiamo utilizzato. Qui di seguito viene riportato il semplice script SQL che abbiamo utilizzato per creare la tabella sul database.

FIGURA 3 Configurazione JMS su BEA WebLogic 8.1

Page 44: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200744

educational

due diverse tecnologie Java, JSP e JSTL. Praticamente, all’interno di una pagina JSP avremo modo di recupe-rare le informazioni sul database grazie alle tag library standard. Qui di seguito potete vedere il codice che rea-lizza la funzione richiesta:

<%@ taglib uri=”http://java.sun.com/jstl/sql” prefix=”sql” %><%@ taglib uri=”http://java.sun.com/jstl/core” prefix=”c” %>

<sql:setDataSource var=”ds” driver=”oracle.jdbc.driver.OracleDriver” url=”jdbc:oracle:thin:@127.0.0.1:1521:HELLOWORLD” user=”system” password=”system”/>

<sql:query var=”messaggi” datasource=”${ds}”> SELECT * FROM hello_message</sql:query>

<c:forEach var=”row” items=”${messaggi.rows}”><c:out value=”${row.messaggio}” /></c:forEach>

In questa pagina JSP vengono utilizzate due diverse tag li-brary, quella relativa al database (sql) e quella base (core).

CREATE TABLE HELLO_MESSAGE (MESSAGGIO VARCHAR2(765));COMMIT;

JSP e JSTL

A questo punto il messaggio, che è partito dal nostro cellulare, è finito dentro il database. Ora dobbiamo occuparci di realizzare una pagina che verrà chiama-ta di continuo da un classico programma JavaSE, per fornire il messaggio che è stato inserito nella tabella HELLO_MESSAGE del database. Per fare ciò utilizzeremo

FIGURA 3 Configurazione JMS su BEA WebLogic 8.1

Esporre un oggetto

RMI, disponibile per

client remoti

Page 45: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 45

educational

Note Biografiche

Federico Paparoni si occupa prevalentemente di sviluppo sulle piattaforme JavaME e JavaEE. Gestisce il portale JavaStaff.com per la pubblicazione di notizie e articoli sul mondo Java.

All’inizio vengono dichiarate le tag library con i relativi prefissi che verranno utilizzati nel codice. Successivamen-te viene definito un DataSource grazie al quale possiamo collegarci al database. Viene quindi fatta una Select sulla tabella utilizzando il tag sql:query. Il risultato di questa query viene memorizzato nella variabile messaggi. Infine, grazie alla tag library core, viene scritto tutto quello che è presente nella riga MESSAGGIO della tabella HELLO_MES-SAGE. Chiaramente, fino a quando non sarà partito il messaggio dal programma JavaME, questa pagina non restituirà niente. Vediamo ora la parte finale del nostro programma.

Programma Desktop

Il programma che alla fine visualizzerà il messaggio partito dal cellulare deve effettuare il polling della pagina JSP che abbiamo appena visto. Per fare ciò estenderemo la classe TimerTask e utilizzeremo un vero e proprio timer che ogni 5 secondi controlla la pagina JSP. Qui di seguito viene ripor-tato il metodo main() dell’applicazione desktop:

public static void main(String[] args) throws Exception{ Timer timer = new Timer(); JavaHelloWorldDesktop task = new

JavaHelloWorldDesktop(); timer.schedule( task, 5000, 5000 ); }

Non resta che implementare il metodo run() della classe JavaHelloWorldDesktop, presentato nel Listato 4. Utiliz-zando il package standard java.net viene effettuata una connessione verso la pagina JSP. Ogni volta viene letta la pagina e viene controllato se è presente o meno del testo. Nel momento in cui verrà restituito il messaggio, l’applica-zione desktop lo visualizzerà a schermo e successivamente terminerà la sua esecuzione.

Conclusioni

In Figura 5 si vede come termina il viaggio del mes-saggio partito dal cellulare. In questo articolo abbiamo utilizzato più tecnologie Java, concentrando il nostro interesse sul modo in cui collegarle. Chiaramente, ognuna delle tecnologie appena viste meritano un ap-profondimento a sé. Ciò nonostante, dopo tanto codice e alcune spiegazioni, possiamo goderci un semplice e simpatico “Hello World”. Proprio come quando si inizia a programmare.

FIGURA 5 Console dove viene mostrato il risultato della nostra applicazione

Utilizziamo JSP e

JSTL per fornire le

informazioni

Page 46: j2007 02 jj3

JAVA Journal

n.1 - novembre/dicembre 2006 35

focus

Page 47: j2007 02 jj3

JAVA Journal

47n.3 - marzo/aprile 2007

focus

Introduzione a Struts

Applicazioni Web e Framework: MVC

Le applicazioni web, funzionano tutte seguendo le stesse regole di base e quindi si assomigliano molto fra loro. Pertanto, è nata la necessità per gli sviluppa-tori di queste applicazioni di dotarsi di infrastrutture che costituiscano l’impalcatura generale dell’applica-zione, le fondamenta del progetto: i framework.Parallelamente, gli ingegneri del software hanno in-dividuato che, in linea generale, alcuni problemi che si presentano nell’informatica sono ricorrenti e ben circoscritti; tipologie di problemi ricorrenti hanno tipologie di soluzione altrettanto ricorrenti: i design pattern.MVC (Model View Controller) è un pattern di pro-getto che si applica alle applicazioni multi tier, come quelle web, e consiste nella separazione netta tra:

• modello dei dati (il model); • controllo del flusso dell’applicazione (il control-ler);

• presentazione dei risultati all’utente (la view).

Struts è un framework che aiuta a perseguire la separazione indicata dal pattern MVC e dalla sua evoluzione Model 2, fornendo un controller già fun-zionante e una base su cui costruire la view.

Struts: quando, dove, come e perché; orientarsi nel sito Struts è un progetto sviluppato negli anni dal 2000 al 2001 ed è ospitato nel grande contenitore di progetti che è l’Apache Software Foundation. È reperibile al-l’indirizzo http://struts.apache.org/.L’apporto principale al suo sviluppo è venuto da Craig McClanahan già principale fautore del progetto

Apache Tomcat ed ora personaggio di spicco nella progettazione di JavaServer Faces dello strato web delle specifiche J2EE.Oggi il popolare framework è diviso in due parti:

• Struts Shale Framework; • Struts Action Framewok.

Noi ci occuperemo di quest’ultimo che è l’evoluzione del framework originario.Struts non è un’IDE, non ha un front-end grafico e non costruisce automaticamente applicazioni web. È semplicemente una libreria di oggetti già costruiti che svolgono alcune funzioni di base essenziali per il buon funzionamento di applicazioni web MVC.Struts non è l’unico framework e non è necessaria-mente il più valido, ma è oggi uno dei più utilizzati e diffusi. Ha molte estensioni tra cui alcune discreta-mente diffuse: Tiles, di cui non parleremo, è una di queste e fornisce un comodo strumento per costruire la view.

Struts è un framework completo e diffuso e offre le basi per sviluppare in modo organico le applicazioni web

>> di Andrea Colleoni ([email protected])

MVC significa Model-

View-Controller ed è un

pattern molto usato

Page 48: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200748

focus

Download e utilizzo

All’indirizzo http://struts.apache.org/downloads.html sono disponibili per il download sia le release con tutte le librerie compilate e pronte per l’uso (i cosidetti “binary”) sia i programmi sorgenti. Nell’archivio struts-x.y.z-bin.zip (oppure tar.gz) contenente le librerie compilate, troviamo le seguenti cartelle:

• /lib: contiene tutti i file JAR necessari a far funzionare le varie parti del framework, più tutte le DTD e le definizio-ni delle tag library utilizzabili;

• /contrib: contiene un’estensione delle tag library di Stru-ts; non ci occuperemo di questa parte

• /webapps: contiene alcune applicazioni web di esempio che utilizzano Struts, più un’applicazione web utiliz-zabile come base di partenza per costruire applicazioni basate su Struts e la documentazione su Struts e Tiles

Per far funzionare le applicazioni di esempio, per consul-tare la documentazione e per provare gli esempi di questo articolo avremo bisogno di un servlet container in cui in-stallare le applicazioni.

Essendo le specifiche Servlet e JSP uno standard, qualunque servlet container è adatto, ma in que-st’articolo ci riferiremo sempre al server Apache Tomcat versione 5.x, reperibile all’indirizzo http://tomcat.apache.org/ e di cui sono disponibili gli installer per Windows o gli archivi compressi, contenenti i file per l’installazione su tutti i siste-mi operativi. Nei nostri esempi il server è installato sul compu-ter locale (localhost) e sulla porta http di default (80) per cui gli indirizzi saranno nella forma:

http://localhost/struts-examples/welcome.do.

L’installazione delle webapp fornite con Struts può avvenire copiando i file .WAR nella directory webapps del servlet container, eseguendone un upload dal pannello di amministrazione del servlet container oppure estraendone i file con un programma per la gestione di file compressi tipo WinZip in una sottodirectory di webapps del

servlet container.Per gli scopi di quest’articolo è necessario installare le se-guenti applicazioni:

• struts-documentation.war • struts-mailreader.war • struts-blank.war

Uno sguardo alle applicazioni di esempio

Struts viene fornito con alcune applicazioni di esempio, tra cui struts-mailreader. Esplorando il contenuto all’in-dirizzo

http://localhost/struts-mailreader/Welcome.do

si accede ad una semplice applicazione di registrazione di informazioni. Tramite un form è possibile registrare un utente, per il quale possono poi essere definiti alcuni ac-count di accesso a server di posta. Una volta registrato, un utente, può rieseguire l’accesso e visualizzare l’elenco degli account definiti. I dati vengono conservati in un database XML nel file WEB-INF/database.xml.

FIGURA 1 la mailreader demo application

FIGURA 2 la struts console per editare la configurazione

Page 49: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 49

focus

Dando un’occhiata più da vicino, cerchiamo di capire come funziona e quale plus dà Struts a questa applicazione. In primo luogo osserviamo il descrittore WEB-INF/web.xml:

// web.xml … <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value> /WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>…

Nella sezione relativa alla definizione dei servlet, viene definito il controller del nostro framework MVC: l’ActionServlet. L’Action-Servlet viene caricato all’avvio e gli vengono passati come parametri due file di configu-razione scritti in XML che il servlet caricherà all’avvio dell’applicazione e di cui vedremo tra poco il contenuto.Per essere invocato dal servlet container, l’ActionServlet, deve essere associato ad un pattern URL:

// web.xml… <servlet-mapping>

<servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>…

Qualunque URL che termini con .do, invoca l’Ac-tionServlet; quindi, a dispetto di quanto possa sembrare a prima vista, non ci sono file “.do” nella webapp.Nella sezione delle Tag Libraries, vengono cari-cate le Tag Libraries di Struts che sono presenti nella cartella WEB-INF.Vediamo il contenuto di una semplice pagina JSP: /index.jsp

<%@ taglib uri=”/tags/struts-logic” prefix=”logic” %><logic:redirect action=”/Welcome”/>

Questo frammento di codice consente di regi-strare l’uso della Tag library struts-logic all’inter-no della pagina JSP e quindi di utilizzare il tag redirect di tale libreria per eseguire un’azione di redirect. In particolare il browser viene rediretto

verso una Action di nome Welcome, che è definita nel file di configurazione di Struts.Nella sezione action-mappings del file WEB-INF/struts-config.xml, viene definita tra le altre l’azione Welcome:

// struts-config.xml … <action path=”/Welcome” type=”org.apache.struts.webapp.example.WelcomeAction”> <forward name=”failure” path=”/Error.jsp” /> <forward name=”success” path=”/welcome.jsp” /> </action>

LISTATO 1 La JSP per la Logincon struts

// logon.jsp

...

<html:form action=”/SubmitLogon” focus=”username” onsubmit=”return validateLogonForm(this);”> ... <html:text property=”username” size=”16” maxlength=”18”/> ... <html:password property=”password” size=”16” maxlength=”18” redisplay=”false”/> ... <html:submit property=”Submit” value=”Submit”/> ... <html:reset/> ...</html:form>

...

LISTATO 2 La Action (java) per la Login con struts

// LogonAction.java

...

public ActionForward execute(...) throws Exception { ... String username = (String) PropertyUtils.getSimpleProperty(form, USERNAME); String password = (String) PropertyUtils.getSimpleProperty(form, PASSWORD); ... return (mapping.getInputForward()); ... return (findSuccess(mapping));

}

...

Page 50: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200750

focus

Questo frammento della configurazione, noto come ActionMapping, fa sì che quando viene richiesta l’URL /Welcome.do (è case sensitive, quindi con la W maiuscola), venga creato un oggetto di classe WelcomeAction, che è istanziato dal fra-mework, ma è definito dal programmatore.Il frammento contiene anche la definizione di due forward di nome failure e success. A questi sono associate due pagine JSP, rispet-tivamente /Error.jsp e /welcome.jsp. Vediamo cosa significano queste impostazioni e come funziona un’azione Struts.

Aprendo il file WEB-INF/src/org/apache/struts/webapp/example/WelcomeAction.java, a cui si ri-ferisce l’action mapping visto sopra, notiamo che l’azione estende una classe fornita nel-l’esempio: BaseAction che a sua volta estende la classe del framework Action introducendo rispetto a quest’ultima solo alcuni semplici metodi di utilità. Una volta individuata la classe corrispondente all’azione, il framework la istanzia e ne invoca il metodo execute() al quale vengono passati tutti gli oggetti per operare con il contesto web e due oggetti Struts: l’ActionMapping che rappresenta il contenuto del file di con-figurazione e l’ActionForm. Il metodo quindi termina restituendo al framework che l’ha invocato, un oggetto di tipo ActionForward.

// WelcomeAction.java …public final class WelcomeAction extends BaseAction { public ActionForward execute( ActionMapping mapping,

ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

... if (messages.size()>0) { ... return findFailure(mapping); } return findSuccess(mapping); }}…

Nel codice, a seconda del successo o meno di alcune istruzioni che non è nostro scopo approfondire, possiamo decidere di “uscire con successo” o “uscire con insuccesso”

FIGURA 3 editiamo una azione

LISTATO 3 un semplice JavaBean

// La classe TextBean è molto semplice: // ha una proprietà di nome text di tipo String // accessibile sia in lettura che in scrittura.

TextBean.javapublic class TextBean { private String text; public String getText() {

return this.text; } public void setText(String text) {

this.text = text; } }

// TextManager ha solo un metodo // che altera il contenuto della // proprietà text del bean TextBean

TextManager.javapublic class TextManager {

public TextManager() { } public void modifica (TextBean tb) { tb.setText(“***” + tb.getText() + “***”); } }

Page 51: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200750

focus JAVA Journal

n.3 - marzo/aprile 2007 51

focus

I metodi findSuccess() e findFailure() sono definiti in BaseAction e facilitano il rintrac-ciamento dei tipici forward success e failure. Nei forward definiti nell’action mapping, vie-ne definito cosa fare in caso di successo e cosa in caso di insuccesso.In caso di successo, nel nostro esempio, viene caricata nel browser la “view” /welcome.jsp che è la pagina che si vede navigando l’URL http://localhost/struts-mailreader/Welcome.do, che chiude gli elementi del paradigma MVC.

In definitiva uno dei compiti del controller è governare il flusso dell’applicazione web at-traverso file di configurazione scritti in XML. Il framework offre anche un altro strumen-to configurabile molto utile: l’ActionForm. Nel file di configurazione, notiamo che c’è un’azione /Logon.do che fa semplicemente un forward alla pagina /logon.jsp.

<action path=”/Logon” forward=”/logon.jsp”/>

La pagina /logon.jsp, contiene un form costruito con i tag della libreria HTML di Struts (Listato 1).

Anche nel file di configurazione di Struts esiste una rap-presentazione di questo form; si trova nella sezione form-beans:

// struts-config.xml … <form-bean name=”LogonForm” type=”org.apache.struts.validator.DynaValidatorForm”> <form-property name=”username” type=”java.lang.String”/> <form-property name=”password” type=”java.lang.String”/> </form-bean>…

Il contenuto del form può essere quindi gestito dal framework (in questo caso viene addirittura valicato automaticamente dal framework attraverso l’uso del Dy-naValidatorForm) e rappresentato al suo interno come un JavaBean. L’azione /SubmitLogon a cui il form invia le informazioni è così definita:

// struts-config.xml … <action path=”/SubmitLogon” type=”org.apache.struts.webapp.example.LogonAction” name=”LogonForm” scope=”request” input=”logon”> ... </action>…

La classe LogonAction conterrà il codice per eseguire l’au-tenticazione utilizzando username e password forniti dal form (Listato 2).

Vale anche la pena di osservare che il metodo execute() è in grado di ritornare alla pagina di logon in caso di errori, con il metodo mapping.getInputForward() che restitui-sce il forward definito nell’attributo input dell’action-mapping.

Uno sguardo alla “blank application”

La “blank-application” è contenuta nell’archivio struts-blank.war e contiene lo “scheletro” di un’applicazione web che funziona con il controller Struts. Ha un web.xml che carica l’ActionServlet con la configurazione definita nel file struts-config.xml, che inizialmente contiene alcuni esempi ben commentati.Per iniziare a costruire applicazione web con Struts la blank-application fornisce quindi una buona base di par-tenza.Per interagire con il file di configurazione di Struts, può essere comodo inizialmente utilizzare uno strumento di supporto grafico che aiuti a ricordare la struttu-ra del file e il suo utilizzo. Un buono strumento in tal senso è la Struts console reperibile all’indirizzo http://www.jamesholmes.com/struts/console/ di cui in questo esempio è stata usata la versione 4.8.Per iniziare con una nuova applicazione, quindi estrarremo il file struts-blank.war in qualche directory nella quale verranno costruiti tutti i percorsi e i file di default, quindi usando la console struts e un kit di svi-luppo per Java procederemo con lo sviluppo di azioni e pagine JSP.

LISTATO 4 la form che visualizza il bean

// text.jsp

<%@ taglib uri=”/tags/struts-html” prefix=”html” %>

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>

<html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8”> <title>Form</title> </head> <body> <html:form action=”/SubmitAction”> Testo: <html:text property=”textproperty” /><br /> <html:submit /> </html:form> </body></html>

Page 52: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200752

focus JAVA Journal

n.3 - marzo/aprile 2007 53

focus

Costruzione di un semplice esempio

Proviamo ora a costruire, partendo dalla blank.application, un’applicazione web che svolga i seguenti compiti:

• Da una pagina /text.jsp venga offerta la possibilità di inse-rire del testo

• All’invio del form tale testo venga trattato da classi di backend e restituito (Figura 4)

Prima di tutto estraiamo con il programma di decompres-sione il file struts-blank.war in una cartella, ad esempio c:\esempi\struts. Poi con un editor Java creiamo secondo la struttura delle applicazioni web, le classi che rappre-sentino il nostro model; costruiamo un JavaBean che rappresenti la nostra informazione ed una classe adatta a trattarlo (Listato 3).Creiamo quindi un semplice form usando la libreria HTML di Struts al posto dei normali tag HTML; il form avrà come

action l’azione /SubmitAction che andremo a definire suc-cessivamente in struts-config.xml (Listato 4).

Usiamo la struts console per costruire il form e mappare l’azione. Dal menù file apriamo il file struts-config.xml che abbiamo estratto in c:\esempi\struts\WEB-INF ed eseguiamo i seguenti passi:

• Aggiungiamo un form bean di nome textform e di tipo DynaActionForm ed a questo aggiungiamo una proprie-tà di nome textproperty di tipo String (Figura 2)

• Ora aggiungiamo un’action-mapping con URL /SubmitAction che usi il form bean che abbiamo appena creato; il tipo di mapping deve essere SubmitAction che è il nome della classe che andremo a creare fra poco per gestire l’azione (Figura 3)

• Aggiungiamo nella configurazione del mapping anche un forward che chiameremo success che punti al path /success.jsp:

• Possiamo salvare lo struts-config.xml, chiudere la struts console e prosegure con l’editor Java

• Ora dobbiamo costruire la nostra classe SubmitAction che preso il valore inserito nel form lo manipola con le classi del model e lo restituisce alla pagina /success.jsp: (Listato 5). Per rendere il risultato disponibile alla pagi-na view, una tecnica utilizzata è quella di valorizzare un attributo dell’oggetto request, il quale poi verrà letto con la libreria di tag di Struts bean.

LISTATO 5 una action per processare il bean

// SubmitAction.java

import org.apache.struts.action.Action;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionForm;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.beanutils.PropertyUtils;

public class SubmitAction extends Action {

public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

ActionForward retValue; TextBean tb = new TextBean(); TextManager tm = new TextManager(); tb.setText((String) PropertyUtils.getSimpleProperty(form, “textproperty”)); tm.modifica(tb); request.setAttribute(“risultato”, tb); return mapping.findForward(“success”); }}

Struts funziona su un

application server che

supporta Servlet e JSP

Page 53: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200752

focus JAVA Journal

n.3 - marzo/aprile 2007 53

focus

• Infine aggiungiamo la pagina success.jsp che deve pre-sentare all’utente il risultato del processo avvenuto nel backend (Listato 6).

Per installare ed eseguire l’esempio è necessario compilare il progetto e copiare tutti i file dell’applicazione web conte-nuti nella cartella c:\esempi\struts nel servlet container.Una volta copiati i file necessari navighiamo all’URL http://localhost/struts-blank/text.jsp. A questo punto, basterà inserire del testo nella casella di testo, inviare il form … e avremo ottenuto il risultato atteso.

Conclusioni

Nell’esempio abbiamo toccato i punti essenziali dell’Action Framework che di fatto è l’elemento architetturale che con-sente di scrivere applicazioni web secondo il paradigma MVC.

Struts in effetti è un framework completo e diffuso e offre anche basi per sviluppare organicamente altre parti delle ap-plicazioni web, come il supporto all’internazionalizzazione, alla validazione che in quest’articolo abbiamo solo sfiorato. L’avvento di altri validi framework di successo ed il tentativo di standardizzare lo sviluppo di applicazioni MVC condizionano lo sviluppo di Struts ed in effetti la divisione tra l’Action Fra-mework e Shale è conseguenza di questo fatto.

FIGURA 4

LISTATO 6 visualizzare il risultato

// Success.jsp

<%@ taglib uri=”/tags/struts-bean” prefix=”bean” %>

<html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8”> <title>JSP Page</title> </head> <body> Il testo contenuto nel JavaBean processato è <bean:write name=”risultato” property=”text” /> </body></html>

Note Biografiche

Andrea Colleoni si occupa professionalmente di sviluppo di sof-tware dal 1996 e di Java dal 2000. Attualmente svolge l’attività di consulente attraverso la sua società, coordinando gruppi di lavoro su progetti software di dimensioni medie o grandi in am-bito finanziario/bancario e industriale prevalentemente con tec-nologie legate a J2EE, ma anche con Microsoft.NET. Si occupa anche di formazione; insegna Informatica alla Facoltà di Eco-nomia dell’Università di Bergamo e in altri corsi più specifici organizzati da vari enti di formazione. Vive a Seriate in provin-cia di Bergamo con mia moglie Elena e la sua piccolina, Greta, arrivata cinque mesi fa.

Page 54: j2007 02 jj3

JAVA Journal

54 n.3 - marzo/aprile 2007

focus

Programmazione AOP con AspectJ

Progettare una libreria di funzioni o un framework di classi, è sicuramente un’operazione lunga e laboriosa.Occorre capire i problemi che si avran-no, il modo col quale astrarli e genera-lizzarli, ma soprattutto prevedere, nel

modo più completo possibile, le nuove esigenze che si potrebbero avere, per evitare di trovarsi, durante lo sviluppo, in problemi architetturali.Esistono però delle esigenze orizzontali ad un fra-mework, che dovrebbero far parte di tutte le classi, ma, per evitare di sporcare tutto il codice, si tende a non integrarle, ad integrarle parzialmente, o a dele-garle al programma chiamante.Esempi classici di queste esigenze sono la gestione degli errori, il debug degli oggetti, il controllo formale dei parametri e così via.Cosa vuol dire affrontare in modo generalizzato que-ste problematiche?Sicuramente significa creare dei sorgenti ridondanti, copiare dei frammenti di codice da un metodo all’al-tro, astrarre esigenze in interfacce ed obbligare le classi ad implementarle. Fino ad arrivare agli assurdi delle dipendenze circolari, schemi dai quali diventa complicato uscire.Quando poi l’esigenza orizzontale muta, ne risente l’intero framework, creando delle destabilizzazioni nel codice: se il tutto non è stato progettato più che bene, ci si può trovare di fronte alla riscrittura di varie classi, che non dipendono direttamente dalla modifica della funzionalità orizzontale, ma semplice-mente sono impattate in quanto utilizzatrici dirette della funzionalità ormai obsoleta.

Perché AOP

Lo scopo di AOP è quello di isolare un’esigenza oriz-zontale, racchiuderla all’interno di una regola (as-pect), ed applicarla solamente nei punti in cui serve, senza impattare minimamente la classe che ne trarrà vantaggio.Questo vuol dire che, le persone che sviluppano una classe e quelle che la arricchiscono con un aspect, possono tranquillamente far parte di due team di svi-luppo diversi, dato che lavorano su due set di classi differenti, che si fondono per creare un unico byteco-de, che sarà quello che andrà ad essere utilizzato in fase di runtime.Sorgenti diversi, impatti minimi al cambio delle funzionalità delle classi, possibilità di aggiungere comportamenti senza modificare il framework che deve essere arricchito, queste sono le caratteristiche principali di AOP.

AspectJ

Lo strumento di cui parleremo in questo articolo è AspectJ, un compilatore gratuito, che si appoggia a javac e permette di integrare, all’interno delle proprie classi, degli aspect.Questo compilatore è facilmente scaricabile da: http://www.eclipse.org/aspectj/, e si installa con la clas-sica invocazione da riga comando: java -jar aspectj-1.5.0.jar.Una volta installato, viene creata una cartella su disco, generalmente c:\aspectj1.5\, che conterrà sia il compilatore che le librerie per poterlo utilizzare.Il passo successivo sarà quello di mettere in path la directory c:\aspectj1.5\bin e in classpath il jar di As-pectJ: c:\aspectj1.5\lib\aspectjrt.jar.

Dopo anni di programmazione strutturata, si è passati ad anni di programmazione ad oggetti. Ora si inizia a parlare di POP (Post Object Programming), e delle tecnologie correlate. AOP (Aspect Oriented Programming), è appunto una di queste tecnologie. Vediamo di cosa si tratta, con esempi pratici e l’utilizzo di un compilatore gratuito come AspectJ.

>> di Matteo Baccan ([email protected])

Page 55: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 55

focus

Fatte queste due operazioni basilari, siamo pronti per uti-lizzare AspectJ e creare le prime applicazioni AOP. Inizia-mo quindi ad introdurre alcuni concetti di base.

Concetti di base

Alla base della programmazione AOP c’è il concetto di cros-scutting concern (CC), traducibile in interesse trasversale.Quando si parla di CC, si fa riferimento ad un requisito che può essere pensato in modo autonomo, ed applicato in più punti, all’interno del progetto che si sta sviluppando, senza essere necessariamente legato alla funzionalità che si intende sviluppare.Il poter astrarre un requisito, per poi applicarlo in modo orizzontale, ci permette di racchiudere la problematica in quello che viene definito aspect. All’interno di un aspect, sono poi presenti le regole che indicano dove applicarlo.Il vantaggio di un aspect è appunto il fatto di essere rac-chiuso all’interno di un proprio sorgente, dove non vi è di-pendenza diretta rispetto alle classi dove verrà applicato.Per questo motivo, è possibile uno sviluppo parallelo di requi-siti. Sarà poi compito del compilatore, nel nostro caso AspectJ, fondere regole e classi, all’interno dello stesso framework. Pro-viamo ora ad approfondire questi concetti con degli esempi.

Log degli accessi

Ipotizziamo di dover controlla-re tutti gli accessi ad una certa classe. Le ragioni potrebbero essere svariate: un controllo di utilizzo, un test di performance o l’applicazione di un controllo di accesso.L’idea è quella di creare un as-pect, in grado di intercettare tutti gli accessi ad un certo metodo di una certa classe, visualizzandoli a video.

Chiaramente, la partenza di tutto è un framework preventivamente costituito, sul quale vogliamo aggiungere il controllo d’accesso.Perché non modificare direttamente il fra-mework? Le ragioni potrebbero essere molteplici, come il non disporre dei sorgenti del framework, oppure il dover applicare tali modifiche solo ad un progetto che lo utilizza, ma non a tutte le applicazioni che lo utilizzano, evitando quindi di aggiungere codice inutile dove non serve.Se vogliamo analizzare la problematica, dal pun-to di vista dell’Object Orientation (OO), il primo approccio che potrebbe venire in mente, in que-sto caso, è quello di creare una classe di controllo accessi, modificare il sorgente della classe che deve aggiungere la funzionalità, inserirvi un me-todo di controllo e modificare tutti i sottometodi che devono essere controllati, con la chiamata a questo metodo.Questo approccio obbliga, necessariamente, la modifica di gran parte del codice della classe,

rendendo, di fatto, il controllo d’accesso una funzionalità obbligatoria, in ogni ambito in cui la classe è utilizzata.In un’ottica di riutilizzo del framework, si traduce nel aver introdotto qualcosa che servirà solamente in un certo caso specifico, ma non nella totalità dei casi in cui verrà utilizzato il framework stesso. Ne consegue una struttura similare a quella presente in Figura 1.

Vediamo invece cosa cambia, nel momento in cui decides-simo di creare un aspect.Ciò che viene stravolto totalmente è il modo col quale applicare il controllo d’accesso. Non occorre più mo-dificare le classi o i framework che devono supportare questo nuovo requisito, ma basta creare singolarmente il requisito, all’interno di un aspect, definire quando deve essere applicato e compilarlo insieme al codice del framework. Questa modalità permette di aggiungere del codice, ad applicazioni già scritte, senza bisogno di modificarle. Le classi quindi, non devono ereditare da un qualcosa, ma è quel qualcosa che si inserisce nelle classi. Ne risulta, quindi, una struttura simile a quella mostrata nella Figura 2, dove non si parla più di ere-ditarietà della classe di controllo degli accessi, ma di utilizzo.

FIGURA 1 Struttura delle classi senza AOP

FIGURA 2 Struttura delle classi con AOP

Page 56: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200756

focus

Elementi fondamentali della programmazione AOP

Chiarita la differenza di approccio rispetto alla program-mazione Object Oriented, vediamo di scendere maggior-mente in dettaglio, rispetto a AOP, introducendo un set minimale di costrutti, con i quali è possibile creare qual-siasi tipo di aspect e di conseguenza poter sfruttare appieno questo paradigma di programmazione.I costrutti che occorre conoscere sono:

• oin Point: è il punto di esecuzione di un programma: il richiamo di un metodo o l’assegnazione di una variabile d’istanza;

• Pointcut: è il meccanismo che permette di selezionare su quali Join Point andrà ad agire un Advice;

• Advice: è il codice che deve essere eseguito nel Join Point selezionato dal Pointcut;

• Aspect: è l’insieme di Advice e Pointcut.

In base a queste descrizioni, se volessimo definire cos’è un aspect potremmo dire: è una regola che indica il punto dove deve essere eseguito del codice. Il concetto di base è molto semplice, ma allo stesso modo molto potente. Vediamo ora di capire quali sono i Join Point sui quali possiamo agire:

• Method execution/call: durante l’esecuzione o il richia-mo di un metodo;

• Constructor execution/call: durante l’esecuzione o il ri-chiamo di un costruttore;

• Class initialization: all’atto dell’inizializzazione di una classe;

• Field read/write: alla scrittura o lettura in una variabile d’istanza;

• Exception handler: quando si verifica un’eccezione;• Object initialization/pre-initialization: all’atto dell’ini-

zializzazione di un oggetto;• Advice execution: all’ese-cuzione di un Advice.

Con queste direttive, si riescono a coprire tutte le casistiche di una normale struttura ad oggetti.Vediamo ora le caratteri-stiche che possono avere i singoli costrutti, per meglio comprendere come e quando applicarli

Applicazione di un Join Point

Come abbiamo spiegato nel paragrafo precedente, un Join Point, può essere applicato sia in fase di esecuzione, sia in fase di ri-chiamo di un certo metodo. La domanda più spontanea che può venire in mente è: perché questa differenza?

In effetti, aggiungere del codice in un solo punto, all’in-terno di un metodo, o aggiungerlo in ogni sua esecuzione, non cambia il risultato che si vuole ottenere. Cambia però a livello di risparmio di codice e cambia soprattutto se non si può modificare direttamente il sorgente della classe che intendiamo controllare.Partiamo da un caso reale: si vuole condizionare l’utilizzo di un certo metodo di una certa classe. Ipotizziamo che, tale metodo, sia all’interno di una classe di cui disponiamo il sorgente.In questo caso, il punto migliore per poter applicare l’aspect è nel momento dell’esecuzione, quindi dentro il metodo stesso. Se però il metodo non ci è stato dato in chiaro, per-ché contenuto in una classe di cui abbiamo solo la libreria (.jar), l’unico modo con cui possiamo applicare l’aspect è al momento del suo utilizzo.Sicuramente questo secondo modo di utilizzare un aspect è più prolisso, ma è l’unico modo col quale possiamo appli-carlo in questo contesto.

LISTATO 1

Classe Demopublic class Demo { public static void main(String[] args){ Demo d = new Demo(); d.go(); }

public Demo(){} public String cVar = “”; public void go(){ metodo1( “PAR1” ); System.out.println( “passo 100 a Metodo2 [“ +metodo2( 100 ) +”]” ); } public void metodo1( String cPar ){ System.out.println( “Metodo1 chiamato con parametro stringa [“ +cPar +”]”); } public String metodo2( int n ){ System.out.println( “Metodo2 chiamato con parametro numerico [“ +n +”]”); return “valore di ritorno*2 (“ +(n*2) +”)”; }}

Esistono delle

esigenze orizzontali

ad un framework, che

dovrebbero far parte di

tutte le classi

Page 57: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 57

focus

Call / Execution

Proviamo quindi a creare un Aspect, partendo dalla classe Demo presente nel Listato 1:

La classe d’esempio dispone di due metodi. Il primo non restituisce alcun risultato, mentre il secondo, restituisce un risultato String. Quello che dobbiamo creare ora è un aspect, come illustrato di seguito:

Aspect

aspect Logging { pointcut primo_metodo(): call( void Demo.metodo1(String)); pointcut primo_metodo2(): execution( String Demo.metodo2(int)); void around(): primo_metodo() { System.out.println(“Prima”); proceed(); System.out.println(“Dopo”); } String around(): primo_metodo2() { System.out.println(„Prima2“); String cRet = proceed(); System.out.println(“Dopo2”); return cRet; }}

Un aspect è sintatticamente molto simile ad una classe, di cui ricorda molto la struttura.Le differenze sono minime, ma importanti.Al posto del token class, per indicare un aspect, occorre scri-vere “aspect”.Dopo la definizione del nome, possiamo passare a definire i pointcut e soprattutto i punti in cui devono agire: se al ri-chiamo, call, del metodo o se alla sua esecuzione, execution.Una volta decisa la modalità, possiamo indicare quale gruppo di metodi, o singolo metodo, deve essere impatta-to. Nel nostro caso si è deciso di indicare i due metodi della classe Demo.Ultimo punto da affrontare, è quello di creare un advice, nel quale inserire il codice da eseguire.Anche l’advice ha una propria sintassi, data dal ritorno del metodo da arricchire, dalla modalità di utilizzo, nel nostro caso around, cioè “attorno” al metodo che stiamo modifi-cando, e da un proprio nome.Una volta definito, possiamo creare tutto il codice Java che desideriamo, ricordandoci di utilizzare il metodo proceed() per attivare il metodo che si stava modificando.Per compilare queste righe con AspectJ è sufficiente chia-mare il compilatore ajc passando, tramite una @, il nome del file contenente l’elenco dei sorgenti da compilare, come in questo esempio: ajc @files.lst. A questo punto, invocando l’esecuzione della classe Demo (java demo), otterremo l’ouput:

Esecuzione

PrimaMetodo1 chiamato con parametro stringa [PAR1]DopoPrima2Metodo2 chiamato con parametro numerico [100]Dopo2passo 100 a Metodo2 [valore di ritorno*2 (200)]

L’effetto è quello di avere, prima e dopo l’esecuzione dei due metodi, la visualizzazione di due messaggi. Chiara-mente, se al posto dei messaggi ci fosse stato il controllo d’accesso, avremmo risolto in modo ottimale la problema-tica, senza impattare la classe Demo.

Staticinitialization

Altro punto interessante, nel quale applicare un aspect, è l’inizializzazione di un oggetto tramite un costrutto static.L’inizializzazione statica viene applicata tutte le volte in cui, in una classe, si ha l’esigenza di creare un qualcosa di comune a più istanze della classe stessa. Un esempio potrebbe essere la lettura di un file di configurazione, o la creazione dati statici.Tale inizializzazione avviene una sola volta sola, in tutto il programma. Potrebbe però essere interessante modificarne il comportamento o semplicemente notificarne l’esecuzio-ne.Anche in questo caso c’è un apposito pointcut da definire. Come si può notare nel prossimo listato, la cosa che cam-bia è la direttiva staticinitialization da passare al pointcut. Per quanto riguarda l’advice, la sintassi è la stessa del caso precedente. La cosa che varia è la presenza di void come valore di ritorno, dato che le inizializzazioni non hanno un valore di ritorno.

Staticinitialization

aspect Logging { pointcut primo_metodo() : staticinitialization( Demo );

L’idea è quella di

creare un aspect, in

grado di intercettare

tutti gli accessi ad un

certo metodo di una

certa classe

Page 58: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 200758

focus

void around() : primo_metodo() { proceed(); }}

Set/Get

Così come possiamo controllare l’accesso ad un metodo, è possibile controllare l’accesso ad una variabile d’istanza, sia in lettura che in scrittura. Per fare questo è possibile utilizzare un pointcut dove indicare quale variabile, di quale classe, andare a controllare. Per quanto riguarda l’advice, rimane tutto invariato, come nel caso del metodo:

Set/Get

aspect Logging { pointcut primo_metodo() : set( String Demo.cVal ); pointcut primo_metodo2() : get( String Demo.cVal ); void around() : primo_metodo() { proceed(); } String around() : primo_metodo2() { String c; c = proceed(); return c; }}

This/Target

Un’altra modalità di attivazione, specificabile all’interno di un pointcut è data dalla classe di attivazione.Ipotizziamo di avere più classi che hanno un metodo co-mune chiamato go. Invece di specificare N pointcut, uno per ogni metodo di ogni classe, possiamo indicarne uno solo, utilizzando la wildcard “*”. Un esempio potrebbe essere “pointcut pc(): execution( * *.go() )”: dato qualsiasi metodo go, di qualsiasi classe, con qualsiasi valore di ritorno, gesti-sci il pointcut pc().Chiaramente, tutto funziona correttamente, nel caso in cui ci siamo poche classi. Quando invece si utilizzano fra-mework molto grandi, potrebbe essere necessario limitare la capacità di questo pointcut. Per questo sono stati intro-dotte le estensioni this( classe ) e target( classe ).Tramite questi due costrutti è possibile limitare un pointcut all’interno di una certa classe (this) o solamente quando viene chiamato in una certa classe (target), come esposto in seguito:

This/Target

aspect Logging { pointcut primo_metodo(): execution( * *.go() ) && this(Demo2); void around(): primo_metodo() { proceed(); }

pointcut primo_metodo2() : execution( * *.go() ) && target(Demo); void around(): primo_metodo2() { proceed(); }}

Args

Altro filtraggio possibile sui pointcut è dato dai parametri passati. È infatti possibile utilizzare delle wildcard e paral-lelamente indicare che, i parametri gestiti dal metodo che si intende controllare, sono di un certo tipo. In seguito è presente un esempio di utilizzo di args() collegato a tutti i metodi che ricevono come argomento un oggetto String.

Args

aspect Logging { pointcut primo_metodo() : execution( void *.*(*) ) && args( String );

void around() : primo_metodo() { System.out.println(“Prima”);

Questa modalità

permette di aggiungere

del codice, ad

applicazioni già scritte,

senza bisogno di

modificarle

Page 59: j2007 02 jj3

JAVA Journal

n.3 - marzo/aprile 2007 59

focus

proceed(); System.out.println(“Dopo”); }}

Advice

Ora che abbiamo ben compreso come creare dei poin-tcut, vediamo quali tipo di esecuzione è possibile far fare ad un advice.Oltre ad around, osservato negli esempi precedenti, è possibile anche indicare before se vogliamo eseguire del codice prima del pointcut, o after, se lo vogliamo esegui-re dopo.Da notare che un advice è di per se molto simile ad un metodo, in quanto, come un metodo:

• Segue delle regole di accesso per essere eseguito• Può generare un’eccezione• Può fare riferimento all’aspect corrente tramite this

Al contrario di un metodo però:

• Non ha un nome• Non può essere chiamato direttamente, è il sistema

che lo esegue• Ha accesso ad alcune variabili valorizzate all’interno

di this che possono servire a prendere informazioni sui join point catturati: thisJoinPoint

Altro aspetto interessante degli advice è quello di poter essere eseguiti dopo il ritorno di un valore da un meto-do, oppure nel momento di un’eccezione nel codice.

Advice su eccezione

Ultimi, ma non meno importanti, sono gli Advice su eccezione. Chiaramente, anche in questo caso, esiste una sintassi ben precisa, che ricalca molto quella vista per i metodi.Si tratta di definire sempre il momento in cui inter-cettare l’eccezione (ex: after), indicare che si vogliono gestire le eccezioni: throwing e definire su quali metodi si intende farlo, nel caso del listato seguente sono stati indicati tutti i metodi: “* *.*()”.

Advice su eccezione

aspect Logging { after() throwing: call(* *.*()) { System.out.println(“ERRORE”); }}

Conclusioni

Questo articolo è un’introduzione alla programmazio-ne AOP. Non sono stati toccati i concetti più complessi

di questo tipo di programmazione, ma solo i concetti base, che permettono di capire come iniziare a pro-grammare. Come si può notare, il concetto base di AOP è molto semplice. Servono poche righe di codice per arricchire in modo concreto, molte classi di nuove funzionalità.Piuttosto, il problema di AOP è la sua giovane età. Il supporto per questo tipo di programmazione non è an-cora molto diffuso, anche se inizia a essere presente in alcuni ambienti di sviluppo.Inoltre, pensare in AOP, richiede un ulteriore passo in avanti, rispetto alla programmazione Object Oriented, passo di cui non si sente ancora l’esigenza diffusa. Come tutte le cose, il tempo ci potrà dare ragione o potrà cancellare completamente questo approccio post-object oriented.

Bibliografia

[1] http://www.eclipse.org/aspectj/, AspectJ[2] http://www.eclipse.org, il progetto Eclipse[3] http://www.eclipse.org/aspectj/downloads.php, la pagina di download di AspectJ[4] http://www.baccan.it/index.php?sezione=webbit2004, dove poter scaricare i sorgenti d’esempio analizza-ti in questo articolo.

Un aspect è una regola

che indica il punto dove

deve essere eseguito

del codice

Note Biografiche

Matteo Baccan è uno specialista di progettazione e svilup-po C++, JAVA e AOP. È ideatore del portale JobCrawler.it e speaker in importanti eventi Java (Javaday, JIP Day). Attual-mente si occupa di analisi presso un importante operatore di telefonia mobile. Può essere contattato tramite il suo sito http://www.baccan.it.

Page 60: j2007 02 jj3
Page 61: j2007 02 jj3

SPEECH Login TopicFREE

nostro codice ci sarà infatti un oggetto che, trami-te un’astrazione, dovrà essere capace di applicare delle logiche che ancora non sono state scritte ed implementate: in un certo senso, sarà a prova di futuro. In un linguaggio fortemente tipato come Java, senza interfacce e polimorfismo sarebbe impossibile scrivere codice estensibile. Ma, con-tinuando nel ragionamento, il polimorfismo im-plica ovviamente un comportamento da rendere polimorfo, e non dei semplici metodi accessors (o getter/setter che dir si voglia). Lungi da me affer-mare che gli accessors siano sempre un errore di design: hanno i loro utilizzi. Quel che è certo è invece che un oggetto che non ha un comporta-mento, un oggetto che non fa nulla, è di solito un segno di programmazione strutturata.

Per cercare nel codice questo problema, seguire i passi:

1. L’Oggetto x della classe X non ha comporta-mento, solo getters/setters.

2. Una logica, un comportamento da qualche par-te ci sarà pure, oppure il software non avrebbe senso

3. Questo comportamento sarà sparso in altre classi, che probabilmente avranno dei nomi si-mili a XHandler, XManager, ecc.

4. Nel caso peggiore, da qualche parte ci sarà qual-cuno che fa un instanceof, ricadendo addirittu-ra nel Polimorfismo dei poveri (vedi Idiomatica del numero 1)

A parte i (pochi) casi in cui un oggetto anemico è giustificato, la soluzione è decisamente semplice. Il comportamento, sparso qui e la, va spostato nel codice delle classi in cui è più appropriato, tipica-

I Falsi oggetti sono molto comuni se non si ap-plicano correttamente i principi di buon design Object Oriented. I falsi oggetti sono spesso asso-ciati con il polimorfismo dei poveri, che ho tratta-to nel primo numero di questa rubrica, e qualche volta ne sono addirittura dei generatori.Ma ripassiamo un momento uno dei cardini della programmazione Object Oriented: un oggetto è fatto di comportamento, o behaviour. Questo com-portamento tipicamente si applicherà su dei dati, che altrettanto tipicamente saranno contenuti nell’oggetto stesso. Da qui il vecchio adagio che un oggetto è composto da dati + comportamen-to, adagio tanto noto quanto poco applicato nella pratica.Se volessimo riassumere in una frase sola cos’è che caratterizza un buon design ad oggetti, po-tremmo dire – magari semplificando un po’ - che un buon design è caratterizzato dal poter aggiun-gere una feature ad un software semplicemente aggiungendo un nuovo oggetto, senza toccare tutto il resto. E possibilmente senza dover ricom-pilare l’esistente. Dovrebbe quindi essere evidente che il polimor-fismo è essenziale per raggiungere questo scopo, addirittura imprescindibile. Da qualche parte nel

IDIOMATICA

n.3 marzo/aprile 2007 61

Falsi Oggetti: oggetti inutili, anemici, tristi. E pericolosi.

In questa rubrica analizzeremo i più comuni errori di codifica, di progettazione ed i tranelli in

cui è facile cadere. Programmatore avvisato, mezzo salvato!

La massima di questo mese:

“A worker may be the hammer’s master, but the hammer still prevails. A tool knows exactly how it is meant to be handled, while the user of the tool can only have an approximate idea”

M.Kundera

>> di Ugo Landini ([email protected])

Page 62: j2007 02 jj3

FREELINUXSPEECH Login TopicFREE IDIOMATICA

mente quelle che hanno i dati di cui il compor-tamento stesso ha bisogno. O, in alternativa, la classe va fatta sparire del tutto. Dunque

5. Se non ci sono validi motivi per non farlo, spostare il comportamento dalle classi Handler/Manager alla classe di dominio

Esercizi:

• Andare a cercare i falsi oggetti nel vostro codi-ce

• Andare a cercare i falsi oggetti in un software open source a piacere

• Elencare i casi in un oggetto anemico è giustifi-cato dal contesto

Conclusioni:

I Falsi oggetti sono molto comuni se non si applicano correttamente i principi di design. Stranamente, sono anche molto comuni fra chi pensa di applicare dei principi di design: tipica-mente, succede quando si da troppa importanza agli strati di Service, magari fuorviati da qualche acronimo di moda di tre lettere

n.3 - marzo/aprile 2007 62

Page 63: j2007 02 jj3
Page 64: j2007 02 jj3