j2006 01 jj1

68

Upload: turing-club

Post on 07-Jun-2015

403 views

Category:

Documents


2 download

TRANSCRIPT

JAVA JOURNAL 1

IN VETRINA JAVA JOURNAL 1

Extending and Embedding PHP

di S. Golemon

Sams456 pp, euro 45.50ISBN 067232704X

Internet Phone Services Simplified (VoIP)di J. Doherty e N.

Anderson

Cisco Press176 pp, euro 21.20ISBN 1587201623

Linux® Patch Manage-ment: Keeping Linux®

Systems Up To Datedi M. Jang

Prentice Hall288 pp, euro 39.95ISBN 0132366754

An Introduction to XML and Web Technologies

di A.Moller e M. Schwartzbach

Addison Wesley568 pp, euro 60.70ISBN 0321269667

Linux - La Guida (con DVD)

di J. Davies et al.

Mc Graw hill860 pp, euro 51.00ISBN 8838644543

Linux for Programmers and Users

di G. Glass e K. Ables

Prentice Hall656 pp, euro 59.80ISBN 0131857487

Scrivi [email protected]

specificandonell’oggettodella e-mail:

IN VETRINAJava Journal n. 1

OPPUREinviaci il coupon

sottostanteal numero di fax0587/732232Potrai acquistare

i libri qui riportati con uno SCONTO

ECCEZIONALE

del 10% anche seacquisti solo un libro

OPPUREdel 20% se acquisti

3 libri

copertina

non

disponibile

EDITORIALEwww.infomedia.it

n.1 - novembre/dicembre 2006 7

JAVA Journal

BIMESTRALE - ANNO 1 - N.1

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, TO N Y MO B I L Y

C O L L A B O R A T O R I

MA T T E O CA M P A N E L L AUG O LA N D I N I

AN D R E A NA S A T OST E F A N O SA N N A

FA B I O ST A R OAN D R E A Z I T O

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 A

(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 -D E N T E D A SU N M I C R O S Y S T E M S , I N C .

Java Journalnumero 1Mentre scrivo queste righe ho in mano il numero della rivista Computer Programming del 1996 con lo speciale su Java, in cui scrissi due articoli cercando di spiegare cosa era Java e come si facevano le applet. Era una delle mie primissime esperienze di autore tecnico, quindi rivivo la cosa con emozione e nostalgia.Java era allora alla versione 1.0; ciò nonostante la sua inclusione nel nuovissimo Netscape 2.0,(qualcuno si ricorda che era il web browser leader di mercato?), ave-va fatto scalpore, creato fermento ed eccitazione, e scatenato un effetto domino di dichiarazioni di supporto della tecnologia. Si erano dichiarati “amici di Java” nomi come IBM, Oracle e perfino Microsoft.Sono passati più di dieci anni (non mi sembra vero, ma è così), e tanto è cambiato. Per esempio, di applet, la tecnologia allora rivoluzionaria, quasi non si parla più (le applet sono rimaste una applicazione di Java tutto sommato di nicchia). Java comunque ha superato i confini del Browser, si è installato stabilmente nei Server, ed è diventato uno dei linguaggi di programmazione più usati al mondo. Pur non essendo (ancora) un linguaggio strettamente Open Source (nel senso di licenza OSI-compatibile), di fatto il suo modello di sviluppo si è sempre avvicinato molto a quello dell’Open Source. Una enorme quantità di ambienti e strumenti di sviluppo per Java sono Open Source. Recentemente Java è diventato il linguaggio più usato nei progetti del repository di SourceForge, il più grande sito che fornisce risorse per lo sviluppo open. Sul lavoro, vengo consultato come esperto di “Java in ambiente Open Source”. Quindi, anche se qualche purista potrà storcere il naso, Java viene associato comunemente all’Open Source.Ricordo che Java ha in gran parte sostituito il Pascal nelle università come linguaggio didattico; questo per due motivi: il primo è che è pulito e chiaro come il Pascal, ma rispetto a quest’ultimo è anche Object Oriented; il secondo è che si tratta di un lin-guaggio effettivamente molto usato in pratica. La maggior parte dei programmatori quindi, anche se lavora con altri linguaggi, generalmente ha qualche interesse verso Java, se non altro per completezza professionale. Nel frattempo, l’altro grande figlio di Internet, Linux, il sistema operativo vessillo dell’Open Source (e del Free Software, per chi è interessato alla differenza) ha an-ch’esso guadagnato molto terreno. Notare che è anche diventato un fenomeno edi-toriale qualche anno fa. In Italia sono comparse numerose riviste dedicate a Linux. Mi aspettavo quindi da un momento all’altro una rivista dedicata a Java. Infatti la quantità di programmatori Java, o aspiranti tali, è di tutto rispetto. Infatti, nonostante l’uso di Internet per trovare informazioni, la rispettabilità, la pia-cevolezza e la qualità di una buona rivista non sono mai venute meno rispetto alla ricerca sul Web. La storia insegna che un nuovo media non sostituisce mai un altro, semmai lo affianca. Purtroppo, per anni, in Italia non ho trovato niente. Abbiamo una quantità impres-sionante di riviste dedicate ai telefonini, ma nessuna rivista dedicata a Java. Eppure in altri paesi di riviste Java ce ne sono parecchie; conosco moltissimi programmatori Java regolarmente abbonati alle riviste estere.Così, quando in una chat session con Tony Mobily, mi lamentavo di questa mancan-za, sono rimasto gelato dalla proposta: “perché non la fai tu”? A breve, mi ha messo in contatto con Marialetizia Mari, direttore responsabile delle riviste del Gruppo Editoriale Infomedia, che mi ha confermato l’interesse.Siccome non è corretto lamentarsi di una mancanza per poi tirarsi indietro quando è il momento di rimediare, mi sono messo al lavoro. Dopo un rapido giro di email... ho quasi riempito il primo numero! Ho trovato tanto entusiasmo e disponibilità. Non ci credevo! I commenti praticamente unanimi sono stati: “bella idea”, “ci vuole”, “collaboro anche io”. Prima di completare il lavoro sono passati mesi, ma eccoci qui: la prima rivista in italiano dedicata a Java è appena nata. Spero vi piaccia e sia utile per lavoro o per studio. Confidiamo nel vostro sostegno concreto, diventando abbonati, ma anche proponendo commenti, critiche e facendola conoscere ad amici e colleghi che, come voi, cercavano una rivista italiana su Java. Fateci sapere cosa ne pensate scrivendo a [email protected].

Michele SciabarràDirettore Esecutivo

Java Journal

Speciale JSFPrimi passi con JavaServer Facesdi Michele Sciabarrà 10Le novità di JSF 1.2di Andrea Nasato 17Un Wizard per il Web con JSF e Shaledi Fabio Staro 23

Focus JavaCarddi Matteo Campanella 30Gcj: Gnu Compiler for Javadi Andrea Zito 36Java ME sviluppare applicazioni per cellulari e PDAdi Stefano Sanna 42

EducationalJava 5, le buone nuove e le novità meno buonedi Ugo Landini 49Fondamenti di Programmazione JavaPrima parte: uno sguardo d’insiemedi Michele Sciabarrà 55

RubricheIdiomaticaCodice orribile, antipattern e pratiche discutibilidi Ugo Landini 62

CommunityIntervista a Daniela Ruggeri, presidente della Java Italian Associationdi Michele Sciabarrà 64

SOMMARIO Novembre/Dicembre 2006

numero 1 JAVA Journal

n.1 - novembre/dicembre 2006

JAVA Journal

10 n.1 - novembre/dicembre 2006

speciale JavaServer Faces

Primi passi con JavaServer Faces

Le JavaServer Faces sono state proget-tate per ridurre il codice da scrivere quando una applicazione Web ha nu-merose form; quasi sempre si tratta di una interfaccia a dati memorizzati su un database relazionale. In una appli-cazione Web in Java “tradizionale”,

ci sono delle JavaServer Pages o delle servlet che producono esplicitamente tutto l’html necessario per visualizzare le form. Per gestire le form il pro-grammatore Web finora doveva fare da solo. Una applicazione Web infatti richiede una serie di auto-matismi che con le sole JSP non possiede: è neces-sario riempire le form con dei dati, mantenere uno stato, raccogliere e decodificare i dati, spesso codi-ficarli o decodificarli, e infine salvarli in un data-base. Per quanto riguarda la gestione del database, questo è compito di librerie ORM (Object Relatio-nal Mapping), e non verrà considerato nel presen-te articolo. Le JavaServer Faces hanno l’obiettivo principale di aumentare l’automatismo per riempire le form con i dati, recuperarli quando l’utente li inserisce, e in generale gestire l’interazione con l’utente. Vedremo come fare costruendo un esempio pratico passo pas-so. Si tratterà di un esempio molto semplice, ridotto all’osso, che visualizza un elenco dati e permette di modificarlo. La memorizzazione dei dati verrà gesti-ta con uno “stub”, una classe minimale (da esten-dere eventualmente) perché altrimenti andremmo fuori dallo scopo dell’esempio.

Personaggi e Interpreti

Prima di entrare nei dettagli, elenchiamo i compo-nenti che compongono una applicazione realizzata con JavaServer Faces. In particolare tratteremo del-le JSF versione 1.1.Innanzitutto avremo alcune pagine JSF. Le pagine

JSF sono in realtà delle pagine JSP che contengo-no dei tag provenienti dalla libreria Faces. Tutta-via, una pagina in JSF deve essere chiamata con l’estensione.faces (non .jsp) o con il prefisso /faces/; su disco però vengono memorizzate con la clas-sica estensione .jsp. Dove è l’inghippo? Semplice: quando installiamo le JSF, dobbiamo configurare nell’applicazione Web una “servlet”, la faces servlet che interpreta le pagine JSF. Questa servlet prepara l’ambiente perché una JSF possa essere eseguita. In effetti è un sistema un po’ strano, non ovvio; pur-troppo questo “trucco” è necessario perché si possa mantenere la compatibilità con molti application server esistenti. Oltre alle pagine JSF avremo delle classi, che sono necessarie per usare le JSF. A differenza delle JSP infatti, le JSF prevedono che molte operazioni delle JSF, vengano svolte in delle classi apposite, dette “Backing Bean”.

Da questi Backing Bean le pagine JSF leggono i dati, li scrivono dopo averli utilizzati, e causano l’esecu-zione di azioni a seguito di “eventi”, che avvengono quando l’utente fa delle operazioni sulle maschere

Le JavaServer Faces sono da molti considerate il tassello mancante per rendere lo sviluppo di appli-cazioni Web più semplice. Nella realtà è uno strumento molto potente per realizzare un certo tipo di applicazioni, ovvero quelle dotate di numerose form per il data-entry. Come tutti gli strumenti di questo genere, sono abbastanza complesse e richiedono un po’ di tempo e impegno per essere pa-droneggiate. Prima di entrare nei dettagli della tecnologia con il prossimo articolo, e descrivere il suo prossimo futuro, mostriamo prima di tutto con un esempio pratico come funzionano.

>> di Michele Sciabarrà ([email protected])

Le pagine JSF sono

pagine JSP che conten-

gono tag provenienti

dalla libreria Faces

JAVA Journal

n.1 - novembre/dicembre 2006 11

JavaServer Faces speciale

prodotte. Per collegare Backing Bean a pagine JSF, si utilizza un file di configurazione, chiamato solitamente faces-config.xml. Questo file innanzitutto contiene la definizione di tutti i backing bean. Un altro elemento importante delle JSF è che la navigazione (il passaggio da una pagina all’altra) viene definita “in astratto”. Ogni volta che serve una navigazione, un backing bean o una jsf non dice espli-citamente dove vogliono andare, codificando l’url della destinazione: invece viene data una risposta generica, codificata con una stringa. La navigazione effettiva viene dichiarata nel faces-config.xml

Installazione di JSF

Prima di andare avanti, vediamo come installare la versione RI 1.1 delle JSF (la Reference Implementation fornita da Sun) nella vostra applicazione Web. Notare che ne esistono altre come le MyFaces, ma la RI sembra al momento essere la più usata. Si presume in questo ar-ticolo che abbiate familiarità con le configurazioni delle WebApp, e in particolare sappiate cosa è e a cosa serve la directory WEB-INF/lib e il file web.xml. Questo esempio fa riferimento all’installazione delle JSF versione 1.1 nel-l’application server Tomcat, in particolare alla sua versio-ne 5.5. Se usate un diverso application server può essere

necessario variare le operazioni opportunamente. Per installare JSF occorre scaricare il pacchetto versione 1.1 da java.sun.com/j2ee/javaserverfaces. In prima approssi-mazione basta copiare due jar nella directory WEB-INF/lib, ovvero la jsf-api.jar e jsf-impl.jar. Come è costume, il primo jar rappresenta la API come definita dalla specifica, mentre il secondo ne è l’implementazione. Questi due JAR però non sono sufficienti in quanto l’implementazione di Sun usa una serie di librerie esterne, peraltro abbastanza note e usate: sono alcuni dei “commons” del progetto Apache. Infine servono anche le le librerie della Java Standard Template Library. Ecco l’elenco di quelle necessarie:

commons-logging.jarcommons-digester.jarcommons-beanutils.jarcommons-collections.jarjstl.jarstandard.jar

Copiato tutto nella WEB-INF/lib occorre configurare, ag-giungendo nel web.xml quanto mostrato nel Listato 1.

La configurazione installa una servlet, la Faces Servlet, che viene richiamata per interpretare le JSP che conten-gono tag di tipo Faces. Ancora una volta ricordo il trucco: se avete un file che si chiama pagina.jsp (e dovete avere una pagina di questo tipo), la dovete richiamare con il nome pagina.faces. Se la chiamate con l’estensione jsp, otterrete un errore, perché non vengono eseguite le ini-zializzazioni necessarie per le JSF.

L’applicazione Agenda

Come esempio scriviamo una applicazione dimostrati-va, una semplice agenda che permette di visualizzare un elenco di nomi, aggiungerli o toglierli, ed editare un dettaglio. Pur nella sua assoluta semplicità questa mini-applicazione è il prototipo di qualunque applicazione significativa per cui si usano le JSF. Il suo studio fornisce un buon trampolino di lancio per avventurarsi in appli-cazioni più complesse. In Figura 1 ho schematizzato con

L’esempio mostrato

è il prototipo di ogni

applicazione basata su

JSFLISTATO 1 Le configurazioni nel web.xml delle JSF

<context-param> <param-name>javax.faces.CONFIG_FILES </param-name> <param-value>/WEB-INF/faces-config.xml </param-value></context-param><servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class> javax.faces.webapp.FacesServlet </servlet-class> <load-on-startup>0</load-on-startup></servlet><servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern></servlet-mapping>

FIGURA 1 I componenti della Agenda

JAVA Journal

n.1 - novembre/dicembre 200612

speciale JavaServer Faces

un diagramma, i principali componenti di questa applica-zione, e la sua navigazione. Il diagramma non usa nessuna notazione particolare: semplicemente ho indicato con l’icona dei documenti, le pagine jsf, mentre con un rombo il backing bean. I dati vengono letti e scritti in un “database”, che in realtà un database vero non è, ma solo una collezione di bean in memoria. Il meccanismo comunque si estende in manie-ra naturale verso la memorizzazione in un vero database, utilizzando un qualsiasi sistema ORM (per esempio Hi-bernate). In figura abbiamo anche evidenziato lo schema di navigazione, che è elementare: dalla lista si passa alla form e viceversa.Come abbiamo detto, i componenti di una applicazio-ne JSF vengono esplicitamente configurati nel faces-config.xml. Di solito il file di configurazione si scrive alla fine; siccome sappiamo già quali file avremo nella nostra applicazione, lo scriviamo per primo e ci togliamo d’im-piccio. Nel file di configurazione ci sono numerose pos-sibilità, ma ai fini del nostro esempio ci interessano solo due cose: definire i backing bean, e configurare la navi-gazione. La configurazione è mostrata nel Listato 2. Il Backing Bean è uno solo, di classe agenda.AgendaBacking, che verrà richiamato con il nome agenda. La navigazio-ne invece va dal file /agenda/AgendaList.jsp al file /agenda/

LISTATO 2 La configurazione del faces-config.xml

<managed-bean> <managed-bean-name>agenda </managed-bean-name> <managed-bean-class>agenda.Agenda

Backing</managed-bean-class> <managed-bean-scope>session </managed-bean-scope> </managed-bean>

<navigation-rule> <from-view-id>/agenda/AgendaList.jsp </from-view-id> <navigation-case> <from-outcome>form</from-outcome> <to-view-id>/agenda/AgendaForm.jsp </to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/agenda/AgendaForm.jsp </from-view-id> <navigation-case> <from-outcome>list</from-outcome> <to-view-id>/agenda/AgendaList.jsp </to-view-id> </navigation-case> </navigation-rule>

AgendaForm.jsp in risposta a una richiesta “form”, e vice-versa in risposta a una richiesta “list”.

Il database

Stiamo costruendo una applicazione che gestisce nei fatti una tabella di dati. Per semplicità, non ci preoccuperemo di leggere e scrivere effettivamente i dati sul database, ma ci limiteremo a mantenerli in memoria, utilizzando consuete strutture dati come liste e mappe. Comunque, sarà possibile salvare i dati effettivamente su database semplicemente implementando i metodi appositi di let-tura e scrittura, che nel nostro caso si limitano a tenere tutto in memoria.Per mantenere un record, utilizziamo un javabean, ovvero una classe Java i cui campi sono accessibili con getter e setter; si tratta di Pojo (Plain Old Java Object) nell’acce-zione corrente. Questo oggetto ha i campi nome, email e telefono, con relativi getter e setter. Per predisporre il file nella scrittura sul database, abbiamo anche un campo id di tipo Long, campo che viene generato automaticamen-te (usando il noto metodo del timestamp per creare un identificatore univoco).Un database di bean viene mantenuto in memoria e ge-stito tramite metodi statici della classe agenda. Sarebbe stato forse opportuno separare i metodi statici dalla clas-se Agenda, ma per semplicità ho messo tutto nella stessa classe. Per creare un nuovo bean useremo Agenda a = new

FIGURA 2 Visualizzazione della lista dei record

I componenti di una

applicazione JSF

vengono configurati nel

file faces-config.xml

JAVA Journal

n.1 - novembre/dicembre 2006 13

JavaServer Faces speciale

Agenda(“nome”, “email”, “telefono”). Per salvarlo useremo Agenda.store(a), mentre per recuperarlo (assumendo di avere già l’id) basterà un Agenda.load(id). Infine, per eli-minarlo possiamo utilizzare Agenda.delete(a). Il codice del “database” segue in Listato 3.

La lista e la form

La nostra applicazione è composta essenzialmente di

due maschere: una maschera principale che elenca tutti i record, e una seconda maschera di dettaglio, che per-mette di modificare il singolo record. Entrambe fanno riferimento a un unico backing bean, agenda. Iniziamo a vedere il codice della lista, in Listato 4:Nel Listato 4 possiamo vedere come si fa a ottenere un elenco di record del database, come è visualizzato nella Figura 2. Si può notare che JSF usa dei tag, con prefisso f: oppure h:, descritti in dettaglio nell’articolo successivo.

LISTATO 3 Il “database” dell’agenda

package agenda;

// import omissis

public class Agenda { // trucco per generare facilmente // id univoci static long counter= System.currentTimeMillis();

// campi con getter e setter Long id = new Long(counter++); public Long getId() { return id; } public void setId(Long id) { this.id

= id; } String nome; public String getNome() { return nome; } public void setNome(String nome)

{this.nome = nome;} String email; public String getEmail() { return email; } public void setEmail(String email)

{this.email = email; } String phone; public String getPhone() { return phone;}public void setPhone(String phone)

{this.phone= phone; } // costruttori public Agenda() { this(“”,””,””); } public Agenda(String nome, String

email,String phone) { super(); this.email = email; this.nome = nome; this.phone = phone; }

// gestione del “database” // in memoria private static List<Agenda> list =

new LinkedList<Agenda>(); private static Map<Long, Agenda>

map = new HashMap<Long, Agenda>(); // ritorna una lista dei bean public static List<Agenda>

getList(){ return list; } // memorizza il bean public static void store(Agenda bean) { if(map.get(bean.getId())==null) list.add(bean); map.put(bean.getId(), bean); } // recupera il bean public static Agenda load(Long id) { return map.get(id); } // elimina il bean public static void remove(Agenda bean) { map.remove(bean.getId()); list.remove(bean); } // inizializzazione (una tantum) // del database static { store(new Agenda(“Michele”,

“msciab@ep”,“347”)); store(new Agenda(“Mirella”,

“mirella@ep”, “328”)); store(new Agenda(“Laura”,

“laura@ep”,“736”)); store(new Agenda(“Massimo”,

“max@ep”,“922”)); } }

JAVA Journal

n.1 - novembre/dicembre 200614

speciale JavaServer Faces

LISTATO 4 La lista dei record dell’agenda

<%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%><%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%><f:view> <h:form> <h:dataTable var=”data” border=”1” binding=”#{agenda.table}” value=”#{agenda.list}”> <h:column> <f:facet name=”header”> <h:outputText value=”Azione” /> </f:facet> <h:commandButton actionListener=”#{agenda.edit}” value=”Modifica” action=”form”/> </h:column> <h:column> <f:facet name=”header”> <h:outputText value=”Nome” /> </f:facet> <h:outputText value=”#{data.nome}” /> </h:column> <h:column> <f:facet name=”header”> <h:outputText value=”Email” /> </f:facet> <h:outputText value=”#{data.email}” /> </h:column> <h:column> <f:facet name=”header”> <h:outputText value=”Telefono” /> </f:facet> <h:outputText value=”#{data.phone}” /> </h:column> <h:column> <f:facet name=”header”> <h:outputText value=”Azione” /> </f:facet> <h:commandButton actionListener=”#{agenda.delete}” value=”Elimina” action=”list”/> </h:column> </h:dataTable> <h:commandButton actionListener=”#{agenda.create}” value=”Nuovo” action=”form”/> </h:form></f:view>

Questi tag definiscono l’interfaccia utente in maniera astratta. Questa è infatti una delle principali difficoltà nell’imparare le JSF: i tag delle JSF sono completamen-te diversi da quelli dell’HTML. Infatti una pagina JSF genera un output HTML utilizzando un render kit, ma è possibile sostituirlo con un render kit di tipo diverso per produrre output come WML (per il Wap) o XUL (per applicazioni GUI basate su Firefox) o usare tecniche Ajax

(si veda l’articolo sulle novità delle JSF 1.2 al riguardo).

Notiamo innanzitutto la h:datatable. Questo tag itera i contenuti di una lista. I valori da rappresentare ven-gono forniti dal backing bean, che ne fornisce la lista. Il backing bean viene richiamato con l’espressione #{agenda.list}. Il file di configurazione faces-config lo definisce, e questo bean viene creato e viene posto in sessione. A questo punto l’output da visualizzare viene generato dal metodo getList() del backing bean. Notare che, come spesso succede, una “proprietà” del backing bean viene chiamata senza usare il prefisso get, ma nel codice occorre scrivere il metodo getList. Viene prodotta così una lista di bean, che sono di classe Agenda. Ogni bean viene posto nella variabile data e vi-sualizzato. Un’altra caratteristica della datatable è che il contenuto viene prodotto per colonna, mentre ricordiamo che in html una tabella viene definita per riga. Non c’è quindi una corrispon-denza diretta tra una datatable JSF e una table HTML.In ogni colonna viene visualizzata la riga corrente usando le outputText che usano #{data.nome},#{data.email},#{data.phone} per accedere alle proprietà del bean (che si aspetta di tipo Agenda).Una altra osservazione è il “binding” della datatable: le JSF costruiscono per ogni tag JSF un oggetto; nel caso della datatable viene creato un og-getto UIData; utilizzando il binding, questo oggetto viene memorizzato direttamente nel backing bean: in questo modo si possono ispezionare e ottenere informazioni come per esempio la riga corrente. Questo uso è comunque abbastanza avanzato, ma una volta compreso può essere molto potente. Vedremo come viene sfrutta-to esaminando il dettaglio del backing bean nel prossimo paragrafo.Infine, i comandi. Notiamo che quan-do si clicca un bottone viene invocato un metodo del bean specificato con ac-

tionListener. Abbiamo #{agenda.create} per creare un nuo-vo bean, #{agenda.delete} per cancellarlo e #{agenda.edit} per la modifica. Attenzione che in questo caso si tratta proprio dei metodi edit, create e delete, non di una proprietà (quindi un metodo con il prefisso get). Tuttavia i meto-di specificati come actionListener hanno anche essi degli obblighi: devono essere di tipo void e prendere un para-metro di tipo ActionEvent. È assolutamente essenziale ren-

JAVA Journal

n.1 - novembre/dicembre 2006 15

JavaServer Faces speciale

dersi conto che le JSF hanno un ciclo di vita sottostante, e che quindi le varie proprietà ed eventi vengono usate in momenti diversi. Le proprietà vengono lette prima della visualizzazione della pagina. Le azioni vengono gestite dopo che l’utente ha premuto un bottone.Proseguiamo l’analisi dell’esempio vedendo il dettaglio della form mostrata nel Listato 5, e il cui snapshot può essere osservato in Figura 3.Anche in questo caso vengono usati tag astratti: la form

usa il panelGrid che permette di disporre i componenti contenuti in una tabella, senza doversi preoccupare della suddivisione in righe e colonne. Se dichiaro un panelgrid con tre colonne, viene creata una tabella con tre colonne; la prima riga conterrà i primi tre elementi, la seconda riga conterrà il quarto, il quinto e il sesto, e così via. Semplice e pratico.Il nostro backing bean è multifunzionale: non solo fornisce

FIGURA 3

LISTATO 5 Il dettaglio dell’agenda

<%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%><%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%><f:view> <h:form> <h:panelGrid columns=”3”> <h:outputLabel value=”Nome:” for=”nome” /> <h:inputText id=”nome” value=”#{agenda.nome}” /> <h:message for=”nome” />

<h:outputLabel value=”Email:” for=”email” /> <h:inputText id=”email” value=”#{agenda.email}” /> <h:message for=”email” />

<h:outputLabel value=”Phone:” for=”phone” /> <h:inputText id=”phone” value=”#{agenda.phone}” /> <h:message for=”phone” />

</h:panelGrid> <h:commandButton value=”Salva” actionListener=”#{agenda.save}” action=”list”/> </h:form></f:view>

la lista degli elementi, ma una volta selezionato un ele-mento permette di accedere alle singole proprietà. Esami-nando il dettaglio del backing bean vedremo che abbiamo creato dei metodi “proxy”: in pratica ogni volta che si chia-ma il getNome del backing bean (di classe AgendaBacking), questo chiamerà il getNome della classe Agenda. In questa pagina abbiamo non solo outputText ma anche e soprattut-to inputText, che permettono non solo di leggere ma anche di scrivere. Quindi questa pagina visualizza innanzitutto il record selezionato, chiamando i metodi getNome, eccetera. Quando l’utente ha compilato il modulo e clicca su un bot-tone, il valore immesso viene riportato nel backing bean chiamando i metodi setNome, setEmail setPhone.

Il backing bean

È venuto il momento di chiudere il cerchio, ri-portando il codice del backing bean mostrato nel Listato 6. Potrebbe sembrare strano che il codice sia così semplice, però è proprio così. Tutti i meto-di sono di una sola riga, e molti metodi possono essere scritti in maniera automatica sfruttando gli automatismi forniti dagli IDE: per esempio per scrivere i getter/setter o i proxy.Per capire come funziona il tutto, vediamo cosa succede nei dettagli, avendo il codice sott’occhio e tenendo presente quanto abbiamo visto nei para-grafi precedenti.Innanzitutto l’utente chiama la pagina AgendaList.jsp che abbiamo visto nel Listato 3. Per visualizzare l’elenco dei metodi la JSF chiama AgendaBacking.getList(). Il backing bean produce la lista dei bean prendendoli dal database, con il me-todo statico Agenda.getList(). I vari bean vengono posti nella variabile data e i dati correnti vengono visualizzati. I vari #{data.name} chiamano il me-todo getName della classe Agenda. La datatable ac-cede direttamente ai bean che contengono i dati.A questo punto un utente decide di modificare un bean, e preme il bottone Modifica. La form vie-

Il ciclo di vita delle

JSF si basa su proprietà

e eventi

JAVA Journal

n.1 - novembre/dicembre 200616

speciale JavaServer Faces

LISTATO 6 Il dettaglio dell’agenda

package agenda;

// import omissis

public class AgendaBacking {

// gestione lista public List getList() { return Agenda.getList(); } private UIData table; public UIData getTable() { return table; } public void setTable(UIData table) { this.table = table; } public void edit(ActionEvent ae) { bean = (Agenda)table.getRowData(); } public void create(ActionEvent ae) { bean = new Agenda(); } public void delete(ActionEvent ae) { Agenda.remove((Agenda)table.getRowData()); }

// gestione form Agenda bean; public AgendaBacking() { bean = new Agenda(); } public String getEmail() { return bean.getEmail(); } public Long getId() { return bean.getId(); } public String getNome() { return bean.getNome(); } public void setEmail(String email) { bean.setEmail(email); } public void setId(Long id) { bean.setId(id); } public void setNome(String nome) { bean.setNome(nome); } public void setPhone(String phone) { bean.setPhone(phone); } public String getPhone() { return bean.getPhone(); } public void save(ActionEvent ae) { Agenda.store(bean); } }

Note Biografiche

Michele Sciabarrà si occupa di Java fin da quando, nel 93, sca-ricò il sorgente di HotJava e per compilarlo saturò il disco del-la Workstation Sun che amministrava. Da allora ha lavorato in Java passando dalle applet per Netscape 2 fino alle applicazioni bancarie di classe enterprise. Dopo aver scritto di Java e averlo insegnato per dieci anni, è direttore esecutivo di Java Journal. Quando non cerca di imparare le ultime API o disquisisce della superiorità del modello Open Source, si diletta a programmare cellulari Symbian in C++ e amministrare sistemi Linux.

ne inviata al server, e viene chiamato il metodo edit del backing bean. A questo punto si sfrutta il binding: la da-tatable sa quale è la riga corrente e la fornisce a richiesta con il metodo table.getRowData(). Quindi il bean corrente viene impostato come campo del backing bean. Notare che mentre il backing bean è uno solo, il bean dei dati può variare. Il trucco è usare dei metodi “proxy”: notare come sono scritti i getNome, getEmail, getPhone: in questo modo si varia il bean corrente e si lascia sempre lo stesso backing bean.

Dopo aver premuto il bottone di mo-difica, viene eseguito il metodo invo-cato dall’actionListener, che imposta il bean corrente a quello selezionato, e poi si naviga alla form. Notare che nel command button è specificato “form” mentre nel faces-config.xml è specificato che da AgendaList.jsp si deve andare, su questa stringa di risposta, ad AgendaForm.jsp.Siamo quindi arrivati alla form; notare però che prima di arrivarci, si è cambiato il bean corrente: in questo modo la form può leggere e poi scrivere direttamente nel bean dati, passando per il backing bean che fa da intermediario. Quando l’utente ha modificato i dati e preme salva, si esegue lo stesso meccanismo: prima viene salvato il bean nel database, poi si ritorna alla lista dei bean.Il percorso della creazione di un nuovo bean è analogo, solo che il metodo create non seleziona il bean corrente ma ne crea uno nuovo. Infine la delete elimina direttamente il bean corrente senza andare alla form.

Conclusioni

Con questo esempio, serrato ma suf-ficientemente dettagliato, abbiamo esplorato abbastanza a fondo come funzionano le JSF: apprendendo bene i concetti qui esposti è possibile cominciare a lavorare proficuamen-te. Le JSF comunque sono molto potenti e ricche di funzionalità: i tag sono ben più numerosi di quelli qui esposti, e la logica sottostante (so-prattutto i misteri del “ciclo di vita”) possono richiedere un po’ di tempo per essere approfonditi. I vantaggi nell’uso della tecnologia comunque compensano di gran lunga il tempo investito nell’apprendimento.

JAVA Journal

17n.1 - novembre/dicembre 2006

JavaServer Faces speciale

Le novità di JSF 1.2La tecnologia JSF (Java Server Faces) continua il suo processo di maturazione. Dopo la versio-ne 1.1 che mirava a dare stabilità alle specifiche, la nuova versione di JSF diventa una tecnologia centrale della piattaforma JEE5. Ad agosto del 2005 infatti sono state pubblicate le specifiche per la versione 1.2, attualmente ancora in stato di “Proposed Final Draft”. In questo articolo vedremo quali sono le novità e a quali problemi è stato posto rimedio.

>> di Andrea Nasato ([email protected])

La nuova versione delle specifiche di JSF si pone essenzialmente due obiettivi. Il primo è quello di inse-rire in maniera più marcata il fra-mework all’interno dell’architettu-ra JEE. Infatti anche altre tecnolo-gie, già presenti in JEE, hanno su-

bito dei cambiamenti e la loro relazione con JSF si è fatta più stretta. Inoltre dalla versione JEE5 troveremo JSF come componente fondamenta-le: ogni vendor che vuole ottenere la certificazio-ne Sun dovrà fornire una implementazione della specifica.Il secondo obiettivo è di porre rimedio ai problemi riscontrati dagli sviluppatori che hanno utilizzato la tecnologia. Si va dalla semplice correzione di bug, all’adeguamento delle specifiche a tecnologie ormai consolidate in internet come AJAX. Nell’articolo ci concentreremo su entrambi questi aspetti tentando di capire quali sono state le motivazioni che hanno guidato l’expert group.

Unified Expression Language

La prima importante novità è l’introduzione dell’Uni-fied Expression Language (EL). In realtà questa non è una vera e propria novità di JSF; il fatto nuovo è che l’EL usato in JSF diverrà comune anche a JSP (Java Server Pages) e a JSTL (Java Standard Tag Library). Ciò ha comportato una revisione delle specifiche an-che per queste due tecnologie. L’expression language che caratterizza JSF, a partire dalla versione 2.1 di JSP, viene “spostato” da JSF a JSP. Ciò comporta che tutto il package javax.faces.el.* di JSF viene deprecato e tutte le sue classi e metodi vengono replicati nel package javax.el.* che sarà con-tenuto in JSP. Anche JSTL si adeguerà al nuovo EL

e quindi anche le specifiche JSTL avanzano di una versione: dalla 1.1 alla 1.2.JSP, a partire dalla versione 2.0, era già dotato di un expression language, derivato da quello presente nel-le JSTL 1.0. L’EL di JSP ha però due importanti limi-tazioni: la valutazione dell’espressione è immediata ed è in sola lettura. La valutazione immediata è quella che avviene nel momento in cui il motore JSP compie il render del-la pagina. L’analisi avviene scandendo il sorgente partendo dall’alto verso il basso. Quando viene in-contrato un token dell’EL, questo viene immediata-mente valutato e ne viene fatto il bind con l’oggetto referenziato. Questo tipo di espressione (della forma ${expr}) può essere usata da sola all’interno della pagina, oppure come valore di un tag JSP che accetta espressioni valutate a run time.

Deferred EvaluationSi pone il seguente problema: in JSP una volta che il bind a una variabile è stato fatto, non è più possibile modificarlo, ovvero l’EL di JSP non ha il concetto di fase che invece è proprio di JSF. Inoltre i token dell’EL JSP sono read-only. Dato ad esempio un bean, di que-sto si può solo fare il get delle proprietà e non il set.L’EL di JSF invece non presenta questi problemi: permette infatti quello che si chiama deferred evaluation.

Novità importante è

l’introduzione di

Unified Expression

Language (EL)

JAVA Journal

n.1 - novembre/dicembre 200618

speciale JavaServer Faces

LISTATO 1 Un esempio di deferred evaluation syntax

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”><%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%><%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%><f:view> <!-- carico il bundle dei messaggi --> <f:loadBundle basename=”it.jugpadova.loginJsf.LocalizedResources” var=”bundle” /> <html> <head> <title><h:outputText value=”#{bundle.welcome}” /></title> </head> <body> <h:form id=”loginForm”> <table cellspacing=”0” cellpadding=”0”> <tr> <td><h:graphicImage value=”/images/LogoJugPadova.png” alt=”Benvenuto” title=”Benvenuto” /></td> <td> <table cellpadding=”5” cellspacing=”3”> <tr> <td colspan=”3”><h:outputText value=”#{bundle.welcome}” styleClass=”login-heading” /></td> </tr> <tr> <td><h:outputLabel for=”userNameInput”> <h:outputText value=”#{bundle.insertUserName}” /> </h:outputLabel></td> <td><h:inputText id=”userNameInput” size=”20” maxlength=”30” value=”#{user.login}” required=”true”> <f:validateLength minimum=”5” maximum=”30” /> </h:inputText></td> <td><h:message for=”userNameInput” styleClass=”errors” /></td> </tr> <tr> <td><h:outputLabel for=”passwordInput”> <h:outputText value=”#{bundle.insertPassword}” /> </h:outputLabel></td> <td><h:inputSecret id=”passwordInput” size=”20” maxlength=”20” value=”#{user.password}” required=”true”> <f:validateLength minimum=”5” maximum=”15” /> </h:inputSecret></td> <td><h:message for=”passwordInput” styleClass=”errors” /></td> </tr> <tr> <td/> <td><h:commandButton action=”#{user.checkUser}” title=”#{bundle.loginButton}” /> </tr> </table> </td> </tr> </table> </h:form> </body> </html></f:view>

JAVA Journal

n.1 - novembre/dicembre 2006 19

JavaServer Faces speciale

Per deferred evaluation si intende che il JSP engine viene sol-levato dal compito di valutare l’espressione, compito che viene invece affidato a fasi successive del ciclo di vita. La forma (precisamente #{expr}) di un’espressione di questo tipo è quella abituale all’interno dei tag JSF che si riferi-scono a proprietà e metodi pubblici di un managed bean. Vediamo un esempio di funzionamento di questo meccani-smo nel Listato 1.

L’esempio propone una semplice pagina di login, in cui sono presenti i classici due campi di input. Sup-poniamo che un utente apra una sessione del browser e richieda la pagina. Quando arriva una tale richiesta, JSF entra nella fase di restore view. Durante questa fase il framework si accorge che è la prima richiesta della pagina, quindi cortocircuita il resto delle fasi e passa il testimone direttamente alla fase di render response (vedi Figura 1). Tale fase valuta l’espressione #{user.login} proprio come se fosse una valutazione immediata. In questo caso all’utente viene proposta la pagina con i due campi di input vuoti.

Quando invece arriva la seconda richiesta (cioè l’utente ha digitato login e password e ha premuto invia), la fase

di restore view (attraverso il nuovo metodo isPostBack() di ResponseStateManager) si accorge che ora è un evento di postback, e fa procedere il ciclo di vita. In particolare i due valori verrano usati in queste fasi:

• process validation: il framework controlla la correttezza formale dei parametri forniti dall’utente;

• update model values: nel caso in cui la fase di validazione sia superata con successo, i due valori servono ad aggior-nare il nostro bean user;

Method expressionUn’altra caratteristica importante dell’EL di JSF, che ver-rà quindi riportata anche nella versione 2.1 di JSP, è la possibilità di inserire espressioni che non si riferiscono a proprietà di oggetti, ma a metodi veri e propri. JSF infatti fornisce la possibilità di richiamare l’esecuzione di un me-todo di un bean. Tornando all’esempio 1, vediamo come l’attributo value del tag commandButton prenda come valo-re il ritorno del metodo checkUser del nostro managed bean. Questo metodo verrà richiamato durante la fase di invoke application per eseguire la logica di business.

FIGURA 1 Il ciclo di vita di JSF

LISTATO 2 esempio di tag JSTL

<%@ taglib uri=”http://java.sun.com/jsf/ html” prefix=”h”%><%@ taglib uri=”http://java.sun.com/jsf/ core” prefix=”f”%><%@ taglib uri=”http://java.sun.com/java/ jstl/core” prefix=”c”%><f:view> <ul> <c:forEach items=”${books}”var=”b”> <li><h:outputText value=”#{b}” /></li> </c:forEach> </ul></f:view>

Per deferred evalua-tion si intende che il JSP engine viene sollevato dal compito di valutare

l’eccezione

JAVA Journal

n.1 - novembre/dicembre 200620

speciale JavaServer Faces

Unified Expression Language e JSTL

Lo unified expression language viene esteso anche a JSTL. Infatti anche i tag JSTL possono contenere delle espres-sioni da valutare a run time e come accade nel caso pre-cedente, tali espressioni vengono valutate dal motore JSP ogniqualvolta la pagina viene interpretata. Consideriamo l’esempio del Listato 2, in cui si compie un ciclo sui valori di un bean attraverso il tag JSTL forEach e si presenta ogni valore attraverso il tag JSF outputText. A causa dei diversi momenti in cui le espressioni vengono valutate, il codice non si comporta come ci aspettiamo. Con la nuova versione di JSTL che si appoggerà all’ex-pression language definito in JSP, il codice del Listato 3 funzionerà correttamente a patto di cambiare $ con # nell’attributo items del tag forEach.

Unified Expression Language – Alcuni problemi di compatibilità

La modifica delle specifiche JSP comporta alcuni problemi di compatibilità con il codice scritto fino alla versione 2.0. Infatti fino a tale versione la coppia di caratteri #{ non rappresentava una parola riservata. Era quindi perfet-tamente lecito usare tale combinazione all’interno della pagina JSP. Supponendo di avere realizzato una web application che usava i caratteri #{ all’interno delle pagine e volendo farne un deploy su un container che supporta le specifiche JSP 2.1 ,si presentano 3 alternative:• procedere all’escape dei caratteri all’interno delle pagine

JSP, ovvero usare l’espressione \#{;• inserire nel deployment descriptor (l’usuale file web.xml)

il codice di Listato 3;• usare in pagina la direttiva <%@page … deferredSyntaxAll

owedAsLiteral=”true” %>Utilizzando uno di questi accorgimenti l’applicazione potrà funzionare anche con la nuova specifica.

Render Kit

Un’altra novità importante riguarda i render kit. Come noto JSF è un framework nato per la presentazione di contenuti sul web, quindi è naturale pensare che l’output inviato al client sia HTML. In realtà JSF astrae il mecca-nismo di presentazione al client definendo il render kit, che è quell’insieme di classi aventi il compito di definire la modalità di presentazione.

JSF fornisce di default il render kit per l’HTML, ma per-mette di aggiungere modalità di presentazione anche per client che interpretano altri meta linguaggi. È ad esem-pio possibile creare un render kit che genera codice SVG (Scalable Vector Grafix) oppure XUL (Xml User Interface Language), usato da Firefox, o addirittura Flex.Questa caratteristica esiste sin dalla prima versione delle specifiche; ciò che non si poteva fare fino ad ora era uti-lizzare render kit differenti all’interno della stessa web ap-plication: ad esempio non si poteva passare da una pagina in HTML a una in SVG ad una in XUL, mantenendo come model e controller JSF. O meglio questo si poteva fare, ma si doveva definire un ViewHandler custom che fosse in gra-do di gestire i vari render kit. Adesso è sufficiente definire in pagina quale sia il render kit da usare, specificandolo nell’attributo renderKitId del tag f:view e avendo l’accortezza di definire nel file faces-config.xml il tag render-kit-id con lo stesso valore.

Nuovo Tree Creation e Content Interweaving Model

Nelle applicazioni con JSF la vista viene spesso realizzata come una pagina JSP all’interno della quale trovano posto i componenti JSF. Fino alla versione 1.1 del framework la convivenza tra scriptlet JSP e tag JSF non era gestita al meglio. Si prenda in considerazione il Listato 4 che rappresenta una pagina JSP contenente un tag JSF che raggruppa due elementi, un tag JSF che stampa un messaggio e, di segui-to, uno scriptlet JSP che stampa un secondo messaggio. Visualizzando la pagina attraverso un browser ci si attende di vedere, in sequenza, “Messaggio 1” e “Messaggio 2”.

Ciò che avviene invece è proprio il contrario: viene prima visualizzato “Messaggio 2” e poi “Messaggio 1”. Il motivo di questo comportamento è il seguente. Il mo-

LISTATO 3 deployment descriptor

<web-app> <jsp-property-group> <deferred-syntax-allowed-as-literal> true </deferred-syntax-allowed-as-literal> </jsp-property-group> ...</web-app>

LISTATO 4 il problema del content interweaving

1:<%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%>

2:<%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%>

3:<f:view>4: <h:panelGroup>5: <h:outputText value=”Messaggio 1” />6: Messaggio 27: </h:panelGroup>8:</f:view>

JSF astrae il mecca-

nismo di presentazione

al client definendo

il render kit

JAVA Journal

n.1 - novembre/dicembre 2006 21

JavaServer Faces speciale

tore JSP analizza la pagina dall’alto verso il basso fino ad incontrare il tag h:panelGroup. I figli di questo tag (h:outputText in questo caso) demandano il render di sé stessi al padre. Quindi il render di outputText non avviene finché non si raggiunge la chiusura del tag panelGroup. A questa regola non sono però soggetti gli scriptlet JSP, quindi appe-na trova “Messaggio 2” il motore JSP ne compie il render. Questo errato comportamento è noto come “content inte-rweaving problem”.Per ovviare a questo inconveniente sono stati apportati numerosi cambiamenti strutturali. La seguente descrizio-ne non è semplice, chi non è interessato può passare al prossimo paragrafo.Sono stati cambiati la specifica di realizzazione del ViewHandler delle pagine JSP e la classe che rappresenta il custom tag JSP usata da tutti i componenti JSF. L’enco-ding non viene più fatto mentre la pagina JSP viene ana-lizzata, durante questa fase viene unicamente costruito l’albero dei componenti e solo quando questo è completo (l’albero comprende anche i componenti non JSF) si pro-cede all’encoding. In questo modo l’autore delle pagine non si troverà più a dover fronteggiare strani comporta-menti come quello descritto nell’esempio 5.

Gestione richieste AJAX

AJAX (Asynchronous Javascript and XML) sta diventando uno degli standard più diffusi per la realizzazione di rich client, permettendo di gestire chiamate asincrone al ser-ver. Le nuove specifiche di JSF partono da questo dato di fatto e tentano di migliorare l’interoperabilità tra queste due tecnologie. Sono stati introdotti pertanto due nuovi concetti, che pur essendo generali, si prestano bene ad un uso con AJAX.

Phase ListenersCome si vede dalla Figura 2, le fasi di un tipico ciclo di vita JSF sono sei. Le nuove specifiche stabiliscono che quando il framework passa da una fase all’altra deve scatenare degli eventi (Phase Event), precisamente deve segnalare quando sta per iniziare e quando è terminata una fase. Chi volesse registrarsi su questi eventi non deve fare altro che creare una classe che implementi l’interfaccia PhaseLi-stener che definisce due metodi: beforePhase(PhaseEvent e) e afterPhase(PhaseEvent e). Il componente che scatena questi eventi spostandosi tra le

fasi è l’istanza di UIViewRoot, che viene creato nella prima fase (la restore view), che per questo motivo è l’unica nella quale non ci sono eventi. Questo meccanismo risulta comodo nel caso in cui si vogliano gestire le richieste AJAX. Si supponga infatti di creare un AjaxPhaseListener il quale avrà il compito di capi-re, una volta ricevuta la notifica, se questa è stata generata da una richiesta AJAX. Se questo è il caso, il listener potrà attivare la logica che soddisfa la richiesta e cortocircuitare il resto delle fasi chia-mando il metodo renderResponse() o responseComplete().In questo modo la richiesta AJAX, non dovendo passare per tutte le fasi del ciclo di vita, viene servita più velocemente.

LifeCycle diversi all’interno della stessa applicazioneUn’altra novità è la possibilità di definire, all’interno del-la stessa applicazione, più istanze della servlet FacesServlet con URI mapping diversi. Ad ognuna di queste istanze è possibile associare un ciclo di vita diverso. Il meccanismo di associazione prevede che nel metodo init della servlet avvenga l’acquisizione dei riferimenti alle particolari istanze di Lifecycle e FacesContextFactory da usare nella web application.Utilizzando il parametro javax.faces.LIFECYCLE_ID, che può essere specificato come init-param della servlet oppure come context-param della web application, si può specifica-re l’implementazione del ciclo di vita da usare.Questo meccanismo permette di creare un ciclo di vita specifico per soddisfare le richieste AJAX (ad esempio con un numero minore di fasi) e di associarlo ad una istanza di servlet dedicata.

Annotations JEE5

Se l’applicazione JSF viene eseguita all’interno di un con-tainer JEE5, nei managed bean è possibile usare il mec-canismo delle annotation. Le annotation vengono usate per dichiarare dipendenze da risorse esterne o per definire dei parametri di configurazione senza che queste informazioni debbano essere riportate in un file di configurazione.La specifica afferma che deve essere possibile inserire, al-l’interno dei managed bean le seguenti annotation:

• @Resource;• @EJB;

L’annotation @Resource viene usata per riferirsi ad esempio ad un data source o ad una destinazione JMS. È responsa-bilità del container impostare il riferimento alla risorsa ed eseguire la corretta mappatura attraverso JNDI. In sostan-za si permette allo sviluppatore di non dover specificare nel deployment descriptor le dichiarazioni di resource-ref, message-destination-ref, env-ref e resource-env-ref.L’annotation @EJB viene usata per riferirsi, all’interno della web application, ad un EJB 3.0. Questo tipo di an-notation permette di evitare di inserire nel deployment descriptor le dichiarazioni ejb-ref o ejb-local-ref.

Due nuovo concetti

si prestano bene ad un

suo con AJAX

JAVA Journal

n.1 - novembre/dicembre 200622

speciale JavaServer Faces

Altre novità

Salvataggio dello statoIn JSF le modalità di salvataggio dello stato tra le request sono due: salvataggio sul server e salvataggio sul client. La specifica fornisce ampia libertà di scelta riguardo la mo-dalità di tale salvataggio, salvo precisare che ogni imple-mentazione delle specifiche deve fornire di default il sal-vataggio tramite la serializzazione della vista, con l’usuale implementazione dell’interfaccia Serializable. Nel caso di salvataggio lato server, la vista viene serializ-zata e messa in sessione. Viene successivamente inviata al client una chiave univoca per il recupero della vista cor-retta. In questo modo si possono usare le funzionalità di failover proprie del container. Nel caso di salvataggio lato client (ad esempio in un campo hidden), la specifica ora suggerisce la necessità che il con-tenuto di tale salvataggio sia cifrato e reso difficilmente accessibile in quanto può rimanere all’interno del client per un tempo non trascurabile.

Resource BundleLa nuova specifica permette di ricavare i valori dei bundle di risorse attraverso il nuovo expression lan-guage, a patto di aver correttamente definito il bundle all’interno del file di configurazione di JSF. In questo modo non è più necessario usare nelle pagine il tag f:loadBundle per caricare il bundle specificato nel file di configurazione.

ResolverDalla versione 1.2 di JSF non sarà più possibile la risolu-zione di oggetti impliciti (quelli che rappresentano mappe o liste di attributi), ovvero non sarà più possibile creare un managed bean con lo stesso nome di un oggetto implicito. Prendiamo ad esempio l’espressione #{param[‘x’]}. In JSF 1.1, attraverso un custom variable resolver si poteva cambia-re il significato di param (associandolo ad un managed bean); dalla versione 1.2 param rappresenterà sempre un Map di parametri e tale significato non potrà essere so-vrascritto. Inoltre non è più possibile eseguire i metodi setVariableRe-solver() e setPropertyResolver() in qualsiasi punto dell’appli-cazione. Dalla versione 1.2, appena arriva la prima request all’applicazione, questi metodi non hanno più effetto. Tale modifica è stata aggiunta per evitare che l’applicazione possa rimanere in uno stato inconsistente a causa del cam-biamento dei resolver.

Glassfish

Abbiamo visto che i prerequisiti per il funzionamento di JSF sono abbastanza stringenti: JSP 2.1, JSTL 1.2, (Servlet 2.5 e EJB 3.0 se vogliamo usare le annotation JEE5) e JSE5 come implementazione della virtual machine java. Molte delle specifiche che si riferiscono a queste tecnologie sono state solo di recente poste in uno stato di final draft, stato che permette alle terze parti di iniziare a realizzare prodotti che poi avranno la certificazione Sun. È quindi legittimo chiedersi se esista attualmente un serv-

let container che ci permetta di utilizzare JSF 1.2 e se esista una implementazione delle specifiche 1.2. L’unico vendor che attualmente fornisce un tale strumento è proprio Sun e lo strumento in questione prende il nome di Glassfish. Glassfish è il nuovo applicatio server che Sun sta svilup-pando in modo collaborativo su http://java.net . Glassfish rappresenta il primo application server che realizza le spe-cifiche JEE5, all’interno delle quali, come detto, si trova anche JSF 1.2.Attualmente Glassfish è in fase di sviluppo, collegandosi però al sito https://glassfish.dev.java.net/ si può scaricare una versione sufficientemente stabile con la quale provare JSF 1.2.

Conclusioni

Le nuove specifiche di JSF danno una maggiore solidità al framework inserendolo appieno all’interno dell’archi-tettura JEE5. Attualmente non esistono implementazioni da usare in produzione, ma è probabile che quando le specifiche assumeranno uno stato finale, le terze parti e la comunità open source (Tomcat e MyFaces ad esem-pio), inizieranno lo sviluppo. Per chi è curioso e non vuole aspettare può provare Glassfish, contribuendo anche allo sviluppo di quest’ultimo.

Bibliografia

Specifiche JSF 1.2 http://www.jcp.org/en/jsr/detail?id=252Specifiche JSP 2.1 http://www.jcp.org/en/jsr/detail?id=245Specifiche JSTL 1.2 http://www.jcp.org/en/jsr/detail?id=52Specifiche Servlet 2.5 http://www.jcp.org/en/jsr/ detail?id=154Glassfish https://glassfish.dev.java.net/

Note Biografiche

Andrea Nasato si è laureato in Ingegneria Informatica all’Uni-versità di Padova e lavora come sviluppatore Java in progetti ri-guardanti la Sanità. I suoi interessi spaziano dai framework web al real time. È socio fondatore del JUG Padova.

Il Java User Group dell’autore

Il Java User Group Padova (www.jugpadova.it) è un gruppo nato per facilitare lo scambio di conoscenze, informazioni ed esperienze tra gli sviluppatori softwa-re dell’area padovana (e non), interessati al linguaggio Java e alle tecnologie correlate. Il gruppo è indipen-dente, senza scopo di lucro, composto da volontari che offrono e condividono le loro conoscenze con gli altri componenti, in un’ottica di crescita e comune inter-scambio di informazioni. Anche chi non ha esperienza con il linguaggio Java è incoraggiato a partecipare al JUG! Le attività del JUG Padova comprendono: ritrovi periodici, organizzazione di corsi, partecipazione alle manifestazioni del settore.

JAVA Journal

23n.1 - novembre/dicembre 2006

JavaServer Faces speciale

Un Wizard per il Web con JSF e ShaleLe applicazioni web presentano, in talune circostanze, elaborazioni in stile wizard. Con Java Server Faces e Shale è possibile realizzare wizard per il web in modo funzionale, chiaro ed elegante.

>> di Fabio Staro ([email protected])

L’uso di wizard, anche noti come crea-zioni guidate, è comune in molte atti-vità svolte davanti al computer: dalla creazione di documenti alla installa-zione di application server o databa-se. Tecnicamente un wizard è una se-quenza di schermate atte a raccogliere

le informazioni necessarie nella realizzazione di uno specifico compito. I wizard rendono l’interazione con gli utenti maggiormente comprensibile, suddividen-do la richiesta di informazione in blocchi logici, evi-tando, pertanto, la proposizione di una unica, com-plessa ed eccessivamente lunga schermata.In questo articolo realizzeremo un wizard per il web con JavaServer Faces (JSF) mostrando come sia van-taggioso realizzarlo attraverso il supporto alla “gestio-ne dei dialoghi” offerto dal framework Shale basato su JSF. L’articolo non è una introduzione a JSF, dandone per acquisita una conoscenza di base, mentre intro-duce Shale e le sue features.Il framework Shale è uno dei progetti della Apache Foundation, collegato al progetto Struts, che ha come obiettivo estendere JSF per fornire nuove funzionali-tà che semplificano lo sviluppo.

Un semplice wizard

Il wizard che vogliamo realizzare, volutamente semplice al fine di soffermarci sugli aspetti tecnici e non funzionali, prevede quattro passi, illustrati nella Figura 1, per la raccolta delle informazioni anagrafiche e professionali di un utente: il primo passo consente l’inserimento dei dati anagrafici del-l’utente, il secondo l’inserimento delle informazioni relative al percorso formativo, il terzo passo permette

l’inserimento delle esperienze in campo professiona-le ed infine il quarto passo chiede una conferma per i dati inseriti. Osserviamo come in ciascun passo sia possibile tornare indietro e modificare i valori prece-dentemente inseriti.

La realizzazione del semplice wizard proposto si basa su quattro pagine JSP. La pagina “anagrafica.jsp” raccoglie i dati anagrafici di un utente, la pagina “istruzione.jsp” i dati relativi alla formazione uni-versitaria, la pagina “esperienzeLavorative.jsp” i dati relativi alle esperienze lavorative ed infine la pagina “confermaDati.jsp” chiede conferma all’utente dei dati inseriti. La navigazione tra le pagine è definita nel file faces-config.xml di cui ne riportiamo uno stral-cio ed in Figura 2 ne diamo una rappresentazione grafica:

…<navigation-rule> <from-view-id>/anagrafica.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/istruzione.jsp</to-view-id> </navigation-case></navigation-rule><navigation-rule> <from-view-id>/istruzione.jsp</from-view-id> <navigation-case> <from-outcome>indietro</from-outcome> <to-view-id>/anagrafica.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/esperienzeLavorative.jsp </to-view-id> </navigation-case></navigation-rule><navigation-rule>

JAVA Journal

n.1 - novembre/dicembre 200624

speciale JavaServer Faces

<from-view-id>/esperienzeLavorative.jsp </from-view-id> <navigation-case> <from-outcome>indietro</from-outcome> <to-view-id>/istruzione.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/confermaDati.jsp </to-view-id> </navigation-case></navigation-rule><navigation-rule> <from-view-id>/confermaDati.jsp</from-view-id> <navigation-case> <from-outcome>indietro</from-outcome> <to-view-id>/esperienzeLavorative.jsp </to-view-id> </navigation-case></navigation-rule>…

Osservando le righe di codice riportate possiamo nota-re come “nativamente” il framework JavaServer Faces supporti un meccanismo che permette di definire, in un file XML di configurazione, le regole di navigazione tra le varie pagine costituenti una applicazione. In particolare, l’algoritmo che definisce la navigazione tra le pagine è definito in JSF dall’implementazione della classe astratta javax.faces.application.NavigationHandler. L’implementazione standard fornita dal framework determina la navigazione da una pagina ad un’altra in base a a tre dati di input:

• Quale pagina sta correntemente processando il form;• Quale azione, tra quelle potenzialmente possibili, è stata

invocata;• Quale è il valore ritornato dall’azione invocata;

Il meccanismo di navigazione offerto dal framework JSF, basato sul valore logico, “logical outcome”, restituito dagli action method presenti nei backing managed bean, riduce l’accoppiamento tra le pagine poiché quando si realizza un action method lo sviluppatore del backing bean deve tener

conto solo di “cosa succede” piuttosto che domandarsi “dove devo andare ora”. Questo concetto è presente nella maggior parte dei framework web basati sul paradigma Model View Controller (MVC) che adottano il design pattern front-controller. Per esempio il framework Struts 1.x, proba-bilmente il più diffuso framework web, presenta il metodo Action.execute() che ritorna un oggetto di tipo ActionForward il quale descrive il valore logico di “outcome”. Tuttavia per quanto analizzato finora dobbiamo notare come il framework JavaServer Faces, analogamente al framework Struts 1.x, permetta una elaborazione in stile wizard ma al prezzo di legare nel codice e nel file di configurazione faces-config.xml i passi del workflow, riducendo di fatto la possibilità di riutilizzare i singoli passi di cui è composto il flusso e soprattutto non isolando chiaramente i flussi stessi (per esempio il wizard presentato non termina con la pagina “confermaDati.jsp” ma con la successiva azione di business invocata sull’onclick() del pulsante “Avanti”). In particolare ogni pagina JSP deve sapere esplicitamen-te quale è l’azione da invocare per proseguire nel passo successivo del wizard. Il seguente frammento di codice, estratto dalla pagina JSP anagrafica.jsp, chiarisce quanto espresso:

<h:commandButton value=”Avanti” action=”#{anagrafica.insertAnagrafica}”/>

L’obiettivo che invece desideriamo ottenere è la possibilità di trattare una elaborazione in stile wizard come una serie di mappe che mimano una conversazione o un dialogo con un utente in cui vi è un preciso e netto disaccoppiamento fra pagine JSP e le azioni di business. Inoltre un wizard deve poter essere visto come un componente o più sempli-cemente come una subroutine richiamabile anche da altri wizard. Queste features sono possibili attraverso il suppor-to del framework Shale ed in particolare del suo Dialog Manager, ossia il gestore dei dialoghi.

Introduzione a Shale

Con il framework Shale estendiamo le JavaServer Faces. FIGURA 1 I passi del wizard

FIGURA 2 Rappresentazione grafica, ottenuta con il tool di sviluppo Oracle JDeveloper 10g, della navigazione tra le quattro pagine JSP del wizard

JAVA Journal

n.1 - novembre/dicembre 2006 25

JavaServer Faces speciale

Infatti il framework JSF versione 1.1 segnala la carenza di alcuni servizi tra i quali:• un sistema evoluto per la gestione del layout delle pagine

web;• un sistema di gestione per la navigazione tra le pagine

web in stile wizard;• una migliore interazione con i managed bean durante

le fasi costituenti il ciclo di vita di una richiesta di tipo faces.

• la presenza di validatori client-side;• il supporto per il remoting (AJAX [2]);

Tuttavia JSF è un framework estremamente flessibile e facilmente estensibile presentando punti di estensione rappresentati da pluggable classes che all’occasione pos-sono essere sostituite o decorate (cfr. il pattern Decorator [GoF] e la Figura 3). Le classi che costituiscono il core di JSF possono essere divise in due gruppi: le classi di infrastruttura e le classi

pluggable. Le classi di infrastruttura sono: Lifecycle, Ren-derKit, Application e FacesContext. Sinteticamente: la classe Lifecycle descrive il ciclo di vita di una richiesta JSF, la classe RenderKit gestisce un insieme di renderer, la classe Application mantiene le reference verso le classi pluggable e, infine, la classe FacesContext gestisce tutte le informa-zioni legate ad una singola richiesta JSF. Queste classi rappresentando il carattere distintivo del framework JSF non sono generalmente modificate dagli sviluppatori o da terzi. Tuttavia l’insieme delle classi pluggable si presta ad operazioni di modifica o estensione. Le classi pluggable sono: VariableResolver, PropertyResolver,ActionListener, Naviga-tionHandler, ViewHandler, e StateManager. Sono tutte classi astratte, eccetto Action Listener che è una interfaccia. Il dia-gramma delle classi della Figura 4 da una vista d’insieme delle pluggable classes.

La classe VariableResolver ha la responsabilità di valutare l’elemento più a sinistra di una espressione JSF EL mentre la classe PropertyResolver valuta gli elementi di una espres-sione JSF EL dopo il segno “.” o all’interno delle parentesi quadre. Così se abbiamo la seguente espressione JSF EL:

#{persona.nome}

la classe VariableResolver identifica l’oggetto Java referenzia-to dalla variabile persona e la classe PropertyResolver ritorna il valore dell’attributo nome dell’oggetto precedentemente

identificato. L’implementazione di default in JSF della classe VariableResolver ricerca un oggetto, identificato dalla chiave specificata, nei diversi “scope” dell’applicazione (re-quest, session o application). Supponiamo ora di estendere il comportamento standard di JSF in modo tale che sia pos-sibile ricavare attraverso una espressione JSF EL anche il valore di variabili definite nel file di deployment descriptor, ossia il web.xml, di una web application (l’esempio è voluto essendo questa una semplice feature di Shale che tuttavia chiarisce il modo di interagire con le classi pluggable). Per ottenere questo risultato le classi di default da estendere sono proprio VariableResolver e PropertyResolver. Decorando le implementazioni standard delle due classi ora descritte può essere possibile ricavare il valore della variabile var1 con una espressione JSF EL del tipo:

#{jndi.var1}

dove la variabile var1 è, per esempio, così definita nel file web.xml:

<env-entry><description>Variabile di test</description><env-entry-name>var1</env-entry-name><env-entry-type>java.lang.Boolean</env-entry-type><env-entry-value>true</env-entry-value></env-entry>

Continuando brevemente la descrizione delle classi plug-gable, la classe ActionListener gestisce tutti gli eventi di tipo ActionEvent, la classe NavigationHandler seleziona una pagi-na web in base al valore di outcome restituito da un action method, la classe ViewHandler crea, recupera e mostra una view delegando alla classe StateManager il salvataggio ed il recupero dello stato della view ed infine la classe StateMa-nager salva e recupera lo stato di una view. Per quanto det-to finora è intuitivo che se volessimo modificare il modo standard di navigare tra le pagine di una applicazione JSF, per esempio attraverso una modalità tipo wizard, do-vremmo estendere, o meglio decorare, l’implementazione di default di JSF della classe NavigationHandler mentre se volessimo fornire a JSF una sorta di integrazione verso un sistema per la gestione del layout delle pagine web, per esempio una integrazione con il noto framework Tiles

FIGURA 3 Il pattern Decorator

FIGURA 4 le classi pluggable del framework JavaServer Faces

JAVA Journal

n.1 - novembre/dicembre 200626

speciale JavaServer Faces

[1], dovremmo estendere, sempre attraverso un processo di decorazione, l’implementazione standard della classe ViewHandler. Per quanto detto finora si evidenziano alcuni limiti del fra-mework JSF, ai quali possiamo aggiungere, per maggiore completezza, l’assenza in JSF di un supporto verso AJAX [2] e l’assenza di validatori client-side. In questo contesto si comprende il perché della necessità di Shale. Apache Shale [3], anche noto come Struts 2, è un fra-mework che arricchisce JSF con una serie di servizi i quali si possono usare a piacere, in base alle proprie necessità. Scopo di questo articolo non è descrivere Shale nella sua interezza non potendo esaurire l’argomento in un solo ar-ticolo. La Tabella 1 riporta le principali feaures di Shale.

Configurazione di Shale

Una volta eseguito il download del framework Shale, rimandando a [3] per i dettagli, la sua configurazione è estremamente semplice. Nel file web.xml della propria ap-plicazione web è sufficiente aggiungere le seguenti righe di codice:

<filter><description>Filtro per Shale</description><display-name>shale</display-name><filter-name>shale</filter-name><filter-class>org.apache.shale.faces.ShaleApplicationFilter<

/filter-class></filter> <filter-mapping><filter-name>shale</filter-name><url-pattern>/*</url-pattern></filter-mapping>

le quali definiscono il filtro che analizza le richieste per il framework Shale. Inoltre, sempre nel file web.xml, dichia-

riamo un parametro di contesto con il quale si specifica il nome del file di configurazione per il gestore dei dialoghi all’interno del quale sarà specificato come le pagine JSP e le classi Java sono tra loro collegate.

<context-param><param-name>org.apache.shale.dialog.CONFIGURATION</param-

name><param-value>/WEB-INF/dialogo.xml</param-value></context-param>

Shale presenta una serie di dipendenze verso alcuni noti progetti di Apache (i cosiddetti “commons” [8]) e pertan-to nella directory lib presente all’interno della directory WEB-INF della applicazione web devono essere presenti i seguenti jar di queste librerie (per una descrizione det-tagliata delle dipendenze di Shale verso librerie esterne si rimanda a [7]). Di seguito indichiamo l’ambiente di runti-me base che supporta Shale:

• JRE 1.4 o superiore;• Servlet 2.4 e JSP 2.0• JSF 1.1 o superiore;• JSP Standard Tag Library 1.1• Apache Commons Bean Utils 1.7 o superiore;• Apache Commons Chain 1.0 o superiore;• Apache Commons Digester 1.7 o superiore;• Apache Commons Logging 1.0.4 o superiore;• Apache Commons Validator 1.2.0 o superiore.

Osserviamo che Shale può funzionare anche con un ap-plication server che supporta la precedente specifica delle Servlet e delle JSP, ossia la versione 2.3 per le Servlet e 1.2 per le JSP (cfr. [7] per i dettagli).

Il gestore di dialoghi

Il modo più semplice ed efficace per rappresentare un dia-

Features Descrizione

View Controller Meccanismo che estende un backing bean associato ad una pagina JSP fornendo al bean metodi di callback (init(), preprocess(), prerender() e destroy()) invocati in base ai precisi eventi che si verificano durante il ciclo di vita di una richiesta JSF.

Validazione Integrazione del componente Apache Commons Validator [4] per la validazione sia lato client che lato server.

JNDI Accesso semplificato, attraverso espressioni JSF EL, alle proprietà definite nel file di configurazione web.xml.

Dialog Manager Gestore per la realizzazione di wizard per il web, configurato attraverso un file XML

Application Manager Un controller per le richieste HTTP a livello application.

Remoting Supporto server-side al modello di programmazione AJAX

Clay Modulo per il riuso delle pagine HTML in modo simile a Facelets [5] e Tapestry [6];

TABELLA 1 Le principali features di Shale

JAVA Journal

n.1 - novembre/dicembre 2006 27

JavaServer Faces speciale

logo, adottando questo termine in sostituzione di wizard per adeguare la terminologia al framework Shale, è un diagramma UML degli stati. I diagrammi di stato sono una tecnica consueta per descrivere il comportamento di un si-stema. Essi descrivono tutti i possibili stati raggiungibili da un particolare oggetto e come cambia lo stato dell’oggetto in conseguenza degli eventi. Il framework Shale definisce quattro tipi di stato, di seguito descritti:

• Action State: rappresenta l’invocazione di un metodo pubblico. Questo metodo non prende nessun parametro di input e restituito una stringa che è trattata come un valore di “outcome”;

• View State: rappresenta il rendering di una pagina JSP in attesa del susseguente submit di una form.

• Subdialog State: consente al dialogo principale di invocare un altro dialogo, visto dal primo come una subroutine;

• End State: termina il dialogo corrente;

Torniamo ora al semplice dialogo presentato all’inizio del-l’articolo. La Figura 5 ne da una rappresentazione attra-verso un diagramma degli stati.

Osservando con attenzione la Figura 5 possiamo notare che le attività espletate durante l’esecuzione del dialogo sono:

1. Setup: operazioni di inizializzazione per il dialogo cor-rente;

2. Anagrafica Form: pagina JSP attraverso la quale l’utente inserisce le informazioni anagrafiche;

3. Inserisci Anagrafica: azione che permette la gestione dei dati anagrafici forniti;

4. Istruzione Form: pagina JSP attraverso la quale l’utente inserisce i dati relativi al proprio percorso formativo;

5. Inserisci Istruzione: azione che permette la gestione dei dati forniti relativi alla formazione;

6. Esperienze Lavorative Form: pagina JSP attraverso la quale l’utente inserisce i dati relativi alle proprie espe-rienze professionali;

7. Inserisci Esperienze Lavorative: azione che permette la gestione dei dati relativi al percorso professionale;

8. FineConferma Form: pagina JSP attraverso la quale l’utente conferma i dati inseriti;

9. Conferma Dati: azione che consente al sistema la confer-ma dei dati e, per esempio, la loro persistenza.

Quanto descritto nell’elenco sopra riportato e rappre-sentato dalla Figura 5 è di fatto il file di configurazione dialogo.xml. Il Listato 1 lo riporta nella sua interezza e la Figura 6 ne da una rappresentazione grafica. In questo file sono riportati gli stati che descrivono il sistema e le transizioni tra questi. Osserviamo come ora vi è un reale disaccoppiamento tra le JSP e le azioni e come il flusso elaborativo sia pienamente e chiaramente descritto. A differenza di quanto avveniva in precedenza con la gestione “nativa” della navigazione nel framework JSF ora le pagine JSP non presentano dipendenze esplicite con le relative azioni. Il seguente frammento di codice,

estratto dalla pagina JSP anagrafica.jsp, chiarisce quanto espresso:

<h:commandButton value=”Avanti” action=”avanti”/>

L’azione “avanti” che deriva dalla pressione del pulsante fa transitare il sistema dallo stato, di tipo View State, Ana-grafica Form -> allo stato, di tipo Action State, Inserisci Anagrafica causando di fatto l’invocazione del metodo anagraficaazioneDialogo.insertAnagrafica(), dove azioneDialogo è un managed bean definito nel file faces-config.xml.Ovviamente non è necessario che tutte le interazioni nel framework Shale siano organizzate in dialoghi. È possibi-le, anzi probabile, avere un misto di processi navigazionali standard e processi navigazionali descritti da dialoghi. Tuttavia per iniziare un dialogo è necessario che un action method torni un valore di outcome che inizi con la parola chiave dialog:xxxxx. Per esempio il dialogo denominato Gestore Anagrafica, cfr. Listato 1, descritto in questo articolo inizia quando il valore di outcome restituito da un action method è dialog:Gestore Anagrafica. Una volta terminato il dialogo riprende il modo, standard al framework JSF, di navigare tra le pagine dell’applicazione. In una applicazione web complessa è possibile avere, mi-gliorando di fatto la chiarezza e la manutenibilità dell’ap-

FIGURA 5 Diagramma degli stati che rappresenta il dialogo Gestore Anagrafica

JAVA Journal

n.1 - novembre/dicembre 200628

speciale JavaServer Faces

plicativo, più file di configurazione per i dialoghi. Questi devono essere specificati sempre attraverso il parametro di contesto org.apache.shale.dialog.CONFIGURATION e separati dalla virgola:

<context-param><param-name>org.apache.shale.dialog.CONFIGURATION</param-name>

<param-value>/WEB-INF/file1.xml, /WEB-INF/file2.xml </param-value></context-param>

Il Dialog Manager mantiene un oggetto di tipo org.apache.shale.dialog Status memorizzato in sessione con chia-ve “dialog” (valore modificabile attraverso un parametro di inizializzazione di contesto). Questo oggetto ha una proprietà

di tipo java.lang.Object chiamata “data” nella quale l’applicazione può salvare un oggetto che rappresentano lo stato del dialogo cor-rente. Pertanto è possibile usare espressioni EL del tipo:

#{dialog.data.nome}

per referenziare la proprietà nome dello stato corrente del dialogo. Quando il dia-logo termina, attraverso una gestione au-tomatica da parte del framework, lo stato corrente del dialogo va in “out of scope”. Di seguito uno stralcio del codice della pagina confermaDati.jsp:…<h:panelGrid columns=”2”> <h:outputLabel value=”Nome:”/> <h:outputLabel value=”#{dia

log.data.nome}”/> <h:outputLabel

value=”Cognome:”/> <h:outputLabel value=”#{dia

log.data.cognome}”/> <h:outputLabel

value=”Laurea in:”/> <h:outputLabel value=”#{dia

log.data.laurea}”/> <h:outputLabel

value=”Votazione:”/> <h:outputLabel value=”#{dia

log.data.votazione}”/> <h:outputLabel

value=”Azienda:”/> <h:outputLabel value=”#{dia

log.data.azienda}”/> <h:outputLabel

value=”Qualifica:”/> <h:outputLabel value=”#{dia

log.data.ruolo}”/></h:panelGrid>…

Punti di estensione in JSF

Prima di concludere osserviamo che all’in-terno dell’archivio shale-core.jar è presen-te un file di configurazione faces-config.xml che presenta le righe di codice che seguono (in una applicazione JSF possono essere presenti più file faces-config.xml di configu-razione [JSF]):LISTATO 1

<?xml version=”1.0” encoding=”UTF-8”?><!DOCTYPE dialogs PUBLIC “-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN” “http://struts.apache.org/dtds/shale-dialog-config_1_0.dtd”><dialogs> <dialog name=”Gestore Anagrafica” start=”Setup”> <action method=“#{azioneDialogo.setup}“ name=“Setup“> <transition outcome=“success“ target=“Anagrafica Form“/> </action> <view name=“Anagrafica Form“ viewId=“/anagrafica.jsp“> <transition outcome=”avanti” target=”Inserisci Anagrafica”/> </view> <action method=”#{azioneDialogo.insertAnagrafica}” name=”Inserisci Anagrafica”> <transition outcome=”success” target=”Istruzione Form”/> </action>

<view name=”Istruzione Form” viewId=”/istruzione.jsp”> <transition outcome=”avanti” target=”Inserisci Istruzione”/> <transition outcome=”indietro” target=”Anagrafica Form”/> </view> <action method=”#{azioneDialogo.insertIstruzione}” name=”Inserisci Istruzione”> <transition outcome=”success” target=”Esperienze Lavorative Form”/> </action> <view name=”Esperienze Lavorative Form” viewId=”/esperienzeLavorative.jsp”> <transition outcome=”avanti” target=”Inserisci Esperienze Lavorative”/> <transition outcome=”indietro” target=”Istruzione Form”/> </view> <action method=”#{azioneDialogo.insertEsperienzeLavorative}” name=”Inserisci Esperienze Lavorative”> <transition outcome=”success” target=”Conferma Form”/> </action> <view name=”Conferma Form” viewId=”/confermaDati.jsp”> <transition outcome=”avanti” target=”Conferma Dati”/> <transition outcome=”indietro” target=”Esperienze Lavorative Form”/> </view> <action method=”#{azioneDialogo.confermaDati}” name=”Conferma Dati”> <transition outcome=”success” target=”fine”/> </action>

<end name=”fine” viewId=”/fine.jsp”/> </dialog></dialogs>

JAVA Journal

n.1 - novembre/dicembre 2006 29

JavaServer Faces speciale

…<application> <navigation-handler> org.apache.shale.dialog.faces.DialogNavigationHandler </navigation-handler>…</application>…

Come osservato in precedenza non è necessario sostituire completamente l’implementazione di default di una classe pluggable con una nuova classe. Infatti il più delle volte è possibile ed anzi è preferibile aggiungere nuove fun-zionalità alla classe originale attraverso un processo di decorazione (decorator pattern, cfr. [GoF]). Di seguito riportiamo la firma del costruttore della classe DialogNa-vigationHandler:

public DialogNavigationHandler(NavigationHandler parent){ … this.parent = parent;}

Possiamo osservare come al costruttore è passato il riferi-mento dell’implementazione originale del NavigationHan-dler. Pertanto la classe DialogNavigationHandler delega alla classe “parent”, implementazione originale della clas-se NavigationHandler, in pratica la soluzione della naviga-zione quando non si è in presenza di un dialogo, mentre gestisce direttamente il nuovo processo di navigazione e transizione tra gli stati in presenza di un dialogo. La classe DialogNavigationHandler pertanto decora l’implementa-zione di default del NavigationHandler.

Conclusioni

In questo articolo abbiamo presentato il framework Shale basato su JSF. Ovviamente non è sufficiente un solo artico-lo per descrivere tutte le features di Shale. Tuttavia risulta evidente come Shale estenda il modello di JSF fornendo servizi e componenti di integrazione. Colpisce di Shale, a

differenza per esempio di Struts 1.x, la sua “discrezione” e poca intrusività presentando una architettura a servizi di supporto per JSF.

Attraverso il pattern Decorator è possibile aggiungere fun-zionalità ad un oggetto senza la necessità di estendere la classe che lo descrive. Il diagramma delle classi che segue ne da una rappresentazione.

Riferimenti

[1] TILEShttp://struts.apache.org/1.x/struts-tiles/index.html[2] http://it.wikipedia.org/wiki/AJAXAJAX[3] http://struts.apache.org/struts-shale/index.html[4] http://jakarta.apache.org/commons/validator/[5] https://facelets.dev.java.net/[6] http://jakarta.apache.org/tapestry/[7] http://struts.apache.org/struts-shale/struts-shale.pdf[8] http://jakarta.apache.org/commons/

Bibliografia

[GoF]: Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. 1995. Design Patterns:Elements of Reusable Object-Oriented Software. Pubblicato da Addison-Wesley.[JSF]: Kito De Mann. 2005. JavaServer Faces In Action. Pub-blicato da Manning Publications Co.

FIGURA 6 L’editor XML per la definizione dei dialoghi presente nel plug-in Exadel Studio per Eclipse

Note Biografiche

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

JAVA Journal

30 n.1 - novembre/dicembre 2006

focus

JavaCard

Negli ultimi tempi la pubblica ammi-nistrazione sta introducendo delle Carte Servizi che presto potranno facilmente sostituire buona parte dei documenti che di solito trovano po-sto nel nostro portafogli. Se a quanto

sopra citato uniamo anche la moltitudine di carte di fidelizzazione cliente e raccolta punti, ci possiamo fare un’idea concreta di quanto sia diventato vasto questo mondo, e di quanto la smart card faccia or-mai parte integrante della nostra vita. Vale la pena di ricordare che, sebbene ci possano apparire come un fenomeno relativamente recente, la prima smart card è stata creata nel lontano 1974, da Roland Moreno; di contro quest’anno sono state prodotte quasi un miliardo di smart card, con una spiccata supremazia di Europa ed Asia (95%) sugli USA (5%).

Cosa è una smart card?

Ma vediamo cosa è esattamente una smart card. Vo-lendo semplificare la questione, si tratta di un com-puter in miniatura, completamente entrocontenuto nello spessore della carta, i cui unici collegamenti con il mondo esterno (e quindi con le apparecchiature che utilizzano la smart card) sono i contatti che affiorano dalla carta. Due di quelle piazzole di rame servono

per alimentare il nostro piccolo computer, una serve per dargli il segnale di clock, e altre due servono come linee di comunicazione (ingresso e uscita). Ne conse-gue che il lettore di smart card altro non è che un di-spositivo che alimenta la carta quando viene inserita, gli fornisce il clock di lavoro, e gestisce lo scambio di informazioni fra carta e computer host. Per comple-tezza bisogna aggiungere che esistono anche delle smart card che non hanno logica programmabile all’interno, ma sono solo delle memorie.

Le Smart Card rispondono ad uno standard ben pre-ciso, che è l’ISO 7816 – esso ne fissa le dimensioni fisiche, le caratteristiche elettriche e i dettagli del protocollo di scambio dati. Sebbene le modalità di in-terazione con una smart card rimangono ben identi-ficate da questo standard (il che riveste fondamenta-le importanza per l’interoperabilità), ogni produttore è libero di implementare i dettami della ISO 7816 nel modo che più gli aggrada, un po’ come succede con Java per il quale Sun Microsystems detta solo le specifiche, demandando a chiunque sia interessato lo sviluppo di una JVM ad esse rispondente.Una delle principali conseguenze di ciò è che ogni costruttore è libero di mettere a punto un ambien-te di sviluppo e un insieme di API, o addirittura un linguaggio di programmazione, che risponde alle proprie esigenze e non ad uno standard.

Cosa è una Java Card?

È in questo contesto che nasce l’idea di Java Card; la finalità è quella di fornire ai costruttori di smart card una piattaforma che consenta di far girare delle piccole applicazioni Java, chiamate applet, su dispo-sitivi caratterizzati da una disponibilità di memoria estremamente limitata, e agli sviluppatori una API standard, oltre alla possibilità di scrivere codice Java per la smart card.

Si identificano tre componenti principali della Speci-fiche Java Card:

Uno degli oggetti che negli ultimi anni è diventato di uso comune, quasi senza che ce ne accorgessi-mo, è la smart card. Probabilmente la prima smart card con cui la maggior parte di noi è venuta in contatto è stata la SIM utilizzata per la telefonia cellulare, seguita a ruota dalle smart card per l’accesso ai bouquet della TV satellitare, senza dimenticare le nuove generazioni di carte di credito e di debito.

>> di Matteo Campanella ([email protected])

FIGJava Card

JAVA Journal

n.1 - novembre/dicembre 2006 31

focus

1. Specifiche della Java Virtual Machine;2. Specifiche del Java Runtime Environment;3. API per la piattaforma Java Card

Riassumendo, la Java Card è essenzialmente una smart card in grado di eseguire programmi Java. Le specifiche prevedono delle risorse hardware veramente esigue: 16KB di ROM, 8KB di EEPROM e appena 256 bytes di RAM. L’esecuzione del bytecode Java è possibile grazie all’im-plementazione di una Java Virtual Machine direttamente sullo strato di sistema operativo della smartcard, di cui nasconde completamente gli aspetti peculiari; chi svilup-pa per Java Card non si deve preoccupare di quale sia il produttore; basta attenersi alle specifiche dell’API e non ci saranno sorprese. Attenzione però, a volte potrebbe venire la tentazione di utilizzare delle estensioni alle API stan-dard fornite dal produttore della card al fine di sfruttare peculiarità della carta: niente di male, si tratta di un passo in alcuni casi indispensabile, ma di fatto pone fine alla completa portabilità del codice – non è infatti detto che un altro fornitore abbia implementato le stesse estensioni (Figura 1).

Come funziona una Java Card?

Per poter girare su una Java Card, le applet vi devono essere preventivamente installate. Non si pensi di avere a disposizione tutta la potenza di Java: il caricamento

dinamico delle classi, il security manager, i thread e la sin-cronizzazione non sono supportati, così come alcuni tipi di dato complessi come float, double, e char. Affinché l’instal-lazione di un’applet possa andare a buon fine, è necessario che essa implementi un metodo public static install, che vie-ne chiamato dal Runtime Environment come ultimo passo della procedura di installazione.

Tutte le applet registrate su una Java Card sono candidate a fornire servizio, e di conseguenza è necessario che esista un meccanismo con cui si possa comunicare alla card quale delle applet installate deve essere mandata in esecuzione.Le Java Card supportano il protocollo di comunicazione fra la card e il lettore così come da specifiche ISO7816; questo protocollo prevede l’uso di pacchetti per la comunicazione, chiamati APDU (Application Protocol Data Units). La card

FIGURA 1 Architettura di una Java Card

La Java Card è es-

senzialmente una smart

card in grado di eseguire

programmi Java

JAVA Journal

n.1 - novembre/dicembre 200632

focus

aspetta che il lettore le invii un APDU di comando, esegue quanto richiesto e restituisce un APDU di risposta, metten-dosi in attesa di una nuova APDU di comando.Fra le molteplici APDU ne esiste una che si chiama SELECT APDU, grazie alla quale il lettore segnala alla card quale applet deve essere selezionata. La card a questo punto chiama prima il metodo deselect dell’eventuale applet che è già in esecuzione, e successivamente chiama il metodo select dell’applet identificata con l’AID (Applet Identifier) passato come parametro della SELECT APDU di cui sopra. Da questo momento in poi tutti i comandi APDU che arri-vano alla card vengono passati all’applet selezionata, fino al prossimo SELECT APDU (Figura 2).

Scrivere applet per Java Card

APDUPoiché l’applet comunica con il lettore di card e quindi con il computer “client” mediante lo scambio di APDU come abbiamo visto sopra, è necessario comprendere appieno cosa dice lo standard ISO7816 a proposito.Per cominciare, ecco i campi che compongono un APDU di comando:

1. CLA (1 byte) – classe del comando2. INS (1 byte) – istruzione del comando3. P1 e P2 (entrambi 1 byte) – parametri del comando4. Lc (1 byte) – numero di byte che compongono il succes-

sivo campo dati5. Dati (Lc byte) – dati passati al comando

6. Le (1 byte) – massimo numero di byte attesi nel campo dati della risposta al comando

Un APDU di riposta invece si compone di:

1. Dati (Le byte al massimo) – campo dati della risposta2. SW1 e SW2 (entrambi 1 byte) – stato

Nell’ambito della tecnologia Java Card, esiste un solo APDU predefinito, ovvero quello di cui abbiamo parlato sopra, il SELECT APDU; in questo caso i campi di cui sopra devono essere:

CLA=0x0, INS=0xA4, P1=0x04, P2=0x00, Lc=0x08, Data=AID, Le=0x0

Il campo Data, in questo caso formato da 8 byte come in-dicato dal campo Lc, contiene l’AID dell’applet che si vuole selezionare, che deve ovviamente essere uguale all’AID utilizzato al momento dell’installazione dell’applet sulla card.L’APDU di risposta, in caso di operazione eseguita con successo, deve contenere nei campi SW1 e SW2 il codice di stato 0x9000; negli altri casi sarà cura dell’applet assegna-re un codice di errore a quei campi.

Applet ContatoreVediamo di seguito come scrivere un’applet che implemen-ta un semplicissimo borsellino elettronico. Questo borselli-no conterrà una certa somma che verrà decrementata nelle operazioni di pagamento e incrementata nelle operazioni di versamento.

Nella progettazione di un’applet Java Card la prima cosa da fare è pianificare la comunicazione fra la card e l’appli-cazione “client”; nel caso del nostro borsellino possiamo immaginare di accettare i seguenti APDU:

1. APDU Accredito – versa una certa cifra nel borsellino, incrementando la giacenza;

2. APDU Addebito – preleva una certa cifra dal borsellino, decrementando la giacenza;

3. APDU Giacenza – ritorna la giacenza del borsellino.

Sarebbe opportuno implementare una qualche logica di sicurezza, come ad esempio fare in modo che ognuna delle tre operazioni sia vincolata dalla digitazione di un codice PIN; per semplicità invece si supporrà un borsellino “al portatore”, il cui valore massimo possa essere contenuto in due byte; le operazioni di accredito e di addebito inoltre saranno limitate ad importi rappresentabili su un solo byte – ciò significa che il borsellino potrà contenere al massimo 32767 “crediti” e le operazioni di versamento o prelievo saranno limitate a 127 “crediti” per volta.

AccreditoAPDU di comando: CLA=0x60, INS=0x61, P1=0x00, P2=0x00, Lc=0x01, Data=importo, Le=0x0APDU di risposta: Dati=null, SW1-SW2=0x9000 (OK), 0x6A00 (KO)

FIGURA 2 Lettore di Smart Card

Il protocollo ISO7816

prevede l’uso di

pacchetti APDU

JAVA Journal

n.1 - novembre/dicembre 2006 33

focus

L’importo da accreditare è specificato nel campo Data, la SW dice se l’accredito è andato a buon fine o meno (ad esempio, il borsellino è troppo pieno).

AddebitoAPDU di comando: CLA=0x60, INS=0x62, P1=0x00, P2=0x00, Lc=0x01, Data=importo, Le=0x0APDU di risposta: Dati=null, SW1-SW2=0x9000 (OK), 0x6A00 (KO)

L’importo da addebitare è specificato nel campo Data, la SW dice se l’addebito è andato a buon fine o meno (ad esempio, il borsellino non contiene abbastanza crediti).

GiacenzaAPDU di comando: CLA=0x60, INS=0x63, P1=0x00, P2=0x00, Lc=0x00,Data=null, Le=0x2APDU di risposta: Dati=giacenza, SW1-SW2=0x9000 (OK)

LISTATO 2 TalkTimerEngine

package it.mc.jctest; import javacard.framework.*; public class Borsellino extends Applet {

final static byte BorsellinoCLA=0x60; final static byte AccreditoINS=0x61; final static byte AddebitoINS=0x62; final static byte GiacenzaINS=0x63; final static short KOSW=0x6a00;

short giacenza;

private Borsellino(byte[] bArray, short bOffset, byte bLength) { register(); } public static void install(byte[] bArray, short bOffset, byte bLength) { new Borsellino(bArray, bOffset, bLength); } public boolean select() { return true; } public void deselect() { } public void process(APDU apdu) {

byte[] buffer=apdu.getBuffer();

if (buffer[ISO7816.OFFSET_CLA]==0x0 && buffer[ISO7816.OFFSET_INS]==0xA4) return; if (buffer[ISO7816.OFFSET_CLA] !=BorsellinoCLA) ISOException.throwIt( ISO7816.SW_CLA_NOT_SUPPORTED); switch (buffer[ISO7816.OFFSET_INS]) { case AccreditoINS: accredito(apdu); return; case AddebitoINS: addebito(apdu); return; case GiacenzaINS: giacenza(apdu); return; default: ISOException.throwIt( ISO7816.SW_INS_NOT_SUPPORTED); }

} private void accredito(APDU apdu) { byte[] buffer=apdu.getBuffer(); byte datalen=buffer[ISO7816.OFFSET_LC]; short readlen= apdu.setIncomingAndReceive(); if (readlen!=datalen) ISOException.throwIt( ISO7816.SW_WRONG_LENGTH); byte crediti=buffer[ISO7816.OFFSET_CDATA]; if (crediti<0) ISOException.throwIt(KOSW); if ((32767-giacenza)<crediti) ISOException.throwIt(KOSW); giacenza=(short)(giacenza+crediti); } private void addebito(APDU apdu) { byte[] buffer=apdu.getBuffer(); byte datalen=buffer[ISO7816.OFFSET_LC]; short readlen=apdu.setIncomingAndReceive(); if (readlen!=datalen) ISOException.throwIt( ISO7816.SW_WRONG_LENGTH); byte crediti=buffer[ISO7816.OFFSET_CDATA]; if (crediti<0) ISOException.throwIt(KOSW); if (giacenza<crediti) ISOException.throwIt(KOSW); giacenza=(short)(giacenza-crediti); } private void giacenza(APDU apdu) {

byte[] buffer=apdu.getBuffer(); short le=apdu.setOutgoing();

if (le!=2) ISOException.throwIt( ISO7816.SW_WRONG_LENGTH); apdu.setOutgoingLength(le); buffer[0]=(byte)(giacenza>>8);

buffer[1]=(byte)(giacenza & 0xff);

apdu.sendBytes((byte)0,le); } }

JAVA Journal

n.1 - novembre/dicembre 200634

focus

Poiché si tratta di un comando di interrogazione non sono previsti parametri passati in chiamata; ci si aspetta che i due byte rappresentativi della giacenza vengano ritornati nel pacchetto di risposta (Listato 1).

La classe Borsellino (che deve estendere la classe javacard.framework.Applet) comincia con la dichiarazione del-le variabili corrispondenti ai CLA, agli INS e ai codici di errore dell’applicazione, così come definiti nel paragrafo precedente. Il contenuto del borsellino è mantenuto nella variabile a 16 bit giacenza. Segue il costruttore dell’Applet, chiamato dal metodo install(), che da specifiche deve preoccuparsi di effettuare tutte le inizializzazioni peculiari dell’applicazione e di chiamare il metodo register(). In breve quindi il JCRE (Java card Runtime Environment) all’atto dell’installazione dell’applet Borsellino chiama il metodo install() che crea una nuova istanza dell’Applet, la quale nel costruttore deve contenere la chiamata al metodo register(). Poiché può esistere una sola istanza per applet, il metodo install() può essere chiamato con successo una sola volta.

I metodi select() e deselect() vengono invocati dal JCRE quando è necessario selezionare o deselezionare la spe-cifica applet. La selezione avviene quando la carta riceve una SELECT APDU recante l’AID dell’applet in questione. Se non si ha la necessità di effettuare delle inizializzazioni, si può tralasciare l’override di questi metodi. È importante tenere conto che il metodo select() torna true o false a secon-da che l’applet accetti la selezione o meno.

Il cuore dell’applet è senza dubbio il metodo process(APDU apdu), chiamato durante il ciclo di attività dell’applet ogni qual volta che JCRE riconosce una APDU valida, che viene passata come parametro. Poiché la ricezione di una SELECT APDU, oltre che causare la selezione dell’applet, viene passata al metodo process, è necessario che il codice preveda questo caso, ritornando semplicemente il control-lo al JCRE. Si noti come i vari campi della APDU siano fa-cilmente accessibili mediante costanti definite in ISO7816. A seguire si effettua un controllo sulla CLA della APDU per essere certi che non si sia stati chiamati con una CLA non supportata dall’applicazione, e si entra in uno switch che chiama, a seconda del campo INS, il giusto metodo di ser-vizio, gestendo come default l’eccezione di INS non servita.

Il metodo accredito(APDU apdu) costituisce un valido esempio di come si presenta un metodo che riceve dei dati dall’APDU. Essendo il campo Dati opzionale, questo non viene passato di default all’applet, ed è necessario, dopo avere estratto il numero di byte che lo compongono dal campo Lc, invocare il metodo setIncomingAndReceive(),che legge il campo Dati nel buffer; tali dati diventano quindi accessibili a partire dall’indice APDU.OFFSET_CDATA. La parte restante del metodo verifica che non si tratti di un numero negativo di crediti e che ci sia ancora “spazio” nel borsellino.Non vi è la necessità di costruire l’APDU di risposta poiché ci pensa il JCRE, utilizzando di default la SW 0x9000 se il metodo process() non solleva nessuna eccezione.

Non ci soffermeremo sul metodo addebito(APDU), poiché esso è del tutto simile al precedente, eccezion fatta per la logica di aggiornamento della giacenza.

Vediamo quindi il metodo giacenza(APDU apdu), partico-larmente interessante in quanto illustra come un metodo possa passare delle informazioni al “client” della carta (in questo caso la giacenza del borsellino). Analogamente a quanto visto prima, poiché il campo Dati nell’APDU di riposta è opzionale, è necessario che quest’ultimo venga predisposto mediante il metodo setOutgoing(), che ritorna il numero di byte del campo, uguale al campo Le dell’APDU di comando. In successione si invocano poi i metodi se-tOutgoingLength() passando come argomento il numero di byte e sendBytes() passando come argomenti l’offset a cui trovare i dati nel vettore buffer e il numero di byte da trasmettere.

Conclusioni

Quando si sviluppa del software per Java Card, codificare l’applet non basta: se infatti la card è assimilabile ad un server che espone dei servizi mediante ADPU di comando e di risposta, serve anche un client in grado di invocare tali servizi. Ecco quindi che per il test della nostra applet Bor-sellino sarà necessario sviluppare un client che generi le APDU di comando e interpreti le APDU di risposta. Il client può essere scritto in qualunque linguaggio supportato dal fabbricante del lettore di card, che mette a disposizione una serie di librerie per lo sviluppo di applicazioni per il controllo del lettore e l’interazione con le applet residenti sulla carta.

Bibliografia

http://java.sun.com/products/javacard/index.jsphttp://www.cyberflex.slb.com/http://www.cryptoflex.com/http://www.reflexreaders.com/

Quando si sviluppa del software per Java Card, codificare l’applet

non basta

Note Biografiche

Matteo Campanella. Classe 1967, ingegnere elettronico, libero professionista, si occupa di consulenze aziendali nell’ambito di open source changeover e java enterprise computing, con parti-colare riferimento ai sistemi di content management e alle web enterprise applications. Nel campo dell’elettronica si occupa di embedded systems, wireless communications e elaborazione numerica dei segnali.

JAVA Journal

n.1 - novembre/dicembre 2006 35

focus

JAVA Journal

36 n.1 - novembre/dicembre 2006

focus

Gcj: Gnu Compiler for Java

Si tratta di un’altra Java Virtual Machi-ne? Questa domanda sorge spontanea: in effetti tramite i vari tool che accom-pagnano gcj è possibile compilare ed eseguire del codice Java, esattamente

come avviene utilizzando la JVM della Sun. Ma allora dove sta la differenza?

Funzionamento classico di una JVM

L’approccio tradizionale a Java è caratterizzato da due fasi: una fase di traduzione ed una di esecuzione.Il codice sorgente viene compilato tramite il pro-gramma javac, che produce una serie di file .class contenenti la rappresentazione binaria delle infor-mazioni relative ad una classe. Queste informazioni sono tradotte in bytecode: il set di istruzioni di una macchina virtuale basata su stack. La fase di esecuzione viene gestita da una JVM (Java Virtual Machine) che ha il compito di leggere ed interpretare i file .class creati precedentemente. Una JVM può essere vista come un emulatore di una macchina il cui set di istruzioni è il Java byte-code.

Questo livello di emulazione chiaramente influisce sulle prestazioni in fase di esecuzione. Una solu-zione al problema prende il nome di JIT (Just In Time) compiler. Grazie a questa tecnica il sistema si accorge che un metodo è stato chiamato un nume-ro sufficientemente cospicuo di volte da renderne giustificabile la compilazione nativa. Tutto questo avviene a run-time.

Un problema di questo meccanismo è l’appesanti-mento delle fasi di inizializzazione: c’è bisogno di controllare quante volte un metodo viene invocato ed inoltre la compilazione richiede del tempo, so-

prattutto se si vogliono introdurre delle ottimizza-zioni. Come se non bastasse un JIT efficiente risulta esse-re molto complesso e di conseguenza richiede una quantità sensibile di memoria, il che può non essere un problema su un desktop od una workstation con una memoria di svariate centinaia di megabyte, ma è sicuramente un fattore rilevante in un sistema embedded. Infine Java nella sua implementazione classica non ha una buona interoperabilità con altri linguaggi: le chiamate fra Java e C/C++ sono lente e non banali.

Semplicemente un altro linguaggio di program-

mazione

Questo è l’approccio alla base di gcj. Java viene visto e trattato come un qualsiasi altro linguaggio basato sulla compilazione.

La tecnica utilizzata prende il nome di “Ahead of time compilation” e prevede le seguenti modalità:

• Compilazione diretta da sorgente ad istruzioni macchina

• Compilazione da sorgente a bytecode

Gcj è il compilatore Java sviluppato dalla Free Software Foundation in seno al progetto Gnu Com-piler Collection. Nato dall’idea di un dipendente di Cygnus Solutions (acquisita da RedHat nel 2000) adotta un approccio estremamente tradizionale alla compilazione ed esecuzione di codice Java.

>> di Andrea Zito ([email protected])

La tecnica utilizzata

da Gcj prende il nome di

“Ahead of time

compilation”

JAVA Journal

n.1 - novembre/dicembre 2006 37

focus

Sun JDK GNU Gcjjavac gcj -Cjava gijjavadoc gjdocjavah gcjhjavap jcf-dump

TABELLA 1 Corrispettivi Sun JDK

• Compilazione da bytecode ad istruzioni macchina

La vera potenza di gcj risiede però nella possibilità di utilizzare soluzioni miste: le vostre applicazioni potran-no essere composte da porzioni compilate nativamente ed altre interpretate! Questa caratteristica fa di gcj uno strumento veramente flessibile, che si adatta facilmente alla esigenze più disparate.

Il vantaggio che consegue dalla compilazio-ne nativa non è tanto la velocità, quanto un miglioramento nell’utilizzo della memoria. Gli sforzi profusi nel miglioramento dei JIT compiler li ha resi estremamente efficienti, tanto che in determinate situazioni possono essere più prestanti rispetto a codice nativo poiché effettuano delle ottimizzazioni in base al contesto attuale. Questo non è fat-tibile con la “ahead of time compilation” poiché la compilazione avviene in una fase precedente a quella dell’esecuzione; di con-seguenza il compilatore non ha informazioni sullo stato attuale della macchina e non può quindi effettuare ottimizzazioni dipendenti dal contesto. In generale, comunque, un eseguibile nativo risulta più veloce in fase di inizializzazione (Riquadro 1) .

Non soltanto un compilatore

Gcj non è soltanto un compilatore. È un am-biente Java completo, paragonabile al JDK della Sun. Assieme al compilatore vengono forniti un interprete di bytecode ed una serie di librerie d’appoggio che completano l’am-biente. Il cuore pulsante di gcj risiede nella sua runtime-library: libgcj. Quest’ultima si occupa di gran parte del lavoro, offrendo un garbage collector, l’interprete di bytecode e un ClassLoader capace di gestire sia librerie native che file .class.

La Tabella 1 riporta l’equivalente di alcuni dei tool disponibili nel JDK della Sun.

Prima compilazione

Adesso che abbiamo un idea di cos’è e di quello che è capace di fare, sporchiamoci le

mani con la prima compilazione nativa tramite gcj. Come primo esempio ci avvarremo del codice riportato nel Li-stato 1, che stampa sullo standard output la famosa frase: Hello World!Per rendere il tutto più interessante useremo due classi interdipendenti.

Il processo che porta ad ottenere un eseguibile si divide in due parti, la compilazione ed il linking. Per chiunque abbia usato almeno una volta il compilatore gcc la prima fase risulterà molto familiare, per quanto ri-guarda seconda invece ci sarà qualche novità.

La prima cosa da fare è istruire gcj su quali file desi-deriamo vengano convertiti in linguaggio macchina:

gcj -c HelloWorld.java Printer.java

Questo comando farà si che i sorgenti vengano

RIQUADRO 1 Un semplice benchmark sulle prestazioni in termini di velocità di esecuzione ed utilizzo di memoria di gcj e del Sun JDK 1.5

Abbiamo usato SciMark2 (http://math.nist.gov/scimark2) per effettuare un veloce benchmark che prendesse in esame velocità ed utilizzo di memoria di gcj (v. 4.0.2) e Sun JDK 1.5.

I test sono stati eseguiti su un Athlon 1000 equipaggiato con 768 Mb di RAM ed è stato uti-lizzato il pacchetto jar disponi-bile al download sul sito di Sci-Mark.Il tempo di esecuzione è stato misurato utilizzando il coman-do time, per l’utilizzo di memo-ria ci si è invece affidati a ps.

L’eseguibile nativo è stato com-pilato con queste opzioni:gcj –main=jnt.scimark2.commandline -O3 -o sci-mark scimark2lib.jar

Le prove sono state effettua-te invocando scimark in que-sto modo:• Nativo: ./scimark• Interpretato: java -cp scimark2lib.jar jnt.scimark2.commandline

SciMark2 può essere eseguito in due modalità: normal e large. La scelta di una piuttosto che l’altra determinerà la comples-sità computazionale del test.

Per maggiore completezza il test è stato effettuato in entrambi i modi.

Velocità di esecuzioneModalità normal:• Sun JDK: 27415 ms• Gcj: 29248 ms

Modalità large:• Sun JDK: 63188 ms• Gcj: 60324 ms

Utilizzo di memoria

Modalità normal

Imple-menta-zione

VM Size (kb)

VM RSS (kb)

Sun JDK 1.5

261436 10472

Gcj 4.0.2 30188 12684

Modalità large

Imple-menta-zione

VM Size (kb)

VM RSS (kb)

Sun JDK 1.5

260412 70364

Gcj 4.0.2 94936 77692

JAVA Journal

n.1 - novembre/dicembre 200638

focus

main per il test delle unità (come avviene nel nostro esempio). Questo comportamento confonde il linker che non sa individuare quale fra i diversi main è quello da cui il programma deve iniziare. Per questo motivo gcj introduce il nuovo switch –main tramite il quale è pos-sibile specificare il percorso completo della classe da cui deve essere iniziata l’esecuzione. Se per esempio la calsse HelloWorld si fosse trovata all’interno del package it.javajournal.gcj, la chiamata corretta sarebbe dovuta essere:

gcj –main=it.javajournal.gcj.HelloWorld -o hello HelloWorld.o Printer.java

A questo punto l’eseguibile è stato creato e linkato alla runtime-library di gcj, tutto è pronto per l’esecuzione.

Librerie dinamiche

In determinate situazioni risulta conveniente compilare porzioni di codice in librerie condivise, così da ottimizzare l’utilizzo di memoria (sia primaria, che secondaria). Per ottenere questo scopo gcj utilizza lo switch -shared, oltre ad una serie di opzioni aggiuntive non strettamente ne-cessarie che però portano a delle ottimizzazioni a vari livelli. Per proporre un esempio pratico, compiliamo Printer.java come libreria dinamica ed agganciamolo a HelloWorld.

La prima fase ora si svolge in due parti:

1. compilazione di Printer.java come libreria dinamica2. compilazione canonica di HelloWorld.java

Il punto 1 si ottiene invocando gcj nel seguente modo:

gcj -shared -fPIC -fjni Printer.java -o libprinter.so

I primi due switch sono parametri standard della creazione di librerie di-namiche, -fjni istruisce il compilatore sul modo in cui trattare i metodi nativi, nello specifico fa in modo che venga usato JNI al posto di CNI (l’implemen-

tradotti nei file HelloWorld.o e Printer.o che ne sono la rappresentazione binaria. In questa fase è possibile spe-cificare tutte le opzioni di ottimizzazione desiderate. A questo punto il nostro programma è in un formato com-prensibile dal computer, ma per funzionare devono essere agganciate fra loro tutte le componenti e le librerie esterne di cui necessita, una su tutte la runtime-library di cgj. Per ottenere questo risultato usiamo il seguente comando:

gcj –main=HelloWorld -o hello HelloWorld.o Printer.o

Come accennato precedentemente, gcj necessita di un parametro aggiuntivo rispetto a quanto accade per gcc. In C/C++ un programma può essere composto da più file ma solamente uno di questi può contenere il metodo main, di conseguenza il linker è sempre in grado di capire da solo quale è la porzione di codice che deve essere ese-guita inizialmente.

In Java invece è pratica comune creare diversi metodi

File HelloWorld.java: 1 class HelloWorld{2 public static void main(String[] args){3 Printer p = new Printer();4 p.print(“Hello World!”);5 }6 }

File Printer.java: 1 class Printer{2 public void print(String s){3 System.out.println(s);4 }56 public static void main(String[] args){7 System.out.println(“Unit testing: OK”);8 }9 }

LISTATO 1 Codice sorgente di HelloWorld.java e Printer.java fornito con gcj 4

FIGURA 1 Schermata comparativa delle 3 librerie per sviluppare applicazioni grafiche. Dall’alto verso il basso: Swing (disponibili da Classpath 0.20), SwingWT, SWT.

Il cuore pulsante di

gcj risiede nella runtime

library: libgcj

JAVA Journal

n.1 - novembre/dicembre 2006 39

focus

tazione ottimizzata di gcj per l’accesso ai metodi nativi) che sarebbe altrimenti utilizzato per default. Quest’ulti-mo parametro non è influen-te sul nostro esempio poiché non viene fatto uso di metodi nativi, ma in presenza di que-sti è molto probabile che tale opzione si renda necessaria. Un eventuale omissione por-terebbe ad avere diversi errori in fase di linking.

Il punto 2 ricalca esattamen-te la procedura seguita nel primo esempio. Una volta che entrambi i file sono stati compilati bisogna eseguire il linking:

gcj –main=HelloWorld -o shello HelloWorld.o -lprinter

In questo modo viene creato l’eseguibile shello, che, nel momento in cui viene lan-ciato, si aggancia alla libreria libprinter.so usufruendo dei

suoi servizi. Perchè la compilazione e la successiva esecuzione abbiano esito positivo il sistema deve riuscire a trovare la nostra libreria, questa deve cioè trovarsi all’interno del path del linker. Per apportare delle modifiche locali a tale path è sufficiente agire sulla variabile d’ambiente LD_LIBRARY_PATH.

Un cocktail al gusto di caffè: nativo e bytecode

Adesso che abbiamo scoperto quanto è vantaggioso l’utilizzo delle librerie dinamiche, potremmo volerci spingere un passo più in là. Considerate lo scenario in cui una azienda esterna sviluppa un modulo per il vostro software, ma non ha l’interesse o le cono-scenze necessarie per fornire una versione nativa dello stesso per tutte le piattaforme target. Sareste disposti a rinunciare al contributo di questa azien-da? Probabilmente no.

Gcj ci viene in soccorso anche in questo caso, infatti ci offre la possibilità di creare applicazioni miste, in parte native e in parte interpretate. Il tutto in modo assolutamente trasparente al programmatore/utilizzatore. Nel momento in cui gcj trova un riferi-mento ad una classe esterna, per prima cosa ne cerca una versione nativa e solamente nel caso questa non fosse disponibile tenta la strada dell’interpretazio-ne.

Per chiarirci le idee osserviamo il Listato 2, in cui possiamo vedere un’applicazione che carica dinami-camente tramite Class.forName due moduli esterni, dei quali uno verrà compilato nativamente, l’altro

in bytecode.

LISTATO 2 Sorgenti della nostra applicazione e dei due moduli, Foo e Bar. Il primo verrà compilato in bytecode, l’altro nativamente

File App.java package it.javajournal; class App{ public static void main(String[] args) throws Exception{ Class f = Class.forName(“it.javajournal.Foo”); Object foo = f.newInstance();

Class b = Class.forName(“it.javajournal.Bar”); Object bar = b.newInstance(); } }File Foo.java package it.javajournal; class Foo{ public Foo(){ System.out.println( “Questo è il modulo Foo”); } }File Bar.java package it.javajournal; class Bar{ public Bar(){ System.out.println( “Questo è il modulo Bar”); } }

FIGURA 2 Eclipse compilato nativamente

JAVA Journal

n.1 - novembre/dicembre 200640

focus

La compilazione in bytecode del modulo Foo si ottiene banalmente con:

gcj -C it/javajournal/Foo.java

Per quanto riguarda Bar invece useremo le nozioni appre-se poc’anzi per creare una libreria dinamica:

gcj -shared -fPIC -o lib-it-javajournal-Bar.so it/javajournal/Bar.java

A questo punto passiamo alla compilazione del corpo dell’applicazione:

gcj –main=it.javajournal.App -o app it/javajournal.App.java

Avrete sicuramente notato il fatto che all’atto della compi-lazione di App non è specificata nessuna libreria. Infatti dal momento che ci avvaliamo dei servizi di Bar mediante Class.forName non è necessario specificare al linker dove si tro-va tale modulo. Nel momento in cui gcj si trova di fronte al metodo forName cerca una li-breria dinamica, contenente la classe desiderata, che segua il pattern: lib-<percorso-completo-del-package>-<NomeClasse>. Se invece avessimo deciso di essere più generosi nei dettagli, avremmo potuto istruire gcj su quale libreria utilizzare diretta-mente all’atto della compilazio-ne, eliminando di conseguenza

il vincolo sul nome:

gcj –main=it.javajournal.App -o app it/javajournal.App.java -lBar

Grazie a questa aggiunta gcj è in grado di accorgersi subito che la classe desiderata si trova all’interno della libreria libBar.so.

In entrambi i casi la libreria si deve trovare all’interno del path del linker, pena il lancio di un’eccezione Clas-sNotFoundException , nel primo caso, o un errore in fase di compilazione nel secondo.

Un compilatore non basta

Gli strumenti necessari per sviluppare ed eseguire un programma Java sono fondamental-mente tre:

• un compilatore• una Virtual Machine/Runtime library• le librerie contenti il codice fornito con J2SE/J2EE

Le prime due componenti sono fornite dal progetto Gcj, però manca ancora un tassello... un tassello di enorme im-portanza. Tutto quello di cui abbiamo parlato finora si riduce ad un semplice giochino, per quanto intrigante, se non possiamo accedere alla vastissima libreria che il linguaggio ci fornisce.

Gnu Classpath

Purtroppo il codice rilasciato dalla Sun è coperto da una licenza che non ne

FIGURA 3 Applicazione demo creata con la libreria SwingWT

FIGURA 4 Alcuni widget offerti da SWT

JAVA Journal

n.1 - novembre/dicembre 2006 41

focus

permette la redistribuzione con Gcj, rendendolo quindi inadatto.

Fortunatamente un altro progetto Gnu ha esattamente questo scopo: sviluppare una versione libera delle libre-rie che stanno alla base di J2SE. La percentuale delle componenti implementate rispetto al JDK 1.4 può es-sere controllato direttamente sul sito di Classpath (http://www.gnu.org/software/classpath/); al momento in cui scrivo questo articolo è circa il 98%.

Una delle mancanze più pesanti all’interno di Classpath è sicuramente Swing. Gli sforzi per raggiungere una imple-mentazione completamente funzionante sono molti, ma ci vorrà ancora un po’ di tempo prima di poter eseguire una applicazione Swing complessa, come ad esempio NetBeans, tramite gcj+Classpath.

È possibile comunque sviluppare applicazioni grafiche mediante le librerie SWT, che grazie alla loro natura open source, si prestano ottimamente alla compilazione nativa ed in generale all’utilizzo con implementazioni libere di Java.

Altre librerie utili

Altre librerie libere che vanno a completare il puzzle sono:• GNU ClasspathX: librerie aggiuntive a J2SE (Java-

Mail, JAXP, Activation Framework ecc).• Jessie: Java Secure Sockets Extension.• GNU Crypto: cryptographic primitives.• SwingWT: implementazione delle API Swing/AWT

sopra la libreria SWT.

Conclusioni

Gnu gcj è uno strumento flessibile e potente grazie al quale potrete sviluppare applicazioni che non richiedono una Virtual Machine per essere eseguite e nello stesso tempo necessitano di un quantitativo minore di memo-ria. Queste caratteristiche lo rendono particolarmente attraente agli sviluppatori di applicazioni embedded.

Il supporto agli statement e direttive di Java 1.4 è com-pleto, mentre è attualmente in corso lo sviluppo per integrare anche le aggiunte fatte con Java 1.5. Questo processo di integrazione si è protratto per lungo tempo poiché è stato deciso di riscrivere da zero il frontend a gcc in modo da rendere meno dispendiosa l’integrazione futura di eventuali aggiunte al linguaggio.

La sua natura libera (Gcj come tutti gli altri progetti della Gnu sono Free Software) ha anche il significativo vantag-gio di avvicinare a Java molti sviluppatori della comunità FOSS che fino ad oggi avevano evitato questo linguaggio, non per ragioni tecniche, ma di licenza.

RIQUADRO 2 Introduzione all’ABI per la compatibilità binaria fornito con gcj 4

Gcj Binary Compatibility ABI

Alcune applicazioni sono scritte assumendo che verrano eseguite solamente all’interno di una Virtual Machine, facendo assunzioni sull’ambiente in cui si trovano. Que-sta pratica rende molto complicato compilare tali pro-grammi nativamente, a meno di pesanti modifiche al co-dice sorgente.Nello specifico questi programmi contengono il codice per leggere stream di bytecode e caricarli come classi tramite il metodo ClassLoader.defineClass(). Un esempio molto cono-sciuto di tali applicazioni, in cui praticamente tutte le com-ponenti sono caricate in questo modo, è Eclipse.Il problema che questa pratica comporta a gcj è molto semplice: non esiste bytecode per una classe compilata nativamente e di conseguenza non è possibile creare uno stream da passare al ClassLoader.Per ovviare a questo problema gcj v.4 ha introdotto una nuova modalità di compilazione, attivabile tramite lo swith -findirect-dispatch ed un nuovo strumeto: gcj-dbtool.

Questo tool genera un file .db che mappa una versione compilata di una classe, alla sua controparte in bytecode. Durante la compilazione nativa, quando gcj incontra de-fineClass(), il bytecode passato viene confrontato (trami-te la mappa contenuta nel file .db) con le librerie dinami-che contenenti le classi native.Perché durante l’esecuzione gcj sappia quale file .db usare è necessario specificare tramite la proprietà gnu.gcj.precompiled.db.path il percorso di quest’ultimo.Grazie a questo meccanismo, gcj è in grado di utilizzare la versione nativa della classe in questione, al solo costo di mantenere anche la versione in bytecode.Il flag -findirect-dispatch attiva l’ABI per la compati-bilità binaria. Quest’ultima oltre ad essere necessaria per il funzionamento del meccanismo descritto poc’an-zi, porta benefici a tutte le applicazioni, garantendone il funzionamento anche nel momento in cui venissero introdotti cambiamenti alla libgcj, senza bisogno di ri-compilare. In futuro diventerà il metodo di compilazio-ne standard.

Note Biografiche

Andrea Zito è studente presso la facoltà di Scienze Informatiche di Trento. È appassionato di Gnu/Linux e di software libero; da qualche anno usa Java come linguaggio principale per lavoro e per studio.

JAVA Journal

42 n.1 - novembre/dicembre 2006

focus

Java MEsviluppare applicazioni per cellulari e PDA

La storia del linguaggio Java inizia nei primi anni ‘90, grazie ai risultati del brillante Green Project. L’obiettivo della semplicità nella scrittura del codice e di alta portabilità tra diverse architetture hardware portarono alla definizione del linguaggio Oak e alla

realizzazione dell’innovativa piattaforma “*7” (la prima applicazione di Java) . Inizialmente si mirava al settore della TV via cavo, ma quanto fino ad al-lora ottenuto apparve particolarmente efficace per risolvere un problema emergente, complice la ina-spettata e rapida diffusione del web: la possibilità di distribuire codice applicativo insieme alle pagine web (codice embedded, ancora una volta!) con il requisito di avere portabilità tra diverse piattaforme hardware (in teoria qualsiasi PC dotato di un web browser, all’epoca Netscape). Nacque Java e le Ap-plet: fu l’inizio di una nuova classe di applicazioni. Negli anni successivi il linguaggio e la libreria stan-dard sono stati arricchiti, portando la tecnologia Java in ambiti quali le applicazioni desktop e i servi-zi enterprise che sembravano appannaggio solo del software scritto in codice nativo (C/C++). Proprio in ambito server, invece, con la piattaforma J2EE, Java ha dimostrato di essere una tecnologia estre-mamente potente, flessibile e robusta. Nel 2001 (6 anni dopo il rilascio delle prime specifiche Java) vennero rese pubbliche le prime implementazioni di CLDC e MIDP: nasceva la piattaforma Java2 Micro Edition (J2ME), rinominata lo scorso anno Java Platform, Micro Edition (Java ME). Il ritorno al settore embedded/consumer è un successo straordi-nario e i numeri lo confermano: 650 modelli di ter-minali Java ME compatibili, con più di 700 milioni

di unità vendute, 150 operatori di telefonia mobile e più di 350 mila sviluppatori nel mondo supportano la piattaforma, mentre mensilmente vengono scari-cate sui telefonini 23 milioni di applicazioni.

Configurazioni e Profili

Rispetto agli ambienti desktop e server, il mondo dei dispositivi mobili è straordinariamente vario. Nume-rose le combinazioni di sistemi operativi (proprietari e non), piattaforme hardware, classi di dispositivi, mercati di riferimento: una architettura monolitica non potrebbe abbracciare un’offerta così vasta. Al fine di essere adattata al maggior numero di tipi di dispositivi, la piattaforma Java ME è organizzata in livelli componibili e, in certa misura, intercambiabili. In questo modo i produttori dei dispositivi possono decidere, in base alle funzionalità supportate dal-l’hardware e agli obiettivi di mercato, quali livelli im-plementare e, dunque, adattare il runtime Java. Tale modularità è ottenuta attraverso una organizzazione in Configurazioni, Profili ed API opzionali.

Java Micro Edition (Java ME) è la piattaforma leader per lo sviluppo di applicazioni multidevi-ce per telefoni cellulari, palmari e dispositivi embedded. Grazie ad una architettura modulare e ad una ricca collezione di API opzionali, in soli 5 anni ha conquistato il mercato dei dispositivi mobili e si appresta alla soglia del miliardo di terminali abilitati già in circolazione. In questo articolo in-troduciamo questa affascinante tecnologia.

>> di Stefano Sanna ([email protected])

La piattaforma

Java ME è organizzata

in livelli componibili e

intercambibili

JAVA Journal

n.1 - novembre/dicembre 2006 43

focus

Configurazioni: CDC e CLDC

La configurazione costituisce l’insieme minimo di fun-zionalità esportate da una famiglia di dispositivi caratte-rizzati dal medesimo hardware di base. Qualche esempio potrà chiarire meglio questa definizione. Si considerino i seguenti dispositivi: un telefono cellulare entry-level, un computer palmare di fascia alta, un piccolo cercapersone tascabile, un decoder (detto anche set-top box) per la TV interattiva, un modulo embedded per il controllo remoto di un distributore di bibite, un sistema di navigazione satellitare per auto. Ciascuno di questi oggetti svolge una funzione ben precisa; ciononostante è possibile, con buona approssimazione, aggregarli in due gruppi caratte-rizzati da prestazioni hardware similari. Un primo gruppo comprende palmari, set-top box e sistema di navigazione: questi dispositivi sono caratterizzati da una buona capaci-tà di elaborazione, memorizzazione e connettività. Anche i requisiti di alimentazione sono abbastanza simili (gli utilizzatori di PDA sanno che l’autonomia delle batterie è ancora un fattore critico). Il secondo gruppo comprende i cellulari (escludendo, dunque, i palmari con funzionalità telefoniche), pager, sistemi embedded: questi dispositivi sono caratterizzati da modeste capacità di elaborazione,

memorizzazione e connettività limitate, mentre l’alimen-tazione è verosimilmente fornita da piccoli accumulatori. Da questa suddivisione scaturiscono le due configurazio-ni attualmente rilasciate: CDC (Connected Device Confi-guration) e CLDC (Connected, Limited Device Configu-ration). La prima è destinata a equipaggiare dispositivi dotati di memoria minima complessiva di 1MB, connet-tività elevata e soprattutto hardware sufficientemente potente da poter eseguire una implementazione della Virtual Machine standard. Viceversa, la CLDC destinata a dispositivi con memoria totale (ROM + RAM) di 512KB, connettività limitata su canale a banda stretta, funzio-namento marcatamente discontinuo e interfaccia grafica ridotta; il runtime environment prevede una virtual ma-chine dedicata e opportunamente ridotta. La configura-zione determina la ricchezza della libreria standard, la complessità del modello multithreading, la presenza di supporto per l’aritmetica in virgola mobile o per l’invo-cazione di metodi nativi (dunque la presenza della Java Native Interface, JNI). Nel caso di CLDC, l’intera libreria standard (java.lang, java.io, java.util...) è notevolmente semplificata (priva di float e double nella versione 1.0). Questa configurazione ha introdotto il GCF (Generic Connection Framework), una infrastruttura estendibile

FIGURA 1 Configurazioni, Profili e API opzionali di Java ME

JAVA Journal

n.1 - novembre/dicembre 200644

focus

per l’implementazione del supporto alla connettività. Esso permette di aggiungere il supporto a nuovi sistemi di comunicazione (ad esempio, Bluetooth o messaging) senza che sia necessario modificare la gerarchia standard delle classi e garantendo, entro certi limiti, massima com-patibilità delle applicazioni (Figura 1).

Profili: MIDP e gli altri

Mentre le configurazioni stabiliscono le caratteristiche comuni a una certa famiglia di hardware, i profili sono la specializzazione per uno specifico prodotto (o insieme di prodotti). Sulla CLDC sono basati i profili MIDP e IMP. Il profilo MIDP (Mobile Information Device Profile) è desti-nato ad equipaggiare telefoni cellulari e computer palma-ri di classe consumer. Il profilo IMP (Information Module Profile), viceversa, è destinato al mercato dei controllori embedded avanzati; esso, dunque, è destinato ad essere installato in macchinari e strumenti per i quali siano necessarie funzionalità di programmabilità, elaborazione di segnali analogici e digitale, controllo di attuattori (ad esempio, motori) e soprattutto di connettività su rete IP (generalmente attraverso rete telefonica GPRS). Si può pensare a IMP come ad una specializzazione di MIDP, in cui è stata eliminata la sezione dedicata all’interfaccia grafica (generalmente inutile o comunque sostituita da hardware dedicato) e aggiunta la gestione degli input e output analogici e digitali. Su CDC si basano attualmente tre profili: FP (Foundation Profile), PBP (Personal Basis

Profile) e PP (Personal Profile). Presi nell’ordine, aggiun-gono funzionalità sempre più complesse alla configura-zione, a partire dalla GUI elementare di FP fino alla im-plementazione completa di AWT fornita da PP. Il Personal Profile può essere riconosciuto, da chi (come l’autore) ha lavorato fin dalle prima implementazioni di Java su PDA, come il successore del PersonalJava, il primo tentativo storico di realizzare un Java per dispositivi embedded.

Panoramica di MIDP 2.0

MIDP è il profilo supportato dalla maggior parte dei terminali in circolazione; in particolare, la versione 2.0 equipaggia la totalità dei modelli di nuova commer-cializzazione (di seguito si farà riferimento a questa versione). MIDP fornisce il supporto alla connettività via HTTP (requisito minimo), persistenza sulla memo-ria del dispositivo, interfaccia grafica a componenti, set minimale di classi per la riproduzione di contenuti multimediali, classi accessorie di supporto allo svilup-po della grafica dei videogiochi (tali classi sono cono-sciute con il nome di Game API). Le classi specifiche della piattaforma Java ME sono contenute nei package javax.microedition.*. La prima particolarità rispetto alla piattaforma standard è la gestione del ciclo di vita delle applicazioni. Queste sono chiamate MIDlet e sono ge-stite dall’Application Manager del dispositivo, respon-sabile della installazione, rimozione, avvio, sospensione e interruzione di ciascuna applicazione. L’interfaccia di gestione dell’Application Manager dipende dal disposi-tivo in uso mentre l’interazione con la MIDlet è gestita attraverso l’invocazione del costruttore e di tre metodi accessori. Il costruttore della MIDlet viene invocato al primo caricamento dell’applicazione, mentre all’avvio vero e proprio l’Application Manager invoca il metodo startApp(). Questo metodo potrebbe essere invocato più volte durante la vita dell’applicazione: in caso di neces-sità, infatti, l’Application Manager potrebbe richiedere all’applicazione di sospendere l’esecuzione (attraverso l’invocazione del metodo pauseApp()) per poi riprenderla in seguito. Infine, l’invocazione del metodo destroyApp()

FIGURA 2 Il ciclo di vita di una MIDlet

I profili sono la

specializzazione per uno

specifico prodotto

(o insieme di prodotti)

JAVA Journal

n.1 - novembre/dicembre 2006 45

focus

LISTATO 1 TalkTimer introduzione

segnalerà che l’utente ha richiesto esplicitamente la chiusura dell’applicazione (Figura 2).

L’interfaccia grafica è costituita da una gerarchia di Di-splayable, visualizzati alternativamente da un Display, a cui la MIDlet è associata. Tra i Displayable vi sono i Form, ai quali è possibile aggiungere componenti quali Text-Field, radio button, slider; vi sono diversi tipi di liste e la classe Canvas, che ricorda l’omonima presente in AWT. Le classi di MIDP permettono la gestione dei softbutton, generalmente situati alla base del display del terminale, attraverso oggetti Command assimilabili ai MenuItem della piattaforma standard. Un’altra caratteristica pecu-liare di MIDP è relativa al rilascio delle applicazioni, che possono essere aggregate in Suite, all’interno della quale le MIDlet condividono le classi e le informazioni memo-rizzare sul servizio di persistenza. Il rilascio dell’applica-zione consiste nella coppia di file JAR e JAD. Il file JAR, come consuetudine, contiene le classi dell’applicazione e delle librerie accessorie, eventuali file di property e altre risorse. Il file JAD (Java Application Descriptor) è un file di testo contenente informazioni sull’applicazione: URL e dimensione del file JAR, nome e classe di avvio di ciascuna MIDlet, property per l’avvio dell’applicazione e soprattutto contiene indicazioni su configurazione e profilo minimi necessari per l’esecuzione. L’applicazione d’esempio di questo articolo ha il JAD file che segue:

FIGURA 3 Il TalkTimer in esecuzione nel Wireless Toolkit, nella Nokia Developer’s Suite e su Windows Mobile 2003 (attraverso remote display)

package it.javajournal.talktimer; import javax.microedition.midlet.*;import javax.microedition.lcdui.*; public class TalkTimer extends MIDlet { TalkTimerEngine gui; public TalkTimer() { gui = new TalkTimerEngine(); gui.display = Display.getDisplay(this); } public void startApp() { Display.getDisplay(this).setCurrent (gui); } public void pauseApp() { } public void destroyApp( boolean unconditional) { }

}

JAVA Journal

n.1 - novembre/dicembre 200646

focus

MIDlet-1: TalkTimer, TalkTimer.png, it.javajournal .talktimer.TalkTimerMIDlet-Jar-Size: 3528MIDlet-Jar-URL: TalkTimer.jarMIDlet-Name: TalkTimerMIDlet-Vendor: My CompanyMIDlet-Version: 1.0MicroEdition-Configuration: CLDC-1.0MicroEdition-Profile: MIDP-2.0

Attraverso queste informazioni, prima di scaricare il file JAR, l’Application Manager può determinare la com-patibilità del runtime e segnalare all’utente eventuali anomalie. Ad esempio, una applicazione basata su CLDC 1.1 (con supporto dell’aritmetica in virgola mobile), non verrà eseguita su un dispositivo CLDC 1.0. Il file JAD vie-ne creato automaticamente dai tool di sviluppo Java ME; essi provvedono anche a replicare le informazioni del file JAD all’interno del file MANIFEST del JAR (con l’esclu-sione dell’URL di quest’ultimo).

L’installazione dell’applicazione sul dispositivo può avve-nire con diverse modalità: attraverso download via web/wap (detto OTA, Over-The-Air, che indica il trasferimento effettuato su canale radio), per mezzo del software di ge-

stione fornito dal produttore del terminale (dunque con il supporto di un PC), via Bluetooth o Infrarossi (tecni-camente detto OBEX Push, modalità non supportata da tutti i terminali).

La prima applicazione Java ME

Le classi di MIDP 2.0 permettono di realizzare appli-cazioni di media complessità, dotate di supporto alla connettività HTTP, persistenza sul dispositivo e grafica in movimento. Per prendere confidenza con la piattaforma Java ME è sufficiente scrivere una MIDlet semplice ma efficace. Si vuole realizzare un semplice timer (TalkTi-mer), da utilizzarsi, ad esempio, durante un seminario: il relatore, all’inizio della presentazione avvierà l’appli-cazione, impostando la durata del proprio intervento. Durante l’esposizione potrà verificare sul display il tempo a sua disposizione e al termine di quest’ultimo un segnale sonoro lo avviserà. La classe di avvio, TalkTimer, estende MIDlet e inizializza la classe TalkTimerEngine, responsa-bile della gestione dell’interfaccia grafica e del timer vero e proprio (Listato 1)

Nel costruttore viene istanziata la classe responsabile

TABELLA 1

API Descrizione

Wireless Messaging API 1.1 e 2.0 (WMA, JSR 120, 205)

Permette l’invio e la ricezione di brevi messaggi, sia in formato testo che binario. Probabilmente è l’API opzionale maggiormente diffusa, anche su modelli entry-level (WMA 2.0 solo su terminali di fascia alta).

Mobile Media API (MMAPI, JSR 135) Fornisce il supporto base per la riproduzione e l’acquisizione di contenuti multimediali audio e video.

Mobile 3D Graphics (M3G, JSR 184) Implementa una ricca libreria per la grafica 3D. Sono stati annunciati cellulari con accelerazione hardware per la M3G.

Java APIs for Bluetooth (BTA, JSR 82) Fornisce i meccanismi per il discovery di device e servizi Bluetooth. OBEX e SPP tra i servizi supportati.

Location API (JSR 179) Permette lo sviluppo di applicazioni basate sulla posizione, con una interfaccia astratta verso sistemi di localizzazione mobile e gestione landmark.

FileConnection & PIM API (JSR 75) Si tratta di funzionalità opzionali ereditate dal PDAP (Pda Profile), che avrebbe dovuto affiancare MIDP nel supporto Java su palmari e telefoni hi-end. In realtà PDAP non vide mai la luce e dalla specifica rimasero questi due importantissimi package, che forniscono supporto ai servizi di Personal Information Management (PIM) e al file system del dispositivo.

Scalable 2D Vector Graphics API (JSR 226) Fornisce supporto alla gestione e visualizzazione di file SVG.

Web Service API (WSA, JSR 172) Implementa le funzionalità di parsing XML e invocazione di metodi remoti su interfaccia Web Service conforme alle specifiche WS-I Basic Profile 1.0

JAVA Journal

n.1 - novembre/dicembre 2006 47

focus

della gestione dell’interfaccia grafica, mentre la visua-lizzazione avviene all’interno del metodo startApp(). Il metodo setCurrent() del display assegnato alla MIDlet permetterà la visualizzazione del Form iniziale. Quest’ul-timo è implementato dalla classe TalkTimerEngine (visi-bile in Listato 2), la quale gestisce gli eventi della gui ed è incaricata dell’avvio e arresto del timer. Il metodo init() provvede a istanziare i componenti e assemblare l’inter-faccia grafica del Form (Listato 2).

All’interno dello stesso metodo si definisce un Timer-Task: questo, unito alla classe Timer, costituisce una specializzazione delle classi Thread e Runnable, arricchiti

LISTATO 2 TalkTimerEngine

package it.javajournal.talktimer; import javax.microedition.lcdui.*;import java.util.Timer;import java.util.TimerTask;import javax.microedition.media. Manager; public class TalkTimerEngine extends Form implements CommandListener {

Display display; private TextField timerField; private StringItem timerItem; private Command startCommand; private Command stopCommand; private int counter; private Timer timer; private TimerTask timerTask; public TalkTimerEngine() { super(“TalkTimer”); init(); } private void init() { // gui startCommand = new Command( “Start!”, Command.SCREEN, 1); stopCommand = new Command (“Stop!”, Command.SCREEN, 2); addCommand(startCommand); addCommand(stopCommand); setCommandListener(this); timerField = new TextField( “Durata (minuti):”, “”, 2,TextField.NUMERIC); timerItem = new StringItem( “Time:”, “”); append(timerField);

// timer timer = new Timer(); timerTask = new TimerTask() { public void run() { counter -= 1; timerItem.setText( Integer.toString(counter)); if (counter == 0) { alarm(); this.cancel(); } } }; } public void commandAction( Command c, Displayable d) { if (c == startCommand) { delete(0); append(timerItem); counter = Integer.parseInt( timerField.getString()); timer.schedule( timerTask, 1000, 60000); } else if (c == stopCommand) { timer.cancel(); delete(0); append(timerField); } } private void alarm() { try { Manager.playTone(0x45, 500, 100); } catch(Exception e) { // non essendo possibile riprodurre // un suono, mostriamo un Alert Alert alert = new Alert( “Attenzione!”, “Tempo scaduto”, null, AlertType.ALARM); display.setCurrent(alert, this); } } }

con metodi per la sospensione e la ripetizione ciclica temporizzata di blocchi di codice (contenuti all’interno del classico metodo run()). Il metodo commandAction(), definito nell’interfaccia CommandListener, è invocato dal runtime alla pressione di un bottone del cellulare (det-to softbutton) assegnato al Command. La selezione del Command “start” provoca l’assegnazione del TimerTask definito nel metodo init() all’interno dello scheduler del Timer. Ogni 60 secondi, il Task verificherà se è trascorso il tempo a disposizione ed eventualmente, attraverso il me-todo alarm(), notificherà all’utente il timeout attraverso l’emissione di un breve tono (Figura 3).

JAVA Journal

n.1 - novembre/dicembre 200648

focus

Note Biografiche

Stefano Sanna si occupa di sviluppo di applicazioni multime-diali per piattaforma Savaje presso Beeweeb Technologies (http://www.beeweeb.com). Ha lavorato per sette anni nel gruppo Network Distributed Applications del CRS4, occupandosi di mobile computing e applicazioni network-oriented per cellula-ri e PDA. Collabora attivamente con JIA, JUG Sardegna e Java Mobile Developers Forum. Il sito sito web personale e’http://www.gerdavax.it

Le API opzionali

Quanto descritto finora rappresenta una frazione delle potenzialità di Java ME. La grande forza della piatta-forma risiede nelle API opzionali, che arricchiscono il runtime Java di funzionalità base e avanzate. Alcune librerie sono da tempo a corredo della maggior parte dei dispositivi (ad esempio, la gestione degli SMS), altre sono presenti solo su modelli di fascia alta (ad esempio, il sup-porto completo a Bluetooth), altre ancora sono appena state rilasciate e si attende l’imminente apparizione dei modelli di prossima commercializzazione. In tabella sono riportate alcune delle API più significative (Tabella 1):

Sul sito del Java Community Process sono attualmente elencate 79 Java Specification Request, a conferma della vivacità che ruota attorno al mondo Java ME.

Strumenti di sviluppo

Per affrontare lo sviluppo di applicazioni per dispositivi Java ME è necessario utilizzare strumenti dedicati. Ri-spetto a Java SE, le applicazioni per dispositivi mobili, prima di essere distribuite, passano attraverso un pro-cesso di preverifica; questo è operato dalla Java Virtual Machine standard in fase di esecuzione, mentre in ambi-to MIDP le ridotte prestazioni dei dispositivi impongono che parte della verifica del bytecode sia effettuata prima del rilascio definitivo. Il runtime Java effettua comunque dei controlli, anche se meno onerosi e complessi della preverifica. Il passo successivo è l’esecuzione all’interno di un emulatore, che permette una prima valutazione dell’applicazione e facilita il debugging. Per CLDC/MIDP Sun Microsystems fornisce il Java Wireless Toolkit (WTK), una collezione di tool a linea di comando e una utility grafica per la compilazione, preverifica e packaging dell’applicazione. Per realizzare una nuova applicazione è sufficiente creare un nuovo progetto e indicare il nome (completo di package) della MIDlet. Il WTK associa una directory all’interno del proprio repository, contenuto nella directory ROOT_WTK\apps (ROOT_WTK è la car-tella di installazione del WTK). Il codice sorgente deve essere salvato nella sottodirectory src, mentre risorse e librerie opzionali troveranno collocazione rispettivamen-te in res e lib. Attraverso i menù BUILD, RUN e CREATE PACKAGE è possibile compilare il codice, eseguirlo all’in-terno dell’emulatore standard e creare i file JAD e JAR per il deployment finale.

All’emulatore fornito con il WTK si affiancano quelli dedicati forniti dai produttori dei modelli in commercio. Nokia, Sony-Ericsson, Motorola, Samsung, Benq (che ha recentemente acquisito la divisione telefonia mobile di Siemens) offrono apposite sezioni dedicate agli sviluppa-tori nei propri siti web, con software, librerie, documen-tazione e articoli di approfondimento.

Gli strumenti a linea di comando e gli emulatori sono il minimo indispensabile per intraprendere lo sviluppo di una applicazione Java ME. Adottare un ambiente di

sviluppo integrato permette di aumentare la produttivi-tà attraverso editor avanzati (con evidenziazione della sintassi, autocompletamento dinamico del codice, assi-stenza alla correzione degli errori più comuni), gestione dei progetti e delle librerie, integrazione con il Wireless Toolkit e emulatori di terze parti, supporto al deployment automatico su server remoto e a configurazioni multiple per dispositivi diversi. Netbeans, Eclipse, IDEA, JBuilder, solo per citarne alcuni, offrono apposite estensioni per lo sviluppo in ambiente Java ME. In ambito CDC/PP è da segnalare l’ottimo WebSphere Device Developer proposto da IBM, che include anche i runtime environment per Windows Mobile e Linux. In realtà, lo sviluppo di appli-cazioni CDC/PP è, per diversi aspetti, meno critico ed è possibile utilizzare strumenti standard (non è necessaria la preverifica). Ciononostante, i produttori di dispositivi stanno iniziando a rilasciare documentazione e tool spe-cifici, che tengano conto delle particolarità che ciascun modello introduce rispetto alla piattaforma ufficiale.

Conclusioni

Dal 2001 ad oggi la piattaforma Java ME è cresciuta no-tevolmente sia per numero di terminali installati (siamo prossimi al miliardo di unità!) che per la ricchezza del runtime environment con tutte le API opzionali. Questa maturità permette agli sviluppatori di realizzare applica-zioni a supporto della totale mobilità degli utenti, con ricco supporto alla connettività (messagging, Bluetooth, IP su rete telefonica e WiFi, web service). Dal 2006 sono annunciate nuove API e dispositivi dalle prestazioni ele-vatissime: l’auspicio è quello di avere una nuova classe di applicazioni a supporto della mobilità degli utenti consu-mer, fortemente connesse e georeferenziate.

Le applicazioni mo-

bile, prima di essere di-

stribuite, passano per un

processo di preverifica

JAVA Journal

49n.1 - settembre 2006

educational

Java 5, le buone nuove e le novità meno buoneprima parte

Scrivere nel 2006 un articolo sulle novità di Java5 può sembrare un po’ fuori tempo massimo, poi-ché Sun ha presentato questa release nel 2004, e Java6 è ormai dietro l’angolo. Ma ci sono da tenere in considerazione diversi aspetti che giustificano questo argomento.

>> di Ugo Landini ([email protected])

V ediamo dunque perché trattare le novità di Java5:• le novità introdotte in Java5 non sono state ancora ben digerite da molti svilup-

patori. Per lavoro mi capita di vedere molto codice Java scritto da altri, ed è comune – molto comune - imbattersi in idiomi ormai resi obsoleti dalle nuove versioni del linguaggio. Di fatto, spesso non vengo-no utilizzate neanche le features di Java 1.4 (per i non avvezzi alle simpatiche regole del marketing, java 1.4 è la release precedente a java5)

• un cambiamento così grande (mi piacerebbe usare l’aggettivo epocale, ma suonerebbe troppo sensa-zionalista) non c’era mai stato e non ci dovrebbe mai più essere: il nuovo processo di rilascio delle versioni di Java e la relativa tempistica – circa 2 anni per major release - rende improbabile cambia-menti drastici da una release all’altra. Da java 1.4 a Java5 sono infatti passati ben 4 anni.

• Diversi cambiamenti sono argomento di discus-sione giornaliero sui forum. Per molti di essi non c’è ancora una chiara posizione della comunità: le Annotations API sono effettivamente utili o peg-giorano il design?

• Java6 non introdurrà nessun cambiamento parti-colare, ma apporterà solo miglioramenti a diverse API, concentrandosi in particolare sul Desktop. Java5 ha introdotto nuove keyword nel linguag-gio e anche nuove api che rendono praticamente obsolete alcune parole chiave (si pensi alle nuove concurrent api, per esempio)

Penso di essermi giustificato abbastanza, per cui passiamo in rassegna le novità. L’obiettivo principale del team di Java5 è stato quello di migliorare la leggi-bilità del codice e aumentarne allo stesso tempo l’af-

fidabilità, mantenendo la compatibilità all’indietro. Particolare attenzione in questa release è stata posta sull’incremento delle performance: alcuni obiettivi iniziali sono invece stati parzialmente rischedulati per Java6. L’obiettivo di questo articolo invece è pas-sare in rassegna le novità, con un accento particolare su quelle che hanno fatto meno clamore.Possiamo raggruppare le novità con l’ausilio della Tabella 1. Ovviamente la tabella è riduttiva, ci sono centinaia di cambiamenti (più o meno piccoli) nelle API e nei tool di supporto [ENHANCEMENTS]. Però ce n’è già abbastanza per scrivere un articolo e lascia-re fuori un sacco di dettagli! Prima di soffermarci sui vari cambiamenti, assicuratevi di usare il compilatore passandogli lo switch per il sorgente 1.5 (-source 5), su alcune “vecchie” versioni di javac il default per questo switch era ancora 1.4.

Generics

Sicuramente è la novità apparentemente più impor-tante, e quella sulla quale se ne è scritto di più. È anche uno dei costrutti più complessi e meno cono-sciuti, con molti “angoli bui”In sostanza, i generics non sono altro che una tecnica per ottenere una maggiore type safety in java. In un linguaggio strongly typed come java, questo non può che essere un bene. Usando infatti le nuove tecniche si risparmieranno molti cast ed il codice sarà teori-camente più robusto. Uso “teoricamente” perchè personalmente non mi è mai capitato un bug dovuto all’inserimento in una collection di un oggetto erra-to, ma diamo atto che un controllo in più fatto dal compilatore non può che essere un buon controllo. “Making Java easier to type and easier to type”, re-citava con un simpatico gioco di parole lo slogan di

JAVA Journal

n.1 - settembre 200650

educational

Pizza/GJ [PIZZA], il precursore dei generics in Java5.È vero infatti che per anni una parte della comunità Java ha lamentato l’assenza dei generics (e proprio per questo qualcuno sentì la necessità di creare Pizza/GJ), mentre un’altra parte ne ha sempre osteggiato l’inserimento, fa-cendo presente soprattutto la complessità e la macchinosi-tà dei template in C++. James Gosling è sempre stato con-trario, ma questa è proprio la dimostrazione che il processo che guida l’evoluzione della piattaforma Java (Java Com-munity Process, JCP) è abbastanza democratico, oppure è la dimostrazione che Gosling sta perdendo smalto).Sia come sia, in Java5 queste feature sono lì e non possono essere ignorate, soprattutto perchè le API sono state tutte genericizzate, quindi perlomeno bisogna avere una qualche confidenza con esse. Fra l’altro nell’implementazione che è stata poi scelta, hanno molto poco a che vedere con quanto a disposizione in C++.

// ...List people = new ArrayList();people.add(“Ugo Landini”);people.add(“Diego Landini”);people.add(“Luca Landini”);// ...String diego = (String)people.get(1);

Questo codice è ormai legacy, sostituito dal codice seguente

// ...List<String> people = new ArrayList<String>();people.add(“Ugo Landini”);people.add(“Diego Landini”);

people.add(“Luca Landini”);// ...String luca = people.get(2); Come si vede chiaramente dal codice, non c’è più bisogno di fare un cast dopo il get(). È infatti garantito che nella collection people ci siano solo delle String, ed un tentativo di inserimento di un oggetto del tipo sbagliato sarebbe individuato addirittura in fase di compilazione (e non a runtime).

Poniamo ad esempio che si provi ad inserire uno StringBui-lder invece di una Stringa: il compilatore si lamenterebbe poichè non riuscirebbe a trovare il metodo add(StringBuilder) all’interno dell’interfaccia List! A questo punto le doman-de sorgono spontanee... come fa a funzionare? Il metodo add() di List non accettava Object come parametro? Esi-ste una classe List<String> con un add(String) ed una List<StringBuilder> con un add(StringBuilder)? Come è possibile?

Cambiamento Costrutto/Tool Scopo

Linguaggio Generics• Semplificazione della gestione delle Collections• Sicurezza del codice

Linguaggio Nuovo ciclo for • Semplificazione della gestione delle CollectionsLinguaggio Autoboxing • Semplificazione del codice

Linguaggio Enumeration• Gestione standardizzata di insiemi di oggetti• Sicurezza codice

Linguaggio Varargs • Soprattutto semplificazione nel porting di codice CLinguaggio Static import • Migliorare la leggibilità del codiceLinguaggio Covarianza • Più espressività, migliore modellabilitàAPI printf • Soprattutto semplificazione nel porting di codice CAPI java.util.scanner • Semplificare l’IO

API xml bundling• Maggiore integrazione con XML• Supporto web services integrato in Java

API Concurrent API• Semplificare la creazione di codice multithreaded• Aumentare le performance del codice multithreaded

Sistema Class sharing• Migliorare lo startup della virtual machine• Diminuire il footprint

Sistema Troubleshooting

• Semplificare il troubleshooting di applicazioni java attraverso l’inserimento nella distribuzione Java di nuovi tool e/o tool che precedentemente dovevano essere scaricati separatamente

TABELLA 1

Per anni una parte

della comunità Java ha

lamentato l’assenza dei

generics

JAVA Journal

n.1 - settembre 2006 51

educational

Per padroneggiare questo meccanismo, è necessario ca-pire come si dichiara un tipo parametrico, e come viene compilato di conseguenza il bytecode. Si vedrà che quella complessità che è in qualche modo sparita dal codice che utilizza le collection - il codice client - in qualche modo si è spostata nel codice delle classi server. Anzi, a dir la verità, il totale di complessità in qualche modo è aumentato... ma andiamo a vedere il sorgente di List per capire un po’ meglio:

public interface List<E> extends Collection<E> {// ...boolean add(E o);E get(int index);// ...}

La prima cosa che salta all’occhio è che List ora è diventato List<E>, leggasi una lista di E. E rappresenta il tipo di ele-mento che può essere gestito da List, ed è un tipo generico. E si chiama Type Parameter o Type Variable, ed è l’iniziale di Element, ed anche se si può usare qualsiasi lettera al suo posto è una scelta piuttosto comune. Si dirà: ma non bastava Object? Cosa è cambiato?È cambiato che per costruire un oggetto List ora si può dire al compilatore quale tipo deve sostituire al posto di E, e da quel momento in poi l’oggetto sarà una lista di String, come nell’esempio di prima, e non più una lista qualsiasi. Nota: è ovviamente possibile e perfettamente legale istanziare una List non parametrizzata, altrimenti tutto il codice pre Java5 diventerebbe di colpo illegale!Per capire meglio, immaginate che il tipo sia un parametro da passare ad un metodo,:

• List<E> è una dichiarazione generica di tipo, equivalen-te al nome di un metodo

• E è il parametro di tipo, equivalente al tipo del parametro di un metodo

• List<String> fornisce un argomento al tipo, in questo caso String, equivalente all’effettivo valore del parametro nella chiamata di un metodo

La prima lezione da imparare sui tipi generici è quindi che List<String> e List<StringBuilder> non sono due differenti classi, ma semplicemente due diverse istanze della stessa classe a cui è stato passato un diverso tipo come parame-tro.Questo può apparire contro intuitivo perché siamo abituati a considerare tutto ciò che è a sinistra dell’identificatore in una dichiarazione come il suo tipo: la difficoltà è che bisogna imparare a leggere le parentesi angolari come se fossero le parentesi tonde di un metodo, e ricordarsi che con Java5 è possibile parametrizzare una classe passando-gli dei valori. In questo modo la classe sarà più specifica, e funzionerà solo con quel determinato tipo che gli è stato passato in fase di dichiarazione: l’oggetto people dell’esem-pio è una Collection che accetta solamente Stringhe e non più oggetti qualsiasi.Questa lezione è di fondamentale importanza: c’è una sola classe, indipendentemente dal numero di parametri di tipo, e questo limita fortemente cosa si può e cosa non si

può fare con il tipo. Ad esempio, essendoci una sola classe, i metodi statici – che appartengono alla classe e non alle istanze - non possono usare il tipo in alcun modo! La cosa interessante sull’implementazione di questa fea-ture è che praticamente il compilatore non fa altro che utilizzare Object e fare il cast al posto vostro, mentre la VM non sa neanche dell’esistenza dei generics! Questa tecnica si chiama erasure, poiché il compilatore cancella tutte le informazioni di tipo dalle classi genericizzate, cosicché List<String> di fatto diventa List, <E> diventa Object, e così via. Infarcendo il bytecode con un po’ di cast, il gioco è fatto.Questa scelta implementativa, che è stata necessaria per non stravolgere le VM esistenti, porta con sé però diversi problemi, e ci sono molte situazioni in cui capire esatta-mente cosa succede, non è per nulla semplice, anche per i più esperti.

L’argomento è molto vasto (troppo?) e non si esaurisce certo in queste poche righe: argomenti come i bounded type, i generic nested types, gli wildcard, il subtyping ed altri hanno bisogno di un certo sforzo di apprendimento e di un po’ di pratica per essere padroneggiati, senza contare gli angoli oscuri a cui abbiamo appena accennato. Quello che abbiamo visto è l’assoluto minimo che bisogna sapere sui generics per non cadere dalle nuvole di fronte a del codice Java5!

Nuovo ciclo for (enhanced for)

Questo nuovo costrutto, insieme ai generics, è quello sicu-ramente più invasivo: volente o nolente, prima o poi con Java5 vi troverete ad usare la nuova sintassi e ad apprez-zarne le qualità. Niente di trascendentale, ma sicuramente una maggiore sinteticità e leggibilità, soprattutto quando combinato con i generics.Dal punto di vista teorico, esistono due tipi di iteratori, esterni ed interni (Booch li definisce attivi e passivi, rispet-to al ruolo che ha il client). Un iteratore è chiamato esterno quando è il client che ha il controllo del suo avanzamento (attivo), mentre uno interno (passivo) controlla da sé l’ite-razione. Gli iteratori “classici” di Java sono esterni: tipica-mente un iteratore esterno offre una maggior flessibilità di uno interno poiché si ha un controllo più fine sull’itera-zione, ed in effetti ci sono dei problemi difficili da risolvere solamente con iteratori interni: basti pensare al confronto degli elementi di due liste per rendersene conto.È però vero che l’iteratore interno è molto più conciso ed elegante nella stragrande maggioranza dei casi! E basta un esempio per rendersene conto.

TABELLA 2

Type Variable SignificatoE ElementK KeyV ValueT Type

JAVA Journal

n.1 - settembre 200652

educational

// ...List people = ...for (String person: people) { System.out.string(name);}

I due punti vanno letti come “in”, dunque qualcosa di si-mile a “per ogni person in people”, che è ovviamente molto più leggibile e conciso dell’equivalente con iteratore ester-no.Come nell’esempio precedente, il nuovo for da il mas-simo di sé quando unito ai generics, ma è comunque molto flessibile e permette anche di iterare su semplici array:

// ...String[] names = {“Ugo”, “Diego”, “Luca”};for (String name: names) { System.out.println(name);}

A voler essere pignoli, sarebbe stato bello fare il passo com-pleto ed avere anche la possibilità di definire dei blocchi, ossia delle porzioni di codice da “passare” al ciclo e che po-tessero essere eseguite sui singoli elementi, ma non si può avere tutto e per ora ci accontentiamo del nuovo for e della possibilità di scegliere fra iteratori esterni ed interni.

Autoboxing/unboxing

Questa nuova feature aggiunge un po’ di zucchero sintat-tico a Java. All’osso, rende il seguente codice compilabile e perfettamente funzionante:

Integer i = 0;

Dietro le quinte, il compilatore si occupa delle necessa-rie conversioni fra tipo base ed oggetto, che da sempre tormentano i programmatori Java. Questa conversione da tipo primitivo ad oggetto wrapper è chiamata boxing e, visto che succede in automatico, la feature è chiamata autoboxing, mentre l’operazione opposta - da oggetto wrapper a tipo primitivo - è chiamata unboxing (senza auto, chissà perché).Ovviamente questo semplice esempio non rende l’idea, ma

utilizzando le Collection e confrontando il nuovo codice con il vecchio ne possiamo apprezzare l’utilità

//...List numeri = new ArrayList();numeri.add(new Integer(1));numeri.add(new Integer(2));numeri.add(new Integer(3));//...int due = ((Integer)numeri.get(2)).intValue();diventa infatti molto più semplice e leggibile//...List numeri = new ArrayList();numeri.add(1);numeri.add(2);numeri.add(3);//...int due = numeri.get(2);

Tutto qui, l’autoboxing/unboxing rende di fatto intercam-biabili i tipi base e i corrispettivi wrapper. Ma attenzione! La cosa da ricordare è che la distinzione fra i tipi base e gli oggetti è ancora lì, solo che ora è nascosta: si badi bene dunque a non usare un Integer come indice in un lungo ciclo, magari nidificato. Il fatto che compili e che funzioni non implica che sia la migliore soluzione. Da questo punto di vista, il boxing e l’autoboxing sono decisamente perico-losi! Basta osservare questo piccolo esempio per renderse-ne conto:

// ...long before = System.currentTimeMillis();int x = 0;for (int i=0; i<10000000; i++) { x = x + i;}System.out.println(System.currentTimeMillis() - before);

before = System.currentTimeMillis();x = 0;for (Integer i=0; i<10000000; i++) { x = x + i;}System.out.println(System.currentTimeMillis() - before);

Il secondo ciclo è circa 20 volte più lento, questo per via di tutte le conversioni automatiche (sia boxing che unbo-xing) che vengono eseguite ad ogni iterazione.Ovviamente non ci si limita ai tipi numerici, ed ora potrete anche scrivere:

Boolean vero = true;Boolean expression = exp1 && exp2 || exp3

Un ultimo dettaglio: il boxing/unboxing non avviene per la risoluzione di metodi in overload, ma continuano a valere le regole pre-Java 1.5. Questo per non variare il compor-tamento di programmi compilati per versioni precedenti. Considerate infatti cosa accadrebbe se il boxing fosse ap-plicato in una situazione simile:

L ’ a u t o b o x i n g /

unboxing rende di fatto

intercambibili i tipi base

e i corrispettivi wrapper

JAVA Journal

n.1 - settembre 2006 53

educational

sere un sottotipo o un supertipo. Per un linguaggio object oriented, se sia meglio avere tipi covarianti o controvarian-ti è una scelta di design che è ancora argomento teorico di dibattito: noi ce ne terremo lontani (Tabella 3).Possiamo avere invarianza, covarianza o controvarianza per i tipi di ritorno di un metodo, per i suoi parametri, o per le eccezioni che lancia.

Un esempio di covarianza pre-Java5 sono le eccezioni: l’override di un metodo che lanci eccezioni è tenuto a lanciare eccezioni in maniera covariante: le stesse, o dei sottotipi, A voler essere precisi può anche non lanciarne nessuna (ma così mi si rovina l’esempio): co-munque, se il metodo lancia eccezioni, queste devono essere covarianti.Discorso diverso invece per i parametri di un metodo, che sono invarianti: scrivere questo codice

public class Base { public void uno(CharSequence sequence) { System.out.println(“Base.print “ + sequence); }}

public class Derived extends Base { public void print(String string) { System.out.println(“Derived.print “ + string); } public static void main(String[] args) { Base b = new Derived(); b.uno(“ciao”); }}

porta in realtà ad un overload e non certo ad un override. Per accertarsene, basta verificare l’output del main: viene eseguito il metodo della classe base e non della classe de-rivataRitornando alle novità di Java5, è ora possibile avere il tipo di ritorno covariante e dunque scrivere codice come questo (mi si perdoni il dominio dell’esempio, che è pa-tetico):

public abstract class Erbivoro { public abstract Erba mangia();}public abstract class Cavallo extends Erbivoro { public abstract Fieno mangia();}

Dove Fieno estende Erba, permettendo dunque ad una sottoclasse di specificare meglio il comportamento rispetto

// ...public void doSomething(double num);public void doSomething(Integer num);

//...int x = 1;doSomething(1);

Per Java 1.4, verrebbe invocato il primo metodo, mentre per Java 1.5 verrebbe invocato il secondo per via dell’autoboxing!

Static import

Lo static import è fortunatamente una delle novità più semplici da imparare.Questa novità permette semplicemente di “importare” variabili e metodi statici, in modo da poterli eseguire direttamente senza il nome della classe. Anche questa quindi è una feature più di forma che di sostanza, e serve per risparmiare qualche carattere e scrivere codice più leggibile:

import static java.lang.System.out;// ...out.println(“Hello, world!”);

ma anche

import static java.lang.Math.*;import static java.lang.System.out;// ...out.println(PI);

oppure

import static Collection.copy;// ...copy(from, to);

Non ne fate un abuso, è molto semplice farsi prendere la mano e scrivere codice molto poco leggibile, ossia l’esatto opposto del beneficio atteso!

Covarianza (sul tipo di ritorno)

La covarianza sul tipo di ritorno è un altro aspetto di Java5 passato un po’ in sordina. In realtà il suo inserimento in Java5 è stato accessorio all’inserimento di altre feature, ma è comunque una caratteristica in più ed utile di per sé, so-prattutto perché può semplificare il design in diversi casi.Qui c’è sicuramente bisogno di un appoggio teorico, anche per chiarire alcuni aspetti che spesso non vengono chiariti abbastanza. Troppo spesso si legge che Java5 supporta la covarianza, in realtà con Java5 ora c’è il supporto della co-varianza sul tipo di ritorno, poichè alcune caratteristiche del linguaggio erano già covarianti da tempo immemore.Ma vediamo le definizioni:Un tipo, relativamente al suo supertipo, può essere inva-riante, covariante o controvariante. Invariante vuol dire evidentemente che deve essere lo stesso. Covariante e controvariante vogliono dire, rispettivamente, che può es-

TABELLA 3

Tipo Relazione con il supertipo

Invarianza Non cambiaCovarianza Può essere un sottotipo

JAVA Journal

n.1 - settembre 200654

educational

Note Biografiche

Ugo Landini ha più di 10 anni di esperienza nel mondo Object Oriented, e segue Java dalla nascita. Si ostina ancora a voler pro-grammare e ha velleità di centravanti, con scarsi risultati in en-trambe le attività. È CTO in Pronetics, dove si è occupa preva-lentemente di architetture distribuite e di tutto ciò che riguarda il mondo Java, XML e in generale l’integrazione. È stato Senior Java Architect in Sun Microsystems.

alla sua superclasse.La covarianza sul tipo di ritorno è dunque un arma in più nel nostro bagaglio di designer, e permette di modellare in maniera decisamente più efficace e parsimoniosa alcu-ni problemi, contribuendo ad evitare l’abuso della classe Object, in linea con le altre feature di Java5.In tabella riassumiamo per comodità lo stato della cova-rianza in Java. (Tabella 4)

Class sharing e troubleshooting

Il class sharing [SHARING] è una novità “sistemistica” di Java5. Questa tecnica è stata in realtà inventata da Apple per il JDK 1.4 di OsX, e successivamente condivisa con il resto della comunità Java ed inserita nella release 5.0.Sostanzialmente il class sharing permette di diminuire il tempo di avvio (startup) della virtual machine e lo spazio occupato in memoria (footprint). Lo startup della Virtual Machine infatti, se troppo elevato, è un ostacolo alla dif-fusione di Java in compiti diversi da quelli di middleware: dal desktop allo scripting, riavviare ogni volta la macchina virtuale è sicuramente uno spreco di risorse.Il class sharing, nella sua forma attuale, consiste nel man-tenere i riferimenti ad una serie di classi java di sistema (alcune classi incluse in rt.jar) in modo che diverse esecu-zioni della virtual machine si trovino già un po’ di lavoro preparato. Tecnicamente, questo avviene utilizzando il memory mapping: queste classi “condivise”, serializzate in un formato particolare, sono a disposizione di tutti in un file, lo shared archive. Questo file, essendo “memory mapped”, permette così alle diverse istanze delle VM di condividere queste classi di sistema e di risparmiare il tem-po del loro caricamento, di fatto diminuendo lo startup ed il footprint.Sotto OsX per PowerPC è noto come, pur non essendo la VM particolarmente performante, il JDK 1.4 aveva un tempo di startup molto basso e le performance “percepite” sembravano così molto elevate. Con Java5 anche gli altri sistemi (x86, Sparc) possono ora beneficiare di questa in-teressante ottimizzazione. Da notare che attualmente ci sono diverse limitazioni, per cui lo sharing delle classi funziona solo se la virtual ma-chine è eseguita in modalità Hot Spot client (d’altronde sul server ha meno senso), e non con tutti i possibili tipi di Garbage Collection. Se volete giocare un po’ con l’archivio shared, con il seguente comando forzate la costruzione del file classes.jsa (Java Shared Archive):

java -Xshare:dump

Il file si trova sotto jre/lib/[arch]/client/classes.jsa per i

sistemi unix e jre/bin/client/classes.jsa per i sistemi win-dows. Sul mio sistema linux è un file di circa 13Mb, il che ad occhio e croce vuol dire che ad ogni esecuzione la Vir-tual Machine avrà un footprint molto più leggero e rispar-mierà pure un bel po’ di tempo per lo startup.Sarà interessante vedere come si evolverà il class sharing in Java6, anche in virtù della probabile introduzione in questa release delle nuove “Isolation API”, descritte nel JSR 121 [ISOLATION], che invece si pongono un proble-ma più ampio: come isolare oggetti e contemporaneamen-te condividere risorse fra diverse applicazioni java. Queste Api dovevano originariamente essere inserite in Java5, quindi ce le aspettiamo tutti in Mustang!L’altra novità sistemistica di rilievo è l’inserimento nella distribuzione standard di moltissimi tool per il troubleshooting/monitoring delle applicazioni. Sostanzial-mente è possibile ora monitorare e diagnosticare problemi in applicazioni Java senza utilizzare costosi sistemi di profiling (ovviamente questi sistemi sono molto più user-friendly delle utility java5) con tool come jstat, jinfo, jmap, jps e jconsole. L’argomento è molto vasto e richiederebbe sicuramente un articolo specialistico di approfondimento, nel frattempo potete però cominciare a sfogliare le oltre 100 pagine di pdf [TROUBLESHOOTING] della guida Sun al troubleshooting!

Conclusioni

Con questa breve rassegna delle novità di Java5 spero di avere incuriosito coloro che, per vari motivi di tempo/lavoro, sono rimasti legati alle “vecchie” release di Java. Per gli approfondimenti, vi rimando alla bibliografia. Il riferimento insuperato ed ufficiale è sicuramente il [GO-SLING], che espone anche i dettagli del linguaggio in uno stile asciutto ma comprensibilissimo. Nella seconda parte di questo articolo tratteremo le concurrent API, i typesafe enums, i varargs e le annotations API. E vedremo cosa bol-le in pentola per Java6.

Riferimenti e bibliografia

[GOF94] Iterator pattern[BLOCH] Effective Java[ENHANCEMENTS] http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html[FLANAGAN] Java 1.5 Tiger, a developer’s notebook[GOSLING] The Java Programming Language, 4th edition[ISOLATION] http://www.jcp.org/en/jsr/detail?id=121[PIZZA] http://www.cis.unisa.edu.au/~pizza/[SHARING] http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html[TROUBLESHOOTING] http://java.sun.com/j2se/1.5/pdf/jdk50_ts_guide.pdf

TABELLA 4

Tipo Varianza in JavaTipo di ritorno Covariante (invariante

fino a JDK 1.4.x)Parametro InvarianteEccezione Covariante

JAVA Journal

55n.1 - settembre 2006

educational

Fondamenti di Programmazione Java

Prima parte: uno sguardo d’insieme

I niziamo il nostro corso spiegando alcuni con-cetti base. Il nome “Java” è un nome che rac-chiude in sé le diverse tecnologie che com-pongono la “piattaforma” Java. In particola-re, Java è innanzitutto un (bel) linguaggio di programmazione, ed è quello che la maggior parte dei neo-programmatori Java desidera

imparare. Java però è anche il nome della “virtual machine”, ovvero l’ambiente di l’esecuzione di pro-grammi, nota più propriamente con l’acronimo JVM (ovvero Java Virtual Machine). La JVM è il più usato (ma non l’unico) ambiente di esecuzione per i pro-grammi scritti in linguaggio Java.

Infine, sotto il nome di Java ricadono anche le ampie e complesse librerie standard della “piattaforma” Java; queste librerie fanno sì che essa sia qualcosa di più di un linguaggio di programmazione: ovvero Java è un completo ambiente di esecuzione di pro-grammi che isola dal sistema operativo sottostante. Per questo motivo si parla di piattaforma: non si tratta di un vero e proprio sistema operativo (non arriva a mettere le radici nell’hardware, fornendo device driver e cose del genere), ma è completamen-te autosufficiente per quanto riguarda lo sviluppo di software. Una volta scritto un programma in Java, per eseguirlo basta il cosiddetto Java RunTime Environment, che esiste per numerosi sistemi ope-rativi: Windows, Linux, Solaris, MacOSX, AS/400 e così via.

Il linguaggio Java

Esaminiamo le caratteristiche specifiche del linguag-gio Java e la sua genesi. Si tratta di un linguaggio

di programmazione, nato oramai più di 10 anni fa. Ai tempi della sua gestazione, uno dei linguaggi di programmazione più usati era il linguaggio C, mentre il suo designato successore era il linguaggio C++. Il C++ è una estensione del linguaggio C che mantie-ne la compatibilità all’indietro: cioè ogni programma scritto in C è, a meno di marginali modifiche, utiliz-zabile come programma C++.

Raccontano le cronache che James Gosling, il prin-cipale autore del linguaggio Java, aveva tentato di usare il C++ per realizzare un editor per l’SGML (il precursore dell’attuale XML), ma si era scontrato con la sua grande complessità. Notoriamente il C++ presenta non poche difficoltà: queste sono indotte anche dal fatto che è un linguaggio sostanzialmente di basso livello; si tratta di una caratteristica eredita-ta dal fatto che è volutamente compatibile con il C. Questo fatto, aggiunto alla grande quantità di “featu-re” (funzionalità) disponibili, lo rende un linguaggio molto difficile, che richiede grande accortezza nella stesura dei programmi, e presenta tanti trabocchetti per i programmatori.

Quando Gosling si trovò a dover scegliere (o pro-gettare) un linguaggio di programmazione per una nuova applicazione, pensò di partire dal C++ proprio perché veniva considerato “il linguaggio del futuro”. Sun stava infatti sviluppando un sistema di nuova concezione (quello che poi, dopo varie peripezie, sa-rebbe diventata la piattaforma Java), e Gosling creò un linguaggio chiamato Oak (in inglese ‘quercia’, che richiama l’idea della solidità e robustezza). L’idea di fondo era quella di riprendere la sintassi e le migliori idee del C++, ma, al prezzo di “rompere con il passato” (ovvero la compatibilità con il C), creare un derivato con una sintassi e una semantica simile, ma molto

Java è il protagonista della nostra rivista; la rivista ovviamente non si rivolge solo a chi lo conosce già, ma anche a chi Java lo vuole imparare. Un corso istituzionale sui fondamenti di Java inagura la sezione educativa di Java Journal. Questo corso comunque è per chi è già un programmatore: si presume che abbiate già le basi di programmazione, ovvero sappiate programmare in almeno un altro linguaggio.

>> di Michele Sciabarrà ([email protected])

JAVA Journal

n.1 - settembre 200656

educational

più semplice, lineare, coerente, facile da imparare e che presentasse meno trappole per i programmatori.

In effetti, chi conosce il C++ e Java si rende conto che molti concetti sono gli stessi: si ha la stessa sintassi di base, ereditata dal C; il modo di definire classi e oggetti in Java è abbastanza simile a quella del C++ (anche se decisamente meno potente). Infatti esaminando in dettaglio si scopre che molte caratteristiche del C++ sono state rimosse. È come se qualcuno avesse voluto usare un sottoinsieme del C++ in-serendo solo quello che era strettamente utile. Ricordo un

white-paper di molti anni fa su Java 1.0 in cui si ripeteva il mantra: less is more (meno è di più).

Praticamente sono state rimosse tutte le caratteristiche che rendevano difficile la lettura del codice (come l’opera-tor overloading, che permette di dare agli operatori come il “+” significati diversi, ma costringe il programmatore a fare molta attenzione al tipo di una variabile). Sono state anche rimosse alcune parti che complicavano parecchio l’implementazione (per esempio l’ereditarietà multipla). Altre caratteristiche del C++ sono rimaste a lungo fuori dal linguaggio Java ma sono state poi reintrodotte solo di recente (come la programmazione generica). In definitiva Java vuole essere un C++ più semplice e lineare. Ma non si è trattato solo di pulire la sintassi: Java ha anche intro-dotto nuove funzionalità, come l’esecuzione su una virtual machine e la “garbage collection”.

La Garbage Collection

Una delle più importanti estensione rispetto al C++ è che Java gestisce la memoria in maniera automatica. Questo concetto è abbastanza delicato ed importante: per cui ne parliamo subito per approfondirlo poi. In linguaggi come il C o il C++, quando si ha bisogno di memoria, viene chie-sta al sistema (si dice che “viene allocata”). Occorre però ricordarsi, quando la memoria non serve più, di restituirla esplicitamente al sistema.

In un programma, l’uso di memoria è continuo: ogni og-getto che si crea (e Java fa tutto usando oggetti) richiede memoria. Notoriamente, la gestione della memoria occupa molto tempo nella programmazione, sia C che C++, ed è soggetta ad errori. Questo avviene soprattutto quando si costruiscono strutture dati complesse, in cui parti sono condivise: in questo modo non è affatto ovvio né semplice determinare quando un blocco di memoria deve essere liberato, perché potrebbe essere in uso da altre parti del programma.

Java permette di richiedere la memoria al sistema, e di recuperarla in maniera automatica. Java infatti rileva automaticamente che un blocco di memoria non serve più al programma. Questa apparente “magia” viene fatta considerando la memoria che in un momento il program-ma sta utilizzando, a partire dalle variabili che sono in uso. Tutta la memoria che il programma non può più utilizzare (semplicemente perché le variabili in uso non consentono

FIGURA 1 la garbage collection

Chi conosce

C++ e Java si rende

conto che molti concetti

sono analoghi

JAVA Journal

n.1 - settembre 2006 57

educational

di raggiungerla) viene recuperata, tramite un meccanismo denominato “raccolta di spazzatura” (appunto garbage collection).

Programmatori esperti in C o Pascal inorridiscono all’idea di “sprecare” tanta memoria, e dubitano fortemente che un meccanismo del genere possa funzionare. Eppure, che ci si creda o no, la garbage collection può essere molto efficiente, e (sui grandi numeri) addirittura più effi-ciente della gestione manuale. Il rovescio della medaglia comunque è che il Java standard necessita di parecchia memoria, nell’ordine dei megabyte. Il Java Micro Edition è ottimizzato per l’uso in ambienti con limitate risorse, e pur mantenendo la garbage collection, richiede me-moria nell’ordine dei kilobyte. Ciò non toglie che Java è un linguaggio con alti requisiti di memoria anche per programmi semplici, anche se oggi giorno la memoria è diventata una risorsa relativamente economica ed è disponibile in quantità anche in ambienti limitati come i telefoni cellulari.

Per capire come funziona la garbage collection possiamo fare riferimento alla Figura 1: ho rappresentato schema-ticamente una situazione tipica di un programma Java in esecuzione. Il programma utilizza la memoria a partire dalle sue variabili. Tutte le variabili attualmente in uso si trovano in un posto noto, chiamato “stack”. Tutta la me-moria usata dal programma è accessibile solo attraverso le variabili in uso, che fanno riferimento all’area di memoria di uso dinamico chiamata “heap”. Nello heap sono “allo-

cati” blocchi di memoria che in Java corrispondono agli oggetti. Alcuni oggetti possono a loro volta fare riferimento ad altri oggetti.

È possibile determinare quale memoria è attualmen-te in uso in questo modo: si considerano tutte le va-riabili del programma (guardando lo stack), e da lì si risale agli oggetti che usano; eventualmente alcuni oggetti possono fare riferimento ad altri oggetti, che

sono in uso anche questi (sia pur indirettamente). La gar-bage collection (raccolta di spazzatura) funziona proprio così: con il processo appena descritto, si “marcano” tutti gli oggetti che sono in uso. Tutti quelli rimasti, non essen-do utilizzabili, vengono considerati spazzatura, e vengono difatti riutilizzati, recuperando la memoria.

La Java Virtual Machine

I programmi scritti in Java possono essere eseguiti in vari modi. Se pensate al C, sapete che i programmi vengono compilati in codice nativo, per poi essere eseguiti diret-tamente dal processore (il C e il C++ è solitamente un compilatore puro). Se pensate al Basic (o al JavaScript per considerare un altro caso più recente), sapete che i programmi possono venire eseguiti così come sono, senza nessun passo intermedio. Si tratta della tradizionale di-stinzione tra interprete e compilatore (che nel caso di Java

non vale del tutto).

Va subito detto che per Java esistono sia compilatori puri che interpreti puri. Esiste per esempio il compilatore GCJ, che trasforma un programma Java in codice nativo, eseguito direttamente dal processore. Esistono anche interpreti puri (come la BeanShell), in grado di esegui-re programmi Java direttamente, così come sono, senza alcuna trasformazione intermedia. Nella maggior parte dei casi tuttavia, Java viene utilizzato seguendo l’approccio originale: ovvero viene prima compilato in un codice intermedio, detto bytecode, e poi eseguito da un interprete, detto Java Virtual Machine. Questo fa di Java un linguaggio essenzialmente interpretato; tuttavia quello che viene interpretato non è il codice Java così come è, ma un suo codice intermedio, risultante da compilazione esplicita, detto bytecode.

LISTATO 2 Il nostro primo listato

public class Hello { public static void main(String[] args) { System.out.println(“Hello, world”); }}

LISTATO 3 II bytecode di Hello

Compiled from “Hello.java”public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 //Method java/lang/Object.”<init>”:()V 1: invokespecial #1; 4: return

public static void main(java.lang.String[]); Code: //Field java/lang/System.out:Ljava/io/PrintStream; 0: getstatic #2; 3: ldc #3; //String Hello, world //Method java/io/PrintStream.println:(Ljava/lang/String;)V 5: invokevirtual #4; 8: return

}

La memoria usata

dal programma è acces-

sibile solo attraverso

le variabili in uso

JAVA Journal

n.1 - settembre 200658

educational

Proviamo adesso a toccare con mano queste caratteri-stiche, partendo dal nostro primo listato, mostrato nel Listato 2. Sfortunatamente, in Java anche il classico programma che stampa al terminale “Hello World”, usa molti concetti che non sono ovvi: occorre necessaria-mente creare una classe, citare concetti avanzati come gli array, imporre la visibilità pubblica, chiamare un meto-do e un campo statico. Tutti concetti che approfondiremo strada facendo. Per il momento non consideriamo perché il listato è scritto così, ci concentriamo su come fare ad eseguire il nostro primo programma, con lo scopo di esplorare il meccanismo di esecuzione e la Java Virtual Machine.

Supponiamo di aver creato il listato in figura e di averlo memorizzato in un file chiamato Hello.java. La scelta non è casuale: se un programma contiene una classe pubbli-ca che si chiama Hello allora deve trovarsi in un file con il nome indicato. Se è così, andiamo alla riga di comando del DOS (o di Linux), cambiamo alla directory dove si trova il sorgente e proviamo a compilare il primo programma, eseguendo javac Hello.java. Se non avete commesso errori di sintassi, non dovreste avere alcun messaggio. (Ricordatevi prima di installare il Java Development Kit, per i dettagli si veda il Riquadro 1).

Il risultato della compilazione è la comparsa, nella di-rectory corrente, del file Hello.class, che contiene il byte-code. È questo il vero codice eseguibile di Java. Senza un “.class”, anche se abbiamo un “.java”, il programma non può andare in esecuzione. Se abbiamo creato il “.class”, possiamo scrivere java Hello e otterremo il fatidico messag-gio Hello, world.

Approfittiamo della disponibilità del file Hello.class per dare un’occhiata a come è fatto il bytecode. Purtroppo se proviamo ad aprire ll suddetto file con un editor di testo rimarremo delusi: il file è binario e illeggibile dagli uma-

ni. Ma se utilizziamo il comando javap -c Hello possiamo decodificare il bytecode ottenendo quello che vediamo nel Listato 3.

Cosa scopriamo pertanto? Che il bytecode assomiglia mol-to ad un vero assemby. In effetti la JVM assomiglia molto ad un vero processore, solo che non è realizzato in silicio ma direttamente in software. C’è da dire comunque che la JVM non è esattamente progettata come un processore fisico, e presenta alcuni concetti “evoluti” come l’invoca-zione di metodi virtuali e altre caratteristiche che rendono particolarmente semplice compilare per essa un linguaggio di alto livello (come Java).

Le prestazioni

Quando si scopre che Java è sostanzialmente interpre-tato, molti programmatori associano immediatamente questo fatto con una lentezza di esecuzione. In realtà le cose non stanno proprio così. La maggior parte degli interpreti Java in realtà sono dei “compilatori Just-In-Time”: questo significa che trasformano il byte code “al volo”, immediatamente prima di eseguirlo, in codice macchina e poi lo eseguono a velocità nativa. Questo

RIQUADRO 1 Installare il Java Development Kit

Siete alle prime armi e non sapete da dove scaricare Java? Allora prima di cominciare a leggere l’articolo leggete queste istruzioni. Java viene fornito con due diversi download: il Java Runtime Environment (JRE), e il Java Development Kit (JDK). Il primo (JRE) serve per eseguire programmi in Java, mentre il secondo (JDK) serve per SVILUPPARE programmi in Java. Poiché vogliamo programmare, è necessario procurarci il JDK. Consigliamo di usare l’ultima versione, la 5.0.Potete scaricare il JDK dal sito http://java.sun.com. Fare attenzione che sito http://www.java.com fornisce il JRE, non il JDK. La posizione del JDK è, al momento in cui scrivo, questa (ma può ovviamente variare in quanto i rilasci di nuove versioni si susseguono con un ritmo frenetico):

http://java.sun.com/j2se/1.5.0/download.jsp

Consiglio per il momento di scaricare solamente il JDK, e non il bundle che comprende anche l’ambiente di program-mazione NetBeans: può essere abbastanza complicato orientarsi con un ambiente di sviluppo tuttofare finché non si conoscono i fondamenti. Gli esempi del nostro corso possono essere provati per il momento con un semplice editor di testo (ad esempio, Notepad su Windows). Ricordatevi comunque, dopo aver installato il JDK, di aggiungere al PATH gli strumenti di sviluppo. Se state usando Windows, dovete andare nel pannello di controllo, scegliere Sistema, Avanzate e poi Variabili di Ambiente, e infine impostare la variabile PATH e aggiungere all’inizio “C:\Programmi\Java\jdk1.5.xxx\bin;” (cambiare xxx con l’effettiva versione che avete nel vostro computer). A questo punto, da una finestra terminale, digitate “java -version”. Se leg-gete la versione di Java siete pronti per lavorare.

La JVM assomiglia

ad un vero processore

realizzato via software

JAVA Journal

n.1 - settembre 2006 59

educational

non significa che non ci sia un degrado di prestazioni rispetto al codice macchina puro; significa che il degra-do di prestazioni è molto inferiore a quello che normal-mente si pensa. In alcuni casi, la velocità di esecuzione di un interprete Java può essere addirittura superiore a quella di codice equivalente scritto in C/C++, perché il compilatore Just-In-Time è in grado di ottimizzare il codice durante l’esecuzione, in base ai risultati delle esecuzioni precedenti!

In verità, Java viene usato spesso per compiti abbastanza complessi: viene utilizzato spesso per realizzare appli-cazioni di tipo Web, che operano su complessi database relazionali. In questi casi, il tempo che viene impiegato per la trasmissione in rete delle pagine Web o per accedere al database occupa una porzione di tempo molto significativa (in certi casi superiore al 99%) rispetto al puro tempo di esecuzione del codice Java. In questi ambiti la pura veloci-tà di esecuzione del linguaggio conta molto poco rispetto al contesto. Infatti vengono comunemente utilizzati per questo tipo di applicazioni anche linguaggi di scripting, che sono, nei fatti, molto più lenti di Java, e raramente si considera la loro “pura” velocità di esecuzione come un fattore determinante.

Ma Java viene anche utilizzato anche per costruire i cosid-detti “Application Server”, ovvero complesse infrastrutture per l’esecuzione di programmi, dei veri e propri “sistemi operativi” per lo sviluppo di applicazioni Web. Siccome Java è nei fatti piuttosto efficiente e veloce, è possibile realizzarli interamente in Java.

La libreria di Java

Abbiamo dunque visto che abbiamo a che fare con un buon linguaggio di programmazione, e un buon supporto a tempo di esecuzione dello stesso, la JVM. Ma tutto questo non fa (ancora) di Java una piattaforma. I linguaggi di program-mazione tradizionali, come il C, il Pascal o lo stesso C++, prevedono nello standard le sole librerie standard minime per fare input/output a riga di comando. Il C++ va un po’ avanti perché fornisce anche, nelle sue versioni più recenti, strutture dati e algoritmi standard. Ma linguaggi più recenti come Visual Basic o Delphi, forniscono anche tutto il ne-cessario per sviluppare applicazioni a interfaccia grafica con connessioni a database: ovvero forniscono allo sviluppatore professionista il necessario per sviluppare applicazioni senza dover ricorrere a ulteriori componenti di terze parti.

Il Java standard fornisce, insieme al linguaggio di pro-grammazione e alla virtual machine, anche una cospicua libreria che permette di fare tutte le principali attività necessarie per lo sviluppo di programmi di tipo Desktop: creazione di interfacce grafiche, accesso a database, ma anche librerie per la manipolazione di strutture dati, di immagini, per processare l’XML, accedere al web e molto molto altro. Il bello della libreria Java è che, come la virtual machine, è totalmente indipendente dal sistema operativo sottostante. Questo fa sì che un programma scritto in Java sotto Windows possa funzionare senza modifiche anche sotto Linux e il Mac. Questa è la grande promessa di Java:

“write once run anywhere”. In realtà il raggiungimento effettivo di questo obiettivo ha richiesto considerevoli sforzi, ma si può dire che, dopo anni di sviluppo, sia stato raggiunto, e non solo in teoria ma anche in pratica.

La libreria di Java, inizialmente piccola e semplice (con la versione 1.0 di Java) si è nel tempo ingrandita in maniera considerevole. In effetti il “nocciolo” della piattaforma Java, la sua portabilità, è legata al fatto che è possibile fare moltissime cose utilizzando solamente la libreria standard di Java. In questo modo un programma dipende solo da essa; a sua volta la libreria Java è stata adattata a gran parte dei sistemi operativi moderni attualmente in uso (Windows, MacOSX, Linux, Solaris, AS/400 eccetera); in questo modo un programma “in Java” può funzionare praticamente dovunque senza modifiche.

In realtà, un programma scritto male può dipendere da comportamenti del sistema operativo sottostante, e quindi comportarsi diversamente su sistemi operativi differenti. Nel corso degli anni però questo problema si è via via at-tenuato, anche se ricorrendo a dei compromessi, a volte eccessivi. La libreria di Java si è da un lato ingrandita (ver-so l’impresa), dall’altro ridotta (verso i dispositivi mobili). Per questo motivo la “piattaforma Java” è stata divisa in tre edizioni: Standard, Micro ed Enterprise. Di fatto la differenza tra queste edizioni consiste, oltre a una virtual machine diversa per la Micro Edition, in un diverso corre-do di librerie fornite.

La Standard Edition è quella che abbiamo quando scari-chiamo Java dal sito http://java.sun.com. Per essere cor-retti, sul sito Sun sono disponibili due diversi pacchetti: il Runtime Environment e il Development Kit. Il primo serve per l’esecuzione di programmi in java; è il minimo assoluto necessario per poter usare programmi in Java sul proprio computer. Il secondo invece comprende degli strumenti per lo sviluppo, in particolare il compilatore e altre utilità per la programmazione.

La Micro Edition è Java adattato per funzionare su pal-mari, cellulari e in generale su dispositivi meno potenti di un Desktop Computer. In un certo senso, si tratta di una versione ridotta della Standard Edition; comprende anche librerie specifiche per funzionalità dei dispositivi mobili che non sono presenti nella Standard Edition. Di solito, troviamo Java già pronto per eseguire applica-

La libreria Java è

indipendente dal

sistema operativo

sottostante

JAVA Journal

n.1 - settembre 200660

educational

zioni in molti dispositivi mobili, come i telefoni cellulari Nokia, Motorola o SonyEriccson (per citare solo i casi più noti). Esistono anche versioni che si scaricano e si instal-lano, come la J9 di IBM disponibile per dispositivi PalmOS e PocketPC. La Micro Edition tuttavia è meno incapsulata della Standard Edition, anzi è piuttosto modulare (molti dicono troppo): esistono infatti diversi profili e configura-zioni. Per i dettagli rimandiamo all’articolo sull’argomento su questo stesso numero.

La Enterprise Edition invece è la Standard Edition estesa con una serie di funzioni che sono utili per la realizzazio-ne di applicazioni complesse per le imprese, di solito con interfaccia Web, ma che comprendono una serie di compo-nenti distribuiti che si parlano tra di loro. Di solito per ave-re la Enterprise Edition occorre procurarsi un applicativo che la implementa, comunemente noto come Application Server. Per esempio sono application server generalmente conformi a una versione di Java Enterprise Edition prodot-ti commerciali come BEA WebLogic o IBM WebSphere, o prodotti Open Source come JBoss o Apache Geronimo. Ma approfondiremo l’argomento in dettaglio in queste pagine prossimamente.

Struttura di un programma in Java

Riprendiamo l’obiettivo principale di questo corso, l’apprendimento del linguaggio Java (nonché di alcu-ne funzioni della libreria di base). Vediamo dunque la struttura dei programmi. Come abbiamo già detto nel nostro primo esempio, sfortunatamente (dal punto di vista didattico) non è possibile scrivere un programma Java che sia semplice come, per esempio, in BASIC. In questo caso, PRINT “HELLO” costituisce un programma valido. Il più piccolo programma valido in Java è forse class Hello { }, ma purtroppo questo programa non fa assolutamente nulla.

Per scrivere un programma che scriva “Hello” occorre digitare tutto questo mostrato nel primo listato. In breve occorre creare una classe, definire un metodo, ivi chiama-re un altro metodo (println) di un’altra classe (System) che stampa la nostra costante. Non è ancora il momento di capire come funziona. Vediamo invece innanzitutto la sintassi dei programmi in Java.

Gli elementi base di un programma in Java sono costanti e variabili. Una costante è per esempio il numero uno (1), un carattere ‘a’, o una stringa “hello”. Ci sono dei dettagli che vedremo più avanti. Una variabile è invece una se-quenza alfanumerica di lettere o numeri: per esempio a è una variabile. Per la verità anche _1 o a$ sono variabili valide in Java: la regola per gli “identificatori” è che siano sequenze alfanumeriche di lettere, numeri, il carattere “_” o il carattere “$”, e non possono cominciare con un nume-ro. In realtà Java permette anche di usare caratteri come le lettere accentate come lettere. Usando variabili, costanti e operatori (+,-,* eccetera) si creano delle espressioni. Quindi nel caso più semplice avremo:

a+1

Notare che in Java (come in C o in JavaScript) l’assegna-mento (=) è un operatore. Si possono anche usare le paren-tesi, quindi la seguente è una espressione:

b = a + (c-1)

Fin qui abbiamo considerato il mattone fondamentale di Java; ma un programma in Java non è solo un calcolo, ma una sequenza di calcoli. Chiameremo comando un singolo passo di esecuzione (che può comprendere un calcolo): i comandi infatti generalmente contengono delle espressio-ni. Un comando semplice è una espressione seguita da un punto e virgola. Per esempio:

b = a + 1 ;

I comandi possono essere posti in sequenza:

a = 1;b = a + 1 ;

Oltre ai comandi semplici, abbiamo anche i comandi com-posti, che possono contenere dei sotto-comandi semplici. Consideriamo questo caso:

a = 1;if(b>2) a = 2;

Il comando composto if contiene una espressione b>2 e un sotto-comando (a=2;); a sua volta esso contiene una espressione. Per il momento non ci soffermiamo oltre, lo scopo di questa introduzione alla sintassi è avere un’idea di come si presenta un programma Java. Affronteremo i dettagli strada facendo.

Un altro elemento importante presente nei programmi in Java, che non sono comandi ma che possono contenere espressioni, è la dichiarazione. Ecco un esempio:

int b

In questo caso int significa intero, ed è il nome di un tipo, mentre b è il nome di una variabile. Questa è una dichiarazio-ne di variabile. In generale prima di usare una variabile oc-

Per utilizzare la Enter-

prise Edition occorre

un applicativo che la

implementi,comunemente

noto come Application

Server

JAVA Journal

n.1 - settembre 2006 61

educational

Note Biografiche

Michele Sciabarrà si occupa di Java fin da quando, nel 93, sca-ricò il sorgente di HotJava e per compilarlo saturò il disco del-la Workstation Sun che amministrava. Da allora ha lavorato in Java passando dalle applet per Netscape 2 fino alle applicazioni bancarie di classe enterprise. Dopo aver scritto di Java e averlo insegnato per dieci anni, è direttore esecutivo di Java Journal. Quando non cerca di imparare le ultime API o disquisisce della superiorità del modello Open Source, si diletta a programmare cellulari Symbian in C++ e a amministrare sistemi Linux.

corre sempre dichiararla, ovvero specificare il suo tipo. Una dichiarazione può anche essere seguita da una espressione di inizializzazione (e conclusa da un punto e virgola)

int a = 1;

Una dichiarazione può essere usata (senza inizializzazio-ne) quando viene dichiarato un metodo, come nel seguente caso:

int sum(int a, int b) { return a+b;}

I metodi in Java assomigliano alle funzioni o alle proce-dure di altri linguaggi di programmazione. Questa strut-tura già diventa più complicata. Abbiamo l’intestazione int sum(int a, int b). In gergo si dice che è la “firma” di un metodo. Indica cosa viene fornito in ingresso e cosa viene ritornato quando viene chiamato. Un metodo in un certo senso assomiglia ad una funzione matematica, ma in realtà è qualcosa in più. La firma dichiara i parametri che prende e il valore che ritorna: il metodo add dunque pren-de due parametri a e b di tipo intero, e ritorna un risultato intero. Dopo la firma abbiamo il corpo del metodo, ovvero una sequenza di comandi racchiusi tra parentesi graffe. In alcuni casi ci serve solo la firma, e non il corpo: in questi casi al posto del corpo c’è semplicemente un punto e virgola.

Un elemento importante è che i metodi non possono es-sere dichiarati da soli. In altri linguaggi è possibile avere una funzione sum, ed è un componente non collegato ad altro in un programma. Non così in Java: non abbiamo un concetto di funzione a sé stante, ma solo di metodo, e come tale deve trovarsi sempre dentro la dichiarazione di una classe.

Come abbiamo detto, una classe è la minima entità auto-noma in java:

class Hello {}

è un programma valido che può essere compilato da solo. Ma non fa assolutamente nulla. Dentro la classe possiamo inserire la dichiarazione di un metodo:

class Sum { int sum(int a, int b) { return a+b; }}

Anche questa è una classe valida, e contiene anche un me-todo di somma. Per completare il discorso, ci serve capire che relazione abbiamo tra un metodo e una classe. Consi-deriamo questo esempio:

class Doubler { int two =2;

int doubler(int x) { int res = x*two; return res; } }

L’esempio non vuole essere codice da usare in programmi reali. È scritto in questo modo per evidenziare due cose: le diverse posizioni in cui è possibile collocare una dichiara-zione di variabile, e le cosiddette variabili libere. Ma andia-mo con ordine.

Per prima cosa notiamo la dichiarazione di variabile: oltre ad essere presente nel parametro del metodo (int x), è pre-sente anche dentro il metodo (int res = x * two) e fuori dal metodo ma dentro la classe (int two=2). Nel primo caso, la variabile viene comunemente chiamata variabile locale. Il motivo è che queste variabili vengono create quando si entra nel metodo, ma scompaiono quando si esce dal metodo. Nel secondo caso (int two=2) queste variabili ven-gono chiamate campi, e sono persistenti. Per essere esatti (ma è un concetto che dovremo riesaminare più avanti in maggior dettaglio) i campi esistono fin tanto che esiste l’oggetto che le contiene.

Infine introduciamo il concetto di “variabile libera”. Se osserviamo in dettaglio il corpo del metodo doubler no-teremo a un certo punto l’espressione res = x*two. Ora, res è una variabile locale, mentre x è un parametro, ma two non è nessuna delle due. Guardando il solo corpo del metodo non si riesce a trovare dove questa variabile è dichiarata: per questo motivo viene detta variabile li-bera. Ma in Java le variabili libere di un metodo possono solo fare riferimento alle variabili della classe, ovvero ai campi.

È abbastanza importante sviluppare occhio per le variabili libere in un metodo: questo ci permette di localizzare fa-cilmente i campi; è dove vengono memorizzate le informa-zioni che devono persistere al di fuori del metodo corrente. In un certo senso, le variabili libere mettono in comunica-zione il metodo con la classe che le contiene.

Conclusioni

Se Java lo conoscevate solo per sentito dire, adesso ab-biamo mosso i primi passi. Abbiamo parlato di virtual machine e di byte code, e abbiamo spiegato le varie edi-zioni di Java. Nel prossimo numero vedremo in dettaglio il linguaggio, esaminando come sono implementati in Java i classici costrutti di programmazione.

SPEECH Login TopicFREE

if (a instanceof b) { // fai qualcosa} else if (a instanceof c) { // fai qualche altra cosa}

Ora, già l’uso di instanceof è di per sé criticabile: instanceof in un linguaggio ad oggetti non dovreb-be mai essere usato, se non in un caso particolare che lascio come simpatico esercizio agli amici let-tori.

Ma usare instanceof per fare eseguire logiche di-verse ad un oggetto a seconda del suo tipo, è vera-mente abominevole: a cosa serve il polimorfismo – che fa esattamente la stessa cosa - se poi devo ricostruirmelo malamente da solo? Notare che il fatto che l’operazione sia eseguita sullo lo stesso oggetto su cui si è operata la condizione o su un altro è irrilevante: in quest’ultimo caso è solo se-gno di un cattivo assegnamento di responsabilità e della necessità di spostare l’eventuale metodo al posto giusto.

a.faiQualcosa()

È evidente come il vero polimorfismo sia infinita-mente superiore alla sua brutta copia: l’”if” viene fatto dal runtime automaticamente, e voi non dovete fare nulla di particolare se non usare degli oggetti in maniera polimorfa. Il polimorfismo dei poveri invece va invece mantenuto, ogni volta che si introducono nuovi tipi e nuove logiche: di solito fra l’altro questo tipo di strutture condizionali si trovano ripetute in diversi punti del codice, poi-chè è molto comune che esistano diverse logiche da eseguire, rendendo l’introduzione di bug così probabile da essere quasi scontata. Il vero poli-morfismo invece vi permette semplicemente di aggiungere nuovi metodi per ogni nuova logica, concentrando così in unico punto tutto ciò che ha

#1: Il polimorfismo dei poveri

Voglio cominciare questa rubrica con una “worst practice” fra le più orribili, il polimorfismo dei poveri. Non che non abbia materiale a disposizio-ne per decine e decine di rubriche, e centinaia di esempi di come non si dovrebbe scrivere del codice in Java... ma questa particolare pratica, oltre a es-sere veramente brutta, ha delle caratteristiche che secondo me la rendono unica. E per questo deve avere l’onore del primo numero di questa rubrica dedicata alle brutture nel design.

• È assolutamente non necessaria, e l’alternativa è nell’abc della programmazione ad oggetti

• Non offre nessun vantaggio particolare rispetto all’alternativa corretta, ma solo svantaggi. Altre brutture perlomeno hanno una qualche giustifi-cazione più o meno fondata, questa no.

• È incredibilmente diffusa

Il polimorfismo dei poveri è caratterizzato da codi-ce simile a questo:

IDIOMATICA

n.1 - novembre/dicembre 200662

Codice orribile, antipattern e pratiche discutibili

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: “My guess is that object-oriented programming will be in the 1980s what structured programming was in the 1970s. Everyone will be in favor of it. Every manufacturer will promote his products as supporting it. Every manager will pay lip service to it. Every program-mer will practice it (differently). And no one will know just what it is.”

T. Rentsch

>> di Ugo Landini ([email protected])

SPEECH Login TopicFREE IDIOMATICA

gli stessi motivi per cambiare.

Eseguite per curiosità un bel

grep -R instanceof .

nella directory demo del vostro JDK, e troverete molti esempi di poliformismo dei poveri. Sembra che Swing sia un portatore (sano?) di polimorfi-smo dei poveri!

Permettetemi di riformulare il concetto in maniera più immediata: se trovate del codice che usa “il po-limorfismo dei poveri”, è codice strutturato e non codice ad oggetti. Che sia nelle librerie di java, che l’autore sia considerato un guru, che sia uno dei software open più blasonati, che l’abbiate trovato su un libro (di solito di API, non certo di design), o che l’abbiate scritto voi stessi in quello che con-siderate il vostro capolavoro di programmazione ad oggetti, non cambia la sostanza: non sarà che in 20 anni questa benedetta programmazione ad oggetti a molti non è ancora entrata in testa?

Esercizi:

Eliminare il polimorfismo dei poveri da uno qual-siasi degli esempi Swing del jdk. Come dite? Eh no, così bisogna rivedere le gerarchie... e poi inserire nuove interfacce. E poi bisogna eliminare quelle istanziazioni di oggetti concreti... bene, quella si chiama programmazione ad oggetti. Ora salutate con la manina quella brutta e vecchia programmazione strutturata, e cercate di lasciar-vela per sempre alle spalle!

Conclusioni:

Il polimorfismo dei poveri è una delle peggiori pratiche che si possa adottare per avere codice dif-ficilmente manutenibile, inutilmente complicato e soggetto a bug. Il polimorfismo dei poveri indica inoltre che non state sfruttando la potenza degli oggetti. Se siete pagati per linee di codice, o per bug risolti, usatelo pure liberamente! Ma se poi vi trovate nei guai, non dite che nessuno vi aveva avvertito...

n.1 - novembre/dicembre 2006 63

SPEECH Login TopicFREE

JJ: Dalla tua posizione di osservatore privilegia-to, come ti sembra sia cambiato il mondo Java in questi anni?

DR: Moltissimo. Ho assistito a cambiamenti radicali su questa tecnologia e visto nascere il mondo opensource che ben si integra con esso.Ho visto la proliferazione di un gran numero di prodotti di ogni genere e qualità, di framework che permettono di risparmiare tempo: sono basati su scheletri gestiti da elementi descrittivi spesso di tipo xml, a partire dei quali è possibile generare codi-ce e costruire per esempio interi portali.Tuttavia non sono completamente favorevole ai fra-mework perché se da una parte permettono di generare un prodotto con meno errori perché si deve intervenire meno nel codice, spesso per imparare ad usarli occor-re un tempo superiore alla vita del framework stesso. Inoltre sono spesso invasivi nel codice e, a causa del livello più alto di astrazione, non sono facili da gestire se qualcosa non funziona, o se si devono effettuare delle personalizzazioni pesanti.

JJ: Come sono i rapporti con i vari Java User Group?

DR: C’è stata un po’ di diffidenza iniziale e qualche incomprensione. Ma confido in un futuro denso di col-laborazioni anche perché abbiamo un obiettivo comune che è la divulgazione di Java e non avrebbe molto senso fare una guerra tra “fratelli” perché sarebbe contropro-ducente per tutti. Inoltre non vedo JIA in contrapposi-zione con i JUG. JIA non è un JUG perché porta avanti temi sociali che siano utili a tutti, anche verso le cate-gorie meno esperte e disagiate. I JUG invece possono occuparsi di tematiche più avanzate e all’avanguardia. Oggi esistono più JUG a livello locale, questo sicura-mente facilita gli incontri dal vivo e in questo modo si possono creare collaborazioni inter-jug. Questa cosa nel JIA non si può fare perché essendo una realtà nazionale ha maggiori difficoltà ad organizzare incontri dal vivo.

Inaguriamo lo spazio community intervistando il presidente di una delle più “antiche” associazioni di sviluppatori Java, il JIA (Java Italian Association).

JJ: Ciao Daniela, ci racconti che cosa è il JIA e da quando tempo esiste?

DR: la Java Italian Association è nata l’11/12/1997 da-vanti ad un notaio di Roma grazie alla volontà di un gruppo di amanti della tecnologia java. Questa associa-zione senza scopo di lucro, costituita da 66 soci fondato-ri, è un punto di riferimento sia per il mondo del lavoro che per quello della scuola. Tramite JIA è possibile per i soci anche ottenere una visibilità maggiore, promoven-do la loro professionalità attraverso la docenza in corsi o seminari java, o nella scrittura di articoli o in altre occu-pazioni sociali e culturali utili alla comunità Java. Nello statuto sono descritte in dettaglio tutte le attività di cui ci JIA si può occupare.

JJ: Quali sono le attività più interessanti che ri-cordi del JIA in questi anni? DR: Ne abbiamo fatte veramente tante: la produzione di CD, la partecipazione a seminari a conferenze im-portanti, la traduzione di corsi java dall’inglese... Direi che il progetto più interessante è stato il progetto scuola diretto a docenti e studenti di scuola media e realizzato assieme alla società Sun Microsystems e al Ministero dell’Istruzione, Università e Ricerca nel 2003. Adesso, nel 2006, siamo in partenza con la seconda release.Nel 2003 Il progetto comprendeva tre corsi web in lingua inglese fornito dalla società Sun Microsytems mentre JIA forniva i tutor di supporto ai docenti sui corsi java. Il progetto ha previsto anche la realizzazione di un mini-portale, che è partito il 15 Gennaio con la pre-registrazione degli studenti e degli insegnanti dopo un incontro con la stampa avvenuto a Milano in data 10/1/2003. La sua durata è stata di circa un anno. Nel 2006 invece il progetto riguarda la possibilità di par-tecipare ai corsi del programma SAI (Sun Accademic Initiative della Sun Microsystems). Anche questa volta JIA fornisce i tutor di supporto ai docenti sui corsi java.

COMMUNITY

n.1 - novembre/dicembre 200664

Intervista a Daniela Ruggeri, presidente dellaJava Italian Association

Ü di di Michele Sciabarrà ([email protected])

SPEECH Login TopicFREE COMMUNITY

JJ: Perché esiste un Linux Day organizzato dalla Italian Linux Society e non esiste un Java Day (al di là dell’annuale conferenza annuale di Sun) ?

DR: Java non è come Linux: essendo un sistema ope-rativo può coinvolgere un maggior numero di persone anche non tecniche e quindi ottenere un pubblico nu-meroso in tali conferenze. Java finora ha interessato soprattutto tecnici e quindi un numero nazionale di persone piuttosto ristretto. Tuttavia il coinvolgimen-to delle scuole e la diffusione di questa tecnologia con i cellulari, ha fatto si che anche persone meno esperte venissero a conoscenza di java. Proprio in questi giorni si sta tentando di organizzare un java-day e stiamo decidendo le date e le città dove tenerlo.

JJ: Come vedi la “concorrenza” a Java di linguaggi come C# dal versante Microsoft?

DR: Non la vedo proprio. Prima di tutto i programma-tori che amavano Java hanno continuato ad amarlo an-che dopo; Java è sicuramente più famoso e più presente nella mente dei clienti. Anche Microsoft ha deciso di occuparsi di nuovo del linguaggio Java perché proba-bilmente si è resa conto che abbracciava un ramo del mercato troppo esteso per ignorarlo....

JJ: E come vedi PHP/Python/Perl/Ruby dal mondo Open Source?DR: Questa è una domanda interessante perché sembra che le nuove leve (ragazzini di 16-18 anni) amino molto questi linguaggi perché più immediati. Però non dimen-tichiamoci che con questi linguaggi si costruiscono ar-chitetture non molto robuste. Java non è un linguaggio ma una tecnologia insegnata all’Università. Non è un

caso che sia molto difficile impararla e applicarla nella maniera adeguata...

JJ: Cosa vorresti che succedesse nel mondo Java nei prossimi anni?DR: Il futuro dei prossimi anni è del mobile e del voip. Java è fatto apposta per questi mondi.Ma se nei prossimi anni esplodesse la robotica e la demo-tica sarebbe il massimo poter applicare java anche qui.

JJ: E che cosa temi di più? DR: Non esistono linguaggi che un programmatore può temere ma la precarietà del mercato si. Soprattutto quando in particolare l’Italia ha la concorrenza di paesi come Cina, Romania, India ecc. dove esistono università anche migliori delle nostre che permettono di preparare programmatori molto validi disposti a lavorare a costi bassissimi.

JJ: Mi racconti un aneddoto divertente che ti è ca-pitato in questi anni come presidente del JIA?

DR: Non ricordo molti aneddoti divertenti, gestire un’associazione, soprattutto virtuale, è un’attività faticosa e densa di problemi. In tutti questi anni ho avuto gioie derivanti da una crescita professionale che un’associazione di questo genere ha l’opportunità di dare, mediante l’incontro con persone di alto livello tecnico e derivanti dal fatto di essere veramente utili nel divulgare una tecnologia interessante come Java.Ma ho avuto anche dolori derivanti da critiche e scontri che in ogni caso però vedo sempre positive perché riten-go che le esperienze negative (forse maggiormente di quelle positive) contribuiscono a far maturare e a non far ripetere determinati errori commessi per leggerezza.La cosa che comunque giudico molto divertente è quan-do finalmente ci si incontra tra noi soci in qualche riu-nione o conferenza per raccontare le nostre esperienze, presiedere uno stand o tenere un seminario. Ma penso che questa sia una sensazione comune di tutte le comu-nità in genere.

n.1 - novembre/dicembre 2006 65

RIQUADRO 1 La Java Italian Association

La Java Italian Association (http://www.jia.it) è un’associazione senza scopo di lucro, costituita da 66 soci fondatori nel 1997 ed è un punto di riferimen-to sia per il mondo del lavoro che per quello della scuola. I suoi obiettivi riguardano la divulgazione del linguaggio java e delle tecnologie emergenti con ogni mezzo come seminari, articoli e progetti. Tra le attività più importanti ci sono il progetto “Java a Scuola” organizzato in collaborazione con Sun Microsystems e con il Ministero dell’Istruzione per la formazione java di studenti e docenti di scuola media superiore (http://www.jia.it/modules.php?name=Content&pa=showpage&pid=93) e “Tecknos” (http://www.tecknos.it) la conferenza sull’Innovazione Tecnologica organizzata con la società Apai (http://www.apai.biz) a Sarzana (La Spezia) con lo scopo di far aumentare il contributo tecnologico italiano in Europa.

Note Biografiche

Daniela Ruggeri è laureata in Matematica presso l’Universi-tà di Studi di Roma. Si occupa di Informatica dal 1982 e di Java dal 1995. È socio fondatore e Presidente della Java Ita-lian Association ed uno dei fondatori di Mokabyte la prima rivista online dedicata a Java, per la quale ha scritto 17 arti-coli. È autrice di vari articoli e ha tenuto diversi seminari per diverse manifestazioni come Inforscuola, Webbit e Infome-dia. Ricopre attualmente la figura professionale di quadro come senior consultant presso la società Aubay SPA (http://www.aubay.it)