Sei sulla pagina 1di 68

www.infomedia.

it EDITORIALE

JAVA Journal
BIMESTRALE - ANNO 1 - N.2

DIRETTORE RESPONSABILE
Java Journal
MARIALETIZIA MARI
(MMARI@INFOMEDIA.IT)

DIRETTORE ESECUTIVO
in presa
diretta
MICHELE SCABARRÀ
(MICHELE.SCIABARRA@JAVAJOURNAL.IT)

EDITORIAL BOARD
UGO LANDINI, STEFANO SANNA,
TO N Y M O B I L Y

COLLABORATORI
M I C H E L E FE R R E T T I
UGO LANDINI
STEFANO SANNA In occasione del secondo numero di una rivista, Java Journal compresa, non è cer-
EDOARDO SCHEPIS to tempo di bilanci; però un resoconto su come sono andate le cose dopo il primo
FA B I O S T A R O numero si può dire. Innanzitutto, la rivista sta riscuotendo interesse. A riprova
MATTEO ZINATO di ciò abbiamo ottenuto un primo riscontro anche dalla casa madre di Java, Sun
Microsystems, dalla quale siamo completamente indipendenti, ma con cui siamo
onorati, quando vi è occasione, di poter collaborare. E in effetti una prima forma di
collaborazione si è concretizzata in occasione dell’evento più importante nel mondo
Java, non solo degli ultimi mesi.
Tra l’uscita del primo numero e la preparazione del secondo, è avvenuta una delle più
importanti transizioni per Java: l’annuncio del rilascio dei sorgenti Java in licenza
GPL. Dopo tanti anni, Java diventa, finalmente e definitivamente, un prodotto sia
GRUPPO EDITORIALE INFOMEDIA SRL
Open Source sia Free Software. In questo modo, Java soddisfa anche i palati più
V I A V A L D E R A P. 1 1 6 esigenti in fatto di “apertura” e di “libertà” della piattaforma.
5 6 0 3 8 PO N S A C C O ( P I ) I T A L I A In seguito a questo importante avvenimento, abbiamo avuto occasione di poter
TE L 0 5 8 7 7 3 6 4 6 0 F A X 0 5 8 7 7 3 2 2 3 2 intervistare, su invito di Sun, il principale artefice di questa trasformazione: Simon
E-MAIL INFO@INFOMEDIA.IT Phipps. Simon, per chi non è addentro agli organigrammi di Sun, è il direttore delle
S I T O W E B W W W. I N F O M E D I A . I T iniziative Open Source di Sun. Prima di lavorare in Sun è stato un importante pro-
tagonista della adozione di Java, XML e dell’Open Source in IBM. Un personaggio
DIREZIONE chiave, quindi, di indiscussa rilevanza.
N A T A L E FI N O (NFINO@INFOMEDIA.IT) E il sottoscritto, vostro umile (ma fiero) direttore della neonata Java Journal, ha avu-
to l’onore di intervistarlo nel corso di una sua visita in Italia, a Milano. Nonostante
CONTATTI l’apprensione del dover sostenere, e in inglese, la prima intervista “ufficiale” per
Java Journal con un personaggio di tale spessore, sono sopravvissuto indenne. E gra-
TE C H N I C A L B O O K zie agli anni di analisi delle problematiche dell’Open Source, gli ho posto un numero
(BOOK@INFOMEDIA.IT) di domande, abbastanza dettagliate. Troverete in questo stesso numero l’intervista
a Phipps, ovviamente … tradotta in italiano (un buon motivo in più per sostenere le
MARKETING & ADVERTISING iniziative di Java Journal).
SEGRETERIA: 0587736460
MARKETING@INFOMEDIA.IT
Detto questo, passiamo alle “comunicazioni di servizio”. Innanzitutto, abbiamo de-
ciso di utilizzare meglio lo spazio cartaceo, e di eliminare il corso base di Java, che
AMMINISTRAZIONE abbiamo invece sostituito con un videocorso. Il videocorso era nato in altri contesti,
(AMMINISTRAZIONE@INFOMEDIA.IT)
ma ho avuto la possibilità di portarlo in dote alla rivista Java Journal. Questo video-
SEGRETERIA corso lo abbiamo anche offerto gratuitamente a tutti coloro che si sono abbonati fino
(INFO@INFOMEDIA.IT) al 31 gennaio 2007.
Inoltre, da questo numero Stefano Sanna inaugura la rubrica “Community Watch”,
GRAFICA in cui ci parla di delle varie iniziative in corso nella comunità Java, di cui è, da sem-
STEFANO BELLANI pre, un membro attivissimo.
(GRAFICA@GRUPPOINFOMEDIA.IT)
Lo speciale di questo numero riguarda la Java Micro Edition (Java ME), che riscuote
sempre più interesse. E non è un caso che il primo codice di Java disponibile come
UFFICIO ABBONAMENTI Open Source sia proprio una implementazione di Java ME. Detto questo, non mi
TE L 0 5 8 7 7 3 6 4 6 0 F A X 0 5 8 7 7 3 2 2 3 2 resta che passare la mano ai collaboratori di questo secondo numero: gli argomenti
ABBONAMENTI@INFOMEDIA.IT presentati sono tutti molto interessanti e gli articoli, come potrete apprezzare, sono
W W W. I N F O M E D I A . I T stati redatti da professionisti di ampia e consolidata esperienza.
JAVA E TUTTI I MARCHI DERIVATI
SONO MARCHI O MARCHI REGISTRATI
DI SUN MICROSYSTEMS, INC. NEGLI Michele Sciabarrà
U S A E I N A L T R I PA E S I . I L G R U P P O Direttore Esecutivo
EDITORIALE INFOMEDIA È INDIPEN- Java Journal
DENTE DA SUN MICROSYSTEMS, INC.

n.2 - gennaio/febbraio 2007 3


JAVA Journal numero 2

SOMMARIO Gennaio/Febbraio 2007

Speciale Java Micro Edition


I package opzionali della Java Micro Edition
di Edoardo Schepis 8
J2ME Best Practice
di Matteo Zinato 15

Educational
Apache Ant
di Michele Ferretti 31
Java 5, le buone nuove e le novità meno buone
Seconda parte
di Ugo Landini 38

Focus
Resource Management con JMX
di Fabio Staro 49
Accedere a file di Excel in Java
di Luigi Zanderighi 63

Rubriche
Community
Intervista a Simon Phipps
Chief Open Source Officer di Sun Microsystems
di Michele Sciabarrà 46

Community Watch
di Stefano Sanna 60

Idiomatica
Codice orribile, antipattern e pratiche discutibili
di Ugo Landini 61

n.2 - gennaio/febbraio 2007


IN VETRINA
Learning JavaScript Mobile 3D Graphics
di S. Power di A. Malizia

Il libro illustra gli elementi fonda-


mentali per la programmazione
Attraverso gli esempi più recenti di grafica 3D mobile con gli standard
pratiche di sviluppo per i moderni API, trattando sia le interfacce di
browser, il libro insegna come in- base che quelle avanzate, oltre ai
tegrare il linguaggio con l’ambiente principali device wireless e mobile
del browser. che supportano la programma-
Attraverso la lettura di questo libro zione grafica 3D mobile. Include
si padroneggerà l’uso dell’intero una spiegazione esaustiva sulla
linguaggio JavaScript e di molti programmazione 3D mobile; un
O’ Reilly object model presenti nei browser Springer lungo elenco di esempi di codice in
351 pp - 31,00 Euro web; sarà anche possibile creare 162 pp - 58,60 Euro C e in Java; combina metodi grafici
ISBN 0596527462 applicazioni Ajax elementari. ISBN 1846283833 2D e 3D.

Ajax trucchi e segreti An introduction to Design


di B. W. Perry Patterns in C++ with Qt 4
di A. Ezust, P. Ezust

Il libro presenta una serie di solu-


zioni pronte all’uso e svela tutte le
potenzialità di Ajax.
Imparerete a dotare le form HTML Si tratta di un tutorial completo
di funzionalità Ajax, personalizzan- che non dà per scontate pregresse
dole per rispondere alle aspettative conoscenze di C, C++, oggetti o
degli utenti, esplorare e combinare pattern.
Tecniche Nuove tra loro le API di Google Maps, di Prentice Hall Una guida a piccoli passi corredata
432 pp - 29,90 Euro Yahoo! Maps e di GeoURL e molto 656 pp - 46,70 Euro di numerosi esempi ed esercizi di
ISBN 8848119751 altro ancora. ISBN 0131879057 Qt 4.1.

Java Generics and Enterprise Service


Collections Oriented Architectures.
di M. Naftalin, P. Wadler Concepts, Challenges,
Recommendations
J. McGovern et al

Enterprise Service Oriented Archi-


Il libro copre ogni ambito, dagli tectures permette al lettore di far
usi dei generics fino ai casi più comunicare diverse applicazioni in
particolari. modo “loosely coupled”.
Insegna tutto ciò che serve sulle Si tratta di un classico attraverso
collections libraries, permettendo cui si possono imparare i principi
O’ Reilly di sapere sempre quale sia la col- Springer basilari e fondamentali di un’archi-
294 pp - 34,95 Euro lection appropriata per il compito 408 pp - 57,80 Euro tettura service-oriented.
ISBN 0596527756 dato e come usarla. ISBN 140203704X

Visual Basic 2005 Reti domestiche


Tecniche e soluzioni di S. Lowe
di J. Kent

Questa guida all’autoapprendi-


mento inizia spiegando i concetti
fondamentali della programma-
zione. Quindi illustra come creare Al giorno d’oggi milioni di compu-
sofisticati elementi dell’interfaccia ter sono connessi a Internet, ma il
utente grafica, tra cui menu, collegamento di pochi computer in
barre degli strumenti e finestre una rete casalinga risulta ancora
di dialogo. Al termine del libro, il difficile.
lettore sarà in grado di realizzare Con un linguaggio chiaro e senza
applicazioni Windows e Web anche termini gergali, e con un tocco di
Mc Graw Hill con l’utilizzo di database. Corredato O’ Reilly/Tecniche Nuove umorismo, il libro aiuta a capire
300 pp, euro 26.00 di quiz alla fine di ogni capitolo ed 250 pp - 24,90 Euro tutto ciò che è necessario per
ISBN 8838644470 un esame finale. ISBN 8848118437 installare una rete domestica.

6 n.2 - gennaio/febbraio 2007


JAVA JOURNAL 2
Programmare con Visual Firewall e VPN
Basic 2005 Express di T. Behrens et al.
di W. Wang

La maggior parte dei libri di pro- Vero e proprio punto di riferimento


grammazione cerca di insegnare nella protezione delle reti e configu-
contemporaneamente come scrive- razione di Firewall e VPN. Oltre alla
re un programma utilizzando un lin- teoria necessaria generale è pre-
guaggio specifico, come program- sente un’attenta descrizione delle
mare, come scrivere un programma procedure con il software 7.0 per
utilizzando un particolare ambiente l’intera famiglia di Firewall Cisco
di sviluppo e un compilatore. Ciò PIX della serie 500. Questo volume
può portare alla confusione. Visual spiega dettagliatamente come
Basic 2005 Express offre una sfruttare le funzionalità integrate
O’ Reilly/Tecniche Nuove introduzione su come funziona la Mc Graw Hill per reti virtuali reti private virtuali
560 pp - 39,90 Euro programmazione indipendentemen- 590 pp - 44,00 Euro ad accesso remoto e site-to-site
ISBN 8848119484 te dal linguaggio usato. ISBN 8838644624 offerte dai Firewall Cisco PIX.

Riparazione & upgrade per Scrivi a book@infomedia.it specificando


pc, workstation e server nell’oggetto della e-mail:
di S. Mueller et al
IN VETRINA JAVA JOURNAL 2
Da quasi 20 anni i testi di Scott
Mueller sono il riferimento per la
OPPURE
manutenzione e la comprensione inviaci il coupon al numero di fax 0587/732232
dei computer. Ora anche gli ammi-
nistratori di workstation e server
troveranno soddisfazione in un te-
sto con spiegazioni complete sulla Potrai acquistare i libri qui riportati
riparazione e sull’upgrade. Questo
libro è la prima linea di difesa per le
con uno SCONTO ECCEZIONALE
Mc Graw Hill
società che gestiscono installazioni del 10% anche se acquisti solo un libro
e supporto dei propri computer e
1050 pp - 74,00 Euro un eccellente riferimento per gli OPPURE
ISBN 8838644640 amministratori esperti.
del 20% se acquisti 3 libri

JAVA JOURNAL 2
speciale Java Micro Edition JAVA Journal

I package
opzionali della
Java Micro Edition
In questo articolo prendiamo in considerazione le principali librerie della Java Micro Edition,
orientate allo sviluppo di applicazioni per dispostivi mobili, tra cui cellulari, smartphone, PDA e
palmari

>> di Edoardo Schepis (edoardo.schepis@javajournal.it)

D
Dal lavoro del JCP vengono fuori tutte le JSR sulle
quali si basano le applicazioni Java attualmente
opo una breve panoramica sulla realizzate nel mondo, negli ambiti Java Standard,
tecnologia e sulle principali im- Enterprise e Micro Edition.
plementazioni oggi presenti sul Per un breve elenco delle principali JSR relative alla
mercato, sposteremo l’attenzione diverse Edition della piattaforma Java rimandiamo al
su quali novità ci riserva il futuro. Riquadro 1. Nel seguito ci occuperemo più in detta-
Sfruttando le API ancora in fase glio di quelle legate alla Micro Edition.
di studio vedremo come sarà pos-
sibile ben presto gestire direttamente da una nostra Le origini della Java Micro Edition
applicazione:
Al momento della sua nascita (parliamo dell’anno
• una conversazione telefonica, 1999) la Java Micro Edition costituiva più che altro il
• i micropagamenti, tentativo di portare Java là dove esisteva solo tecno-
• ed anche una trasmissione interattiva del digitale logia embedded proprietaria. Nessun altro operatore
terrestre. tecnologico nel campo del software aveva investito
abbastanza in quell’area, lasciando così che ciascun
Per capire quanto sia articolato e vario il mondo delle produttore di hardware si occupasse dello sviluppo
specifiche Java in campo Micro Edition dobbiamo in- del software secondo modalità e specifiche del tutto
nanzitutto fare qualche premessa riguardante il pro- chiuse e proprietarie.
cesso relativo alla loro stesura e implementazione.
Il primo tentativo di rompere con questo approccio
Il Java Community Process fu fatto con l’obiettivo di permettere agli svilup-
patori Java di creare proprie applicazioni anche
Tutto nasce, e direi cresce, nell’ambito del Java su quei dispositivi che fino ad allora erano rimasti
Community Process (JCP): una organizzazione com- accessibili solo nei laboratori delle aziende produt-
posta da membri attivi, aperta a tutti (chiunque può trici.
prendervi parte), che si occupa della stesura e dello Si partì con un approccio a dir poco analitico: biso-
sviluppo delle specifiche tecniche nel mondo Java: le gnava innanzitutto classificare il vasto mondo della
cosiddette Java Specification Requests (JSR). tecnologia “micro”; e non era certo semplice. In que-
st’area rientravano infatti le smart card, i dispositivi
Il JCP ha come compito principale quello di defini- mobili con cui oggi abbiamo maggiore confidenza
re ed alimentare l’evoluzione della tecnologia Java, (cellulari e PDA), ma anche i navigatori satellitari
assicurandone un elevato livello di stabilità e di delle nostre automobili e i decoder del digitale ter-
interoperabilità proprio grazie alla partecipazione al restre tanto in voga oggi. Si iniziò così a parlare di
processo di tutti i suoi membri. configuration e profile.

8 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

RIQUADRO 1 Elenco delle principali JSR presenti nella Java Enterprise e nella Standard Edition

Elenco delle principali JSR presenti nella Java Enterprise e nella Standard Edition
Nella tabella di seguito sono riportate le principali JSR definite per le piattaforma Java Enterprise, Standard e Micro
Edition.
È possibile approfondire lo studio di ciascuna di esse collegandosi al sito “http://www.jcp.org/en/jsr/detail?id=” se-
guito dal numero della JSR di interesse.

Nel sito è possibile trovare un documento contenente le specifiche e una reference implementation da utilizzare per lo
sviluppo software.

Java Enterprise Edition


JSR 3 Java Management Extensions (JMX) Specification
JSR 16 J2EE Connector Architecture
JSR 19 Enterprise JavaBeans 2.0
JSR 53 Java Servlet 2.3 and JavaServer Pages 1.2 Specifications
JSR 54 JDBC 3.0 Specification
JSR 116 SIP Servlet API
JSR 124 J2EE Client Provisioning Specification
JSR 127 JavaServer Faces
JSR 151 Java 2 Platform, Enterprise Edition 1.4 (J2EE 1.4) Specification
JSR 162 Portlet API
JSR 220 Enterprise JavaBeans 3.0
JSR 233 J2EE Mobile Device Management and Monitoring Specification

Java Standard Edition


JSR 12 Java Data Objects (JDO) Specification
JSR 51 New I/O APIs for the Java Platform
JSR 63 Java API for XML Processing 1.1
JSR 80 Java USB API
JSR 93 Java API for XML Registries 1.0 (JAXR)
JSR 101 Java APIs for XML based RPC
JSR 176 J2SE 5.0 (Tiger) Release Contents
JSR 189 Java 3D API 1.4
JSR 197 Generic Connection Framework Optional Package for the J2SE Platform
JSR 241 The Groovy Programming Language
JSR 270 Java SE 6 (“Mustang”) Release Contents

Java Micro Edition


JSR 30 J2ME Connected, Limited Device Configuration
JSR 36 Connected Device Configuration
JSR 37 Mobile Information Device Profile for the J2ME Platform
JSR 75 PDA Optional Packages for the J2ME Platform
JSR 82 Java APIs for Bluetooth
JSR 118 Mobile Information Device Profile 2.0
JSR 120 Wireless Messaging API
JSR 135 Mobile Media API
JSR 172 J2ME Web Services Specification
JSR 177 Security and Trust Services API for J2ME
JSR 179 Location API for J2ME
JSR 184 Mobile 3D Graphics API for J2ME
JSR 272 Mobile Broadcast Service API for Handheld Terminals

n.2 - gennaio/febbraio 2007 9


speciale Java Micro Edition JAVA Journal

FIGURA 1 Confronto delle Edition della Java Platform

Configuration e profile In Figura 1 è possibile vedere a confronto le diverse Edi-


tion della Java Platform.
Una configuration definisce il minimo ambiente per l’ese-
cuzione del Runtime Java per una certa famiglia di disposi-
tivi. Si tratta in altre parole dell’accoppiata Java VM e API Superare i limiti: l’approccio a package
di base che permettano l’esecuzione di una applicazione
Java su una particolare famiglia di dispositivi che risponda Di configuration e profile ne sono state rilasciati un paio
a certe caratteristiche: di versioni a testa. Attualmente siamo alla CLDC 1.1 e al
MIDP 2.0, ma l’idea sulla quale si fonda tale classificazione
• con la connected limited device configuration (CLDC) si ci fa suonare da subito un piccolo campanello d’allarme.
indirizzano i dispositivi con capacità molto limitate in Chi ha avuto a che fare con i sistemi embedded sa, più
termini di I/O, di risorse di memoria e di possibilità com- degli altri, che suddividere le librerie per lo sviluppo sulla
putazionali; base delle risorse hardware a disposizione può portare ad
• con la connected device configuration (CDC), un sovrain- una limitazione. Dopo pochi anni l’hardware fa grossi pas-
sieme della precedente, si approcciano i dispositivi con si in avanti e il supporto allo sviluppo applicativo rischia di
qualche risorsa hardware in più e che si avvicinano di restare al palo.
più al mondo della Standard Edition. Se infatti parlare di MIDP nel 2000 significava affrontare
quanto di più all’avanguardia ci fosse in campo Java ME,
Un profile rappresenta invece l’insieme delle API che, aggiunte già dopo qualche anno si sono scoperti i limiti di questo
ad una configuration, forniscono il supporto completo per lo svi- approccio.
luppo di una applicazione per un certo insieme di dispositivi. Il Non era possibile infatti pensare di andare avanti inse-
Mobile Information Device Profile (MIDP), ad esempio, costituisce guendo l’evoluzione dell’hardware a colpi di profile (oggi
quell’insieme di librerie che si basa sul CLDC e che permette lo saremmo al MIDP 5.0) e ad un insieme di librerie da
sviluppo di applicazioni per dispositivi, tra cui i cellulari. dichiarare obsolete (approccio utilizzato da altri e che si

10 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

FIGURA 2 Trend della piattaforma Java ME

è rivelato dannoso per la complessità e la poca chiarezza l’evoluzione della tecnologia rischia di essere un freno. Nel
delle specifiche e delle interfacce a disposizione dei pro- prossimo paragrafo vedremo come il JCP ha perciò iniziato
grammatori). a rilasciare numerose JSR che vengono definite opzionali
in quanto non rientrano nella categoria di configuration o
È così che il JCP decide di risolvere questa esigenza gesten- profile e che il costruttore di hardware può decidere di in-
do l’evoluzione della tecnologia Java ME con l’approccio a cluderle o meno nei propri prodotti.
package. Nulla di nuovo sotto il sole, si tratta di quanto vie-
ne normalmente fatto in area Enterprise e Standard, ma in Alcuni di questi optional package sono ormai degli standard
area Micro c’è un problema da non sottovalutare. de-facto, perché presenti sulla maggior parte dei dispositi-
Se infatti nelle altre Edition rilasciare una nuova libreria vi; altri sono delle vere e proprie chimere … al cui insegui-
significa rilasciare una JSR con relativa reference imple- mento si gettano gli sviluppatori più smaliziati.
mentation e permettere così allo sviluppatore di utilizzarla
includendola nel suo ambiente Java Runtime, in ambito
Micro non è altrettanto immediato.
In Java ME, infatti, si ha a che fare con il firmware! Ossia
le API di una certa JSR vivono all’interno dell’ambiente
di esecuzione, inglobate nel dispositivo. In altre parole
una nuova versione di MIDP o una nuova libreria potrà Sull’emulatore fun-
vedere la luce solo su un nuovo cellulare; mentre i prodotti
rilasciati fino ad allora non avranno alcuna possibilità di
ziona tutto… ma non sui
evoluzione. dispositivi!
Non si tratta né di una scelta del JCP né dei costruttori del-
l’hardware, ma di una esigenza imprescindibile del settore
tecnologico di riferimento. Infatti, in questo settore ogni
libreria ha una sua implementazione solo se è strettamente
agganciata all’hardware sul quale risiede.
Tanto per fare un esempio: le librerie per la gestione del di- Optional package: lo stato dell’arte
splay incluse in MIDP permettono la visualizzazione di im-
magini ad una risoluzione che verrà scelta e implementata Si potrebbe proseguire nella panoramica delle JSR in area
da ciascun costruttore di cellulari in modo proprietario. Java ME passo dopo passo, ma dopo la “relazione intro-
Se da una parte lo sviluppatore ha a disposizione una API duttiva” sulla teoria, penso sia proprio ora di passare ai
(interfacce) standard, dall’altra il costruttore ha il compito risvolti pratici di quanto si è detto. Perciò, affronteremo in
(non banale) di tradurre l’astrazione in implementazione dettaglio i presupposti dello sviluppo di applicazioni basa-
effettiva. E ciò, se per gli sviluppatori può essere sicura- te sulle tecnologie CLDC e MIDP, perché di maggior uso e
mente visto come un vantaggio, dal punto di vista del- diffusione sul mercato: infatti, il numero di cellulari sui

n.2 - gennaio/febbraio 2007 11


speciale Java Micro Edition JAVA Journal

quali è possibile trovare una implementazione Java ME è Nel mondo Java ME ciò continua a valere, a patto che nes-
in frenetica crescita! suno dimentichi cosa offre il mercato e le specificità delle
In Figura 2 è possibile vedere il trend positivo del 2005: implementazioni: la qual cosa è valida anche nelle altre
tanto per fornire qualche numero, siamo di fronte a 635 edition, ma di fatto è esasperata in questo settore.
diversi modelli di cellulari, pari a più di 700 milioni di uni- Rischiando di somigliare un po’ troppo a Monsieur de la
tà installate. In altre parole, più di 7 cellulari su 10 hanno Palice (il più illustre “lapalissiano”), potrei dire:
una Java Virtual Machine a bordo!
• non basta una JVM, ma serve una JVM più le librerie
necessarie all’esecuzione dell’applicazione.

In altre parole: gli sviluppatori creano l’applicazione uti-


lizzando emulatori e kit di sviluppo che includono le im-
Una configurazion plementazioni di riferimento delle librerie scelte, ma poi
dovranno fare i conti con le librerie presenti sul cellulare
definisce il minimo am- di riferimento.
Se volessimo quindi affrontare lo sviluppo di una appli-
cazione che sfrutti sul serio le peculiarità di un cellulare
biente per l’esecuzione (ossia un dispositivo mobile in grado di inviare messaggi,
gestire audio e video, ed effettuare connessioni di rete)
del Runtime Java per avremmo bisogno di un minimo di package opzionali a
bordo del cellulare. In particolare:
una certa famiglia di di-
• Wireless Messaging API 1.1 (JSR 120) e Wireless Messaging
spositivi API 2.0 (JSR 205) per la gestione della messaggistica;
• Bluetooth API (JSR 82) per la gestione delle connessioni
bluetooth;
• Mobile Media API (JSR 135) per la gestione avanzata di
audio e video;
• PDA API (JSR 75) per la gestione del Personal Informa-
I ferri del mestiere: necessari e sufficienti tion Management (PIM) e del File System.

Abbiamo visto che CLDC e MIDP coprono le aree principali In pratica, se volessimo implementare in Java un’applica-
per lo sviluppo di applicazioni per cellulari. E allora di co- zione “a caso” per il nostro cellulare, che permetta di ac-
s’altro si avrebbe bisogno? quistare dalla rete dei brani musicali, salvarli sul cellulare,
Se da una parte CLDC e MIDP rappresentano un supporto ascoltarli e scambiarli con gli amici attraverso messaggi e/o
essenziale per lo sviluppo di applicazioni (fornendo i mat- via Bluetooth avremmo bisogno che il suddetto cellulare
toni base e le API per l’accesso alla grafica di alto e basso supporti, oltre a CLDC e MIDP, anche le sopra citate cinque
livello e alla rete), dall’altra parte gli sviluppatori hanno API opzionali.
sin dall’inizio notato alcune carenze.
Alcune aree, infatti, furono demandate in apposite JSR, Siamo al punto di svolta. Da un mercato pervaso di di-
che iniziarono a popolare i cosiddetti optional package. spositivi Java-based ci spostiamo verso un sottoinsieme:
La gestione della messaggistica (CBS, ossia Cell Broadcast significativo, ma pur sempre un sottoinsieme. Non tutti
System, SMS, ossia Short Messaging System, e MMS, ossia i cellulari hanno infatti a bordo queste librerie e quindi
Multimedia Messaging System), delle connessioni via Blue- la nostra applicazione potrà funzionare solo in tale sot-
tooth, dell’audio, della grafica avanzata e del file system toinsieme.
del cellulare, sono funzionalità lasciate al di fuori del
MIDP e di competenza di alcune librerie opzionali. Lo stato dell’arte delle implementazioni Java ME in
Ecco allora che viene alla luce il vero significato di optional quest’area ci permette di dire che ad oggi i cellulari con
packages: questi package a bordo (non più da considerarsi opzionali
a nostro avviso) sono la maggior parte, e comunque sono
• un costruttore di cellulari per fregiarsi del marchio Java quelli di riferimento per il mercato. Il che assicura una
On Board deve implementare CLDC e MIDP, poi ha la grande diffusione, almeno potenziale, della nostra appli-
facoltà di includere quanti e quali package opzionali de- cazione.
sidera.
Ma c’è dell’altro. Non paghi di questo scenario i nostri svi-
Gli sviluppatori, quindi, sono costretti a fare i conti con luppatori, sempre alla ricerca della sottile linea di confine
questa frammentazione, affidandosi ad una nuova acce- “tra la scienza e la fantascienza”, hanno “sollevato altre
zione del motto vincente di Java “Write Once, Run Anywhere” eccezioni” e sono alla ricerca di un giusto “catch”: mi pia-
(ossia, una volta scritta, la mia applicazione sarà eseguita cerebbe gestire il segnale GPS per localizzare l’utente; e se volessi
dappertutto, basta che sia installata una Java Virtual Ma- interagire con i Webc service? E se volessi creare un’applicazione di
chine). segreteria telefonica per il mio cellulare?

12 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

Da qui in poi entriamo in un campo minato; e ci entriamo delle applicazioni perfettamente integrato (il Sun
bendati! Ci avventuriamo, cioè, in un settore che sa poco di Wireless Toolkit) che li supporta in tutte le fasi del
implementazione e ancora troppo di specifiche. ciclo di vita del software.
Molte delle JSR sono ancora poco diffuse sui cellulari, ma
è già possibile utilizzarle nell’emulatore. Più precisamente
si tratta delle:

• Location API (JSR 179);

Un profile sono le


Security and Trust Services API (JSR 177);
SIP API (JSR 180);
API che forniscono il • J2ME Web Services Specification (JSR 172).

supporto completo per Ci aspettiamo naturalmente una rapida diffusione sul


mercato anche di queste implementazioni e, come nel caso
lo sviluppo di una appli- delle API ormai consolidate, consigliamo vivamente di
cazione anticipare i tempi sfruttando l’enorme vantaggio di avere
a disposizione una piattaforma per lo sviluppo più avanti
rispetto al mercato.

Cosa bolle in pentola

Manca poco Ma c’è di più. Pensateci un attimo: cosa vi piacerebbe


avere a disposizione sul vostro cellulare che sia gestibile
“Ma sugli emulatori tutto funziona!”. È questa la frase attraverso la vostra “killer application”? Ecco che saltano
che tormenta la vita dello sviluppatore Java ME. Ma fuori le applicazioni del futuro: micropagamenti, il digitale
ancora più si tormenta quando riesce a scrivere un’ap- terrestre sul cellulare, l’RFID. Ci vorrà ancora un bel po’
plicazione perfettamente funzionante, ma che non può per vederle all’opera, ma la direzione è segnata. Esistono
vedere funzionare su nessun cellulare attualmente in già le JSR e i relativi comitati di studio, quindi c’è solo da
commercio. Già, perché, grazie alla prolificità del JCP, ben sperare.
molte specifiche sono rilasciate con la relativa referen- Quello che invece ci sembra utile rimarcare è la tendenza
ce implementation molto prima di finire sui cellulari; e del mercato a spostare l’accento verso la configuration meno
grazie ai laboratori Sun gli sviluppatori hanno a dispo- limited. Già alcuni produttori di cellulari hanno annunciato
sizione uno strumento per lo sviluppo e l’emulazione l’intenzione di portare una intera serie di cellulari verso

FIGURA 3 Gerarchia delle classi del GCF

n.2 - gennaio/febbraio 2007 13


speciale Java Micro Edition JAVA Journal

la CDC e altri stanno puntando su sistemi operativi scritti scheme://user:password@host:port/url-path;parameters


interamente in Java. Di questo passo ben presto avremo
non solo una piattaforma Java completa per lo sviluppo di dove:
applicazioni sul cellulare, ma qualcosa di molto vicino alla
Standard Edition. • scheme specifica il metodo di accesso o il protocollo (http,
Ed allora a conclusione di quest’articolo ci viene il dub- https,…). In GCF per ciascuno schema ci si aspetta una
bio che la frontiera della Micro Edition in realtà non sia, specializzazione dell’interfaccia Connection (HttpConnec-
semplicemente, la Standard Edition (come si poteva tion, HttpsConnection, …);
immaginare nei primi giorni), ma piuttosto sia la fan- • user e password sono opzionali;
tasia degli operatori di marketing del mondo wireless e • host è l’indirizzo del server sul quale è ospitata la risor-
mobile… E vi assicuriamo che di fantasia ne hanno da sa;
vendere! • port è opzionale e la sua interpretazione dipende dallo
schema utilizzato;
• url-path è il percorso della risorsa. Il suo formato e la sua
interpretazione dipendono dallo schema e può richiede-
re ulteriori parametri.

La più grande spinta Facciamo un esempio. Se vogliamo creare una connessione


http verso un certo URL basterà utilizzare la seguente riga
per la diffusione dello di codice:

sviluppo in Java Me è HttpConnection httpConn =

stato il Generic Connec- (HttpConnection) Connector.open(“http://www.javajournal.it”);

tion Framework (GCF) L’implementazione del GCF residente sul cellulare inter-
pretando l’URL capirà di dover creare una HttpConnection
verso l’host specificato e così via per altri casi.

Per creare una connessione socket:

SocketConnection socketConn =
(SocketConnection)Connector.open(“socket://myhost.com:8081”);
Il Generic Connection Framework

Crediamo di non fare torto a nessuno dicendo che la più Per accedere ad una risorsa presente nel filesystem del
grande spinta per la diffusione dello sviluppo in Java ME, cellulare:
e che permette allo sviluppatore di creare in pochissimo
tempo una applicazione completa, sia stato il Generic Con- FileConnection fileConn =
nection Framework (GCF). Si tratta di un meccanismo per (FileConnection) Connector.open(“file:///myMusic.mp3”);
la creazione di connessioni che consente di astrarsi dallo
specifico dell’implementazione sottostante. Il vantaggio Per creare una connessione utile all’invio di un SMS:
dell’approccio per astrazioni qui raddoppia: infatti, oltre
ad avere a che fare con una macchina virtuale, in Java ME MessageConnection msgConn =
si ha il notevole vantaggio di poter creare connessioni di (MessageConnection) Connector.open(“sms://+12345689:5000”);
diverso tipo verso l’esterno, utilizzando la stessa gerarchia
di classi descritta nella Figura 3.
Approfondimenti sul GCF
Il GCF nasce dal bisogno di avere un sostituto nella Micro
Edition delle librerie java.net e java.io ivi mancanti o ridot- Per tutte le altre sfaccettature relative al GCF, che tra l’altro
te. Si tratta, infatti, di una gerarchia di classi che fornisce può essere utilizzato anche in ambito Java Standard Edi-
proprio un approccio generico alla connettività. Grazie ad tion, si rimanda a http://www.jcp.org/en/jsr/detail?id=197
una gerarchia estendibile di interfacce, ad una factory di e alle risorse reperibili sul sito http://developers.sun.com/
connessioni e all’utilizzo delle specifiche standard degli techtopics/mobility/.
Uniform Resource Locator (URL), lo sviluppatore ha un unico
punto di ingresso verso le connessioni: la classe Connector e
l’interfaccia Connection. Il GCF supporta molte connessioni
e permette di delegare all’implementazione sottostante i Note Biografiche
dettagli per la loro costruzione e tutto passa attraverso lo Edoardo Schepis è Java ME Tech Lead presso Funambol. È stato
schema degli URL. Java Architect in Sun Microsystems e ha fatto parte del grup-
po di lavoro che ha prodotto la certificazione Sun Certified
Il formato generico di un URL è definito nelle RFC 1738 e Mobile Application Developer (SCMAD). Edoardo è il fonda-
2396 ed è il seguente: tore e responsabile del Java Mobile Developers Forum (http:
//www.jmdf.org), community italiana dedicata al mondo Java e
alle tecnologie wireless.

14 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

J2ME
Best Practice
La diffusione di J2ME è ormai un dato di fatto

>> di Matteo Zinato (matteo.zinato@javajournal.it)

ancora, più che delle best-practice, potrebbero essere


definite delle regole di buon senso nei riguardi di

D
quello che sarà l’utilizzatore finale della nostra ap-
plicazione.
Se qualche anno fa c’era grande
scetticismo sulla possibile diffu-
sione di J2ME, oggi si può affer-
mare che la tecnologia Java per la
programmazione dei cellulari si è
ritagliata una discreta porzione di
mercato, forse non grande quan- U n’ a p p l i c a z i o n e
to ci si aspettava, ma sicuramente incoraggiante. Gli
applicativi scritti in C++ sviluppati per Symbian deve essere robusta,
hanno avuto una partenza bruciante e sembravano
dover superare e affossare J2ME; ma relativamente efficiente, chiara da
pochi cellulari si basano su Symbian e la percentua-
le di diffusione del sistema operativo, anche se de-
stinata a crescere, difficilmente andrà a coprire tutto
comprendere, facile da
il mercato dei cellulari. A tutto ciò si aggiunge una
sempre maggiore necessità di sviluppare applicati- modificare ed estendere
vi che siano utilizzabili anche da dispositivi mobili e
sempre più spesso si vedono cellulari inseriti nei dise- nelle funzionalità
gni di architetture di applicazioni enterprise.

Da applicazioni amatoriali o poco più, gli applicativi


J2ME si sono quindi trasformati in componenti di
sistemi client-server molto importanti e sofisticati.
Se qualche anno fa ci si poteva accontentare che L’applicazione di esempio
l’applicazione funzionasse, ora questo non basta più.
Un buon programmatore questo lo sa bene, ma per Per non parlare solo a livello teorico presentiamo un’ap-
altri può non essere così scontato. Un’applicazione plicazione di esempio, che comprende al suo interno
deve ovviamente funzionare, ma deve anche essere gran parte delle possibili situazioni che si presentano
robusta, efficiente, chiara da comprendere e facile ad uno sviluppatore di applicativi J2ME. L’applicazione
da modificare ed estendere nelle funzionalità. Per in questione è un semplice esempio di gestione di una
questo motivo si sono sviluppate, come per parecchie rubrica telefonica, in cui un utente ha la possibilità di
delle tecnologie che già sono molto diffuse, delle così inserire dei contatti che vengono salvati nel database
dette best-practice, una sorta di lista di cose da fare e locale, di effettuare delle ricerche sui contatti inseriti,
cose da non fare nello sviluppo di un’applicazione. di inviare i dati inseriti ad un server e di riceverli dallo
Alcune delle cose che vedremo riguarderanno la tec- stesso server. Vedremo principalmente come realizzare
nica di implementazione di alcune funzionalità, altre la parte J2ME ma anche come implementare la tecno-
riguarderanno la progettazione più in generale, altre logia lato server che riceve e invia i dati.

n.2 - gennaio/febbraio 2007 15


speciale Java Micro Edition JAVA Journal

Ciò che si deve fare è distinguere e separare le classi se-


guendo una sorta di paradigma MVC (Model View Con-
troller) che dovrebbe risultare familiare a chi ha esperien-
za di programmazione in ambiente J2EE. Nel nostro caso i
package saranno così organizzati (Figura 1):

• view: contiene tutte le classi che svolgono funzionalità


di visualizzazione grafica sul display;
• model: contiene tutte le classi che contengono la logica
dell’applicativo che nella nostra applicazione consiste
prevalentemente nell’accesso ai dati in locale o in remo-
to;
• shared: contiene le classi che vanno condivise con il
server;
• utils: contiene classi di utilità per la nostra applicazio-
ne;

In questo modo ci accorgeremo subito, nel momento di


scrivere il codice, se stiamo commettendo un errore di
design dell’applicativo. Se ad esempio stiamo scrivendo
una classe di view, per la visualizzazione di una form per
la raccolta dei dati, ed all’interno della stessa classe ci tro-
viamo a scrivere del codice per effettuare connessioni al
server, dovremmo capire che stiamo sbagliando qualcosa.
L’approccio corretto è scrivere il codice per la connessio-
ne al server all’interno di una classe nel package model e
richiamarne i metodi dalla classe di view. Può sembrare
macchinoso ma chi ha esperienza di programmazione sa
quanto sia importante diversificare la logica applicativa
FIGURA 1 L’organizzazione delle classi sul progetto
dallo strato di visualizzazione.
J2me best Practice (J2ME) in Eclipse
È importante anche prevedere una classe che faccia da
L’organizzazione delle classi e dei package controller, che centralizzi, attraverso dei semplici metodi,

Una delle prime cose di cui occuparsi in un’applicazione, public void displayUserForm(){
anche di piccole dimensioni, è l’organizzazione delle classi userForm.clearForm();
e la suddivisione in package. È vero che con i moderni IDE display.setCurrent(userForm);
per lo sviluppo Java il refactoring delle classi e la riorga- }
nizzazione in package è molto semplice, ma è sempre
bene partire organizzando il lavoro nel giusto modo. La public void displayUserForm(
scelta delle funzionalità che una classe deve compiere (in Contact user){
altre parole i metodi che deve avere) non è soltanto una userForm.loadForm(user);
questione di pulizia o di stile del codice, ma va anche ad display.setCurrent(userForm);
influire sulle prestazioni dell’applicativo. Infatti le classi di }
una midlet vengono caricate in memoria solo al momento
dell’utilizzo, per cui, dovremmo riuscire a raggruppare le public void displayUserList(){
funzionalità nelle giuste classi, in modo che se l’utente uti- userList.loadUserList(“”, “”);
lizza solo una determinata funzionalità dell’applicativo, il display.setCurrent(userList);
sistema non vada a caricare anche classi che non vengono }
utilizzate, se non per un metodo.
Facciamo un esempio: se scriviamo in una classe tutti i public void displaySearchUserList(
metodi per l’accesso al database locale (RMS) e in un’altra String name, String surname){
classe tutti i metodi per l’accesso ai dati in remoto sul server userList.loadUserList(name, surname);
(con connessioni http) e l’utente utilizza l’applicativo solo display.setCurrent(userList);
nelle funzionalità di salvataggio in locale, tutte le altre classi }
non verranno caricate, con un risparmio nel tempo di esecu-
zione e soprattutto nella memoria occupata a runtime. public void displayUserSearch(){
Invece, per quanto riguarda l’organizzazione delle classi display.setCurrent(userSearchForm);
in package la strategia non influisce sulle prestazioni e }
sull’efficienza dell’applicativo, ma soprattutto sull’ordine
delle classi all’interno del progetto (e non è poco…).
LISTATO 1 Alcuni metodi della classe UIController

16 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

UIController uiController = null; serie di immagini, disegna delle forme geometriche e scri-
ve del testo. In casi come questo si deve valutare l’utilizzo
protected void startApp() throws della lazy initialization delle classi (“lazy” letteralmente
MIDletStateChangeException { significa “pigro”, e in questo caso assume il significato di
“solo quando serve”). Questa tecnica consiste nel caricare
// ... l’istanza di una classe solo quando si è sicuri che verrà
uiController = new UIController(this); utilizzata e cioè un attimo prima di caricarla sullo schermo
} (Listato 3 e Listato 4).

Con l’aiuto del Memory Monitor del Wireless Toolkit (che


LISTATO 2 Pezzi di codice del MainMidlet.java vedremo meglio più avanti) possiamo avere un riscontro
immediato della differenza tra i due diversi modi di scrive-
il passaggio da una view ad un’altra. In questo modo, un re il codice. Nel primo caso (senza utilizzare la lazy initia-
riferimento alla classe UIController verrà passato a tutte le lization dell’oggetto Canvas), infatti, la memoria si assesta
istanze delle classi di view e queste invocheranno i metodi subito sui 58.824 byte; nel secondo caso, invece, il valore di
di UIController per gestire il passaggio della visualizzazione memoria occupata rimane molto più basso e sale soltanto
alla view successiva (Listato 1). al momento in cui la classe viene effettivamente richiesta
In questo modo, abbiamo ricreato, con le dovute limitazio- (Figura 2 e Figura 3).
ni del caso, una sorta di pattern MVC che ci aiuta a lavora-
re con più ordine sulle nostre applicazioni J2ME. A questo Molte altre volte, però, è più semplice caricare subito tutte
punto non resta che entrare nel dettaglio delle classi e ve- le classi nel costruttore dell’UIController. Se le classi che
dere caso per caso quali sono le best practice da seguire. dobbiamo utilizzare non contengono oggetti pesanti o
semplicemente ci vogliamo fidare del cellulare su cui dovrà
girare l’applicazione partendo dal presupposto che abbia
una buona disponibilità di memoria (anche se è sempre
meglio evitare questo tipo di presupposti) la lazy initializa-
È buona norma rag- tion può essere evitata. In questo caso, però, è necessario
predisporre un’indicazione per l’utente sullo stato di avan-
zamento del caricamento. Una delle regole più importanti
gruppare tutte le stringhe nel design di un’applicazione Java ME è:

di testo che caratterizza- • Informare sempre l’utente su quello che sta facendo l’applica-
zione durante le operazioni che richiedono qualche secondo.
no le interfacce grafiche
Ciò, banalmente, per evitare che l’utente pensi che l’ap-
in un’unica classe plicazione si sia bloccata. In questo caso è sufficiente pre-
disporre un oggetto di tipo Gauge che viene aggiornato al
momento della creazione delle singole istanze delle classi
della nostra applicazione (Listato 5).

La classe MIDlet e il caricamento delle classi.

Come abbiamo detto, il lavoro di visualizzazione sul di-


splay delle varie classi di view viene fatto dall’UIControl-
ler; per cui, la classe principale che estende MIDlet, non
dovrà fare altro che creare un’istanza di UIController e
passare a questa ultima classe il controllo dell’applicazio-
ne (Listato 2).
La classe UIController, da parte sua, non deve fare altro
che istanziare tutti gli oggetti di view che compongono la
nostra applicazione, ma con le dovute precauzioni. Creare
un’istanza di una classe significa caricarla completamente
in memoria con tutti i suoi oggetti ed elementi annessi.
Pensiamo, ad esempio, ad una classe di tipo Canvas che al
suo interno ha immagini, testo, disegni, ecc. Istanziarla si-
gnificherebbe occupare gran parte della memoria disponi-
bile a run-time, ma a volte può succedere che la classe non
viene nemmeno mai utilizzata, perché chi usa l’applicazio-
ne va ad agire su altre classi. Nel nostro esempio, abbiamo FIGURA 2 L’utilizzo della memoria (valore
inserito una classe di view AppInfoCanvas che carica una “Current”) senza utilizzare la lazy initialization
sulla classe AppInfoCanvas

n.2 - gennaio/febbraio 2007 17


speciale Java Micro Edition JAVA Journal

dell’incapsulamento delle funzionalità viene sovente tra-


scurato e ci troviamo ad avere codice ripetuto, o al limite
inserito all’interno di metodi di utilità dichiarati come
static. Prendiamo ad esempio la nostra applicazione per la
rubrica telefonica: tutto ruota intorno al concetto di con-
tatto telefonico, che nell’applicazione è rappresentato dalla
classe Contact. Questa classe conterrà al suo interno tutte
le proprietà che caratterizzano l’oggetto contatto e tutti i
metodi per accedere alle proprietà (get e set). Ma non basta,
abbiamo anche bisogno di:

private LoadingForm loadingForm = null;


private Menu menu = null;
private ContactForm userForm = null;
private ContactList userList = null;
private ContactSearchForm
userSearchForm = null;
private ConnectionSaveForm
FIGURA 3 L’utilizzo della memoria connectionSaveForm = null;
(valore “Current”) utilizzando la lazy private ConnectionGetForm
initialization sulla classe AppInfoCanvas
connectionGetForm = null;
private AppInfoCanvas
Utilizzare una progress bar con un oggetto Gauge è la appInfoCanvas = null;
soluzione più semplice (Figura 4), ma nessuno vieta di
realizzare interfacce graficamente più gradevoli con ogget-
ti di tipo Canvas. public UIController(MainMIDlet mainMidlet){
this.mainMidlet = mainMidlet;
display = Display.
getDisplay( this.mainMidlet );

loadingForm = new LoadingForm(this);


Le operazioni di display.setCurrent(loadingForm);

connessione ad un ser- loadingForm.


updateProgress(LanguageLabel.LOADING);
ver devono essere fatte menu = new Menu(this);

loadingForm.updateProgress();
col l’ausilio dei thread userForm = new ContactForm(this);

loadingForm.updateProgress();
userList = new ContactList(this);

loadingForm.updateProgress();
Internazionalizzazione delle applicazioni userSearchForm =
new ContactSearchForm(this);
Al di là del fatto che l’applicazione che dobbiamo svilup-
pare debba essere tradotta o meno in altre lingue, è buona loadingForm.updateProgress();
norma raggruppare tutte le stringhe di testo che caratteriz- connectionSaveForm =
zano le interfacce grafiche in un’unica classe. La classe in new ConnectionSaveForm(this);
questione sarà simile a quella mostrata nel Listato 6.
In questo modo, la traduzione e la distribuzione del- loadingForm.updateProgress();
l’applicazione in altre lingue si ridurrebbe al semplice connectionGetForm =
lavoro di modifica delle etichette contenute nel file new ConnectionGetForm(this);
LanguageLabel.java, evitando di dover spulciare i singoli file
Java alla ricerca del testo da tradurre. displayMenu();

Programmare ad oggetti }

Può sembrare una provocazione ma molte volte ci si di-


mentica che Java è un linguaggio ad oggetti. Il concetto LISTATO 3 Se non si utilizza la lazy initialization tutte le
classi vengono instanziate nel costruttore dell’UIController

18 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

• due metodi che serializzano e deserializzano i dati del-


l’oggetto (per inviarlo al server);
• due metodi che restituiscono una rappresentazione del-
l’oggetto in array di byte (per il salvataggio su RMS);
• dei tipici metodi save(), delete() e update() per effettuare il
salvataggio dell’oggetto in locale;
• e possiamo anche prevedere un metodo validate() che
controlla se le proprietà dell’oggetto hanno dei valori
congruenti.

Il relativo codice è contenuto nel Listato 7 e nel Listato 8.


Una volta che la classe Contact è stata scritta come si deve,
la scrittura del codice nel resto dell’applicazione diventa
molto semplice e intuitiva, proprio come si richiede nella
programmazione ad oggetti (Listato 9).

C’è da fare una piccola precisazione. La classe Contact in


realtà estende un’altra classe, ContactBean che è all’interno
del package shared. ContactBean va condivisa con il server,
ossia dovrà essere presente sia sul server sia sul client
J2ME? In questo modo, dal server, al momento opportuno
richiameremo gli stessi metodi serialize() e deserialize() per
preparare o ricevere gli stream di dati. ContactBean viene
poi estesa da Contact aggiungendo i metodi di scrittura e
lettura sul Record Management System. Questi metodi, FIGURA 4 La progress bar visualizzata sul
infatti, non potrebbero esistere sul server, in quanto le terminale
classi del package javax.microedition.rms non esistono in un
contesto J2EE, e non sarebbe possibile compilare la classe. dei thread. Utilizzare un Thread per gestire una connes-
In altre parole, al momento di inviare i dati di un contatto sione non è soltanto un buon consiglio, ma è a tutti gli
al server, verrà richiamato il metodo serialize() sull’istanza effetti un obbligo. Le specifiche MIDP, infatti, dichiarano
della classe da inviare; il server riceverà lo stream di dati testualmente che:
serializzato e invocherà il metodo deserialize() della classe
ContactBean presente nel server, ottenendo così gli stessi
valori dell’istanza originale inviata dal client.
loadingForm = new LoadingForm(this);
display.setCurrent(loadingForm);
Comunicare con il server

Abbiamo appena accennato alle comunicazioni con il loadingForm.updateProgress(


server. Vediamo ora nel dettaglio come gestire questo ge- LanguageLabel.LOADING);
nere di problematiche sia nella parte client sia nella parte menu = new Menu(this);
server.
loadingForm.updateProgress();
userForm = new ContactForm(this);
Utilizzare i Thread
loadingForm.updateProgress();
Innanzi tutto, cominciamo col dire che le operazioni di
userList = new ContactList(this);
connessione ad un server devono essere fatte col l’ausilio
loadingForm.updateProgress();
public void displayCanvas(){ userSearchForm =
appInfoCanvas = new ContactSearchForm(this);
new AppInfoCanvas(this);
display.setCurrent(appInfoCanvas); loadingForm.updateProgress();
} connectionSaveForm =
new ConnectionSaveForm(this);
public void closeCanvas(){
appInfoCanvas = null; loadingForm.updateProgress();
display.setCurrent(menu); connectionGetForm =
} new ConnectionGetForm(this);

LISTATO 4 Se si utilizza la lazy initialization le LISTATO 5 L’utilizzo di un oggetto Gauge per


classi in questione vengono instanziate solo nel visualizzare una progress-bar che viene aggiornata
momento in cui ne viene richiesto l’utilizzo dopo il caricamento di ogni classe di view

n.2 - gennaio/febbraio 2007 19


speciale Java Micro Edition JAVA Journal

public static String LOADING =


“Caricamento in corso...”;
public static String MENU =
“Menu”;
public static String MENU_NEW_USER =
“Nuovo Utente”;
public static String MENU_USER_LIST =
“Lista degli utenti”;
public static String MENU_SEARCH_USER =
“Ricerca Utente”;
public static String MENU_SEND_HTTP =
“Invia dati al server”;
public static String MENU_GET_HTTP =
“Ricevi dati dal server”;
public static String MENU_INFO_APP =
“Info”;
public static String DELETE =
“Cancella Utente”;

LISTATO 6 La classe LanguageLabel contiente


tutte le stringhe di testo visualizzate negli oggetti
di view

• “ogni azione associata ad un comando dell’utente deve ritornare FIGURA 5 Menu di opzioni della midlet di
subito il controllo dell’applicazione per non rischiare deadlock”. collegamento con il server

Nel momento in cui l’utente preme il pulsante per inviare permettergli di fermare eventuali operazioni che l’applica-
dei dati al server, l’applicazione non farà altro che far par- zione sta svolgendo (quando queste non sono immediate).
tire un Thread separato, che effettua la connessione e in- Per cui, tornando alla comunicazione delle midlet con il
forma l’utente dello stato di avanzamento delle operazioni; server, è molto importante mantenere informato l’utente
mentre il Thread principale dell’applicazione non subisce e dargli la possibilità di fermare il collegamento se i tempi
nessun tipo di blocco di attesa per lo svolgimento delle si rivelano troppo lunghi (cosa più che normale per le con-
operazioni di comunicazione col server. nessioni GPRS). Vediamo come realizzare in pratica quello
che si è descritto finora (Figura 5).
Visualizzare un’indicazione di avanzamento
Siamo nel caso in cui un utente debba inviare ad un server
Come abbiamo detto nella prima parte dell’articolo, “best una serie di informazioni residenti nella midlet. Dal menù
practice” non vuol dire solamente soluzione tecniche, ma dell’applicazione, l’utente sceglie la voce che corrisponde
anche soluzioni che vadano a favore dell’usabilità dell’ap- all’azione di invio dei dati al server; verrà visualizzata sul
plicazione da parte degli utenti. In questa logica, un fat- display un’istanza di una classe di tipo Form (all’interno
tore molto importante è tenere sempre informato l’utente del package view) che contiene al suo interno un oggetto
di quello che l’applicazione sta facendo, e soprattutto di tipo Gauge, che, a sua volta, visualizzerà l’avanzamento

FIGURA 6 Risultato dell’esecuzione del codice FIGURA 7 Grafico di occupazione della memoria
della classe view prima dell’invocazione della GC

20 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

/**
* popola l’oggetto ContactBean partendo /**
* da uno DataInputStream * popola l’oggetto UserBean partendo
* @param DataInputStream * da un array di byte
* @throws IOException * @param data
*/ * @throws IOException
public void deserialize( */
DataInputStream reader ) public void fromByteArray(
throws IOException { byte[] data )
throws IOException {
name = reader.readUTF();
surname = reader.readUTF(); ByteArrayInputStream stream =
long dataLong = reader.readLong(); new ByteArrayInputStream( data );
if (dataLong != 0)
borndate = new Date(dataLong); DataInputStream reader =
telephone = reader.readUTF(); new DataInputStream( stream );
email = reader.readUTF();
} deserialize( reader );
stream.close();
/** }
* restituisce un DataOutputStream
* dei dati dell’utente /**
* @param DataOutputStream * Restituisce una array di byte
* @throws IOException * dell’oggetto utente
*/ * @return
public void serialize( * @throws IOException
DataOutputStream writer ) */
throws IOException { public byte[] toByteArray()
throws IOException {
writer.writeUTF( name );
writer.writeUTF( surname ); ByteArrayOutputStream stream =
if (borndate != null){ new ByteArrayOutputStream();
writer.writeLong(
borndate.getTime()); DataOutputStream writer =
} else { new DataOutputStream(stream);
writer.writeLong(0);
} serialize( writer );
writer.writeUTF(telephone); writer.close();
writer.writeUTF(email);
} return stream.toByteArray();
}

LISTATO 7 I metodi inseriti nella classe ContactBean per la serializzazione e la deserializzazione

della connessione e del trasferimento dei dati al server. guita in modo indipendente dal resto dell’applicazione. La
Tutta la parte che gestisce la connessione sarà inserita in classe RemoteModel è una classe dell’applicazione che con-
un’apposita classe, a sua volta inserita nel package model tiene al suo interno tutti i metodi alla base di una connes-
in modo da tenere separato il codice di view dal codice di sione HTTP e verrà estesa da tutte le classi che dovranno
model. La classe di view conterrà un codice del tipo riportato eseguire collegamenti col server (Listato 13).
nel Listato 10, il cui risultato è visibile nella Figura 6.
La cosa importante da tenere presente è che il metodo Torniamo ora alla classe RemoteContactSaveList.java con-
performConnection() deve essere esplicitamente invocato centrandoci sul codice contenuto nel metodo run() che,
dall’esterno; per cui, al momento della selezione dell’ope- ricordiamo, viene invocato quando il Thread viene lanciato
razione di invio dei dati al server dovrà essere eseguito il con start(). A parte gli aggiornamenti alla progress bar che
codice riportato nel Listato 11. l’utente vede a video, dopo aver aperto la connessione, ed
aver aperto un outputStream per l’invio dei dati al server
Vediamo ora come è costruita la classe di model per la con- (utilizzando i metodi della superclasse RemoteModel) la
nessione http (Listato 12). La prima cosa che si nota è prima cosa che viene fatta è quella di scrivere nello stream
che la classe estende RemoteModel ed implementa Runnable. in uscita un byte. Il valore di questo byte è quello della
L’implementazione dell’interfaccia Runnable è indispensa- costante MessageConstants.OPERATION_SAVE_USER_LIST.
bile per avere una classe di tipo Thread che può essere ese- Un’operazione di questo tipo viene fatta perché in questo

n.2 - gennaio/febbraio 2007 21


speciale Java Micro Edition JAVA Journal

inseriti a loro volta nello stream. Quando tutti i dati sono


stati serializzati all’interno dell’outputStream questo viene
chiuso e si attende la risposta del server, che dovrebbe
inviare a sua volta un byte che indica se l’operazione è an-

Le operazioni di data a buon fine. Il lavoro di controllo sul valore di questo


byte viene eseguito dal metodo openConnectionInputStream
(Connection) della superclasse RemoteModel che abbiamo
connessione ad un visto prima. Se dal server non arriva un byte con il valore
MessageConstants.ERROR_NONE, viene lanciata un’eccezio-
server devono essere ne che la classe RemoteContactSaveList catturerà come una
normale eccezione nel collegamento http.
fatte col l’ausilio dei Se invece che inviare dei dati al server avessimo avuto la
necessità di ricevere dei dati dal server, la logica dell’appli-
thread cativo sarebbe stata molto simile. In questo caso le infor-
mazioni da inviare al server sarebbero state circoscritte al-
l’invio del byte che identifica l’operazione da eseguire (ad
esempio MessageConstants.OPERATION_GET_USER_LIST).
Una volta chiuso l’outputStream riceveremmo lo stream con
tutte le informazioni inviate dal server, sempre precedu-
te dal byte che indica l’esito (il controllo lo fa il metodo
openConnectionInputStream(Connection)).
modo possiamo gestire, lato server, un unico servizio a cui
connettersi. Questo servizio, che di fatto non è altro che La servlet sul server
una servlet, come prima cosa legge quel byte dalla richiesta
http e, in base al suo valore, esegue le operazioni che sono Vediamo velocemente come è realizzato il servizio che sul
state richieste. La classe MessageConstants infatti è inserita server riceve le richieste. Come detto si tratta di una serv-
nel package shared che, come detto, contiene le classi che let ed il suo funzionamento è centralizzato all’interno del
devono essere presenti anche sul server (Listato 14). metodo perfom() che viene invocato in caso di richiesta di
tipo POST. A questo metodo arrivano tutte le richieste fatte
Il resto del codice nella classe RemoteContactSaveList è sem- dal client; come prima cosa legge quel byte che gli viene in-
plice e leggibile. Non fa altro che scrivere sull’outputStream viato come prima informazione della richiesta e esegue un
tutte le informazioni che devono essere inviate al server. metodo piuttosto che un altro, in base al valore di quest’ul-
Nel nostro caso, per prima cosa viene inserito in valore di timo, che viene confrontato con i valori di MessageConstants
tipo long che indica il numero di oggetti Contact che ver- che è una classe shared (Listato 12).
ranno poi serializzati (con i metodi della classe Contact) e

FIGURA 8 Percentuale di occupazione degli oggetti prima della Garbage Collection

22 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

/** // byte dell’oggetto utente


* Effettua il salvataggio dell’oggetto byte[] rec = this.toByteArray();
* userBean nel db
* @return esito < 0 se si sono //apre il recordStore ed
* verificati errori > 0 altrimenti // effettua il salvataggio
*/ RecordStore rs = RecordStore.
public synchronized int save() { openRecordStore(Constants.DB_NAME, true);

int esito = -1; rs.setRecord(this.getRecordId(),


rec,0,rec.length);
try {
rs.closeRecordStore();
// ottiene l’array di byte esito = 1;
// dell’oggetto utente
byte[] rec = this.toByteArray(); }catch (IOException e) {
Utils.debug(“Errore nella
// apre il recordStore ed preparazione del DataOutputStream”);
// effettua il salvataggio esito = -1;
RecordStore rs = RecordStore. }catch (RecordStoreFullException
openRecordStore(Constants.DB_NAME, rsfe) {
true); Utils.debug(“RecordStore full”);
esito = -2;
esito = rs.addRecord(rec,0, }catch (RecordStoreException rse) {
rec.length); Utils.debug(“Errore durante il salvataggio”);
esito = -3;
rs.closeRecordStore(); }
return esito;
}catch (IOException e) { }

Utils.debug(“Errore nella /**


preparazione del DataOutputStream”); * Cancella uno user
esito = -1; * @param user
}catch (RecordStoreFullException rsfe) { * @return esito < 0 se si sono
Utils.debug(“RecordStore full”); * verificati errori > 0 altrimenti
esito = -2; */
}catch (RecordStoreException rse) { public synchronized int delete(){
Utils.debug(“Errore durante int esito = -1;
il salvataggio”);
esito = -3; try {
} RecordStore rs = RecordStore.
openRecordStore(Constants.DB_NAME,
return esito; true);
}
rs.deleteRecord(this.getRecordId());
rs.closeRecordStore();
/** esito = 1;
* Effettua l’aggiornamento
* dell’oggetto userBean nel db }catch (RecordStoreFullException rsfe) {
* @return esito < 0 se si sono Utils.debug(“RecordStore full”);
* verificati errori > 0 altrimenti esito = -2;
*/ }catch (RecordStoreException rse) {
public synchronized int update() { Utils.debug(“Errore durante il salvataggio”);
esito = -3;
int esito = -1; }

try { return esito;


//ottiene l’array di }

LISTATO 8 I metodi inseriti nella classe Contact per il salvataggio, l’aggiornamento e la cancellazione

Ai metodi che possono essere eseguiti vengono passati i appende gli eventuali dati di risposta che dal server devono
riferimenti ad un DataInputStream per la lettura di tutti i passare al client.
dati allegati alla richiesta, e un DataOutputStream per la Questo metodo di gestione delle richieste al server è molto
scrittura di tutti i dati di risposta. semplice da realizzare e soprattutto molto facile da man-
Dopo aver terminato l’esecuzione del metodo richiesto, tenere visto che tutte le richieste entrano nell’applicativo
il metodo perform scrive come prima cosa un byte in cui server da un’unica porta di accesso e la logica applicativa
indica che l’esito dell’operazione è positivo e subito dopo di ogni singola richiesta può essere gestita nel modo che

n.2 - gennaio/febbraio 2007 23


speciale Java Micro Edition JAVA Journal

da effettuare. Provate, ad esempio, ad eseguire la nostra


if ( user.validate() ){
applicazione di gestione contatti: caricate qualche con-
tatto e infine visualizzate la lista. Se tenete sott’occhio
if (recordId != -1){
la memoria, vedrete che questa aumenta sensibilmente,
//effettua l’aggiornamento
nonostante tutti gli oggetti vengano rilasciati. Se diamo
//di un nuovo record
un’occhiata alla memoria, e soprattutto esplodiamo l’al-
int esito = user.update();
bero degli oggetti che occupano la memoria, vedremo che
if (esito < 0){
gran parte dell’aumento della memoria occupata è causato
uiController.showAlert(
Constants.AT_INSERT_ERROR); da variabili di tipo char[] istanziate dalla classe com.sun.mid
} p.rms.RecordStoreFile. A questo punto, non resta che inserire
uiController.showAlert( nel codice delle chiamate esplicite al garbage collector. Nel
Constants.AT_INSERT_OK); nostro caso, inserendo una chiamata a System.gc() subito
dopo aver letto dal recordStore la lista de contatti, vedremo
}else{ che molti degli oggetti prima occupati vengono subito libe-
//effettua il salvataggio rati (Figura 7 e Figura 8).
//di un nuovo record La chiamata esplicita al garbage collector è una pratica che
int esito = user.save(); deve essere usata con cautela, in quanto molto onerosa a
if (esito < 0){ livello computazionale per il terminale. Di norma bisogna
uiController.showAlert( sempre aiutare il garbage collector a liberare in modo au-
Constants.AT_INSERT_ERROR); tonomo gli oggetti non più utilizzati settandoli a null. Solo
} quando ciò non basta, si può inserire qualche chiamata
uiController.showAlert( esplicita al metodo System.gc().
Constants.AT_INSERT_OK);
}//else
.... Distribuzione dell’applicazione

Una fase molto importante nella creazione di un’applica-


LISTATO 9 La semplicità nell’effettuare un
zione J2ME è quella che riguarda il packaging. Come sap-
salvataggio di un oggetto Contact
piamo, la distribuzione di un’applicazione avviene tramite
due file, il jar (che contiene le classi e tutti i file dell’ap-
si ritiene più opportuno (nell’esempio di fatto non è stata plicazione) e il jad (un semplice file di testo che descrive
implementata nessuna logica applicativa). l’applicazione). Anche se le specifiche J2ME prevedono la
presenza obbligatoria di entrambi i file per l’installazione
dell’applicazione, molti cellulari consentono l’installazione
Controllo della memoria partendo dal solo file jar. In questo modo, oltre a bypassare
tutti i controlli sull’effettiva compatibilità dell’applicazio-
Nello sviluppo di una midlet è fondamentale avere un ne con il cellulare in questione, si perdono anche tutti gli
controllo costante sulla memoria che l’applicativo occupa eventuali parametri di configurazione dell’applicazione
durante il suo ciclo di vita. Quello della memoria occupata eventualmente presenti nel jad. Se, ad esempio, preve-
è un problema molto ostico soprattutto nello sviluppo di diamo un parametro che indica l’indirizzo del server web
giochi, in cui il caricamento di immagini, ma soprattutto a cui connettersi, cosa non solo legittima ma altamente
l’esecuzione in un loop continuo della logica del gioco, por- consigliata, bisogna però sempre prevedere la possibile
ta a facili accumuli di memoria occupata. Ciò porta, come mancanza di quel parametro.
si può immaginare, ad un blocco dell’applicazione con la Ecco il contenuto del file jad:
tipica eccezione OutOfMemory. Evitare ciò è molto semplice
utilizzando uno dei tool che viene fornito all’interno del MIDlet-1: J2meBP, , it.wmlscript.bestpractise.MainMIDlet
Java Wireless Toolkit. È sufficiente abilitare il monitor MIDlet-Jar-Size: 42457
sulla memoria (dal menu Edit/preferences) e al successivo MIDlet-Jar-URL: J2ME_BP.jar
avvio dell’applicazione verrà visualizzata un grafico della MIDlet-Name: J2ME_BP
memoria occupata durante l’esecuzione dell’applicazione. MIDlet-Permissions: javax.microedition.io.Connector.http
In un’applicazione ben scritta, la linea verde della memo- MIDlet-Vendor: wmlscript.it
ria dovrebbe mantenersi più o meno costante durante il MIDlet-Version: 1.0
ciclo di vita del software o comunque non seguire dei trend MicroEdition-Configuration: CLDC-1.0
di crescita costante. MicroEdition-Profile: MIDP-2.0
A volte può capitare che la memoria salga senza apparenti serverurl: http://localhost:8080/bpserver/
motivi. A questo punto, è necessario capire quali oggetti RemoteContactService
occupano memoria che non dovrebbero occupare e, dopo
aver individuato questi oggetti, agire di conseguenza. Per cui all’interno della nostra applicazione avremo qual-
Molte volte è sufficiente rilasciare qualche oggetto non cosa di simile a quanto riportato nel Listato 15. In questo
appena questo non è più utilizzato, ma molte volte anche modo l’applicazione funziona anche in mancanza del file
questo tipo di operazione non basta o non è così semplice jad con i relativi parametri.

24 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

public class ConnectionSaveForm * classe RemoteContactSaveList


extends Form * di tipo Runnable,
implements CommandListener { * passandoli il riferimento a questa
* classe di view in modo che il
UIController uiController = null; * Thread che viene lanciato possa
* aggiornare la progress bar
private StringItem stringItemStatus * invocando il metodo updateProgress();
= null; */
private Command cmdStop = null; public void performConnection(){
private Command cmdDone = null; addCommand(cmdStop);
removeCommand(cmdDone);
private static final int GAUGE_MAX = 5; remote =
int current = 0; new RemoteContactSaveList(this);
Gauge gauge = null; remote.start();
}
RemoteContactSaveList remote = null;
public void updateProgress() {
/** current += 1;
* Nel costruttore vengono istanziati: if (current > GAUGE_MAX)
* - un oggetto di tipo gauge current = GAUGE_MAX;
* per la progress bar gauge.setValue(current++);
* - un comando di ok che viene }
* visualizzato suolo alla fine
* delle operazioni /**
* - un comando per interrompere * Viene invocato dal Thread
* le operazioni che viene * Gestisce la barra per
* visualizzato subito * il progresso delle operazioni
* e fino a che non vengono */
* terminate le operazioni public void updateProgress(String note) {
*
* @param controller if (note != null){
*/ setTitle(note);
public ConnectionSaveForm( stringItemStatus.setLabel(note);
UIController controller) { }
updateProgress();
super(LanguageLabel.WAITING);
return;
uiController = controller; }

stringItemStatus = /**
new StringItem(“”, “”); * Viene invocato dal Thread
gauge = new Gauge(“”, * Notifica alla classe di view il
false, GAUGE_MAX, 0); * termine delle operazioni.
* Rimuove il tasto di cancel e mette
cmdDone = new Command( * quell di ok.
LanguageLabel.CONFIRM, */
Command.OK, public void notifyFinish() {
0); removeCommand(cmdStop);
addCommand(cmdDone);
cmdStop = new Command( }
LanguageLabel.UNDO,
Command.BACK, public void commandAction(Command c,
0); Displayable d) {

addCommand(cmdStop); if (c == cmdStop){
remote.stop();
append(stringItemStatus); uiController.displayMenu();
append(gauge); }
if (c == cmdDone){
setCommandListener( this ); uiController.displayMenu();
} }
}
/**
* viene creata un’istanza della }

LISTATO 10 La classe ConnectionSaveForm che contiene solo istruzioni di view

n.2 - gennaio/febbraio 2007 25


speciale Java Micro Edition JAVA Journal

• Evitare di lanciare eccezioni quando non è strettamente necessa-


public void displaySendHttpData(){ rio.
display.setCurrent(connectionSaveForm); Evitare di scrivere istruzioni del tipo:
connectionSaveForm.performConnection();
} if (validate == false)
throw new Exception(“Dati non validi”)
LISTATO 11
ma scrivere piuttosto dei valori di ritorno nei metodi che
Per quanto riguarda il file jar, è sempre consigliato effet- indichino eventualmente l’esito delle operazioni, ad esem-
tuare un’operazione di obfuscation prima della sua distri- pio
buzione. Lo scopo principale per cui si crea un obfuscated
package è di nascondere il codice sorgente delle classi da if (validate == false)
operazioni di decompilazione, ma allo stesso tempo si return false;
ottengono anche dei piccoli miglioramenti nelle perfor-
mance dell’applicazione. Offuscando una midlet, infatti, • Usare con cura le collection.
tutte le classi che la compongono vengono rinominate in Ricordiamo che le classi Collections non sono altro che dei
singole lettere dell’alfabeto (ad esempio MainMidlet.class wrapper per gli array, per cui è preferibile utilizzare diret-
diventa a.class) e tutti i metodi e gli attributi delle classi tamente gli array (ad esempio new int[]) piuttosto che
vengono rinominati allo stesso modo (ad esempio UIContr una collection di tipo Vector. Se decidiamo si usare Vector o
oller.displaySearchUserList() diventa b.a()). In questo modo, HashTable è bene cercare di dimensionarli in modo corretto
la dimensione delle classi caricate in memoria durante al momento della loro istanziazione. Se un vettore supe-
l’esecuzione dell’applicativo diminuisce, e di conseguenza ra la capacità con la quale era stato creato, viene creato
diminuisce l’occupazione di memoria. È ovvio che si tratta un array interno più grande, vengono copiati i valori nel
di una miglioria di poco conto, ma è sempre bene tenerlo nuovo array e viene eliminato quello vecchio. Come ben
presente. capite, una gestione di questo tipo è piuttosto onerosa per
un terminale con ridotte capacità computazionali. Anche
l’utilizzo di HashTable è oneroso per il terminale, in quanto
ad ogni inserimento e cancellazione di elementi viene ef-
fettuato il rehashing degli elementi.
Nello sviluppo di • Evitare la concatenazione di stringhe.

una midlet è fondamen- La concatenazione di stringhe dovrebbe essere evitata in


qualsiasi applicativo Java, anche in ambiente Enterprise
proprio perché molto onerosa, in termini di occupazione di
tale avere un controllo memoria e di complessità computazione delle operazioni;
infatti, concatenando più stringhe con l’operatore + ven-
costante sulla memoria gono create delle stringhe temporanee, poi copiate nell’og-
getto di destinazione. Per ovviare al problema è sufficiente
utilizzare un oggetto di tipo StringBuffer:

String x = “a” + “b” + “c”;

Tuning delle performance diventa:

Descriviamo, infine, alcuni consigli per effettuare il co- Stringx=newStringBuffer().append(“a”).append(“b”).append


siddetto tuning delle performance in un’applicazione java (“c”).toString()
per cellulari. Sono piccole cose, che migliorano la gestione
della memoria e aumentano la velocità di esecuzione, e che
potrebbero sembrare banali e inutili quando ormai si di- Conclusioni
spone di terminali con più di 1 MB di memoria per l’esecu-
zione run-time (heap-memory) e di processori nell’ordine Abbiamo visto come realizzare un’applicazione seguendo
dei 30 MHz. Non dimenticate, però, che Java è stato pen- le più importanti “best practice” nello sviluppo di appli-
sato per far girare applicazioni su tutti i cellulari abilitati a cativi Java ME, dal design dell’applicazioni ai più semplici
questa tecnologia, e che sviluppare un’applicazione che poi consigli per evitare problemi banali, ma a volte molto peri-
non funziona su gran parte dei cellulari è sicuramente una colosi, con la memoria del terminale Java.
cosa da evitare. Un’applicazione dovrebbe sempre essere
sviluppata basandosi sui requisiti minimi, per cui è sempre Note Biografiche
bene avere a disposizione un terminale di prima generazio-
Matteo Zinato: esperto ed appassionato di wireless, segue Java
ne Java, niente di meglio di un vecchio Nokia 6310i, con Micro Edition sin dalla sua presentazione. Lavora nel mon-
pochi Kb di memoria heap. Ecco quindi una lista di cose do dell’IT coordinando progetti JEE e JME e nel tempo li-
da fare e non fare: bero cura i contenuti del portale sul wireless programming
www.wmlscript.it

26 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

public class RemoteContactServlet extends Http- bufferedResult.toByteArray();


Servlet {
writer.writeByte(MessageConstants.ERROR_NONE);
public void doGet(
HttpServletRequest request, //appende al DataOutputStream i byte
HttpServletResponse response) //scritti dal metodo con i dati
throws ServletException, IOException { //da inviare al client
writer.write(bufferedBytes, 0,
perform(request, response); bufferedBytes.length);
}
response.setContentType(
public void doPost( “application/octet-stream”);
HttpServletRequest request, int contentLength = writer.size();
HttpServletResponse response) response.setContentLength(
throws ServletException, IOException { contentLength);

perform(request, response); }else{


}
//nessun dato ricevuto

private void perform( }


HttpServletRequest request,
HttpServletResponse response) }//perform
throws ServletException, IOException {
private void saveContactList(
DataInputStream reader,
if (request.getContentLength() > 0){ DataOutputStream result)
throws IOException {
InputStream is =
request.getInputStream(); long numOfRecords = reader.readLong();
DataInputStream reader =
new DataInputStream(is); for (int i=0; i<numOfRecords; i++){
ContactBean contact =
OutputStream out = new ContactBean();
response.getOutputStream();
DataOutputStream writer = contact.deserialize(reader);
new DataOutputStream(out);
//...
//due stream per i dati di ritorno }
ByteArrayOutputStream bufferedResult =
new ByteArrayOutputStream(); return;
DataOutputStream methodResult = }//saveContactList
new DataOutputStream(bufferedResult);
private void getContactList(
DataInputStream reader,
byte operation = reader.readByte();
DataOutputStream result)
switch (operation) {
throws IOException {
case MessageConstants.
long numItem = 10;
OPERATION_SAVE_USER_LIST:
result.writeLong(numItem);
saveContactList(reader, methodResult);
for (int i=0; i<numItem; i++){
break;
ContactBean contact =
new ContactBean();
case MessageConstants.
contact.setName(“nome”+i);
OPERATION_GET_USER_LIST:
contact.setSurname(“cognome”+i);
getContactList(reader, methodResult);
contact.setBorndate(new Date());
break; contact.setEmail(“email@email.it”);
contact.serialize(result);
default: }
break;
} }//getContactList
methodResult.flush();
byte[] bufferedBytes = }//RemoteContactServlet

LISTATO 12 La classe RemoteContactSaveList che contiene solo istruzioni di model

n.2 - gennaio/febbraio 2007 27


speciale Java Micro Edition JAVA Journal

public class RemoteModel { throws Exception {

public static String serverURL = try {


“http://localhost:8080/bpserver/ int responseCode = connection.
RemoteContactService”; getResponseCode();

/** if (responseCode == HttpConnection.HTTP_OK


* Apre la connessione al server || responseCode == HttpConnection.HTTP_CREA-
* impostando user-agent e content-type TED) {
* @return HttpConnection: la
* connessione al server DataInputStream inputStream =
* @throws Exception connection.openDataInputStream();
*/
protected HttpConnection openConnection() byte returnCode =
throws Exception { inputStream.readByte();

try { switch (returnCode) {


HttpConnection conn = (HttpConnection)
Connector.open(serverURL); case MessageConstants.ERROR_NONE: {
return inputStream;
conn.setRequestProperty(“User-Agent”, }
System.getProperty(“microedition.profiles”
)); default:{
conn.setRequestProperty(“Content-Type”, throw new Exception(
“application/octet-stream”); “Errore nel server”);
conn.setRequestMethod(HttpConnection.POST); }
}
return conn; }//if
} catch (IOException ioe) {
throw new Exception(“Impossibile
throw ioe; effettuare la connessione”);
}
} //openConnection } catch (IOException ioe) {
throw ioe;
/** }
* Apre un DataOutputStream sulla }//openConnectionInputStream
* connessione
* @param connection /**
* @return DataOutputStream * Chiude la connessione e gli eventuali
* @throws IOException * stream catturando eventuali Exception
*/ * @param connection
protected DataOutputStream * @param outputStream
openConnectionOutputStream( * @param inputStream
HttpConnection connection) */
throws IOException { protected void closeConnection(
HttpConnection connection,
try { DataOutputStream outputStream,
return connection. DataInputStream inputStream) {
openDataOutputStream();
if (outputStream != null) {
} catch (IOException ioe) { try {
throw ioe; outputStream.close();
} } catch (IOException ioe) {}
} }

/** if (inputStream != null) {


* apre un DataInputStream sulla try {
* connessione, controlla che il response inputStream.close();
* code della connessione sia } catch (IOException ioe) {}
* HTTP_OK (200) e come prima cosa legge }
* un byte che indica se le operazioni
* lato server sono andate a buon fine if (connection != null) {
* (MessageConstants.ERROR_NONE). try {
* In caso negativo lancia una Exception. connection.close();
* @param connection } catch (IOException ioe) {}
* @return DataInputStream }
* @throws Exception
*/ return;
protected DataInputStream }
openConnectionInputStream(
HttpConnection connection) }

LISTATO 13

28 n.2 - gennaio/febbraio 2007


JAVA Journal Java Micro Edition speciale

public final class MessageConstants {


String serverUrl = this.
public static final byte
getAppProperty(“serverurl”);
OPERATION_SAVE_USER_LIST = 0;
public static final byte
OPERATION_GET_USER_LIST = 1; if (serverUrl != null &&
public static final byte serverUrl.length() > 0)
ERROR_NONE = 101;
RemoteModel.serverURL = serverUrl;
public static final byte
ERROR_UNKNOWN_OPERATION = 101; else
public static final byte RemoteModel.serverURL =
ERROR_SERVER_ERROR = 102; “http://localhost:8080/bpserver/
RemoteContactService”;
}

LISTATO 14 La classe MessageConstants che


contiene i codici che identificano le operazioni da
fare sul server LISTATO 15

n.2 - gennaio/febbraio 2007 29


JAVA Journal educational

Apache Ant
Il progetto Apache mette a disposizione una notevole quantità di software open source, in partico-
lare possiamo trovare parecchie librerie e software utili (e forse indispensabili) allo sviluppo Java.
Uno dei più importanti software di Apache è Ant, la formichina software che lavora per voi

>> di Michele Ferretti (michele.ferretti@javajournal.it)

eccellenza è XML. A mio parere, l’uso del formato

A
XML è la vera forza di questo progetto. La sintassi
nt si basa sui concetti di uno strumento di di XML è universalmente condivisa e semplice da
sviluppo molto vecchio: Make. Make è, ed è apprendere. Nei vecchi Makefile la sintassi era
stato per anni, uno strumento fondamen- particolarmente complessa. Ovunque c’è una virtual
tale per gli sviluppatori software. Make ese- machine Java c’è la possibilità di utilizzare Ant. Make
gue una sequenza di operazioni per ottenere un ri- invece è più difficile da installare proprio per la sua
sultato finale, che di solito è il pacchetto software da natura C.
distribuire. Ant fa lo stesso, ma con maggiore elegan- Make è a tutti gli effetti uno standard in tutti i
za e con un framework a plug-in, che permette di ag- sistemi operativi della famiglia Unix, comprese le
giungere funzionalità codificandole in classi Java. centinaia di distribuzioni Linux. Utilizzare Make
su Windows è un dramma perché siamo costretti a
Make crearci un ambiente particolare per eseguirlo. Ant
è molto più semplice, più flessibile e portabile. Per
Per capire a fondo cosa è e cosa fa Apache Ant, compilare un software Java su Linux, Mac OSX o
bisogna capire quali sono le esigenze che hanno Windows si utilizza sempre lo stesso file XML.
portato gli sviluppatori a crearsi strumenti per In Ant il nome predefinito per un file di build è
velocizzare operazioni ridondanti e noiose. Make è build.xml. Se si lancia il comando “ant” in una
un software che processa dei file di testo denominati directory, il programma cerca un file chiamato
Makefile. I Makefile sono file che contengono direttive build.xml e lo processa. Se non viene specificato il
raggruppate per target. I target sono dei gruppi di target, Ant esegue quello che viene dichiarato come
comandi che permettono di compilare i sorgenti, predefinito all’interno del progetto.
creare archivi dei binari, ecc. Make è nato per essere
utilizzato in ambiente C ma con il tempo è stato Il formato dei file build.xml
utilizzato per parecchi altri compiti.
Come già accennato il formato dei file di build è XML
La filosofia di Ant e la sua struttura può essere riassunta in breve con
questo esempio:
Quando James Duncan Davidson cominciò a
sviluppare Tomcat si trovò di fronte un sacco di <project name=”ProjectName”
sorgenti e parecchie operazioni da eseguire per default=”dist” basedir=”.”>
compilarli. Decise quindi che era arrivato il momento <target name=”dist”>
di creare un nuovo strumento di sviluppo. Ant nacque <!—Lista di task -->
proprio da questa esigenza: poter eseguire una </target>
serie di operazioni indipendentemente dal sistema </project>
operativo. Java, per definizione, è multipiattaforma e
quindi richiede un tool e un formato portabile per la
compilazione delle applicazioni. Il tag project è il contenitore generale di un file
Ovviamente il linguaggio più adatto per creare lo build.xml e al suo interno racchiude diversi blocchi
strumento è Java stesso, e il formato portabile per target. Ogni target al suo interno può contenere

n.2 - gennaio/febbraio 2007 31


educational JAVA Journal

Ant Esegue un altro build file.


AntCall Chiama l’esecuzione di un altro target.
Gzip Comprime un file con l’algoritmo Bzip o Bzip2.
Chmod Cambia i permessi di un file in sistemi Unix.
Copy Copia una file o una lista di file.
Copydir Copia una directoty.
Cvs Esegue una serie dicomandi su CVS.
Delete Elimina un file o una directory ricorsivamente.
Echo Stampa a video un messaggio.
Exec Esegue un comando di sistema o un programma esterno.
Import Importa un altro build file in quello corrente.
Input Permette l’iterazione con l’utente durante la fase di build.
Jar Crea un archivio Jar.
Java Esegue codice Java.
Javac Compila sorgenti Java.
Mail Invia messaggi di posta elettronica.
Mkdir Crea una directory.
Move Sposta un file.
Tar Crea un archivio Tar.
Unzip Decomprime un archivio Zip.
Xslt Processa uno o più file XSLT.
Zip Crea un archio Zip.

TABELLA 1 Una lista dei più importanti task

diversi tag chiamati task. Project richiede un attributo


“name” dove viene specificato il nome del progetto, un <target name=”build”>
attributo “default” che contiene il nome del target che <zip
deve essere considerato predefinito, e l’attributo “basedir” destfile=”${ant.project.name}-1.0.zip”
che contiene la directory corrente quando si inizia la basedir=”classes” />
compilazione. </target>
Il nome del progetto è importante, perché può essere
riutilizzato come variabile all’interno del build.xml per In questa maniera è possibile creare un archivio con il
creare pacchetti per la distribuzione. Ad esempio, potreste contenuto di una directory chiamata “classes”. Questo
dichiarare il nome del software come “Pippo” e poi in fase comando è disponibile in tutti i sistemi operativi ed è
di creazione del pacchetto, aggiungere a questo nome il veramente molto potente. Il tag zip è chiamato task. I task
numero di versione e l’estensione del file. Il risultato sarà sono delle direttive di Ant che implementano operazioni.
“Pippo-1.0.zip”. Esiste una lista di task già disponibili in Ant, e questi
Il nome del progetto sarà utilizzabile in una qualunque rappresentano la libreria standard. Inoltre, per chi non si
parte del file build.xml come una sorta di variabile accontenta, è disponibile un numero notevole di task di
stringa Java. La sintassi da utilizzare per richiamare terze parti per le funzionalità più diverse.
queste “variabili” è ${nomevariabile}. Nel caso del nome
del progetto si utilizza ${ant.project.name}. Questa sorta di I target
variabili si chiamano property. Ant ne definisce diverse a cui
possiamo facilmente accedere. Contengono informazioni Il cuore di ogni build.xml sono i target: tutto avviene
come il classpath, il nome del sistema operativo, la versione al loro interno. Sono questi che definiscono il flusso
della virtual machine ecc. Ecco un esempio banale di come delle operazioni, seguendo le dipendenze. Ogni target
si può richiamare una property: ha un nome, una lista di altri target da cui dipende,

32 n.2 - gennaio/febbraio 2007


JAVA Journal educational

una descrizione e due attributi “if” e “unless” che ne che ci permettono di caricare in automatico l’ultima
determinano l’esecuzione. Un esempio di target completo versione del software su un server FTP e magari segnalare
è il seguente: automaticamente via mail della sua creazione.
Per queste funzionalità esistono già dei task, ma se proprio
<target non vi accontentate potete crearvi un task personalizzato.
name=”compile” L’architettura di Ant è flessibile e permette l’introduzione
depends=”init,setup” di altri task personalizzati. Per creare un proprio task basta
description=”descrizione” estendere la classe Task di Ant. Comunque reputo remota
if=”a” unless=”b”> la necessità di dover scrivere un proprio task.
</target> Fra i più importanti task di terze parti ricordo: JUnit, FTP e
MS Visual SourceSafe. Alcune di questi sono, ovviamente,
Questo target si chiama “compile”, dipende dall’esecuzione utilizzabili solo su piattaforme specifiche. Ad esempio, il
di altri due target “init” e “setup” (nella seguenza indicata task per lavorare con SourceSafe non può essere utilizzato
nell’XML) e sarà eseguito se la variabile “a” sarà settata su Linux proprio perché il software di Microsoft non è
e se la variabile “b” non sarà settata. Pensate quindi ad disponibile per questa piattaforma.
un target specifico, che deve essere eseguito solamente in
un determinato caso; potete valorizzare una variabile che Ant nelle applicazioni Java
rappresenta lo stato booleano di quel caso. Nel caso in cui
quella particolare variabile sarà valorizzata, i task presenti Ant è nato dall’esigenza di sviluppatori Java; infatti i primi
all’interno del target saranno eseguiti. target a nascere sono stati:
Raramente ho utilizzato gli attributi if e unless. Anche
perché è possibile richiamare esplicitamente l’esecuzione di • Javac
un altro target, e di conseguenza condizionarlo. Solamente • Java
il nome è obbligatorio, gli altri attributi possono essere • Javadoc
tralasciati, oppure inseriti in varie combinazioni in base • Jar
alle caratteristiche che dovrà avere il target. Per esempio, if
e unless compaiono di rado insieme. Questi infatti sono presenti fin dagli albori del progetto.
La pratica comune è quella di creare innanzitutto target Ant è un ottimo strumento di sviluppo per un progetto
che racchiudono comandi destinati ad uno scopo preciso. Java e può essere utilizzato per eseguire le varie fasi. Le fasi
Il passo successivo è inserire le dipendenze fra questi standard di un progetto Java, possono essere riassunte in:
target, in modo che l’esecuzione di un target causi a
cascata l’esecuzione di tutti gli altri. Un probabile target 1. Inizializzazione dell’ambiente (init)
“init” potrebbe contenere una lista di task “mkdir”: 2. Compilazione dei sorgenti (compile)
questi creano la struttura del file system di partenza per 3. Creazione dell’archivio jar (build)
la compilazione e la creazione del pacchetto software da 4. Generazione della documentazione Javadoc
distribuire. Esempio: (doc)
5. Creazione del pacchetto per la distribuzione
<target name=”init”> (dist)
<mkdir dir=”build”/> 6. Rimozione dei file generati (clean)
<mkdir dir=”dist”/>
</target> La generazione della documentazione non è necessaria
ma in un progetto che si rispetti lo sviluppatore rilascia
Nella directory “build” andranno a finire i file compilati sempre la documentazione autogenerata da Javadoc. Ad
e nella directory “dist” verrano spostati i file binari e gli ogni voce di questo elenco va associato un target specifico.
altri file che andranno a far parte del pacchetto finale Prendiamo come esempio la preparazione di un pacchetto
da distribuire. Più avanti presenterò un file di build da di rilascio per una classe HelloWord.java. All’interno di
utilizzare per un progetto software Java. questi target farò uso di proprietà che inizializzerò con
visibilità globale nel progetto.
La libreria standard dei task
Inizializzazione dell’ambiente
La libreria standard dei task di Ant è molto vasta e
comprende strumenti basilari per la manipolazione di Preparare un ambiente per il rilascio di un pacchetto,
codice Java ma anche del file system e per altri migliaia significa creare le directory che conterranno i file
di scopi. Non si possono elencare qui tutti i task, pertanto compilati e il resto dei file che andranno a far parte della
nella Tabella 1 è riportata una lista dei più importanti con distribuzione. Questo target lo chiameremo “init” e non
a fianco una breve descrizione. avrà dipendenze con altri target. All’interno di questo
Con i task racchiusi in questa piccola lista è possibile fare target metteremo i task che creeranno le directory.
già parecchie cose. Nella maggior parte dei casi infatti, ci si
limita a creare directory, compilare, spostare e archiviare. <!-- Inizializzazione -->
Quasi tutto il lavoro si basa su operazioni specifiche <target name=”init”>
su file system. Ovviamente è interessante inserire task <mkdir dir=”${build}”/>

n.2 - gennaio/febbraio 2007 33


educational JAVA Journal

vadoc -->
<project name=”HelloWord” default=”dist” base- <target name=”doc”>
dir=”.”> <javadoc packagenames=”com.*”
sourcepath=”${src}”
<!-- proprieta’ utilizzate all’interno dei destdir=”${doc}”
target --> author=”true”
<property name=”src” value=”src” /> version=”true”
<property name=”build” value=”build” /> />
<property name=”dist” value=”dist” /> </target>
<property name=”doc” value=”doc” />
<property name=”version” value=”1.0” /> <!-- Creazione del pacchetto per la di-
stribuzione -->
<!-- Inizializzazione dell’ambiente --> <target name=”dist” depends=”build,doc”>
<target name=”init”> <zip destfile=”${dist}/
<mkdir dir=”${build}”/> ${ant.project.name}-${version}.zip”>
<mkdir dir=”${build}/classes”/> <fileset dir=”.” includes
<mkdir dir=”${dist}”/> =”${ant.project.name}.jar” />
<mkdir dir=”${doc}”/> <fileset dir=”.”
</target> includes=”${doc}/**/*” />
</zip>
<!-- Compilazione dei sorgenti --> </target>
<target name=”compile” depends=”init”>
<javac srcdir=”${src}” <!-- Rimozione dei file e directory gene-
destdir=”${build}/classes” /> rati -->
</target> <target name=”clean”>
<delete dir=”${build}”/>
<!-- Creazione dell’archivio jar --> <delete dir=”${dist}”/>
<target name=”build” depends=”compile”> <delete dir=”${doc}”/>
<jar destfile=”${ant.project.name <delete file=”${ant.project.name}
}.jar” basedir=”${build}/classes”/> .jar”/>
</target> </target>

<!-- Generazione della documentazione ja- </project>

LISTATO 1 Scheletro di un file build.xml

<mkdir dir=”${build}/classes”/> srcdir=”${src}”


<mkdir dir=”${dist}”/> destdir=”${build}/classes” />
<mkdir dir=”${doc}”/> </target>
</target>

Creazione dell’archivio jar

Compilazione dei sorgenti A questo punto, dobbiamo creare l’archivio jar della classe.
Come per la compilazione, la creazione di un archivio jar
La compilazione dei sorgenti Java è una pratica si basa su un unico task che accetta diversi parametri
fondamentale e si basa tutta sul task Javac, che riproduce di configurazione. Si può creare un archivio partendo
le funzionalità del programma javac, distribuito con il JDK. dal contenuto di una intera directory, oppure si possono
Questo task permette di compilare le classi Java partendo specificare i file, utilizzando anche caratteri wildcard. Nel
da una directory base, dove sono presenti i sorgenti. Si caso specifico, creiamo l’archivio dal contenuto dell’intera
possono specificare i package e molti altri parametri, come directory “classes” presente all’interno della directory
ad esempio il target della JVM. “build”.
Questo target dipende dall’esecuzione del target
precedente. Al suo interno è dichiarato il task Javac <!-- Creazione dell’archivio jar -->
con i parametri “srcdir” e “destdir” che contengono, <target
rispettivamente, la directory dei sorgenti e la directory di name=”build”
destinazione delle classi compilate. depends=”compile”>
<jar destfile=”${ant.project.name}.jar”
<!-- Compilazione dei sorgenti --> basedir=”${build}/classes”/>
<target name=”compile” </target>
depends=”init”>
<javac

34 n.2 - gennaio/febbraio 2007


JAVA Journal educational

# ant
Buildfile: build.xml

init:
[mkdir] Created dir: /Users/michele/Desktop/Articolo Ant/esempi/build
[mkdir] Created dir: /Users/michele/Desktop/Articolo Ant/esempi/build/classes
[mkdir] Created dir: /Users/michele/Desktop/Articolo Ant/esempi/dist
[mkdir] Created dir: /Users/michele/Desktop/Articolo Ant/esempi/doc

compile:
[javac] Compiling 1 source file to /Users/michele/Desktop/Articolo Ant/esempi/build/classes

build:
[jar] Building jar: /Users/michele/Desktop/Articolo Ant/esempi/HelloWord.jar

doc:
[javadoc] Generating Javadoc
[javadoc] Javadoc execution
[javadoc] Loading source files for package com.acme...
[javadoc] Constructing Javadoc information...
[javadoc] Standard Doclet version 1.4.2_09
[javadoc] Building tree for all the packages and classes...
[javadoc] Building index for all the packages and classes...
[javadoc] Building index for all classes...

dist:
[zip] Building zip: /Users/michele/Desktop/Articolo Ant/esempi/dist/HelloWord-1.0.zip

BUILD SUCCESSFUL
Total time: 4 seconds

LISTATO 2 Targets che genera un archivio zip

Generazione della documentazione javadoc la compressione, la lista dei file da includere ecc.
La sua esecuzione dipende da quella del target “build” e
In Java possiamo documentare il codice mentre lo poi del target “doc”.
scriviamo. In un secondo tempo, con lo strumento javadoc,
è possibile generare la documentazione in formato HTML <!-- Creazione del pacchetto per la distribuzione -->
delle classi. In questo target, chiamato “doc” si genera la <target name=”dist” depends=”build,doc”>
documentazione per la classe HelloWord e per tutte quelle <zip
classi che appartengono ad un package che inizia per destfile=”${dist}/${ant.project.name}-${version}.zip”>
“com”. <fileset dir=”.” includes=”${ant.project.name}.jar” />
<fileset dir=”.” includes=”${doc}/**/*” />
<!-- Generazione della </zip>
documentazione javadoc --> </target>
<target name=”doc”>
<javadoc packagenames=”com.*”
Rimozione dei file e directory generati
sourcepath=”${src}”
destdir=»${doc}» Questo target non fa parte di una procedura di build ma
author=»true» definisce tutte le operazioni necessarie affinché l’ambiente
version=»true»/> ritorni nello stato iniziale. Ciò garantisce che in una nuova
</target> procedura di build non si trovi “sporcizia” lasciata dalla
precedente. Questo target si chiama “clean” e va lanciato
Creazione del pacchetto per la distribuzione prima di rieseguire nuovamente il file di build.

Il pacchetto per la distribuzione sarà un file zip <!-- Rimozione dei file
contenente l’archivio jar appena creato e la directory con e directory generati -->
la documentazione. Il task per compiere questa operazione <target name=”clean”>
è zip e, come gli altri, ha una serie di parametri per definire <delete dir=”${build}”/>

n.2 - gennaio/febbraio 2007 35


educational JAVA Journal

<delete dir=”${dist}”/> di distribuzione di una estensione che ho realizzato per


<delete dir=”${doc}”/> Mozilla Firefox.
<delete file=”${ant.project.name}.jar”/> Per esempio, volendo creare le pagine HTML di un sito
</target> Internet si potrebbe partire dal contenuto di un file XML,
applicare un file XSLT a questo XML e avere in uscita uno o
Assemblando tutti questi target assieme, otteniamo il più file HTML. Sempre con Ant sarebbe possibile caricare,
file di build definitivo, riprodotto nel Listato 1. Il primo via FTP, quell’HTML sul server del provider del nostro
target ad essere chiamato sarà dist e il flusso di esecuzione servizio di hosting. Il task XSLT potrebbe essere usato
sarà: init, compile, build, doc, dist. In cima, prima anche per generare versioni distribuibili di documenti
della dichiarazione del target init, sono presenti cinque scritti con DocBook.
dichiarazioni di property:

<!-- proprieta’ utilizzate


all’interno dei target -->
<property name=”src” value=”src” />
Antnacque proprio
<property name=”build” value=”build” />
<property name=”dist” value=”dist” />
da questa esigenza:
<property name=”doc” value=”doc” />
<property name=”version” value=”1.0” /> quella di poter eseguire
Si tratta di quattro directory e della stringa che identifica una serie di operazioni
la versione del software. In genere, qui si inseriscono
anche eventuali informazioni su: autore, data di creazione, indipendentemente dal
copyright, ecc. Vediamo ora se il file appena creato
funziona. Per convenzione lo rinominiamo “build.xml” e
dal prompt di comando digitiamo il relativo comando. Nel
sistema operativo
Listato 2 è mostrato un esempio di compilazione.
L’output di Ant permette di capire se è andato tutto bene
o se ci sono stati dei problemi, ed eventualmente la causa Conclusione
di questi problemi. La maggior parte dei task di Ant, se
va in errore, blocca l’esecuzione dell’intero file. Questa Ant è uno strumento di lavoro estremamente utile e
caratteristica di Ant è molto importante, perché è inutile completo. Viene utilizzato in ambito open source nei
continuare nella compilazione di una classe se non si è progetti della fondazione Apache e in moltissimi progetti
riusciti a creare la sua directory di destinazione. commerciali. Alcune delle aziende più influenti nel
panorama Java, come Bea, rilasciano task per l’integrazione
Se abbiamo bisogno di ricreare di nuovo il pacchetto, con i loro prodotti. Viene supportato da quasi tutti gli IDE
perché nel frattempo abbiamo aggiunto un metodo alla Java in circolazione. Ne cito solamente alcuni: JBuilder,
nostra classe, prima dobbiamo ripulire l’ambiente. Il target Eclipse e NetBeans. Non vorrei sbagliarmi, ma credo
“clean” è stato creato proprio a questo scopo. Per eseguirlo che, NetBeans lo utilizzi come motore per eseguire azioni
digitiamo: all’interno dell’ambiente di sviluppo. Alcuni di questi IDE
sono provvisti di wizard grafici per la creazione di file Ant.
# ant clean Non si tratta di un progetto Java sconosciuto ma di uno
standard de facto apprezzato e riconosciuto da tutti gli
e il risultato sarà la cancellazione di tutti file sviluppatori Java. Non a caso sono nati alcuni progetti
“cloni” come Nant (http://nant.sourceforge.net/) che
In generale se volete richiamare l’esecuzione di un target cercano di riprodurre le funzionalità per ambienti diversi
particolare, potete farlo specificando il suo nome come da Java, come .NET.
primo dei parametri del comando ant. Quindi se volete
solo rigenerare la documentazione potete usare: Bibliografia

# ant doc [1]_Home page del progetto Apache Ant (http://


ant.apache.org/)
[2]_Manuale ufficiale di Ant (http://ant.apache.org/
Ant per usi diversi da Java manual/index.html)
[3]_Alcuni tutorial su Ant (http://blog.ideoplex.com/
Apache Ant è un progetto nato per uno scopo preciso: software/java/#ant)
la compilazione dei programmi in Java. Con gli anni [4]_Wiki_su_Ant_(http://en.wikibooks.org/wiki/
però, ci si è resi conto che risulta adatto ad eseguire Programming:Apache_Ant)
un’enorme quantità d’operazioni. Ci sono persone che
Note Biografiche
lo utilizzano per creare siti Internet oppure per sostituire
operazioni ridondanti che prima descrivevano in file Michele Ferretti è un giovane programmatore che si occupa di
sviluppo Java per lavoro e nel tempo libero si diletta con Python
batch. Personalmente, lo utilizzo per creare il pacchetto ed ultimamente con il mondo Ruby e Ruby On Rails

36 n.2 - gennaio/febbraio 2007


educational JAVA Journal

Java 5, le buone
nuove e le novità
meno buone
seconda parte
>> di Ugo Landini (ugo.landini@javajournal.it)

C
e così via. Di fatto il compilatore sostituisce l’ellipsis
ontinuiamo la nostra carrellata sulle novi- con un array (di String in questo caso, ma potrebbe
tà di Java5 (linguaggio e piattaforma). Nel- ovviamente essere un array di Object o di quello che
la prima parte abbiamo trattato i Generics, volete), ma vi permette anche di non passare nessun
l’enhanced for, l’autoboxing, gli static im- parametro, cosa molto comoda. Iterare sulla lista di
port, la covarianza e il class sharing. In questa secon- argomenti è quanto di più semplice si possa pensare,
da parte vedremo le concurrent utilities, i typesafe ovviamente usando il nuovo ciclo for:
enums, i varargs e le annotations, ed in più vedremo
cosa bolle in pentola per Java6. for (String feature: features) {
Per tutti coloro che avessero perso la prima parte, System.out.println(feature);
riportiamo la tabella (riassuntiva e molto ad alto }
livello) dei più importanti cambiamenti introdotti in
Java5 (Tabella 1). Essendo di fatto un array, potete ovviamente memo-
rizzare i varargs tramite un semplice assegnamento:

String[] myFeatures = features;


Varargs

Come dice il nome stesso, con Java5 si può ora dichia- o anche, perché no, passare un array come parame-
rare un metodo con numero variabile di argomenti, tro:
cosa che farà felice qualche programmatore C e farà
probabilmente inorridire i puristi della programma- new Phone(“Nokia”, “6310i”, new String[]{“Bluetooth”,
zione ad oggetti. Questa caratteristica apre anche la “MIDP 1.0”});
porta alla printf, nel più puro stile C. Sia come sia, è
una feature che può sicuramente tornare utile. Un Attenzione però alle conversioni! In qualche (raro)
costruttore con questa signature (notare l’ellipsis, caso, potrebbero interferire con le vostre vere inten-
ossia i 3 puntini) zioni. Supponiamo di voler stampare l’indirizzo di
un array di oggetti, magari per fare debugging, con
public Phone (String manufacturer, String name, questo codice:
String... features)
Object[] array = new String[] {“qualche”, “stringa”,
può essere invocato con: “a caso”}
out.printf(“ Indirizzo dell’array di oggetti: <%s> “,
new Phone(“Nokia”, “6310i”); array);
new Phone(“Nokia”, “6310i”, “Bluetooth”);
new Phone(“Nokia”, “6310i”, “Bluetooth”, “MIDP 1.0”); Essendo il secondo parametro di printf in realtà un va-
rarg, verrà passato il primo parametro dell’array a %s,

38 n.2 - gennaio/febbraio 2007


JAVA Journal educational

Cambiamento Costrutto/Tool Scopo


• Semplificazione della gestione delle Collections
Linguaggio Generics
• Sicurezza del codice
Linguaggio Nuovo ciclo for • Semplificazione della gestione delle Collections
Linguaggio Autoboxing • Semplificazione del codice
• Gestione standardizzata di insiemi di oggetti
Linguaggio Enumeration
• Sicurezza codice
Linguaggio Varargs • Soprattutto semplificazione nel porting di codice C
Linguaggio Static import • Migliorare la leggibilità del codice
Linguaggio Covarianza • Più espressività, migliore modellabilità
API printf • Soprattutto semplificazione nel porting di codice C
API java.util.scanner • Semplificare l’IO
• Maggiore integrazione con XML
API xml bundling
• Supporto web services integrato in Java
• Semplificare la creazione di codice multithreaded
API Concurrent API
• Aumentare le performance del codice multithreaded
• Migliorare lo startup della virtual machine
Sistema Class sharing
• 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 Sintesi delle novità introdotte in Java5

e non l’indirizzo come vi aspettereste. Per forzare la mano a Joshua Bloch propose allora una soluzione più o meno
java, bisogna indicare esplicitamente le nostre intenzioni: standard a questo problema, soluzione che potete trovare
nel suo eccellente libro Effective Java [BLOCH], e chiamò
out.printf(“ Indirizzo dell’array di oggetti: <%s> “, questo idioma “type safe enum”
(Object)array);
// idioma typesafe enum: ottimo fino al JDK 1.4
public class Suit {
Typesafe Enums (o Enumerated Types)
public static final Suit CLUBS = new Suit(“clubs”);
I typesafe enum sono un caso di idioma entrato diretta- public static final Suit DIAMONDS = new Suit(“diamonds”);
mente in una nuova release del linguaggio: qui è necessa- public static final Suit HEARTS = new Suit(“hearts”);
ria un po’ di storia per capire meglio. public static final Suit SPADES = new Suit(“spades”);
La keyword enum del C era stata volontariamente tenu- public String toString() {return name;}
ta fuori dal linguaggio Java, poiché non era altro che un private Suit(String name) {this.name = name;}
modo per dare un nome ad un set di costanti intere, senza private final String name;
nessun concetto di type safety. In java un idioma (idioma }
= pattern a livello di linguaggio) standard era quello di
dichiarare delle costanti direttamente nelle classi o in Questo idioma permette ovviamente una maggiore type
un’interfaccia, ma in fondo non era molto meglio del- safety: non c’è modo di usare oggetti di tipo Suit che non
l’equivalente enum in C. siano quelli elencati come static all’interno della classe
stessa: la classe non espone costruttori e non può quindi
// in C neanche essere estesa (se non sapete perché, vi consiglio di
typedef enum {CLUBS, DIAMONDS, HEARTS, SPADES} suit; ripassare i costruttori!), per cui l’idioma è sufficientemente
// in Java: NON USARE robusto.
public class Card { Esistono diverse varianti ed estensioni di questo idioma,
public static final int SUIT_CLUBS = 0; per aggiungere feature come la serializzabilità, l’estendi-
public static final int SUIT_DIAMONDS = 1; bilità, o per gestire tipi ordinali (si noti che nella forma
public static final int SUIT_HEARTS= 2; mostrata utilizza delle stringhe), che complicano legger-
public static final int SUIT_SPADES= 3; mente il tutto. Con Java5 si è deciso dunque di inserire
} questo idioma direttamente all’interno del linguaggio, in

n.2 - gennaio/febbraio 2007 39


educational JAVA Journal

modo da semplificarne un po’ il suo utilizzo, inserendo la sare a soluzioni alternative con “normali” classi. Se avete
parola chiave enum: invece bisogno di una lista di costanti e volete essere sicuri
che il compilatore controlli su eventuali abusi, enum è la
enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES} soluzione perfetta.

che si usa esattamente come il “vecchio” idioma di Bloch. Concurrent Utilities

Suit current = Suit.DIAMONDS; Le concurrent utilities sono, a mio modo di vedere, la no-
if (current == Suit.HEARTS) ... vità in assoluto più importante di Java5. Ma solo chi ha bi-
sogno di scrivere codice multithreaded ne può apprezzare
Andando più a fondo, una enum non è altro che una classe la portata, molto spesso passa inosservata.
un po’ speciale: Anche qui è d’obbligo un po’ di storia. Java, da sempre, ha
avuto un ottimo supporto alla programmazione concorren-
• usa la keyword enum al posto di class te, tramite le feature implicite in Object (wait() e notify()/no-
• come prima cosa deve dichiarare tutte le sue costanti, tifyAll()), le keyword synchronized e volatile e la classe Thread
prima di qualsiasi attributo o metodo aggiuntivo (e le altre classi/interfacce correlate).
• è implicitamente final, ma non può essere dichiarata
final (poiché non può essere direttamente estesa, ma le
costanti sono di fatto delle classi anonime che la esten-
dono!)
• non può estendere da altre classi perché implicita- I
vararg sono di fatto
mente estende java.lang.Enum e di conseguenza
un array: si possono trat-
o ha un toString() di default (che può ovviamente essere
overridden) che ritorna il nome della costante tare in modo ordinario, ma
o ha un metodo name() che ritorna il nome della costan-
te, e non può essere overridden attenti alle conversioni
o è implicitamente Comparable e implementa corretta-
mente hashCode e equals
o è impossibile da clonare, clone() è final e inoltre ritorna
l’eccezione CloneNotSupportedException
o ha un metodo ordinal() che ritorna il numero ordinale Come è risaputo, questi meccanismi base permettono – per
corrispondente alla costante chi li conosce e li sa usare correttamente, cosa più facile a
dirsi che a farsi – di gestire la maggior parte delle situazio-
• è implicitamente Serializable ni. Il problema è proprio che questi meccanismi, seppur
• ha due metodi statici automaticamente generati dal sufficienti, sono ad un livello di astrazione molto basso.
compilatore: Creare una classe thread-safe può essere molto più difficile
di quello che può sembrare, e creare un’applicazione con-
o public static E[] values() che torna la lista delle co- corrente senza deadlock e che sfrutti al massimo le risorse
stanti disponibili è invece appannaggio di pochi.
o public static E valueOf(String name) che ritorna la Per questo Doug Lea, professore specializzato nella pro-
costante associata al nome grammazione concorrente, cominciò nel 1995 a mettere
insieme una libreria avanzata di componenti ad alto livello
• non può fare l’override di finalize di astrazione sulla sua homepage [LEA]. La libreria ebbe
• non può essere dichiarata abstract, ma può avere metodi un notevole successo e diverse revisioni, fino alla pubblica-
abstract (questa è lunga da spiegare!) zione nel 1999 del libro “Concurrent programming in Java”
• le costanti possono essere usate in uno switch, a diffe- [CONCURRENT], best seller che - sfortunatamente - non è
renza dei normali oggetti ancora stato aggiornato. Le idee di Doug Lea trovarono poi
spazio nel JSR 166, che ebbe proprio il compito di inserire
Dopo tutte queste piccole differenze, può dichiarare me- le librerie ed i costrutti avanzati direttamente all’interno di
todi e membri come una qualsiasi altra classe. Il codice Java. Lavorando con il supporto dell’engineering, l’expert
generato per una enum è molto simile a quello dell’idioma group del JSR 166, guidato da Doug Lea, modificò addirit-
type safe enum di Bloch, ed usa ampiamente i generics. tura il memory model di Java e la Vm stessa per sfruttare
A mio modo di vedere le Enum sono un ottimo costrutto al meglio alcune idee. Il frutto di questi sforzi congiunti
se usate in maniera molto semplice, come nell’esempio si trova ora soprattutto nel package java.util.concurrent, è
riportato: se si comincia ad usarle aggiungendo comporta- perfettamente integrato con tutte le altre librerie ed è a
mento alle costanti e cose simili si ottiene solo un sostituto disposizione di tutti.
“povero” per la normale programmazione ad oggetti, con Di fatto, non esiste più ragione per utilizzare i “vecchi”
molte più limitazioni (fra l’altro spesso poco intuitive). meccanismi di sincronizzazione. Le nuove concurrent API
Anche qui il consiglio è: prendete le enum, ma a piccole permettono prestazioni spesso superiori, sono più facili da
dosi. Se vi trovate a complicarvi la vita, forse è meglio pen- usare, e risolvono in maniera diretta diversi problemi noti

40 n.2 - gennaio/febbraio 2007


JAVA Journal educational

nascondendo la complessità necessaria per risolverli. A


questo punto molti nostalgici sosterranno che in fondo le
concurrent Api non fanno altro che usare correttamente il
supporto multithreaded “base” di Java, ma sarebbe come
dire che in fondo le JVM sono scritte in C, che a sua volta I typesafe enum
è compilato in linguaggio macchina! Eppure le differenze
fra lo scrivere un middleware in Java ed uno in linguaggio sono un idioma che
macchina sono abbastanza evidenti...
Inoltre, la maggior parte del codice nel package permette una maggiore
java.util.concurrent non utilizza affatto synchronized: le nuo-
ve VM, proprio in seguito agli sforzi del JSR166, espongo-
no ora primitive hardware di compare and swap o load-linked/
type safety
store-conditional (CAS su Sparc/Intel, LL/SC su PowerPC)
che permettono ad alcune classi di utilizzare complessi
algoritmi lock-free, ossia capaci di proteggere risorse senza
utilizzare i classici mutex. È inutile dire che questi algorit-
mi permettono di realizzare codice decisamente più perfor-
mante e scalabile di prima.
Considerate poi che uno degli obiettivi dichiarati del JSR • Utilità generiche di sincronizzazione ad alto livello
166 era quello di realizzare per la programmazione multi-
thread quanto le Collection API di Java 2 avevano realizzato o Semaphore
per le strutture dati, e che inizialmente si era addirittura o CountDownLatch
pensato a modificare e/o inserire parole chiave nel linguag- o CyclicBarrier
gio, ipotesi poi scartata. o Exchanger
Dopo questa lunga introduzione, facciamo una breve
panoramica di quanto possibile con le nuove concurrent • Nuove Collection thread-safe, in generale lock-free
utilities: una classe Lock ad alte performance (un lock,
ma implementato in lock-free!) per sostituire la parola o ConcurrentHashMap
chiave synchronized. Fra le varie implementazioni c’è o CopyOnWriteArrayList
anche un ReadWriteLock bello e pronto, che permette di o le interfacce Queue e BlockingQueue, ed alcune imple-
gestire efficientemente i casi in cui sono possibilità di mentazioni: ArrayBlockingQueue, PriorityBlockingQueue,
letture simultanee ma scritture esclusive. In generale ConcurrentLinkedQueue, ecc.
i nuovi lock si utilizzano in un modo leggermente più
complesso perché costringono ad un finally per il rila- La classe ConcurrentHashMap, per esempio, è molto diver-
scio: sa da una normale HashMap sincronizzata, che si ottiene
utilizzando il metodo Collections.synchronizedMap(), ed è
Lock l = ...; ottimizzata per la scalabilità e le performance: può infatti
l.lock(); gestire un numero infinito di letture contemporanee, e
try { fino a sedici scritture contemporanee, nella maggioranza
// access the resource protected by this lock dei casi in maniera lock-free.
} finally { Se vi dovete occupare della scrittura di codice server ad
l.unlock(); alte prestazioni, le concurrent utilities sono sicuramente il
} punto da cui partire! Se dovete semplicemente costruire
codice thread safe, vi potete accontentare delle nuove Lock/
Ma sono infinitamente più flessibili: si possono acquisire Condition e magari dell’Executor.
in maniera non-blocking con tryLock(), in maniera “inter- In generale, è possibile (ed auspicabile) mandare in pen-
ruttibile” con lockInterruptibly() o anche con un timeout sione i vecchi sistemi e scrivere codice più performante e
con tryLock(long, TimeUnit). meno soggetto ad errori con queste nuove API.

• una classe Condition per rappresentare diversi set di con-


dizioni d’attesa, che sostituisce il meccanismo di wait(), Annotations
notify() e notifyAll().
• variabili Atomiche, ossia variabili per cui è garantito Le annotation sono una di quelle novità di cui inspiega-
l’assegnamento in una unità di tempo indivisibile, senza bilmente si è parlato moltissimo, ma che in realtà hanno
l’ausilio di lock. Possono essere usate per costruirsi i pro- una portata molto più limitata: tipicamente sono molto
pri algoritmi lock-free importanti per i produttori di tool e non certo per i comuni
• granularità a livello di nanosecondi (per i Sistemi operati- sviluppatori.
vi che ne sono capaci!), tramite la nuova classe TimeUnit. È comunque importante sapere perlomeno di cosa si
• un Executor framework per il dispatching di task, com- tratta, poiché come vedremo è molto facile incontrare del
prensivo di un Thread pool e di un servizio di schedu- codice annotato, ed inoltre l’argomento è di per sé molto
ling affascinante.

n.2 - gennaio/febbraio 2007 41


educational JAVA Journal

Le annotation permettono di associare delle informazioni che indica che il metodo è deprecato, esattamente come il
ulteriori a del codice (metadati), informazioni che possono tag @deprecated di javadoc. La differenza è che l’override di
poi essere trattate da altri tool per gli scopi più vari. questo metodo genererà un warning a livello di compila-
Un esempio di annotazioni ante-litteram sono i javadoc. zione, ed un warning più dettagliato sul particolare meto-
@deprecated ,per esempio, è una forma di metadato, che do usando questa sintassi:
esprime la semantica “usatelo a vostro rischio e pericolo,
dalla prossima release potremmo cancellarlo”, semantica javac -Xlint:deprecation *.java
ovviamente non esprimibile in Java! Ovviamente un nor-
male commento non è una forma di metadato (o se lo è Dichiarare un metodo @Override farà invece in modo che il
molto primitivo), poichè non ha una struttura e dunque compilatore controlli effettivamente che il metodo effettui
non può essere gestito da un tool, mentre il tag @deprecated l’override di qualche altro metodo, ed è utile per control-
viene gestito dal tool javadoc, che lo inserisce automatica- lare i classici errori di battitura come tostring(), equal(),
mente nella documentazione di progetto. o hashcode() che spesso portano via prezioso tempo allo
Le annotations sono una generalizzazione di questo mec- sviluppatore.
canismo che permette di definire ed usare dei nuovi meta- Anche creare un nuovo Annotation Type è semplicissimo,
dati, per qualsiasi motivo ne abbiate bisogno (ovviamente tramite il costrutto @interface:
non per la documentazione, per quella c’è già javadoc) . Per
ottenere ciò, le annotations consistono di: public @interface TODO {
String nota();
• una sintassi per dichiarare annotation types }
• una sintassi per annotare il codice
• API per leggere le annotazioni per cui si potrà usare l’annotazione in questo modo, pas-
• modifiche alla rappresentazione dei class files per sando una stringa alla proprietà nota
“contenere” le annotazioni
• un tool per processare le annotazioni @TODO(nota=”Questo metodo va riscritto, è troppo complesso”)
public void faiQualcosa() { //... }
le annotations non influiscono direttamente sul runtime,
ossia non modificano la semantica del codice, ma in realtà Per concludere velocemente questa carrellata: si possono
possono farlo indirettamente, per esempio influenzando creare annotazioni con più di un parametro, si può omet-
l’eventuale ambiente in cui il codice è eseguito a runtime: tere il nome della proprietà se questa si chiama value, si
un application server potrebbe eseguire un particolare possono usare dei valori di default per i parametri e si pos-
componente utilizzando diversi cicli di vita a seconda di sono anche annotare le annotazioni (meta-metadati) per
come questo sia annotato, o decidere sulla base di un’an- definirne meglio il comportamento.
notazione se persistere l’oggetto e come. A runtime, si può poi interrogare un class file ed ot-
È per questo che le annotazioni possono semplificare mol- tenere informazioni sui metadati e sui valori delle
to la vita dei produttori di tool: non è un caso che le nuove proprietà associate tramite nuovi metodi delle reflection
specifiche EJB 3.0 utilizzeranno pesantemente questo API. (vedere l’interfaccia java.lang.reflect.AnnotatedElem
meccanismo. Pensandoci bene, le informazioni contenute ent per i dettagli). Dopo di che, l’uso che ne farete è
nei file XML di un EJB non sono infatti altro che metadati, completamente a vostro carico!
rappresentati tramite file XML in assenza di altri mecca- Per chiudere il cerchio, avrete a disposizione il tool apt, che
nismi Java. Se a questo punto vi viene in mente Xdoclet potete trovare nella solita $JAVA_HOME/bin. Brevemente,
[XDOCLET], siete sulla strada giusta. Se poi vi viene in questo tool serve per generare, di solito a build time, dei
mente di eliminare tutti i file di configurazione del vostro file che contengano delle informazioni derivate da quelle
software e sostituirli con delle annotazioni da distribuire presenti nelle annotazioni, ed è dunque fondamentale per
insieme al sorgente, siete probabilmente sulla strada sba- mantenere in modo automatico la sincronia fra le annota-
gliata: le annotations sono un’altra medicina da prendere zioni ed il mondo “esterno”. Vi rimando alla guida ufficiale
a piccole dosi, altrimenti è velenosa. per i dettagli [APT]
Un uso intelligente e non invasivo delle annotations è per
Esistono tre annotazioni standard predefinite in Tiger esempio fatto nei Testing framework (TestNG, Junit 4). Gli
(Java 5): unit tests devono infatti essere eseguiti da un ambiente
esterno, ed hanno bisogno di semantiche particolari come
@Override, indica che il metodo effettua l’override di un “questo metodo è un testcase”, “questo metodo deve esse-
altro metodo re eseguito prima di ogni testcase” che, seppur esprimibili
@Deprecated, equivalente al @deprecated per i javadoc correttamente in Java, sono sicuramente più chiari e con-
@SuppressWarnings, “spegne” gli warning del compilatore cisi se espressi tramite annotazioni come @test, @before e
per una porzione di codice @after.

Usare le annotations è quanto di più semplice si possa Java 6


pensare:
Mustang, (ovvero Java 6) questo il nome in codice del
@Deprecated public void faiQualcosa() { //... } successore di Tiger (Java5), ha beneficiato di un supporto

42 n.2 - gennaio/febbraio 2007


JAVA Journal educational

Cambiamento Nome Scopo


È possibile mostrare uno splash screen, senza aspettare che la
Desktop Splash screen
virtual machine sia completamente “up”.
• Drag and drop avanzato
• miglioramenti delle performance e soprattutto del look
Swing
Desktop and feel per le varie piattaforme, molto più integrato
enhancements
con il sistema operativo ospite
• miglioramenti per la gestione dei layout (finalmente!)
Supporto ad eventi per icone, tool-tips e menu nelle System
Desktop System tray
bar
Le java.awt.Desktop permettono di interagire con il browser di
Desktop Desktop API sistema, con il client email di default e con altre applicazioni in
maniera standard (ad eventi)
Diversi miglioramenti nelle performance, nel double buffering e
Java 2d
Desktop nell’antialiasing dei font, anche questo molto più integrato con
enhancements
il sistema operativo ospite
È ora possibile far lanciare alla VM uno script quando l’heap è
Application
Sistema pieno, oltre ad avere uno stack trace molto più completo nei casi
management
di OutOfMemory. Integrazione delle VM solaris con Dtrace.
Ancora migliorie per il supporto nativo di XML e standard
Sistema Web services annessi. JAX-WS 2.0, Streaming Api per XML (StaX), Digital
Signatures API, JAXB 2.0
Supporto per GSS/Kerberos, un modulo JAAS per LDAP e
Sistema Security nuove API per la gestione delle Smart card (JSR 268, anche se
probabilmente queste slitteranno a Java7)
Un framework standard per eseguire linguaggi di scripting
Java scripting dalla JVM, permettendogli anche di avere accesso alle API java.
Sistema
(JSR 223) Insomma, un modo per avere linguaggi dinamici (alla Ruby)
senza rinunciare alle caratteristiche di Java.
Accesso da Java al suo compilatore. Ora potrete (in maniera
standard, si intende, quindi indipendentemente dal fornitore
Java Compiler API
Sistema della VM) compilare dinamicamente dei sorgenti java
(JSR 199)
provenienti dalle fonti più disparate. Niente che serva tutti i
giorni, sicuramente!

TABELLA 2 Le principali novità di Java6

della comunità molto più ampio. L’intero ciclo di sviluppo di andare in produzione con le nightly build di Java6, mi
questa release è stato infatti all’insegna della collaborazione raccomando!
e della trasparenza, con sorgenti, nightly build, forum, blog Mustang è sicuramente una release dedicata al Desktop: la
delle persone dell’engineering e paper vari a disposizione maggior parte degli sforzi si sono concentrati proprio in que-
sul sito del progetto [MUSTANG]. “Enter the Participation sto settore. È infatti noto che Java è ormai lo standard defacto
Age”, per dirla con i nuovi slogan del marketing Sun. per il server side computing, poiché – oltre alla portabilità -
Il nuovo ciclo di sviluppo di Java fa sì che le novità offre eccellenti caratteristiche a chi si occupa di middleware
verranno da ora introdotte in maniera graduale, poi- di qualsiasi tipo. Nel settore desktop però ci sono sempre stati
ché i rilasci fra una versione e l’altra saranno sempre diversi problemi, alcuni insiti nella natura stessa di linguag-
compresi fra 1 anno e mezzo e due anni, e quindi molto gio multipiattaforma, altri sicuramente dovuti al fatto che in
probabilmente non assisteremo più a “salti” come quel- questi anni in Java si è fatto soprattutto altro.
lo fra Java 1.4 e Java5. Inoltre la quantità e la qualità Ma vediamo (Tabella 2) alcune (elenco assolutamente
delle informazioni a disposizione degli sviluppatori è non esaustivo!) delle novità di Java6. La tabella 2 non è
molto migliorata: qualsiasi software house ha ora la ovviamente comparabile con quella generale su Java5, poi-
possibilità di pianificare correttamente la transizione da ché qui il livello di granularità è molto più basso. Se avessi
una release all’altra, anticipando i possibili problemi ed dovuto elencare a questo livello di dettaglio i cambiamenti
avendo un canale diretto con l’ingegneria del prodotto in Java5, mi ci sarebbero volute 10 pagine!
molto prima che sia effettivamente disponibile. Ovvia- È evidente che questa release, a differenza della preceden-
mente questo non va interpretato come un consiglio di te, è più orientata a caratteristiche “bells and whistles”.

n.2 - gennaio/febbraio 2007 43


educational JAVA Journal

Non ci sono cambiamenti nel linguaggio, nuove keyword Riferimenti e bibliografia


o sostanziali nuovi modi di fare le stesse cose, escludendo
forse il supporto standard allo scripting Java (JSR 223). [APT]_http://java.sun.com/j2se/1.5.0/docs/guide/apt/
Però ora si può fare un’applicazione Java che – oltre ad GettingStarted.html
avere un gui con look nativo e prestazioni di prima fascia [GOF94] Iterator pattern
- lascia l’iconcina nel System tray, può reagire al click e lan- [BLOCH] Effective Java
ciare per esempio il browser di default aperto su una pagi- [CONCURRENT] Concurrent programming in Java: Desi-
na di amministrazione, e può automaticamente accorgersi gn principles and patterns
di anomalie di sistema (e con l’integrazione con Dtrace si [ENHANCEMENTS] http://java.sun.com/j2se/1.5.0/docs/
possono raggiungere – purtroppo per ora solo su Solaris 10 relnotes/features.html
- risultati incredibili) [FLANAGAN] Java 1.5 Tiger, a developer’s notebook
Insomma, sicuramente un passo avanti per la maturità [GOSLING] The Java Programming Language, 4th edition
della piattaforma, e, fortunatamente, niente che richieda [ISOLATION]_http://www.jcp.org/en/jsr/detail?id=121
giorni e giorni di studio. A meno che non stiate usando [LEA] http://gee.cs.oswego.edu/dl/
ancora Java 1.4, si intende! [MUSTANG] https://mustang.dev.java.net/
[PIZZA] http://www.cis.unisa.edu.au/~pizza/
Conclusioni [SHARING]_http://java.sun.com/j2se/1.5.0/docs/guide/
vm/class-data-sharing.html
Siamo così giunti alla conclusione di questa mini-rassegna [TROUBLESHOOTING] http://java.sun.com/j2se/1.5/pdf/
su Java5 e Java6, che, se il tempismo è corretto, dovrebbe jdk50_ts_guide.pdf
aver visto la luce nella sua prima release FCS (First Custo- [XDOCLET]_http://xdoclet.sourceforge.net/xdoclet/
mer Shipment) proprio in queste settimane. index.html
Ho riportato i link della prima parte, oltre al materiale
nuovo specifico per gli argomenti trattati in questa secon-
da parte, sperando che siano di utilità anche a chi non ha
potuto leggere l’articolo per intero.
In ogni caso, cominciate ad usare (e non abusare) le nuove Note Biografiche
feature della nostra piattaforma preferita, e vedrete che ne Ugo Landini ha più di 10 anni di esperienza nel mondo Object
beneficeranno le performance, la chiarezza e la leggibilità, Oriented, e segue Java dalla nascita. Si ostina ancora a voler pro-
grammare e ha velleità di centravanti, con scarsi risultati in en-
migliorando sia l’esperienza dei vostri clienti che il vostro trambe le attività. È CTO in Pronetics, dove si è occupa preva-
lavoro quotidiano. E se pensate che qualcosa può essere lentemente di architetture distribuite e di tutto ciò che riguarda
il mondo Java, XML e in generale l’integrazione. È stato Senior
ulteriormente migliorato, sottoponete le vostre riflessioni Java Architect in Sun Microsystems.
al team di Dolphin (Java7)!

44 n.2 - gennaio/febbraio 2007


COMMUNITY
FREESPEECH Login Topic

Intervista a Simon Phipps


Java è diventato definitivamente Open Source e Free
Software da poco tempo. Due settimane dopo questo Ü di di Michele Sciabarrà
importante avvenimento, abbiamo avuto l’opportu- (michele.sciabarra@javajournal.it)
nità di intervistare, su invito di Sun Microsystems
stessa, uno dei principali artefici di questa trasforma-
zione: Simon Phipps.

L’OpenJDK ha bisogno di aiuto, in quanto alcune parti


di Java non possono essere Open Source. La comunità
Simon è il direttore delle iniziative Open Source di Sun Classpath ci può venire in aiuto a riscrivere quelle
(Chief Open Source Officer). Abbiamo incontrato Phipps parti. Il punto principale è che la piattaforma Java sia
in visita in Italia, a Milano, e lo abbiamo sottoposto a un disponibile come standard.
vero fuoco di fila di domande. Penso che per loro (i progetti Classpath e Harmony, nda) sia
bene che siano delle implementazioni complete. Sono
JJ: Perchè avete scelto la GPL come nuova licenza molto contento che Harmony dia il benvenuto a Java
per i sorgenti di Java? Open Source So che le persone che lo sviluppano ci
daranno una mano amichevole. E sono molto felice di
SP: È molto semplice: la GPL ci offre le maggiori supportare il loro lavoro
opportunità per la piattaforma Java. Selezionando la
GPL diventa disponibile nelle versioni free di Unix, dove JJ: È corretto dire che Java ME sarà rilasciato senza la
Java non era prima disponibile. classpath exception? Perché?

JJ: Può spiegarci perché il nuovo OpenJDK Per la piattaforma Java SE abbiamo bisogno della
(la versione Open Source del JDK) è GPL con Classpath Exception perché alcune persone, quando
la eccezione “classpath”. Che cosa è questa distribuiscono una applicazione , distribuiscono anche
eccezione? la piattaforma Java.
Per esempio, senza la classpath exception, non sarebbe
SP: Abbiamo semplicemente scelto di utilizzare la possibile distribuire sia OpenJDK che Tomcat nello
licenza con cui le versioni open di Java erano distribuite. stesso pacchetto.
La più evidente era il progetto Classpath, quindi abbiamo Per quanto riguarda il JavaME, invece, non sei nella
deciso di distribuire OpenJDK con la stessa licenza del situazione di dover distribuire sia l’applicazione che la
progetto Classpath. Che è appunto la licenza GPL con piattaforma. I soli che hanno bisogno di farlo sono i
una eccezione che consente di distribuirlo insieme a produttori del dispositivo.
un prodotto proprietario, senza dover rilasciare l’intero
prodotto come GPL. JJ: Non siete preoccupati che possa esserci un
“fork” (versione divergente indipendente) di
JJ: Siccome ci sono già due progetti Java Open Java?
Source, il progetto Classpath e il progetto Apache
Harmony. Il rilascio del “vero” Java come Open SP: Non ho paura, perché penso che per il mercato
Source li renderà obsoleti? sarebbe una cattiva cosa creare un fork incompatibile. E
non credo che vedremo un fork incompatibile.
SP: Non credo che diventeranno obsoleti. La comunità Abbiamo parlato con le comunità di Classpath e di
di classpath ci è stata molto di aiuto, e credo che Harmony, ed entrambe sono convinte della necessità di
uniremo le forze con loro. essere compatibili.

46 n.2 - gennaio/febbraio 2007


COMMUNITY
FREESPEECH Login Topic

JJ: Ma cosa farà Sun se qualcuno, per qualsiasi


ragione, decidesse di creare una versione JJ: Perché è stato scelto Mercurial come strumento
indipendente e incompatibile? per la gestione del codice sorgente?

SP: Gli ricorderemo che non può chiamare il prodotto SP: Avevamo un albero di decisioni davanti a noi. Prima
“Java” se non passa il TCK (il TCK è il Kit di Test di di tutto, internamente, per mantenere il codice sorgente
Compatibilità che assicura che una implementazione di Java usiamo TeamWare, che è molto vecchio e i cui codici
sia conforme alle specifiche, nda). Noi abbiamo rilasciato sorgenti non sono disponibili pubblicamente. Per cui
il codice sorgente, ma il codice sorgente non diventa abbiamo dovuto scegliere un diverso sistema di gestione
“Java” se non passa i test del TCK. dei codici sorgenti. E abbiamo dovuto confrontare i
sistemi di controllo di versione centralizzati, come
JJ: Ci sarà mai un Java “leggero”, piccolo e subversion, e quelli distribuiti. TeamWare è un sistema
semplice come il Flash Player? Cosa ne pensa se di controllo di versione distribuito, e per come è
qualcuno usa il sorgente per costruire un simile sviluppato Java, abbiamo scelto un sistema di controllo
applet player leggero? di versione distribuito.
La comunità di OpenSolaris aveva sperimentato diversi
SP: Penso che non potrà chiamarlo Java se non passa sistemi di controllo di versione, come Subversion,
il TCK. Mercurial, SCCS e altri. La conclusione è stata che il
sistema di controllo più adatto era Mercurial.
JJ: Non esiste ancora una versione Sun di JavaME
per la piattaforma Pocket PC. Il rilascio di Java JJ: Ma non è molto conosciuto …
come Open Source favorirà l’apparire di una
versione Sun per PocketPC? SP: Nessuno dei sistemi di controllo di versione
distribuiti è ben conosciuto. Ciononostante ci siamo
SP: Una volta che i sorgenti sono stati rilasciati ognuno convinti che Mercurial era la scelta migliore. Per il
può farci quel che vuole. Non vedo ostacoli al fatto che rilascio iniziale di Javac e Hotspot useremo Subversion.
qualcuno faccia il porting. Renderemo anche il codice disponibile come package
di Netbeans in modo che si possa utilizzare un sistema
JJ: È ben noto che IBM ha avuto benefici da Linux familiare.
vendendo hardware e servizi software. Java e
Solaris Open Source permetteranno a Sun di JJ: Quali parti della piattaforma Java non possono
vendere più hardware? essere rilasciati perché contengono codice
proprietario non posseduto da Sun?
SP: Sì.
SP: Due parti: il Gestore dei Colori, e il rasterizzatore dei
JJ: IBM è da molto tempo una azienda di servizi font True Type.
software. Sun sta diventando anche una azienda
di servizi software, che rilascia software open JJ: La comunità può aiutare a rimpiazzare queste
source e supporta i clienti nell’adattare il software parti con una implementazione open?
alle loro esigenze di business?
SP: Abbiamo parlato con la comunità Classpath e siamo
SP: Recentemente IBM si è ri-registrata al NY Stock molto lieti di collaborare con loro. In particolare in
Exchange (la borsa di New York) come una azienda di Classpath c’è già una implementazione alternativa del
servizi. Non è questa l’intenzione di Sun. Sun intende Gestore dei Colori. E sono stati molto lieti di contribuire.
rimanere una azienda di sistemi. Abbiamo un business Per quanto riguarda il rasterizzatore dei font, è un altro
di sistemi, storage, software e servizi, e Sun fa il suo problema perché l’architettura di Classpath è diversa
meglio combinando queste cose insieme in sistemi. Ci dall’architettura del JDK di Sun. Per cui c’è bisogno
sarà un incremento nel numero di soluzioni per sistemi di maggior lavoro, ma c’è già un team nel gruppo di
che forniamo.
Note Biografiche
JJ: Quale sarà il processo per poter contribuire ai
miglioramenti della piattaforma? Michele Sciabarrà Dopo aver scritto di Java e averlo insegna-
to per dieci anni, attualmente è il direttore esecutivo di Java
SP: È ancora in corso di definizione. Stiamo studiando Journal. Quando non cerca di imparare le ultime API o di-
alcune interessanti opinioni della community, ci squisisce della superiorità del modello Open Source, si dilet-
ta a programmare cellulari Symbian in C++ e amministra-
aspettiamo di poter dire di più in primavera. Intendiamo
re sistemi Linux.
realizzare un processo trasparente ed equo.

n.2 - gennaio/febbraio 2007 47


JAVA Journal focus

n.1 - novembre/dicembre 2006 35


JAVA Journal focus

Resource
Management
con JMX
Java Management eXtension (JMX) è una specifica che offre una API ed una architettura per la
gestione ed il monitoraggio delle risorse in Java

>> di Fabio Staro

Per l’hardware management esistono una serie di

L
standard tra i quali il più noto è il protocollo
a gestione di una risorsa software SNMP [1], acronimo di Simple Network Ma-
e/o hardware è la possibilità di poter nagement Protocol, usato nella gestione delle
misurare, a runtime e nel tempo, reti TCP/IP; mentre per l’application management
informazioni relative allo stato della esistono, per ogni prodotto, soluzioni proprie-
risorsa. È anche la possibilità di po- tarie costruite ad hoc. In questo contesto la
ter alterare il comportamento della specifica Java Management eXtension [2], o
risorsa a fronte delle evidenze riscontrate. più brevemente JMX, si presenta come una so-
Il deploy in un ambiente di produzione di una luzione standard e globale al tema del resource
applicazione software ben progettata, realizzata management in ambiente Java: infatti definisce
e testata, non è la conclusione di un progetto. una architettura, dei design pattern, una serie di
Tipicamente, per un software in produzione, API ed una serie di servizi per la gestione ed il
vi è la necessità di monitorare informazioni a monitoraggio delle applicazioni. Gli obiettivi ed
livello di business: per esempio il numero degli i benefici dell’architettura JMX si riassumono
ordini inevasi in un sistema di commercio elet- nei seguenti punti:
tronico. Oppure informazioni a livello di siste-
ma: per esempio, il consumo di memoria heap, • Scalabilità: l’approccio basato a componenti
il numero di thread attivi, il tempo medio per la consente di scalare nella gestione ed ammi-
garbage collection e così via. Queste misure sono nistrazione da decine a decine di migliaia di
indicatori diretti del corretto funzionamento risorse;
della applicazione. In modo analogo, la gestione • Integrazione con soluzioni legacy di mana-
della rete e dei dispositivi hardware è sempre gement come SNMP, WBEM (Web-Based
più critica. Gli amministratori di rete impiegano Enterprise Management), CIM (Common In-
un’ampia varietà di strumenti per il controllo formation Model, ossia il modello di dati che
del sistema, al fine di assicurare la continuità e descrive gli oggetti presenti in un ambiente di
l’affidabilità delle operazioni. gestione) e TMN (Telecommunications Ma-
Il resource management è la disciplina che orga- nagement Networks);
nizza la gestione delle risorse hardware e sof- • Semplicità nell’instrumentation, ossia nel ren-
tware di una organizzazione ed è caratterizzato dere accessibile via JMX, risorse software o
dalla necessità di: hardware.

• recuperare informazioni relative alla risorsa; Le informazioni esposte via JMX possono essere
• misurare nel tempo tali informazioni; recuperate e visualizzate da sistemi di manage-
• alterare a runtime il comportamento della ment evoluti come IBM Tivoli, HP Openview o
risorsa a fronte delle evidenze riscontrate. da semplici tool come l’HTML protocol adapter

n.2 - gennaio/febbraio 2007 49


focus JAVA Journal

della SUN [3] o la Jconsole [4] presente dal Java De- • Parametri per i costruttori ed i metodi;
velopment Kit 5.0. • Notifiche emesse dalla risorsa in broadcast attra-
verso l’infrastruttura JMX.

L’architettura JMX Ovviamente, la classe MBean può avere più attributi


e/o metodi di quelli definiti nella relativa interfaccia
La specifica JMX definisce una architettura per la ge- di gestione, ma questi, anche se dichiarati con il co-
stione di risorse. I livelli nell’architettura JMX sono strutto public, sono funzioni non disponibili al siste-
tre, illustrati nella Figura 1: ma di management. L’instrumentation level definisce
anche un meccanismo di notifica. Questo consente
• Instrumentation level; agli MBean di generare e propagare eventi di notifica
• Agent level; ad altri MBean ed in generale ai componenti presenti
• Distributed level. presso gli altri livelli della architettura. Il modello di
notifica si poggia sui seguenti componenti:
L’instrumentation level fornisce le regole attraverso le
quali una risorsa può essere gestita da una piattafor- • Classe Notification: è il messaggio di notifica più le
ma compatibile col modello JMX. Fondamentalmen- informazioni relative al messaggio stesso;
te, una risorsa è resa accessibile alle applicazioni di • Interfaccia NotificationListener: è implementata dal
management dopo averla incapsulata in un managed ricevente i messaggi;
bean, o più brevemente MBean, che espone attributi • Interfaccia NotificationEmitter: è implementata dal-
della risorsa indicativi del corretto funzionamento. In l’oggetto che emette messaggi di notifica;
definitiva quindi un MBean rappresenta una risorsa • Classe NotificationBroadcasterSupport: classe di sup-
hardware o software controllata e amministrata dal porto che implementa l’interfaccia NotificationE-
sistema di management. Nella specifica, un MBean mitter;
è una classe Java concreta che implementa la sua • Interfaccia NotificationFilter: consente di filtrare i
corrispondente interfaccia di gestione o l’interfaccia messaggi di notifica di un listener.
DynamicMBean, nel qual caso l’interfaccia di gestione
è definita a runtime. L’interfaccia di gestione di un La specifica JMX definisce quattro tipi di MBeans:
MBean può essere composta da: Standard, Dynamic, Open e Model MBeans. Si veda la
Tabella 1 per maggiori dettagli.
• Attributi in lettura e/o modifica per conoscere lo L’Agent level fornisce una specifica per implementa-
stato della risorsa; re agenti JMX. Un agente JMX controlla direttamente
• Costruttori per creare istanze della risorsa; le risorse e le rende disponibili alle applicazioni re-
• Metodi per eseguire operazioni sulla risorsa; mote di management. Un agente JMX è costituito da

FIGURA 1 I livelli in una architettura JMX

50 n.2 - gennaio/febbraio 2007


JAVA Journal focus

Tipo Descrizione

Sono gli MBean più semplici da definire ed implementare. Tutti gli attributi, le
operazioni e gli eventi associati ad uno Standard MBean sono specificati staticamente
nella sua interfaccia di gestione. Gli Standard MBean devono implementare una
interfaccia che è dichiarata seguento ben precise regole di coding convention (regole
Standard MBean
di codifica indicate con il termine lexical design pattern nella specifica JMX 1.2). Per
esempio per instrumentare una classe chiamata com.xyz.MyClass la interfaccia di
gestione si deve chiamare com.xyz.MyClassMBean. Un agente JMX attraverso un
processo di introspezione scopre la interfaccia di gestione di uno Standard MBean.

I Dynamic MBean devono implementare l’interfaccia javax.management.Dyna


micMBean. Tutti gli attributi, le operazioni e gli eventi associati con il managed
Dynamic MBean bean, ossia i suoi metadati, sono determinati a runtime attraverso l’interfaccia
DynamicMBean. Pertanto una risorsa da gestire può avere attributi, operazioni ed
eventi che possono variare nel tempo.

Un Model MBean è un Dynamic MBean infatti l’interfaccia ModelMBean


estende l’interfaccia DynamicMBean. La specifica JMX impone che tutte le
implementazioni della specifica devono fornire un istanza di Model MBean
Model MBean
chiamata RequiredModelMBean presente nel package javax.management.modelmbe
an. Questo è un generico, pre-fabbricato e dinamico MBean pronto all’uso per
instrumentare le risorse.

Un Open MBean è un Dynamic MBean dove tutti gli attributi del managed bean
appartengono ad un insieme ben definito di tipi di dati Java (per esempio String,
Integer, Boolean, etc.). Un Open MBean non estende nessuna particolare interfaccia,
Open MBean a parte l’interfaccia DynamicMBean, e l’agente JMX capisce che è in presenza di un
Open MBean perché riceve un oggetto che implementa la interfaccia OpenMBeanInfo
presente nel package javax.management.openmbean descrittiva dei metadati del
bean.

TABELLA 1 Gli MBeans nella specifica JMX

un managed bean server, da una serie di agent services dell’object name attraverso il quale si individua un
e almeno un protocol adapter e/o un connettore. Il oggetto (operazione detta di name lookup), e se ne
managed bean server, o più brevemente MBean server, invoca un suo metodo. Pertanto, una eventuale mo-
è il componente fondamentale nell’architettura difica introdotta nell’interfaccia del managed bean
JMX poichè tutte le operazioni di management su- non richiede la redistribuzione della medesima.
gli MBean sono mutuate dal server che si propone Questa scelta, se da un lato semplifica la gestione
come un broker fra le applicazioni di management di strutture complesse, costituite per esempio da
e le risorse gestite. Gli MBean sono registrati nel un alto numero di oggetti, dall’altro elimina il type
managed bean server che pertanto funge da registro checking sui parametri e sui valori restituiti (cfr. Fi-
centralizzato. Attraverso il concetto di object name, gura 2).
oggetto che identifica univocamente il managed La specifica JMX prevede come obbligatori quattro
bean registrato nel managed bean server, si realizza il agent services mentre altri possono essere aggiunti
disaccoppiamento tra applicazione di management dalle varie implementazioni proprietarie. Gli agent
e risorsa. Una applicazione di management può in- services definiti dalla specifica sono il Dynamic Class
teragire con un managed bean fornendo il suo nome Loading service, il Timer service, il Relation service ed il
all’agente JMX per ogni operazione invocata. Il Monitoring service. Il primo servizio consente di cari-
meccanismo di invocazione remota non si basa sul care e di instanziare dalla rete nuove classi o librerie
modello stub-skeleton, come accade per esempio nel- native; il Timer service fornisce un meccanismo di
le architetture RMI (Remote Method Invocation) schedulazione degli eventi e consente di eseguire
ed EJB (Enterprise JavaBean), ma solo sull’uso operazioni a determinati intervalli di tempo; il Rela-

n.2 - gennaio/febbraio 2007 51


focus JAVA Journal

mento incrementale nel tempo del-


l’attributo di tipo contatore (cfr. Figu-
ra 3). Il Gauge monitor osserva la varia-
zione del valore di attributi numerici
inviando una notifica quando il valore
della variazione supera in eccesso un
limite superiore o in eccesso un limite
inferiore (cfr. Figura 4). È fornito un
meccanismo (hysteresis mechanism) per
evitare l’invio continuo di notifiche
quando vi sono piccole variazioni
intorno al valore di soglia. Lo String
monitor osserva gli attributi di tipo
stringa inviando una notifica quando
FIGURA 2 Il modello di invocazione JMX la variazione è uguale o differisce da
una stringa predefinita.

tion service consente di creare relazioni fra gli MBean Il Distributed level contiene almeno un protocol adapter
e, per concludere, il Monitoring service misura ad in- o un connettore attraverso i quali gli agenti JMX sono
tervalli regolari di tempo la variazione del valore di accedibili remotamente. Gli adapter forniscono una
un attributo di una risorsa e in base al valore della vista degli agenti JMX attraverso un dato protocollo
variazione invia notifiche ai listener associati. Sono (per esempio HTTP o SNMP). Questi mappano la se-
disponibili tre tipi di monitor: mantica delle interazioni sugli MBean e sullo MBean
server in una rappresentazione adatta ad un dato
• Counter monitor; protocollo e ad un modello informativo differente
• Gauge monitor; come, per esempio, il protocollo SNMP. Nell’esem-
• String monitor. pio che segue useremo l’HtmlAdaptorServer [3] con
il quale l’interfaccia di gestione è visibile attraverso
Il Counter monitor osserva in continuazione gli in- un browser web. I connettori, viceversa, consentono
crementi non negativi degli attributi di tipo intero di connettere un agente JMX con un’applicazione
che si comportano come un contatore, inviando una remota compatibile al modello JMX usando una tec-
notifica quando il valore dell’attributo raggiunge o nologia distribuita, ad esempio RMI. Questo tipo di
supera un certo valore di soglia (threshold). È possi- comunicazione prevede un connettore che funge da
bile impostare un valore di offset che viene aggiunto server nell’Agent level e un connettore con il ruolo di
al valore di soglia ogni volta che questo è raggiunto client installato nella JVM dell’applicazione di ma-
e superato: in tal modo è possibile seguire l’anda- nagement (cfr. Figura 5).

FIGURA 3 Counter monitor: figura tratta dalla JMX Instrumentation and Agent Specification, v1.2

52 n.2 - gennaio/febbraio 2007


JAVA Journal focus

FIGURA 4 Gauge monitor: figura tratta dalla JMX Instrumentation and Agent Specification, v1.

FIGURA 5 Protocol Adapter e connettori: figura tratta dalla JMX Instrumentation and Agent Specification, v1.2

Management di un’applicazione software dominio di interesse. L’applicazione di esempio è


costituita dalle classi Java Esecutore e Configurazione
L’applicazione software che desideriamo ammini- ed è stata sviluppata con la J2SE versione 5.0 la
strare e gestire è volutamente semplice al fine di quale integra le API di management e monitoring
approfondire l’API e l’architettura JMX, eliminan- [5]. La classe Esecutore è un thread che ogni 10 se-
do complessità applicative legate ad un particolare condi circa invoca il metodo getValore() della classe

n.2 - gennaio/febbraio 2007 53


focus JAVA Journal

out.println(“CONF_1:”
public final class Configurazione {
+Configurazione.INSTANCE
.getValore(“conf_1”));
private static final String NOME_FILE
out.println(“CONF_2:”
= “/configurazione.xml”;
+Configurazione.INSTANCE
private Date lastUpdate = null;
.getValore(“conf_2”));
private final Properties prop = new Properties();
try {
Thread.sleep(10000L);
// Unica istanza della classe Configurazione
} catch (InterruptedException e) {…}
// presente ed invocabile da parte di altre classi.
}
public static Configurazione INSTANCE
}
= new Configurazione();

// Costruttore privato
private Configurazione(){loadConfigurazione();}
La classe Configurazione legge i parametri di configu-
razione, conf_1 e conf_2, dal file XML durante la fase
private void loadConfigurazione() {
di inizializzazione e li memorizza in un oggetto di
InputStream is = Configurazione.class
tipo java.util.Properties. La classe è un singleton (cfr. il
.getResourceAsStream(NOME_FILE);
pattern Singleton [GoF]) e pertanto è presente una
try {
sola instanza in memoria della classe referenziata at-
prop.clear();
traverso l’attributo pubblico e statico INSTANCE (cfr.
prop.loadFromXML(is);
il Listato 1 per i dettagli).
lastUpdate = new Date();
La risorsa software che desideriamo amministrare
} catch (Exception e) {
è la classe Configurazione. In particolare, attraverso
err.println(“Eccezione nella lettura del file:”
una console di amministrazione JMX, deve essere
+e.toString());
possibile:
}
}
• Eseguire a caldo, ossia senza fermare e far ripartire
l’applicazione, la rilettura del file XML di configu-
public synchronized
razione (metodo reload());
String getValore(String nomeProprieta)
• Visualizzare il valore di un parametro di configura-
{
zione presente nel file XML (metodo getValore());
return this.prop.getProperty(nomeProprieta);
• Visualizzare la data in cui è avvenuta l’ultima
}
lettura dei valori presenti nel file XML (attributo
lastUpdate).
// Metodo che legge il file XML.
public synchronized void reload()
Come è stato precedentemente descritto, l’instru-
{
mentation level definisce le regole per “instrumen-
loadConfigurazione();
tare” le risorse in modo che queste possano essere
}
gestite da un agente JMX. L’instrumentazione
delle risorse avviene attraverso gli MBean. Ini-
// Metodo che restituisce
ziamo con intrumentare la classe Configurazione
// l’ultima data di lettura del file XML.
attraverso uno Standard MBean. Pertanto, definia-
public Date getLastUpdate() {
mo l’interfaccia di gestione tramite la quale un
return lastUpdate;
oggetto della classe Configurazione potrà essere
}
manipolato. L’interfaccia deve esporre i metodi
}
da invocare per eseguire una operazione sulla
risorsa ed i metodi per la lettura e la modifica di
un attributo. La regola sui nomi degli attributi
LISTATO 1 La classe Configurazione segue la naming convention dei JavaBean e pertanto
in presenza dei metodi set () e get () l’agente JMX
Configurazione scrivendo sulla console di output il deduce che vi sia una proprietà in lettura e modi-
valore restituto dal metodo. Il metodo getValore() fica. L’assenza di uno dei due metodi implica che
consente di recuperare il valore di due parametri, l’attributo sia di sola lettura o di sola scrittura. I
denominati conf_1 e conf_2, memorizzati inizial- nomi dei metodi da invocare, ossia le operazio-
mente in un file XML. Di seguito riportiamo uno ni sulla risorsa, non seguono nessuna regola e
stralcio del codice dalla classe Esecutore esplicativo ogni metodo che non inizia per get o per set è per
di quanto descritto: l’agente JMX un metodo di esecuzione e non un
metodo per la manipolazione diretta di un attri-
… buto della classe. L’interfaccia di management
public void run() deve avere un nome formato dal nome della clas-
{ se da gestire con l’aggiunta del suffisso MBean.
while(true) { Per esempio la classe Java it.articolo.Configurazione

54 n.2 - gennaio/febbraio 2007


JAVA Journal focus

FIGURA 6 Console di amministrazione fornita dall’adapter HTTP della implementazione JMX della Sun

deve implementare l’interfaccia it.articolo.Configur t.MBeanServerFactory. La riga di codice che segue crea
azioneMBean. Di seguito la definizione della inter- un oggetto che implementa l’interfaccia javax.mana
faccia ConfigurazioneMBean: gement.MBeanServer mantenendo internamente una
reference all’oggetto appena creato. In tal modo attra-
public interface ConfigurazioneMBean { verso il metodo findMBeanServer(), sempre presente
// operazione per ottenere il valore nella classe MBeanServerFactory, è possibile ricercare
// di un parametro di configurazione e ritornare la reference all’istanza precedentemente
public String getValore(String nomeProprieta); creata.
// operazione di rilettura del file XML
public void reload(); MbeanServer server =
// attributo di sola lettura MBeanServerFactory.createMBeanServer();
public Date getLastUpdate();
} Lo stralcio di codice che segue mostra come regi-
strare un managed bean all’interno dello MBeanServer
Una volta che l’MBean è stato definito è necessario: in modo tale che possa essere acceduto attraverso
chiamate JMX:
1. Creare o recuperare una istanza del managed bean
server; ObjectName name =
2. Registrare l’MBean all’interno del server; new ObjectName(
3. Collegarsi al server attraverso un protocol adapter “Articolo:name=ConfigurazioneStandardMBean”);
e interagire con la risorsa, per esempio attraverso server.registerMBean(
una console HTML di amministrazione. Configurazione.INSTANCE ,name);

Tutte le operazioni sopra elencate sono racchiuse Ogni MBean deve essere univoco all’interno dello
nella classe AgenteHelper (cfr. Listato 2). Un’istanza stesso MBeanServer e il suo nome è gestito tramite
di MBeanServer può essere creata o recuperata at- la classe javax.management.ObjectName. Un ObjectNa-
traverso i metodi helper della classe javax.managemen me è composto da un domain name, che rappresen-

n.2 - gennaio/febbraio 2007 55


focus JAVA Journal

= new HtmlAdaptorServer();
ta il namespace all’interno del JMX Agent, seguito adapter.setPort(9092);
da una lista di proprietà che identificano univoca- ObjectName name
mente l’MBean e forniscono informazioni relative = new ObjectName(“Articolo:name=HTMLAdapter”);
all’oggetto: server.registerMBean(adapter ,name);
adapter.start();
domain: key1 = value1 , key2 = value2
Osservando le righe di codice sopra riportate, possia-
nel nostro esempio il domain name è Articolo e l’unica mo notare come l’HTML adapter sia esso stesso un
proprietà che impostiamo è il nome del managed MBean registrato nel managed bean server. Attraverso
bean. un qualsiasi browser è ora possibile collegarsi sulla
Infine, per accedere al managed bean utilizziamo porta 9092 all’host dove è in esecuzione l’agente
l’HTML protocol adapter fornito dalla SUN [3]. Le JMX ed interagire con gli MBean (Figura 6 e Figu-
seguenti righe di codice permettono la creazione, ra 7).
la registrazione e l’avvio dell’adapter sulla porta Con l’esempio precedente è possibile notare come
9092: instrumentare una classe Java attraverso uno
Standard MBean sia un’operazione sostanzialmen-
HtmlAdaptorServer adapter te semplice. Infatti, uno Standard MBean dichiara

FIGURA 7 Console di amministrazione fornita dall’adapter HTTP della implementazione JMX della Sun

56 n.2 - gennaio/febbraio 2007


JAVA Journal focus

FIGURA 8 Diagramma delle classi che descrivono i metadati di un Mbean

esplicitamente la propria interfaccia di gestione e • Recuperare dinamicamente la interfaccia di gestio-


questa è costruita seguendo delle naming conven- ne (metodo getMBeanInfo()).
tion. Tuttavia, uno Standard MBean è ideale per la
gestione di risorse statiche, ossia per risorse la cui
interfaccia di gestione non cambia nel tempo e
che può essere definita per esempio già durante il
processo di sviluppo. Di contro, un Dynamic MBean Il
resource manage-
è ideale per la gestione di risorse che evolvono nel
tempo o per risorse esistenti che non seguono il ment è la disciplina che
paradigma dei JavaBean. Un Dynamic MBean defi-
nisce l’interfaccia di gestione a runtime attraverso organizza la gestione
meta-classi descrittive. Se con gli Standard MBean
i metadati sono ricavati dall’agente JMX tramite delle risorse hardware e
un processo di introspezione (la reflection Java),
con i Dynamic MBean lo sviluppatore è responsabi-
le di definire i metadati della risorsa. Un Dynamic
software
MBean deve implementare l’interfaccia javax.mana
gement.DynamicMBean. I metodi dichiarati nell’in-
terfaccia consentono di: La classe MBeanInfo, presente nel package
javax.management, descrive l’interfaccia di gestione
• Recuperare il valore di uno o più attributi (metodi (ossia l’insieme di attributi e metodi che sono di-
getAttribute() e getAttributes()); sponibili per operazioni di management) esposta
• Impostare il valore di uno o più attributi (metodi dallo MBean. Come osservato in precedenza, una
setAttribute() e setAttributes()); istanza della classe MBeanInfo è restituita dal me-
• Invocare una operazioni esposta nella interfaccia todo getMBeanInfo() per i Dynamic MBean, e quindi
di gestione (metodo invoke()); anche per i Model MBean e per gli Open MBean che

n.2 - gennaio/febbraio 2007 57


focus JAVA Journal

class AgenteHelper // dello Standard e del Model MBean.


{ void recordMBean()
private MBeanServer server = null; {
try {
AgenteHelper() { // Registra lo StandardMBean
server = MBeanServerFactory.createMBeanServer ObjectName name =
(); new ObjectName(
} “Articolo:name=ConfigurazioneStandardMBean
”);
// Metodo per la registrazione nel server server.registerMBean(Configurazione.INSTANCE
// dello HtmlAdaptorServer e suo avvio sulla ,name);
porta out.println(“REGISTRATO MBEAN:”+name.getCanoni
// 9092 calName());
void attivaHTMLAdapter() { // Registra il Model MBean
HtmlAdaptorServer adapter = new HtmlAdaptor- name = new ObjectName(
Server(); “Articolo:name=ConfigurazioneModelMBean”);
try { RequiredModelMBean model
ObjectName name = new RequiredModelMBean(
= new ObjectName(“Articolo: ConfigurazioneInfo.getInfo());
name=HTMLAdapter”); model.setManagedResource(
server.registerMBean(adapter ,name); Configurazione.INSTANCE,
out.println(“REGISTRATO MBEAN:”+name.getCan “objectReference”);
onicalName()); server.registerMBean(model ,name);
} catch (Exception e) { out.println(“REGISTRATO MBEAN:”+name.getCanoni
err.println(“ECCEZIONE:”+e.toString()); calName());
} } catch (Exception e) {
adapter.setPort(9092); err.println(“ERRORE NEL REGISTRARE IL BEAN:”+
adapter.start(); e.toString());
} }
}
// Metodo per la registrazione nel server } // fine della classe

LISTATO 2 La classe AgenteHelper

sono dei tipi di Dynamic MBean, mentre è ricavata patibile con la specifica JMX. Al costruttore della
con la reflection Java dallo MBean server per gli Stan- classe RequiredModelMBean passiamo una istanza
dard MBean. Il diagramma delle classi della Figura della classe ModelMBeanInfo. È opportuno osservare
8 riporta tutte le classi che descrivono i metadati di come un Model MBean debba esporre i suoi metada-
un MBean. ti descrittivi attraverso un’istanza della classe Mo-
Nell’esempio che segue instrumentiamo sempre la delMBeanInfoSupport che estende la classe MBeanIn-
classe Java Configurazione ma in questo caso attraver- fo e implementa l’interfaccia ModelMBeanInfo. Nel
so un Model MBean. Le righe di codice che seguono nostro caso, la classe Java ConfigurazioneInfo (cfr.
mostrano come registrare il Model MBean nel managed il Listato 3 per i dettagli) restituisce un oggetto
bean server: ModelMBeanInfoSupport. Per terminare, definiamo
per l’instanza della classe RequiredModelMBean
name = new ObjectName( l’oggetto da gestire e sul quale eseguire tutte le
“Articolo:name=ConfigurazioneModelMBean”); operazioni di management:
RequiredModelMBean model =
new RequiredModelMBean( model.setManagedResource(
ConfigurazioneInfo.getInfo()); Configurazione.INSTANCE, “objectReference”);
model.setManagedResource(
Configurazione.INSTANCE, In modo analogo all’esempio precedente possiamo
“objectReference”); amministrare il bean attraverso la console HTML
server.registerMBean(model ,name); dello adapter SUN.

Il Model MBean che abbiamo registrato nel managed Conclusioni


bean server è una istanza della classe RequiredMo-
delMBean presente nel package javax.management In questo articolo abbiamo introdotto la specifica
.modelmbean. Una implementazione del Required- JMX per la gestione ed il monitoraggio delle risor-
ModelMBean è presente in ogni agente JMX com- se in Java ed abbiamo instrumentato una risorsa

58 n.2 - gennaio/febbraio 2007


JAVA Journal focus

// Classe helper per ottenere un oggetto info[2] = new ModelMBeanOperationInfo(


// ModelMBeanInfo con i metadati “getLastUpdate”,
// della risorsa da gestire “Ritorna la data di modifica della config “,
public final class ConfigurazioneInfo { null, “java.util.Date”,
ModelMBeanOperationInfo.INFO);
public static ModelMBeanInfo getInfo() { return info;
return new ModelMBeanInfoSupport( }
“it.articolo.Configurazione”,
“Gestore della configurazione”, private static ModelMBeanConstructorInfo[]
getAttributesInfo(), getConstructorsInfo() {
getConstructorsInfo(), return null;
getOperationsInfo(), }
null);
} private static ModelMBeanAttributeInfo[]
getAttributesInfo() {
private static ModelMBeanOperationInfo[] ModelMBeanAttributeInfo[] info
getOperationsInfo() { = new ModelMBeanAttributeInfo[1];
ModelMBeanOperationInfo[] info Descriptor oDesc = new DescriptorSup-
= new ModelMBeanOperationInfo[3]; port();
MBeanParameterInfo[] pInfo oDesc.setField(“name”, “lastUpdate”);
= new MBeanParameterInfo[1]; oDesc.setField(“descriptorType”, “attri-
pInfo[0] = new MBeanParameterInfo( bute”);
“keyProperty”, oDesc.setField(“displayName”,
“java.lang.String”, “Data ultimo reload della config”);
“chiave della propietà”); oDesc.setField(“getMethod”, “getLastUpda-
info[0] = new ModelMBeanOperationInfo( te”);
“getValore”, info[0] = new ModelMBeanAttributeInfo(
“Ritorna il valore di un param di config”, “lastUpdate”,
pInfo, “String”, “java.util.Date”,
ModelMBeanOperationInfo.INFO); “Data ultimo reload della config”,
info[1] = new ModelMBeanOperationInfo( true, false, false, oDesc);
“reload”, return info;
“Ricarica il file di configurazione”, }
null, “void”,
ModelMBeanOperationInfo.ACTION); } // fine della classe

LISTATO 3 La classe ConfigurazioneInfo

software Java attraverso uno Standard ed un Model http://java.sun.com/products/JavaManagement/


MBean. Ovviamente, la ricchezza degli argomenti download.html
da trattare è tale da non considerare esaurito l’ar- [4]_Jconsole:_http://java.sun.com/j2se/1.5.0/docs/
gomento del resource management in Java. Tuttavia tooldocs/share/jconsole.html
per gli esempi portati è chiaro che implementare la [5]_J2SE_5.0_API:_http://java.sun.com/j2se/1.5.0/
gestione delle risorse attraverso la specifica JMX è docs/api/index.html
un processo sostanzialmente semplice. L’integra-
zione della API JMX nella J2SE 5.0 sottolinea
come il progettare e realizzare la gestione delle Bibliografia:
risorse attraverso una soluzione standard debba
essere una fase integrata nello sviluppo di un pro- [GoF]: Gamma, Erich, Richard Helm, Ralph John-
getto software. son, and John Vlissides. 1995. Design Patterns:
Elements of Reusable Object-Oriented Software. Pubblicato
da Addison-Wesley.
Riferimenti

[1]_Protocollo_SNMP:_http://it.wikipedia.org/wiki/
SNMP Note Biografiche
[2]_Home page JMX : Fabio Staro, dottore in Fisica è Responsabile Tecnico per i pro-
[3]_Adapter_HTML_(presente nella JMX refer- getti Java presso la Direzione Ricerca ed Innovazione di Engi-
neering Ingegneria Informatica S.p.A
ence_implementation,_archivio_jmxtools.jar) :

n.2 - gennaio/febbraio 2007 59


COMMUNITY
FREESPEECH Login Topic

COMMUNITY WATCH
Ü di Stefano Sanna
(stefano.sanna@javajournal.it)

Quando si presenta Java (linguaggio, piattaforma, itinerante, un roadshow che tocca diverse città italiane
tecnologia, librerie, applicazioni...) è inevitabile in tutta la penisola, portando la tecnologia Java anche
sottolineare che attorno ad esso vive una comunità in ambiti geografici normalmente esclusi dai circuiti
numerosa e operosa di programmatori e aziende. Non dei grandi eventi. Questa caratteristica fa di JavaDay
è, dunque, la sola “potenza tecnologica” a decretarne un momento unico e qualificante, dove la tecnologia,
il successo, ma anche lo spirito di collaborazione e le istituzioni, gli sviluppatori e le imprese si possono
condivisione che nelle community (reali e virtuali) incontrare direttamente sul proprio territorio per
trova la sua massima espressione. Questa pagina confrontarsi, capire, conoscere e verificare tante
di Java Journal vuole offrire una panoramica sulle opportunità”. Questa è la forza della community!
community (nazionali e non), dove poter segnalare
eventi, raccontare cosa accade nel mondo Java, cercare Avremo modo di “incontrare” i diversi gruppi nello
di trasmettere ed esaltare lo spirito di collaborazione di spazio offerto da Java Journal. Segnaliamo brevemente
cui si è detto. due JUG che si sono distinti in modo particolare. Il JUG
Sardegna ONLUS è stato premiato da James Gosling
La community italiana e gli eventi durante la JavaOne dello scorso maggio, ricevendo il
prestigioso Duke Award per il progetto “JUG Sardegna
In Italia esistono numerose realtà, a partire dai Java
per l’AVIS” (http://jug-avis.dev.java.net), destinato
User Group (JUG), che hanno respiro locale, fino alla
a supportare le attività di reperimento di donatori di
Java Italian Association (JIA); o comunità come Java
sangue condotte dall’Associazione Volontari Italiani
Italian Portal (JIP, uno dei gruppi più vivaci della
Sangue (http://www.avis.it). È doveroso, poi, un
penisola!). Community significa mailing list, forum,
riferimento al JUG Torino, che ha (coraggiosamente!)
risorse condivise ma soprattutto meeting, seminari,
dato inizio al JavaDay: l’evento nel capoluogo
giornate di approfondimento e supporto agli eventi
piemontese è stato un successo, grazie all’eccellente
nazionali. Se, infatti, gli incontri a livello locale
lavoro svolto dal team organizzatore.
mantengono viva l’attività all’interno dei singoli gruppi,
quelli di più ampio respiro costituiscono un’occasione
per conoscersi, scambiare esperienze, avviare nuove
collaborazioni. Oltre ai forum e alle liste, dunque,
una opportunità per aprire nuovi contatti. La Java Note Biografiche
Conference, evento nazionale per eccellenza organizzato
da Sun Microsystems, si avvale della collaborazione dei Stefano Sanna si occupa di sviluppo di applicazioni multi-
mediali per piattaforma Savaje presso Beeweeb Technolo-
JUG e delle altre community già dal 2005; e il legame gies (http://www.beeweeb.com). Ha lavorato per sette anni
è stato rafforzato nell’edizione di quest’anno. Nasce, nel gruppo Network Distributed Applications del CRS4, oc-
invece, dalle community il JavaDay, il primo evento cupandosi di mobile computing e applicazioni network-orien-
ted per cellulari e PDA. Collabora attivamente con JIA, JUG
itinerante su Java. Grazie allo sforzo congiunto dei JUG, Sardegna e Java Mobile Developers Forum. Il sito sito web
di JIA e JIP, come indicato sul sito ufficiale dell’iniziativa personale è http://www.gerdavax.it
(http://www.javaday.it), “JavaDay è una manifestazione

60 n.2 - gennaio/febbraio 2007


IDIOMATICA
FREESPEECH Login Topic

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


cui è facile cadere. Programmatore avvisato, mezzo salvato!

Codice orribile, antipattern e


pratiche discutibili
>> di Ugo Landini (ugo.landini@javajournal.it)

• una volta che il bug è apparentemente risolto, sincro-


nizzare solo gli accessi in scrittura, perché le letture
La massima di questo mese è: tanto sono in read only e così si ottimizza un po’;
“What we do not understand we do not possess” • al riapparire di bug che sembravano risolti, prenderse-
la con la VM o con l’application server.
Goethe
Seriamente, ecco un semplice test per verificare se si è
capito il meccanismo di sincronizzazione di Java:

• I metodi statici e quelli non statici, se sincronizzati,


sono fra loro in mutua esclusione?
Sincronizzazioni che non si sincronizzano, o che • Un costruttore può essere dichiarato synchronized?
si sincronizzano troppo! • Se un thread A esegue lo statement a = 42 all’istante
T0, è sicuro che il thread B in un istante successivo T1
Agli albori di Java, una delle funzionalità più importanti > T0 “veda” il valore 42 in a?
per chi decideva di passare a questo nuovo linguaggio,
era la capacità di poter gestire in maniera relativamente Per ogni sì risposto, un punto di penalizzazione!
semplice (e ovviamente multipiattaforma) la program- La parola chiave synchronized fa in realtà tre cose di-
mazione concorrente. verse:
Java aveva, ed ha tuttora, un supporto eccellente per la
gestione di Thread multipli di esecuzione: dalla parola • Si occupa dell’atomicità di una operazione: sempli-
chiave synchronized alle concurrent utilities (inserite in cemente fa sì che la VM cerchi di acquisire il lock
Java 5), il supporto alla programmazione concorrente dell’oggetto prima di “eseguire” il metodo (o il blocco
in Java è sempre stato (almeno in teoria) alla portata di codice), acquisendolo se è libero o mettendosi in
di tutti. attesa se non lo è. Ma, badate bene, il lock è dell’og-
Ma la realtà è che molti pensano di sapere cosa faccia getto: non del metodo, né della classe. È un attributo
realmente synchronized: e, di solito, si sbagliano di gros- della classe Object, per cui ogni istanza ha il suo lock.
so... Personalmente in questi anni ne ho sentite di tutti i E questo implica diverse cose:
colori, e spesso anche da persone apparentemente molto
preparate. o Due metodi sincronizzati di una stessa classe sono
Il cammino tipico di un programmatore ignaro delle in- in mutua esclusione fra loro, se eseguiti sullo stesso
fide trappole che si celano dietro alla programmazione oggetto.
concorrente è più o meno questo: o Un metodo statico sincronizzato ed uno non statico
sincronizzato non sono fra loro in mutua esclusione,
• non sincronizzare nulla, ignari di essere in un am- perché usano lock diversi. Il metodo statico (che, ri-
biente inerentemente multithread (servlet/jsp, per cordiamoci, non ha il this), si sincronizza sul lock
esempio); dell’oggetto di classe Class, quello non statico sul-
• all’apparire di bug misteriosi, sincronizzare metodi l’istanza relativa.
più o meno a caso; o Metodi sincronizzati non statici, eseguiti su istanze
• al persistere dei bug, sincronizzare tutti i metodi, tan- diverse, non sono fra loro in mutua esclusione.
to per sicurezza; o Un costruttore non ha senso che sia sincronizzato,

n.2 gennaio/febbraio 2007 61


IDIOMATICA
FREESPEECH Login Topic

perché l’oggetto ancora non esiste (lo si sta co- Regola


struendo), e dunque neanche il lock relativo. In ef-
Vanno sincronizzate anche le letture, e non solo le scrit-
fetti, non compila neanche, ma questo è marginale
ture, altrimenti non è affatto assicurato che un thread
o Si occupa della visibilità delle operazioni eseguite
che cerca di leggere la variabile done abbia visibilità di
fra diversi thread
una precedente scrittura della stessa da parte di un altro
o Si occupa di garantire l’ordinamento delle opera-
thread. Il perché di questo comportamento, apparente-
zioni eseguite da un thread dal punto di vista di un
mente strano, va cercato nei meandri del Java Memory
altro thread che “osserva”.
Model. Avendo esaurito lo spazio a disposizione in questa
rubrica su questo numero, sarà bene rimandare ulteriori
Se il primo punto è più o meno conosciuto, anche se
spiegazioni ad un prossimo approfondimento!
spesso male interpretato, gli ultimi due sono ai più del
tutto misteriosi. In caso di insufficiente sincronizzazio-
Esercizi
ne è perfettamente possibile che accadano le cose più
strane, per esempio che il seguente codice abbia un loop •_Andare a cercare eventuali servlet con il doGet() sin-
infinito cronizzato.
•_Andare a cercare eventuali servlet con il
class MyThread extends Thread { SingleThreadModel.
public void run() {
while (!done) {
Conclusioni
// fa qualcosa ...
} Scrivere codice multithreaded è difficile ed è una cosa
}
nota. Scrivere codice semplicemente thread safe non è
public synchronized void setDone() {
done = true;
così difficile, ma non è neanche così banale come po-
} trebbe sembrare ad una prima, superficiale analisi: il
private boolean done; meccanismo di sincronizzazione va compreso a fondo
} per evitare gli errori più comuni ed ottenere il meglio
da Java.

n.1 - novembre/dicembre 2006 62


JAVA Journal focus

Accedere a file di
Excel in Java
Microsoft Excel è un applicativo molto usato, e quindi occorre “conviverci”, anche se siete program-
matori Java e amate la portabilità e l’apertura. Leggendo questo articolo, se i clienti vi chiederanno
l’importazione e l’esportazione di dati in formato Excel, saprete come fare

>> di Luigi Zanderighi

ti dalle librerie per accedere ai dati dei fogli di

E
Excel:

ntrate in ufficio e il vostro collega • tramite uno strato API interamente Java
esperto in tecnologie Microsoft, • tramite un bridge per le API native di Micro-
è particolarmente sorridente e vi soft.
informa che “è arrivata la richiesta
di automatizzare la generazione I due prodotti che descriviamo in questo arti-
dei report amministrativi in Excel; colo sono Jakarta POI e JACOB: POI sfrutta l’ap-
è lavoro delicato perché i report andranno proccio Java mentre JACOB sfrutta l’approccio
all’amministratore delegato”, dice con tono nativo.
ironico e un po’ beffardo. E aggiunge: “Mi sa
che questa volta dovrò pensarci io”. Per circa 10
millisecondi temete abbia ragione lui; ma vi ri- Jakarta POI
prendete subito, sapendo di poter “competere”
anche nell’automazione dei documenti Office Il progetto nasce nel 2001 dall’esigenza di
Microsoft. Andrew Oliver di accedere ai file di Excel con
Esistono numerosi prodotti per generare re- uno strumento Open Source in Java. Nel corso
port aziendali (ad esempio, BusinessObjects, degli anni, le librerie POI sono diventate le più
iReport), che si interfacciano direttamente ai note e complete sul mercato dell’Open Source;
database per recuperare i dati, e che producono oggi sono un punto di riferimento in materia.
dei report con grafici altamente professionali. Quando Oliver si imbatté per la prima volta
Eppure molti utenti sono abituati ad utilizza- nel formato “Microsoft’s OLE 2 Compound “
re Microsot Office: principalmente perché lo dei documenti Office, si rese conto che questo
conoscono e non vogliono rinunciare a utiliz- formato non è altro che la trasposizione di par-
zarlo. Ma anche perché l’elevata diffusione di te di un file system su singolo file. Da questa
Microsoft Office garantisce che i file prodotti constatazione ebbe origine l’acronimo POI: Poor
siano facilmente accessibili e modificabili. Obfuscation Implementation (che tradotto, al-
Inoltre, l’installazione di software aggiuntivo è l’incirca suona come “scarsa implementazione
un’operazione non sempre vista di buon occhio di una offuscazione”).
dagli utenti ed è anche proibita in molti contesti
aziendali. Il progetto POI è formato da un insieme di com-
Automatizzare la generazione di questi docu- ponenti:
menti con .NET non presenta alcuna difficoltà.
Fare altrettanto tramite Java è più complesso, • POIFS è il cuore del progetto, ed è l’infra-
ed ha delle limitazioni che dipendono dal pro- struttura per leggere e scrivere OLE 2 Com-
dotto che avete deciso di utilizzare per interfac- pound Documents; tutti i componenti fanno
ciarvi a questi documenti uso di questo componente. Tramite POIFS
Esistono principalmente due approcci, utilizza- si possono accedere alle informazioni dello

n.2 - gennaio/febbraio 2007 63


focus JAVA Journal

//prima creiamo la cella


pseudo-filesystem del formato OLE 2 Compond; HSSFCell cell = row.createCell((short)0);
• HSSF (che è poi l’acronimo di Horrible Spreadsheet //poi impostiamo il valore
Format), è il porting Java delle librerie di accesso cell.setCellValue(1);
ad Excel. Sono supportate le operazioni di lettura //eseguiamo l’impostazione del
e scrittura. Dal nome che è stato dato alle librerie // valore contestualmente alla creazione
risulta evidente che Oliver considerava il formato row.createCell((short)1).setCellValue(1.2);
Excel assolutamente inadatto e ostico, di fatto or- row.createCell((short)2).setCellValue(“Testo libero”);
ribile. row.createCell((short)5).setCellValue(true);
• HWPF è il porting Java delle API per accedere ai
documenti Word. Sono supportate le operazioni Supponiamo di voler formattare e celle in modo par-
base di lettura e scrittura. HWPF è l’acronimo di ticolare: anche in questo caso le librerie POI fornisco-
Horrible Word Processor Format. no un supporto semplice da usare:
• HPSF segue la scia degli acronimi precedenti ed è
l’abbreviazione di Horrible Property Set Format. For- //creiamo lo stile da applicare
nisce le API di supporto per l’accesso ai summary //e impostiamo le sue proprietà
dei documenti office HSSFCellStyle style = workbook.createCellStyle();
• DDF è l’ultimo componete del progetto POI è con- style.setDataFormat(
sente la decodifica dei formati Drawing di Office, HSSFDataFormat.getBuiltinFormat(“($#,##0_)”));
in pratica fornisce il supporto per accedere ai gra- style.setFillBackgroundColor(HSSFColor.AQUA.index);
fici. Questa volta l’acronimo è più originale, anche style.setFillPattern(HSSFCellStyle.BIG_SPOTS);
se non nasconde una nota di biasimo nei confronti //applichiamo lo stile su una cella
del formato: Dreadful (terribile) Drawing Format cell.setCellStyle(style);

Vediamo ora come si utilizzano queste librerie per L’ultima cosa che rimane da fare è scrivere il file su
risolvere il problema che avevamo in origine: leggere disco:
e scrivere un file excel.
FileOutputStream fileOut
= new FileOutputStream(“c:\\temp\\test.xls”);
wb.write(fileOut);

Java
fileOut.close();
ha le carte in
regola per competere Leggere il file di Excel

anche nell’automazione Il file appena creato può essere letto anche con
Microsoft Office, ma noi proviamo a leggerlo utiliz-
zando nuovamente le librerie POI. La lettura risulta
dei documenti Microsoft ancora più semplice della scrittura, e fino all’accesso
a livello di cella non c’è bisogno di alcun commento,
Office il codice parla da sé:

FileInputStream fis
= new FileInputStream(“c:/temp/test.xls”);
HSSFWorkbook wb = new HSSFWorkbook(fis);
Scrivere un file Excel
HSSFSheet sheet = wb.getSheetAt(0);
Iniziamo a creare un documento Excel, così da poter- HSSFRow row = sheet.getRow(0);
lo leggere in seguito. Le API sono molto intuitive ed HSSFCell cell = row.getCell(0);
autoesplicative. Non è necessario assegnare subito
un nome al file in fase di creazione, quest’operazione Per leggere il valore della cella occorre qualche
può essere rimandata all’atto del salvataggio del file spiegazione sul formato di memorizzazione: infatti,
su disco: Excel prevede una tipizzazione dei valori delle celle,
che è diverso da quello a cui siamo abituati nei data-
HSSFWorkbook wb = new HSSFWorkbook(); base relazionali o in Java. Questi tipi sono codificati
nell’oggetto HSSFCell e sono:
A questo punto possiamo creare i worksheet, le righe
e le celle del documento Excel. Ad ogni foglio, riga e • formula
cella è associato un indice che equivale alla posizione • numeric
in cui si vuole creare l’oggetto: • boolean
• string
HSSFSheet sheet = wb.createSheet(); • blank
HSSFRow row = sheet.createRow((short)0); • error

64 n.2 - gennaio/febbraio 2007


JAVA Journal focus

Tipo Excel Tipo Java


date java.util.Date
boolena boolean
numeric double
string java.lang.String
error byte
formula java.lang.String

TABELLA 1 Informazioni relative all’HSSFCell

Una corrispondenza con i tipi Java è riportata nella


Tabella 1. Per ottenere il contenuto della cella oc- Il contenuto della cella 2 è :This is a string
corre prima verificare il tipo Excel del contenuto, in Il contenuto della cella 4 è :true
modo da richiamare il metodo corretto. Nel Listato Il contenuto della cella 1 è :1.2
1 è presente il codice che mostra il contenuto delle Il contenuto della cella 0 è :1.0
celle di una riga. L’output che otterremo sarà del
tipo:
JACOB
Iterator it=row.cellIterator();
Le librerie JACOB seguono un approccio diame-
while (it.hasNext()) { tralmente opposto a quello di POI. Infatti vengono
sfruttate le librerie native per accedere ai documenti
cell = (HSSFCell) it.next(); Office: JACOB è infatti l’acronimo di JAva COrba Bri-
dge, progetto ideato e mantenuto da Dan Adler.
System.out.print(“Il contenuto della cella Il progetto è composto da due componenti:
“+cell.getCellNum()+ “ è :”);
• la libreria nativa jacob.dll, che va copiata in una
switch (cell.getCellType()) { cartella nel path di Java (ad. es nella directory bin
case HSSFCell.CELL_TYPE_BOOLEAN:
sotto la JAVA_HOME),
System.out.print(cell.getBooleanCellValue
• la seconda libreria è un classico jar.
());
Come si può notare, l’approccio JACOB non è por-
break;
tabile: le applicazioni sviluppate con JACOB girano
case HSSFCell.CELL_TYPE_NUMERIC:
solo su macchine Windows su cui è installato Micro-
System.out.print(cell.getNumericCellValue
soft Office. Il vantaggio di JACOB risiede proprio nel
());
fatto di appoggiarsi alle librerie native, disponendo
break;
quindi di una maggior completezza in termini di
case HSSFCell.CELL_TYPE_STRING: funzionalità e di compatibilità di formato (soprat-
System.out.print(cell.getStringCellValue( tutto per il supporto di macro o di grafici complessi).
)); Tramite JACOB, infatti, si possono invocare macro
break; presenti nei file; mentre le librerie POI, nelle mie
case HSSFCell.CELL_TYPE_BLANK: prove, spesso corrompono le macro durante le ope-
break; razioni di lettura/scrittura.
case HSSFCell.CELL_TYPE_ERROR: Chi ha avuto esperienze con la programmazione in
System.out.print(cell.getErrorCellValue() Visual Basic si trova leggermente avvantaggiato ad
); utilizzare JACOB: infatti, vengono riproposti alcuni
break; concetti ben noti, come l’oggetto di tipo Variant. I
case HSSFCell.CELL_TYPE_FORMULA: metodi che possono essere invocati sono gli stessi
System.out.print(cell.getCellFormula()); delle librerie Microsoft.
break; A questo punto non resta che provare le librerie
} creando un file Excel. Il primo passo è aprire in
modalità nascosta l’applicazione Excel tramite il
System.out.println(“”); controllo ActiveX:
}
ActiveXComponent xls
= new ActiveXComponent(“Excel.Application”);
LISTATO 1 Breve programma che mostra il
contenuto delle celle di una riga

n.2 - gennaio/febbraio 2007 65


focus JAVA Journal

e get consentono di leggere e scrivere le proprietà di


Dispatch sheet = Dispatch.get(workbook,”ActiveShee
un oggetto.
t”).toDispatch(); L’ultimo metodo che vediamo è il metodo invoke, che
consente di chiamare i sottostanti metodi call,get e
Dispatch a1 = Dispatch.invoke(sheet, “Range”, put passando un numero arbitrario di parametri:
Dispatch.Get,
new Object[] {“A1”}, new int[1]).toDispatch(); public static Variant invoke(
Dispatch dispatchTarget,
Dispatch a2 = Dispatch.invoke(sheet, “Range”, String name,int wFlag,
Dispatch.Get, Object[] args,int[] errors);

new Object[] {“A2”}, new int[1]).toDispatch();


I parametri vengono passati attraverso args, mentre
il flag wFlag consente di selezionare la tipologia di
Dispatch.put(a1, “Value”, “123.456”);
operazione da invocare: Dispatch.Get, Dispatch.Put e
Dispatch.put(a2, “Formula”, “=A1*2”); Dispatch.Method.
} Con le nozioni appena acquisite siamo in grado di
creare uno foglio di calcolo e di popolarne le celle
LISTATO 2 Come creare uno spreadsheet e (Listato 2).
popolare le sue celle
Riesaminiamo il codice che abbiamo scritto. La prima
riga recupera la proprietà ActiveSheet; dal workbook,
Una volta aperto Excel dobbiamo creare il nuo- sullo sheet recuperato, viene invocato il metodo
vo Workbook. Questo lo facciamo recuperando Range, passando come parametro il nome della cella
l’elenco dei workbook aperti da Excel e aggiun- da modificare. Nelle ultime due righe impostiamo la
gendone uno: proprietà Value della cella con il valore 123.456 men-
tre nella cella a2 impostiamo la proprietà Formula.
Dispatch workbooks = xls.getProperty(“Workbooks”).toDispatch(); Ora possiamo chiudere il documento Excel appena
Dispatch workbook = Dispatch.get(workbooks,”Add”).toDispatch(); creato:

A questo punto, soffermiamoci su queste righe Variant f = new Variant(false);


di codice appena scritte. Come possiamo notare Dispatch.call(workbook, “Close”, f);
dall’ultima riga, l’invocazione dei metodi è molto xl.invoke(“Quit”, new Variant[] {});
particolare. Per eseguire le operazioni sulle API na-
tive di Office, si deve infatti passare, praticamente Come si può vedere, il codice scritto per JACOB è
sempre, attraverso i metodi statici della classe Di- poco intuitivo e leggibile; soprattutto, in fase di com-
spatch. Questi metodi prendono sempre come primo pilazione non può essere fatta alcuna verifica sulla
parametro l’oggetto Dispatch su cui si sta agendo; e correttezza delle chiamate ai metodi nativi COM.
come secondo parametro il nome del metodo o della Tutto “passa” attraverso metodi molto generici. Vi-
proprietà su cui si agisce. Infine i parametri suc- ceversa, da un punto di vista funzionale il supporto
cessivi verranno passati alle librerie native. L’even- JACOB è molto più completo e la compatibilità dei
tuale valore restituito dai metodi è di tipo Variant, documenti è totale.
come nella migliore delle tradizioni Visual Basic.
Se si vuole interagire con il Variant, per richiamare
metodi o leggere/impostare proprietà, occorre recu- Conclusioni
perare il Dispatch di quel Variant con il metodo to-
Dispatch(). I principali metodi messi a disposizione A questo punto è bene capire quando usare Jakarta
dal Dispatch sono i seguenti: POI e quando usare JACOB. Sicuramente l’approc-
cio POI è portabile e semplice, ma pone delle forti
public static Variant call( limitazioni. Va quindi usato quando non ci sono di
Dispatch dispatchTarget, mezzo macro, formule complesse o grafici. Inoltre, se
String methodName,Objecti obji,...); sono presenti delle macro, i file possono corrompersi.
L’approccio JACOB vi lega all’ambiente: spesso non è
public static Variant get( un grosso problema, se l’utente ha necessità di otte-
Dispatch dispatchTarget,String name); nere file in formato Excel lo fa proprio perché lavora
con Office, e la portabilità non è un prerequisito a cui
public static put( è interessato.
Dispatch dispatchTarget,
String name,Object val);

Il metodo call permette di invocare il metodo nativo Note Biografiche


methodName sull’oggetto dispatchTarget, passandogli n Luigi Zanderighi Ingegnere del software esperto nella progetta-
parametri definiti dagli oggetti obji. I due metodi put zione di architetture distribuite e software Java

66 n.2 - gennaio/febbraio 2007